diff --git a/code/datums/supply_packs/explosives.dm b/code/datums/supply_packs/explosives.dm index 76e5e9461fdd..b3a74c48b770 100644 --- a/code/datums/supply_packs/explosives.dm +++ b/code/datums/supply_packs/explosives.dm @@ -31,6 +31,17 @@ containername = "\improper explosive mine boxes crate (WARNING)" group = "Explosives" +/datum/supply_packs/explosives_satchel_charges + name = "M17 satchel charges crate (x3)" + contains = list( + /obj/item/storage/box/explosive_mines/satchel_charges, + /obj/item/storage/box/explosive_mines/satchel_charges, + /obj/item/storage/box/explosive_mines/satchel_charges, + ) + cost = 30 + containertype = /obj/structure/closet/crate/explosives + containername = "\improper explosive M17 charges crate (WARNING)" + group = "Explosives" /datum/supply_packs/explosives_m15 name = "M15 fragmentation grenades crate (x6)" contains = list( diff --git a/code/game/machinery/vending/vendor_types/requisitions.dm b/code/game/machinery/vending/vendor_types/requisitions.dm index 40942d0cbd96..f77cc818d30e 100644 --- a/code/game/machinery/vending/vendor_types/requisitions.dm +++ b/code/game/machinery/vending/vendor_types/requisitions.dm @@ -61,6 +61,8 @@ list("M40 MFHS Metal Foam Grenade", floor(scale * 6), /obj/item/explosive/grenade/metal_foam, VENDOR_ITEM_REGULAR), list("Plastic Explosives", floor(scale * 3), /obj/item/explosive/plastic, VENDOR_ITEM_REGULAR), list("Breaching Charge", floor(scale * 2), /obj/item/explosive/plastic/breaching_charge, VENDOR_ITEM_REGULAR), + list("Satchel Charges", floor(scale*3), /obj/item/explosive/satchel_charge, VENDOR_ITEM_REGULAR), + list("Satchel Charge Box (x3 charges)", floor(scale*3), /obj/item/storage/box/explosive_mines/satchel_charges/req, VENDOR_ITEM_REGULAR), list("M5510 Laser-Guided Rocket", floor(scale), /obj/item/ammo_magazine/rocket/brute, VENDOR_ITEM_REGULAR), list("WEBBINGS", -1, null, null), diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm index 54cfd014f86e..d5643f64d662 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_engineer.dm @@ -9,6 +9,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_engi, list( list("JIMA Planted Flag", 0, /obj/item/defenses/handheld/planted_flag, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_MANDATORY), list("UA 42-F Sentry Flamer", 0, /obj/item/defenses/handheld/sentry/flamer, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_MANDATORY), list("UA 571-C Sentry Gun", 0, /obj/item/defenses/handheld/sentry, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_MANDATORY), + list("Satchel charge breacher belt",0, /obj/item/storage/belt/marine/satchelcharge, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_MANDATORY), list("M6H-BRUTE",0, /obj/item/storage/belt/gun/brutepack/full, MARINE_CAN_BUY_ATTACHMENT, VENDOR_ITEM_MANDATORY), list("Sentry Upgrade kit", 15, /obj/item/engi_upgrade_kit, null, VENDOR_ITEM_REGULAR), @@ -22,6 +23,7 @@ GLOBAL_LIST_INIT(cm_vending_gear_engi, list( list("Plasteel x10", 7, /obj/item/stack/sheet/plasteel/small_stack, null, VENDOR_ITEM_RECOMMENDED), list("Plastic Explosive", 3, /obj/item/explosive/plastic, null, VENDOR_ITEM_REGULAR), list("Breaching Charge", 5, /obj/item/explosive/plastic/breaching_charge, null, VENDOR_ITEM_RECOMMENDED), + list("Satchel Charge Box (x5 charges)", 10, /obj/item/storage/box/explosive_mines/satchel_charges, null, VENDOR_ITEM_RECOMMENDED), list("Sandbags x25", 10, /obj/item/stack/sandbags_empty/half, null, VENDOR_ITEM_RECOMMENDED), list("Super-Capacity Power Cell", 10, /obj/item/cell/super, null, VENDOR_ITEM_REGULAR), list("ES-11 Mobile Fuel Canister", 4, /obj/item/tool/weldpack/minitank, null, VENDOR_ITEM_REGULAR), diff --git a/code/game/objects/effects/aliens.dm b/code/game/objects/effects/aliens.dm index 204442932372..bf04a5f71420 100644 --- a/code/game/objects/effects/aliens.dm +++ b/code/game/objects/effects/aliens.dm @@ -584,8 +584,8 @@ if(empowered) new /datum/effects/acid(H, linked_xeno, initial(linked_xeno.caste_type)) var/found = null - for (var/datum/effects/boiler_trap/F in H.effects_list) - if (F.cause_data && F.cause_data.resolve_mob() == linked_xeno) + for(var/datum/effects/boiler_trap/F in H.effects_list) + if(F.cause_data && F.cause_data.resolve_mob() == linked_xeno) found = F break if(found) diff --git a/code/game/objects/items/explosives/explosive.dm b/code/game/objects/items/explosives/explosive.dm index 461d4adcef99..24cd41f404d0 100644 --- a/code/game/objects/items/explosives/explosive.dm +++ b/code/game/objects/items/explosives/explosive.dm @@ -279,3 +279,178 @@ falloff_mode = EXPLOSION_FALLOFF_SHAPE_LINEAR to_chat(usr, SPAN_NOTICE("You disable [src]'s blast wave dampener, restoring the blast radius to full.")) playsound(loc, 'sound/items/Screwdriver2.ogg', 25, 0, 6) + +/obj/item/satchel_charge_detonator + name = "M38-D Multipurpose Detonator" + desc = "An ergonomic detonator capable of detonating multiple types of command explosives, notable being satchel charges, detcords and plastic explosives." + icon = 'icons/obj/items/weapons/grenade.dmi' + icon_state = "detonator" + w_class = SIZE_TINY + + /// list of linked explosives to handle + var/list/linked_charges = list() + var/pressed = FALSE + var/maximal_connected_charges = 5 + +/obj/item/satchel_charge_detonator/proc/can_connect() + if(length(linked_charges)>= maximal_connected_charges) + return FALSE + return TRUE + +/obj/item/satchel_charge_detonator/attack_self(mob/user, parameters) // when attackl_self, detonate charges + . = ..() + if(!skillcheck(user, SKILL_ENGINEER ,SKILL_ENGINEER_ENGI)) + to_chat(user, SPAN_WARNING("The ID lock prevents you from using this.")) + return + + to_chat(user, SPAN_BOLDWARNING("You hold down the detonator button.")) + if(pressed) + return + pressed = TRUE + flick("detonator_active", src) + playsound(src.loc, 'sound/handling/charge-detonator.ogg', 25, 1) + sleep(40) + pressed = FALSE + var/detonation_count = 0 + for(var/obj/item/explosive/satchel_charge/charges in linked_charges) + if(charges.detonate(src)) + detonation_count++ + to_chat(user, SPAN_NOTICE("[src] reported [detonation_count] charge[detonation_count > 1 ? "s" : ""] detonated.")) + +/obj/item/satchel_charge_detonator/clicked(mob/user, list/mods) // kill me + if (isobserver(user) || isxeno(user)) + return + + if (mods["alt"]) // alt+click to ping charges? + to_chat(user, SPAN_NOTICE("You ping the detonator's [length(linked_charges)] linked charges.")) + for(var/obj/item/explosive/satchel_charge/charges in linked_charges) + flick("satchel_primed", charges) + charges.beep(TRUE) + return TRUE + return + +/obj/item/satchel_charge_detonator/Destroy() + for(var/obj/item/explosive/satchel_charge/charges in linked_charges) + charges.linked_detonator = null + linked_charges = null + return ..() + +/obj/item/explosive/satchel_charge + name = "M17 Satchel Charge" + desc = "After linked to a detonator, and thrown, will become primed and able to be detonated." + desc_lore = "The M17 is a simple satchel charge system used by Marines in situations where their usual fire support can't reach, designed to be thrown at or into structures before exploding. This one is set to automatically disarm after a short period, to reduce the chances of civilian injuries from abandoned UXO.\nTo detonate it, link the satchel charge with the included M38-D universal detonator beforehand, then throw it. The detonator's safety mechanism takes four seconds to deactivate after being thrown." + gender = PLURAL + icon = 'icons/obj/items/weapons/grenade.dmi' + icon_state = "satchel" + flags_item = NOBLUDGEON + w_class = SIZE_SMALL + antigrief_protection = TRUE + max_container_volume = 180 + reaction_limits = list( "max_ex_power" = 260, "base_ex_falloff" = 90, "max_ex_shards" = 64, + "max_fire_rad" = 6, "max_fire_int" = 26, "max_fire_dur" = 30, + "min_fire_rad" = 2, "min_fire_int" = 4, "min_fire_dur" = 5 + ) + + var/prime_time = 3 SECONDS + var/prime_timer = null + var/obj/item/satchel_charge_detonator/linked_detonator = null + var/activated = FALSE + var/armed = FALSE + +/obj/item/explosive/satchel_charge/attack_self(mob/user) + . = ..() + if(antigrief_protection && user.faction == FACTION_MARINE && explosive_antigrief_check(src, user)) + to_chat(user, SPAN_WARNING("[name]'s safe-area accident inhibitor prevents you from planting it!")) + msg_admin_niche("[key_name(user)] attempted to prime \a [name] in [get_area(src)] [ADMIN_JMP(src.loc)]") + return + if(!linked_detonator) + to_chat(user, SPAN_NOTICE("This Charge is not linked to any detonator")) + return + icon_state = "satchel_primed" + playsound(src.loc, 'sound/handling/charge-primed.ogg', 25, 1) + var/mob/living/carbon/living_carbon = user + if(istype(living_carbon) && !living_carbon.throw_mode) + living_carbon.toggle_throw_mode(THROW_MODE_NORMAL) + to_chat(user, SPAN_NOTICE("You activate the M17 Satchel Charge, it will now arm itself after a short time once thrown.")) + w_class = SIZE_MASSIVE + activated = TRUE + addtimer(CALLBACK(src, PROC_REF(un_activate)), 10 SECONDS, TIMER_UNIQUE) + +/obj/item/explosive/satchel_charge/attackby(obj/item/weapon_thing, mob/user) + . = ..() + if(armed) + to_chat(user, SPAN_WARNING("This charge is armed, its linking cannot be altered unless disarmed.")) + return + if(!istype(weapon_thing, /obj/item/satchel_charge_detonator)) + return + var/obj/item/satchel_charge_detonator/detonator = weapon_thing + if(linked_detonator == detonator) + detonator.linked_charges -= src + linked_detonator = null + to_chat(user, SPAN_NOTICE("You unlink the charge from [detonator].")) + icon_state = "satchel" + return + + if(!detonator.can_connect()) + to_chat(user, SPAN_NOTICE("[detonator] already has too many linked charges.")) + return + else + linked_detonator?.linked_charges -= src + detonator.linked_charges |= src + linked_detonator = detonator + to_chat(user, SPAN_NOTICE("[detonator] indicates a new charge has been linked.")) + playsound(src.loc, 'sound/handling/charge-connection.ogg', 25, 1) + icon_state = "satchel_linked" + +/obj/item/explosive/satchel_charge/proc/un_activate() + if(activated) + activated = FALSE + w_class = SIZE_SMALL + if(linked_detonator) + icon_state = "satchel_linked" + else + icon_state = "satchel" + +/obj/item/explosive/satchel_charge/throw_atom(atom/target, range, speed, atom/thrower, spin, launch_type, pass_flags) + . = ..() + dir = get_dir(src, thrower) + if(activated && linked_detonator) + icon_state = "satchel_primed" + prime_timer = addtimer(CALLBACK(src, PROC_REF(arm)), prime_time, TIMER_UNIQUE) + beep() + +/obj/item/explosive/satchel_charge/proc/beep(beep_once) + playsound(src.loc, 'sound/weapons/mine_tripped.ogg', 10, 1) + if(!armed && beep_once != TRUE) + addtimer(CALLBACK(src, PROC_REF(beep)), 1 SECONDS, TIMER_UNIQUE) + + +/obj/item/explosive/satchel_charge/proc/arm() + activated = FALSE + if(!linked_detonator || armed) + return + icon_state = "satchel_armed" + armed = TRUE + +/obj/item/explosive/satchel_charge/pickup(mob/user) + if(armed) + if(linked_detonator) + icon_state = "satchel_linked" + else + icon_state = "satchel" + armed = FALSE + w_class = SIZE_SMALL + return ..() + +/obj/item/explosive/satchel_charge/proc/detonate(triggerer) + if(!armed || linked_detonator != triggerer) + return FALSE + cell_explosion(loc, 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, cause_data) + qdel(src) + return TRUE + +/obj/item/explosive/satchel_charge/Destroy() + linked_detonator?.linked_charges -= src + linked_detonator = null + return ..() + diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index ad3ac9128ce1..8cbcf30ff8d0 100644 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -1172,6 +1172,20 @@ new /obj/item/explosive/grenade/high_explosive/airburst(src) new /obj/item/explosive/grenade/high_explosive/airburst(src) +/obj/item/storage/belt/marine/satchelcharge + name = "\improper M910 Pattern EOD Harness" + desc = "A specialized storage rig designed to carry a high volume of various demolition charges, blasting caps, and fuses for explosive ordinance disposal. A separate, smaller pouch made to fit a detonator is affixed to the upper part of the shoulder strap. Made to hold a detonator, this pouch has been recently fitted with an anti-electromagnetic liner after one too many... incidents." + storage_slots = 26 + can_hold = list(/obj/item/explosive/satchel_charge, /obj/item/satchel_charge_detonator) + var/starting_charges = 20 + icon_state = "satchelbelt" + item_state = "satchelbelt" + +/obj/item/storage/belt/marine/satchelcharge/fill_preset_inventory() + new /obj/item/satchel_charge_detonator(src) + for(var/i = 1 to starting_charges ) + new /obj/item/explosive/satchel_charge(src) + /obj/item/storage/belt/grenade/large/dutch name = "\improper Dutch's Grenadier Rigging" desc = "A high capacity rig filled to the brim with all the explosives you could ask for, what else is there to want?" diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index b3663ec13a2a..af720d287774 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -688,6 +688,30 @@ for(var/i in 1 to 5) new /obj/item/explosive/mine/pmc(src) +/obj/item/storage/box/explosive_mines/satchel_charges + name = "\improper M17 satchel charge box (x5)" + desc = "A secure box holding five M17 satchel charges, don't lose it!" + icon_state = "satchelbox" + max_storage_space = 16 + can_hold = list( + /obj/item/explosive/satchel_charge, + /obj/item/satchel_charge_detonator, + ) + +/obj/item/storage/box/explosive_mines/satchel_charges/fill_preset_inventory() + for(var/i in 1 to 5) + new /obj/item/explosive/satchel_charge(src) + +/obj/item/storage/box/explosive_mines/satchel_charges/req + name = "\improper M17 satchel charge box (x3)" + max_storage_space = 10 + desc = "A secure box holding three M17 satchel charges." + +/obj/item/storage/box/explosive_mines/satchel_charges/req/fill_preset_inventory() + new /obj/item/satchel_charge_detonator(src) + for(var/i in 1 to 3) + new /obj/item/explosive/satchel_charge(src) + /obj/item/storage/box/m94 name = "\improper M94 marking flare pack" desc = "A packet of eight M94 Marking Flares. Carried by USCM soldiers to light dark areas that cannot be reached with the usual TNR Shoulder Lamp." diff --git a/code/game/objects/items/storage/pouch.dm b/code/game/objects/items/storage/pouch.dm index f6f8a966dcc9..451cc4b54824 100644 --- a/code/game/objects/items/storage/pouch.dm +++ b/code/game/objects/items/storage/pouch.dm @@ -645,6 +645,8 @@ /obj/item/explosive/plastic, /obj/item/explosive/mine, /obj/item/explosive/grenade, + /obj/item/explosive/satchel_charge, + /obj/item/satchel_charge_detonator, ) /obj/item/storage/pouch/explosive/attackby(obj/item/W, mob/user) diff --git a/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm index e56721299d52..9a3d541b7163 100644 --- a/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm +++ b/code/modules/mob/living/carbon/xenomorph/strains/castes/boiler/trapper.dm @@ -74,7 +74,7 @@ var/mob/living/carbon/human/target_human = target_atom var/datum/effects/boiler_trap/found = null - for (var/datum/effects/boiler_trap/trap in target_human.effects_list) + for(var/datum/effects/boiler_trap/trap in target_human.effects_list) if (trap.cause_data?.resolve_mob() == bound_xeno) found = trap break diff --git a/icons/mob/humans/onmob/clothing/belts/belts_by_map/classic.dmi b/icons/mob/humans/onmob/clothing/belts/belts_by_map/classic.dmi index b14650e4c6b8..28db4fb3bcf8 100644 Binary files a/icons/mob/humans/onmob/clothing/belts/belts_by_map/classic.dmi and b/icons/mob/humans/onmob/clothing/belts/belts_by_map/classic.dmi differ diff --git a/icons/mob/humans/onmob/clothing/belts/belts_by_map/desert.dmi b/icons/mob/humans/onmob/clothing/belts/belts_by_map/desert.dmi index 6895c535e12d..9dbe401b9141 100644 Binary files a/icons/mob/humans/onmob/clothing/belts/belts_by_map/desert.dmi and b/icons/mob/humans/onmob/clothing/belts/belts_by_map/desert.dmi differ diff --git a/icons/mob/humans/onmob/clothing/belts/belts_by_map/jungle.dmi b/icons/mob/humans/onmob/clothing/belts/belts_by_map/jungle.dmi index c0eb59845744..4beff501368a 100644 Binary files a/icons/mob/humans/onmob/clothing/belts/belts_by_map/jungle.dmi and b/icons/mob/humans/onmob/clothing/belts/belts_by_map/jungle.dmi differ diff --git a/icons/mob/humans/onmob/clothing/belts/belts_by_map/snow.dmi b/icons/mob/humans/onmob/clothing/belts/belts_by_map/snow.dmi index 3741cae5b9e3..23b587ed1e8c 100644 Binary files a/icons/mob/humans/onmob/clothing/belts/belts_by_map/snow.dmi and b/icons/mob/humans/onmob/clothing/belts/belts_by_map/snow.dmi differ diff --git a/icons/mob/humans/onmob/clothing/belts/belts_by_map/urban.dmi b/icons/mob/humans/onmob/clothing/belts/belts_by_map/urban.dmi index 3741cae5b9e3..786e86d33b68 100644 Binary files a/icons/mob/humans/onmob/clothing/belts/belts_by_map/urban.dmi and b/icons/mob/humans/onmob/clothing/belts/belts_by_map/urban.dmi differ diff --git a/icons/obj/items/clothing/belts/belts_by_map/classic.dmi b/icons/obj/items/clothing/belts/belts_by_map/classic.dmi index 55fd279f3235..fa9187eea479 100644 Binary files a/icons/obj/items/clothing/belts/belts_by_map/classic.dmi and b/icons/obj/items/clothing/belts/belts_by_map/classic.dmi differ diff --git a/icons/obj/items/clothing/belts/belts_by_map/desert.dmi b/icons/obj/items/clothing/belts/belts_by_map/desert.dmi index ac7e1fc9e073..8f3425ac5070 100644 Binary files a/icons/obj/items/clothing/belts/belts_by_map/desert.dmi and b/icons/obj/items/clothing/belts/belts_by_map/desert.dmi differ diff --git a/icons/obj/items/clothing/belts/belts_by_map/jungle.dmi b/icons/obj/items/clothing/belts/belts_by_map/jungle.dmi index 55fd279f3235..fa9187eea479 100644 Binary files a/icons/obj/items/clothing/belts/belts_by_map/jungle.dmi and b/icons/obj/items/clothing/belts/belts_by_map/jungle.dmi differ diff --git a/icons/obj/items/clothing/belts/belts_by_map/snow.dmi b/icons/obj/items/clothing/belts/belts_by_map/snow.dmi index 8588d77189e0..368481c81b74 100644 Binary files a/icons/obj/items/clothing/belts/belts_by_map/snow.dmi and b/icons/obj/items/clothing/belts/belts_by_map/snow.dmi differ diff --git a/icons/obj/items/storage/packets.dmi b/icons/obj/items/storage/packets.dmi index e382636d004d..03f2dbbac333 100644 Binary files a/icons/obj/items/storage/packets.dmi and b/icons/obj/items/storage/packets.dmi differ diff --git a/icons/obj/items/weapons/grenade.dmi b/icons/obj/items/weapons/grenade.dmi index 59fed46a2cbf..96b607290ded 100644 Binary files a/icons/obj/items/weapons/grenade.dmi and b/icons/obj/items/weapons/grenade.dmi differ diff --git a/sound/handling/charge-connection.ogg b/sound/handling/charge-connection.ogg new file mode 100644 index 000000000000..8b92f2f42d02 Binary files /dev/null and b/sound/handling/charge-connection.ogg differ diff --git a/sound/handling/charge-detonator.ogg b/sound/handling/charge-detonator.ogg new file mode 100644 index 000000000000..8bb228ab76c6 Binary files /dev/null and b/sound/handling/charge-detonator.ogg differ diff --git a/sound/handling/charge-primed.ogg b/sound/handling/charge-primed.ogg new file mode 100644 index 000000000000..bdfeabf64fdb Binary files /dev/null and b/sound/handling/charge-primed.ogg differ