From 3c1d985e317a38dee4de1ca75bd836e02bf96292 Mon Sep 17 00:00:00 2001
From: CRUNCH <143041327+CRUNCH-Borg@users.noreply.github.com>
Date: Tue, 21 Apr 2026 05:58:44 +0100
Subject: [PATCH] Attack Chain Migration: Grenades & Plastic Explosives
(#31874)
* Update bomb.dm
* migration
* Fix CI
* Update mining_charges.dm
* Update deployable.dm
---
code/game/machinery/deployable.dm | 7 +-
code/game/objects/items/weapons/explosives.dm | 119 ++++++++-------
.../items/weapons/grenades/bananade.dm | 29 ++--
.../items/weapons/grenades/chem_grenade.dm | 136 ++++++++++--------
.../items/weapons/grenades/ghettobomb.dm | 42 +++---
.../objects/items/weapons/grenades/grenade.dm | 17 ++-
.../items/weapons/grenades/syndieminibomb.dm | 9 +-
.../mining/equipment/mining_charges.dm | 74 +++++-----
.../mining/equipment/wormhole_jaunter.dm | 4 +-
code/modules/mod/modules/modules_security.dm | 17 ++-
10 files changed, 252 insertions(+), 202 deletions(-)
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index 04926808e32..84071704fef 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -384,10 +384,9 @@
to_chat(user, "[src] is now in [mode == AUTO ? mode : dir2text(mode)] mode.")
-/obj/item/grenade/barrier/dropwall/attack_self__legacy__attackchain(mob/user)
- . = ..()
+/obj/item/grenade/barrier/dropwall/activate_self(mob/user)
armer = user
-
+ return ..()
/obj/item/grenade/barrier/dropwall/end_throw()
if(active)
@@ -538,7 +537,7 @@
inhand_icon_state = "flashbang"
var/owner_uid
-/obj/item/grenade/turret/attack_self__legacy__attackchain(mob/user)
+/obj/item/grenade/turret/activate_self(mob/user)
owner_uid = user.UID()
return ..()
diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm
index c8c1fe95428..486a710c5ce 100644
--- a/code/game/objects/items/weapons/explosives.dm
+++ b/code/game/objects/items/weapons/explosives.dm
@@ -8,7 +8,8 @@
det_time = 10
display_timer = FALSE
origin_tech = "syndicate=1"
- var/atom/target = null
+ custom_activation = TRUE
+ var/atom/target_atom = null
var/image_overlay = null
var/obj/item/assembly/nadeassembly = null
var/assemblyattacher
@@ -28,30 +29,34 @@
/obj/item/grenade/plastic/Destroy()
QDEL_NULL(nadeassembly)
- target = null
+ target_atom = null
plastic_overlay_target = null
return ..()
-/obj/item/grenade/plastic/attackby__legacy__attackchain(obj/item/I, mob/user, params)
- if(!nadeassembly && istype(I, /obj/item/assembly))
- var/obj/item/assembly/A = I
+/obj/item/grenade/plastic/wirecutter_act(mob/living/user, obj/item/used)
+ if(nadeassembly)
+ playsound(src, used.usesound, 20, 1)
+ nadeassembly.loc = get_turf(src)
+ nadeassembly.master = null
+ nadeassembly = null
+ update_icon(UPDATE_ICON_STATE)
+ return TRUE
+
+/obj/item/grenade/plastic/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(!nadeassembly && istype(used, /obj/item/assembly))
+ var/obj/item/assembly/A = used
if(!user.transfer_item_to(A, src))
return ..()
+
nadeassembly = A
A.master = src
assemblyattacher = user.ckey
to_chat(user, SPAN_NOTICE("You add [A] to [src]."))
playsound(src, 'sound/weapons/tap.ogg', 20, 1)
update_icon(UPDATE_ICON_STATE)
- return
- if(nadeassembly && istype(I, /obj/item/wirecutters))
- playsound(src, I.usesound, 20, 1)
- nadeassembly.loc = get_turf(src)
- nadeassembly.master = null
- nadeassembly = null
- update_icon(UPDATE_ICON_STATE)
- return
- ..()
+ return ITEM_INTERACT_COMPLETE
+
+ return ..()
/obj/item/grenade/plastic/proc/on_atom_entered(datum/source, atom/movable/entered)
if(nadeassembly)
@@ -71,36 +76,43 @@
var/obj/item/assembly/voice/voice_analyzer = nadeassembly
voice_analyzer.hear_input(M, msg, 1)
-/obj/item/grenade/plastic/attack_self__legacy__attackchain(mob/user)
+/obj/item/grenade/plastic/activate_self(mob/user)
+ if(..())
+ return ITEM_INTERACT_COMPLETE
+
if(nadeassembly)
nadeassembly.attack_self__legacy__attackchain(user)
- return
+ return ITEM_INTERACT_COMPLETE
+
var/newtime = input(usr, "Please set the timer.", "Timer", det_time) as num
if(user.is_in_active_hand(src))
newtime = clamp(newtime, 10, 60000)
det_time = newtime
to_chat(user, "Timer set for [det_time] seconds.")
+ return ITEM_INTERACT_COMPLETE
+
+/obj/item/grenade/plastic/interact_with_atom(atom/target, mob/living/user, list/modifiers)
+ if(isstorage(target) || ismodcontrol(target))
+ return ..() // Let us not have people C4 themselves. Especially with a now 1.5 second do_after().
+
+ if(ismob(target))
+ if(isobserver(target))
+ to_chat(user, SPAN_WARNING("Your hand just phases through [target]!"))
+ return ITEM_INTERACT_COMPLETE
+
+ var/mob/M = target
+ if(M.stat == CONSCIOUS)
+ to_chat(user, SPAN_WARNING("You can't get the [src] to stick to [M]! Perhaps if [M] was asleep or dead you could attach it?"))
+ return ITEM_INTERACT_COMPLETE
-/obj/item/grenade/plastic/afterattack__legacy__attackchain(mob/AM, mob/user, flag)
- if(!flag)
- return
- if(ismob(AM) && AM.stat == CONSCIOUS)
- to_chat(user, SPAN_WARNING("You can't get the [src] to stick to [AM]! Perhaps if [AM] was asleep or dead you could attach it?"))
- return
- if(isstorage(AM) || ismodcontrol(AM))
- return ..() //Let us not have people c4 themselfs. Especially with a now 1.5 second do_after
- if(isobserver(AM))
- to_chat(user, SPAN_WARNING("Your hand just phases through [AM]!"))
- return
to_chat(user, SPAN_NOTICE("You start planting [src].[isnull(nadeassembly) ? " The timer is set to [det_time]..." : ""]"))
-
- if(do_after(user, 1.5 SECONDS * toolspeed, target = AM))
+ if(do_after(user, 1.5 SECONDS * toolspeed, target = target))
if(!user.unequip(src))
- return
+ to_chat(user, SPAN_DANGER("[src] is stuck to your hand!"))
+ return ITEM_INTERACT_COMPLETE
- target = AM
+ target_atom = target
loc = null
-
if(notify_admins)
message_admins("[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at ([target.x],[target.y],[target.z] - JMP) with [det_time] second fuse", 0, 1)
log_game("[key_name(user)] planted [name] on [target.name] at ([target.x],[target.y],[target.z]) with [det_time] second fuse")
@@ -126,8 +138,9 @@
plastic_overlay_target.add_overlay(plastic_overlay)
if(!nadeassembly)
- to_chat(user, SPAN_NOTICE("You plant the bomb. Timer counting down from [det_time]."))
+ to_chat(user, SPAN_DANGER("You plant the bomb. Timer counting down from [det_time]."))
addtimer(CALLBACK(src, PROC_REF(prime)), det_time SECONDS)
+ return ITEM_INTERACT_COMPLETE
/obj/item/grenade/plastic/suicide_act(mob/user)
message_admins("[key_name_admin(user)]([ADMIN_QUE(user,"?")]) ([ADMIN_FLW(user,"FLW")]) suicided with [src.name] at ([user.x],[user.y],[user.z] - JMP)",0,1)
@@ -150,7 +163,7 @@
else if(role == SPECIAL_ROLE_DEATHSQUAD || role == ROLE_ERT)
message_say = "FOR NANOTRASEN!"
user.say(message_say)
- target = user
+ target_atom = user
sleep(10)
prime()
user.gib()
@@ -184,9 +197,9 @@
. = ..()
desc += SPAN_NOTICE("
Use [src] in-hand to adjust the detonation timer.")
-/obj/item/grenade/plastic/c4/afterattack__legacy__attackchain(atom/movable/AM, mob/user, flag)
- aim_dir = get_dir(user, AM)
- ..()
+/obj/item/grenade/plastic/c4/interact_with_atom(atom/target, mob/living/user, list/modifiers)
+ aim_dir = get_dir(user, target)
+ return ..()
/obj/item/grenade/plastic/c4/prime()
var/turf/location
@@ -194,14 +207,14 @@
plastic_overlay_target.cut_overlay(plastic_overlay, TRUE)
if(istype(plastic_overlay_target, /obj/effect/plastic))
qdel(plastic_overlay_target)
- if(target)
- if(!QDELETED(target))
- location = get_turf(target)
- if(!ex_breach && iswallturf(target)) //Walls get dismantled instead of destroyed to avoid making unwanted holes to space.
- var/turf/simulated/wall/W = target
+ if(target_atom)
+ if(!QDELETED(target_atom))
+ location = get_turf(target_atom)
+ if(!ex_breach && iswallturf(target_atom)) //Walls get dismantled instead of destroyed to avoid making unwanted holes to space.
+ var/turf/simulated/wall/W = target_atom
W.dismantle_wall(TRUE, TRUE)
else
- target.ex_act(EXPLODE_DEVASTATE)
+ target_atom.ex_act(EXPLODE_DEVASTATE)
else
location = get_turf(src)
if(location)
@@ -238,10 +251,10 @@
/obj/item/grenade/plastic/c4/shaped/flash/prime()
var/turf/T
- if(target && target.density)
- T = get_step(get_turf(target), aim_dir)
- else if(target)
- T = get_turf(target)
+ if(target_atom && target_atom.density)
+ T = get_step(get_turf(target_atom), aim_dir)
+ else if(target_atom)
+ T = get_turf(target_atom)
else
T = get_turf(src)
@@ -263,15 +276,15 @@
plastic_overlay_target.cut_overlay(plastic_overlay, TRUE)
if(istype(plastic_overlay_target, /obj/effect/plastic))
qdel(plastic_overlay_target)
- if(target)
- if(!QDELETED(target))
- location = get_turf(target)
+ if(target_atom)
+ if(!QDELETED(target_atom))
+ location = get_turf(target_atom)
else
location = get_turf(src)
if(location)
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(8, FALSE, location, aim_dir)
- if(target && target.density)
+ if(target_atom && target_atom.density)
var/turf/T = get_step(location, aim_dir)
for(var/turf/simulated/wall/W in range(1, location))
W.thermitemelt(speed = 30)
@@ -282,8 +295,8 @@
addtimer(CALLBACK(null, GLOBAL_PROC_REF(explosion), T, 0, 0, 2), 3)
addtimer(CALLBACK(smoke, TYPE_PROC_REF(/datum/effect_system/smoke_spread, start)), 3)
- if(isliving(target))
- var/mob/living/M = target
+ if(isliving(target_atom))
+ var/mob/living/M = target_atom
M.adjust_fire_stacks(2)
M.IgniteMob()
qdel(src)
diff --git a/code/game/objects/items/weapons/grenades/bananade.dm b/code/game/objects/items/weapons/grenades/bananade.dm
index a6311031519..01a26aeaf14 100644
--- a/code/game/objects/items/weapons/grenades/bananade.dm
+++ b/code/game/objects/items/weapons/grenades/bananade.dm
@@ -30,27 +30,22 @@
desc = "A grenade casing made of bananium."
icon_state = "banana_casing"
deliveryamt = 0
-
-/obj/item/grenade/bananade/casing/attack_hand()
- return // No activating an empty grenade
-
-/obj/item/grenade/bananade/casing/attack_self__legacy__attackchain()
- return // Stop trying to break stuff
+ custom_activation = TRUE // Used to make it unprimable.
/obj/item/grenade/bananade/casing/prime()
- return // The grenade isnt completed yet, dont even try to blow it up
+ return // The grenade isnt completed yet, dont even try to blow it up!
-/obj/item/grenade/bananade/casing/attackby__legacy__attackchain(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/grown/bananapeel))
- if(deliveryamt < 9)
- to_chat(user, "You add another banana peel to the assembly.")
- deliveryamt += 1
- qdel(I)
- else
- to_chat(user, SPAN_NOTICE("The bananade is full, screwdriver it shut to ready it."))
- return
+/obj/item/grenade/bananade/casing/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(!istype(used, /obj/item/grown/bananapeel))
+ return ..()
- return ..()
+ if(deliveryamt < 9)
+ to_chat(user, SPAN_NOTICE("You add another banana peel to the assembly"))
+ deliveryamt += 1
+ qdel(used)
+ else
+ to_chat(user, SPAN_WARNING("[src] is full. Screwdriver it shut to ready it."))
+ return ITEM_INTERACT_COMPLETE
/obj/item/grenade/bananade/casing/screwdriver_act(mob/living/user, obj/item/I)
if(!deliveryamt)
diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm
index 352bf757c7e..bec43d3e850 100644
--- a/code/game/objects/items/weapons/grenades/chem_grenade.dm
+++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm
@@ -7,6 +7,7 @@
desc = "A do it yourself grenade casing!"
icon_state = "chemg"
materials = list(MAT_METAL = 2000)
+ custom_activation = TRUE
var/bomb_state = "chembomb"
var/payload_name = null // used for spawned grenades
force = 2
@@ -93,7 +94,10 @@
underlays += "[O]_r"
-/obj/item/grenade/chem_grenade/attack_self__legacy__attackchain(mob/user)
+/obj/item/grenade/chem_grenade/activate_self(mob/user)
+ if(..())
+ return ITEM_INTERACT_COMPLETE
+
if(stage == READY && !active)
var/turf/bombturf = get_turf(src)
var/area/A = get_area(bombturf)
@@ -128,43 +132,45 @@
return TRUE
return ..()
-/obj/item/grenade/chem_grenade/attackby__legacy__attackchain(obj/item/I, mob/user, params)
- if(istype(I,/obj/item/hand_labeler))
- var/obj/item/hand_labeler/HL = I
+/obj/item/grenade/chem_grenade/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(istype(used, /obj/item/hand_labeler))
+ var/obj/item/hand_labeler/HL = used
if(length(HL.label))
label = " ([HL.label])"
- return 0
- else
- if(label)
- label = null
- update_icon(UPDATE_ICON_STATE)
- to_chat(user, "You remove the label from [src].")
- return 1
- else if(stage == WIRED && is_type_in_list(I, allowed_containers))
+ return ITEM_INTERACT_COMPLETE
+ if(label)
+ label = null
+ update_icon(UPDATE_ICON_STATE)
+ to_chat(user, "You remove the label from [src].")
+ return ITEM_INTERACT_COMPLETE
+
+ if(stage == WIRED && is_type_in_list(used, allowed_containers))
if(length(beakers) == 0)
container_type = TRANSPARENT // Allows to see reagents in player's made bombs
- if(length(beakers) == 2)
+ if(length(beakers) >= 2)
to_chat(user, SPAN_NOTICE("[src] can not hold more containers."))
- return
- else
- if(I.reagents.total_volume)
- to_chat(user, SPAN_NOTICE("You add [I] to the assembly."))
- user.drop_item()
- I.forceMove(src)
- beakers += I
- // Saving reagents to show them via scanners
- reagents.reagent_list.Add(I.reagents.reagent_list)
- reagents.update_total()
- else
- to_chat(user, SPAN_NOTICE("[I] is empty."))
+ return ITEM_INTERACT_COMPLETE
- else if(stage == EMPTY && istype(I, /obj/item/assembly_holder))
- var/obj/item/assembly_holder/A = I
+ if(used.reagents.total_volume)
+ to_chat(user, SPAN_NOTICE("You add [used] to the assembly."))
+ user.drop_item()
+ used.forceMove(src)
+ beakers += used
+ // Saving reagents to show them via scanners
+ reagents.reagent_list.Add(used.reagents.reagent_list)
+ reagents.update_total()
+ else
+ to_chat(user, SPAN_NOTICE("[used] is empty."))
+ return ITEM_INTERACT_COMPLETE
+
+ if(stage == EMPTY && istype(used, /obj/item/assembly_holder))
+ var/obj/item/assembly_holder/A = used
if(!A.secured)
- return
- if(isigniter(A.a_left) == isigniter(A.a_right)) //Check if either part of the assembly has an igniter, but if both parts are igniters, then fuck it
- return
+ return ITEM_INTERACT_COMPLETE
+
+ if(isigniter(A.a_left) == isigniter(A.a_right)) // Check if either part of the assembly has an igniter, but if both parts are igniters, then fuck it.
+ return ITEM_INTERACT_COMPLETE
user.drop_item()
nadeassembly = A
@@ -174,34 +180,17 @@
stage = WIRED
to_chat(user, SPAN_NOTICE("You add [A] to [src]!"))
update_icon(UPDATE_ICON_STATE)
+ return ITEM_INTERACT_COMPLETE
- else if(stage == EMPTY && istype(I, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/C = I
+ if(stage == EMPTY && istype(used, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/C = used
C.use(1)
-
stage = WIRED
to_chat(user, SPAN_NOTICE("You rig [src]."))
update_icon(UPDATE_ICON_STATE)
+ return ITEM_INTERACT_COMPLETE
- else if(stage == READY && istype(I, /obj/item/wirecutters))
- to_chat(user, SPAN_NOTICE("You unlock the assembly."))
- stage = WIRED
- update_icon(UPDATE_ICON_STATE)
-
- else if(stage == WIRED && iswrench(I))
- to_chat(user, SPAN_NOTICE("You open the grenade and remove the contents."))
- stage = EMPTY
- payload_name = null
- label = null
- if(nadeassembly)
- nadeassembly.forceMove(get_turf(src))
- nadeassembly.master = null
- nadeassembly = null
- if(length(beakers))
- for(var/obj/O in beakers)
- O.forceMove(get_turf(src))
- beakers = list()
- update_icon(UPDATE_ICON_STATE)
+ return ITEM_INTERACT_COMPLETE
/obj/item/grenade/chem_grenade/screwdriver_act(mob/living/user, obj/item/I)
if(stage == WIRED)
@@ -242,6 +231,34 @@
to_chat(user, SPAN_NOTICE("You need to add an activation mechanism."))
return TRUE
+/obj/item/grenade/chem_grenade/wrench_act(mob/living/user, obj/item/I)
+ if(stage != WIRED)
+ return TRUE
+
+ to_chat(user, SPAN_NOTICE("You open the grenade and remove the contents."))
+ stage = EMPTY
+ payload_name = null
+ label = null
+ if(nadeassembly)
+ nadeassembly.forceMove(get_turf(src))
+ nadeassembly.master = null
+ nadeassembly = null
+ if(length(beakers))
+ for(var/obj/O in beakers)
+ O.forceMove(get_turf(src))
+ beakers = list()
+ update_icon(UPDATE_ICON_STATE)
+ return TRUE
+
+/obj/item/grenade/chem_grenade/wirecutter_act(mob/living/user, obj/item/I)
+ if(stage != READY)
+ return TRUE
+
+ to_chat(user, SPAN_NOTICE("You unlock the assembly."))
+ stage = WIRED
+ update_icon(UPDATE_ICON_STATE)
+ return TRUE
+
/obj/item/grenade/chem_grenade/HasProximity(atom/movable/AM)
if(nadeassembly)
nadeassembly.HasProximity(AM)
@@ -371,14 +388,15 @@
//I tried to just put it in the allowed_containers list but
//if you do that it must have reagents. If you're going to
//make a special case you might as well do it explicitly. -Sayu
-/obj/item/grenade/chem_grenade/large/attackby__legacy__attackchain(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/slime_extract) && stage == WIRED)
- to_chat(user, SPAN_NOTICE("You add [I] to the assembly."))
+/obj/item/grenade/chem_grenade/large/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(istype(used, /obj/item/slime_extract) && stage == WIRED)
+ to_chat(user, SPAN_NOTICE("You add [used] to the assembly."))
user.drop_item()
- I.loc = src
- beakers += I
- else
- return ..()
+ used.loc = src
+ beakers += used
+ return ITEM_INTERACT_COMPLETE
+
+ return ..()
/// Intended for rare cryogenic mixes. Cools the area moderately upon detonation.
/obj/item/grenade/chem_grenade/cryo
diff --git a/code/game/objects/items/weapons/grenades/ghettobomb.dm b/code/game/objects/items/weapons/grenades/ghettobomb.dm
index 4ed86dcd04d..4d7b37936bc 100644
--- a/code/game/objects/items/weapons/grenades/ghettobomb.dm
+++ b/code/game/objects/items/weapons/grenades/ghettobomb.dm
@@ -7,6 +7,7 @@
throw_range = 7
display_timer = FALSE
modifiable_timer = FALSE
+ custom_activation = TRUE
var/list/times
/obj/item/grenade/iedcasing/examine(mob/user)
@@ -33,26 +34,31 @@
can_underlay.plane = FLOAT_PLANE
underlays += can_underlay
+/obj/item/grenade/iedcasing/activate_self(mob/user)
+ if(..())
+ return ITEM_INTERACT_COMPLETE
-/obj/item/grenade/iedcasing/attack_self__legacy__attackchain(mob/user) //
- if(!active)
- if(clown_check(user))
- to_chat(user, SPAN_WARNING("You light [src]!"))
- active = TRUE
- overlays -= "improvised_grenade_filled"
- icon_state = initial(icon_state) + "_active"
- add_fingerprint(user)
- var/turf/bombturf = get_turf(src)
- var/area/A = get_area(bombturf)
+ if(active)
+ return ITEM_INTERACT_COMPLETE
+
+ if(clown_check(user))
+ to_chat(user, SPAN_WARNING("You light [src]!"))
+ active = TRUE
+ overlays -= "improvised_grenade_filled"
+ icon_state = initial(icon_state) + "_active"
+ add_fingerprint(user)
+ var/turf/bombturf = get_turf(src)
+ var/area/A = get_area(bombturf)
- message_admins("[key_name_admin(user)] has primed a [name] for detonation at [A.name] [ADMIN_JMP(bombturf)]")
- log_game("[key_name(user)] has primed a [name] for detonation at [A.name] [COORD(bombturf)]")
- investigate_log("[key_name(user)] has primed a [name] for detonation at [A.name] [COORD(bombturf)])", INVESTIGATE_BOMB)
- add_attack_logs(user, src, "has primed for detonation", ATKLOG_FEW)
- if(iscarbon(user))
- var/mob/living/carbon/C = user
- C.throw_mode_on()
- addtimer(CALLBACK(src, PROC_REF(prime)), det_time)
+ message_admins("[key_name_admin(user)] has primed a [name] for detonation at [A.name] [ADMIN_JMP(bombturf)]")
+ log_game("[key_name(user)] has primed a [name] for detonation at [A.name] [COORD(bombturf)]")
+ investigate_log("[key_name(user)] has primed a [name] for detonation at [A.name] [COORD(bombturf)])", INVESTIGATE_BOMB)
+ add_attack_logs(user, src, "has primed for detonation", ATKLOG_FEW)
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ C.throw_mode_on()
+ addtimer(CALLBACK(src, PROC_REF(prime)), det_time)
+ return ITEM_INTERACT_COMPLETE
/obj/item/grenade/iedcasing/prime() //Blowing that can up
update_mob()
diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm
index 8c48b122faa..cc80c0acd5e 100644
--- a/code/game/objects/items/weapons/grenades/grenade.dm
+++ b/code/game/objects/items/weapons/grenades/grenade.dm
@@ -13,6 +13,7 @@
resistance_flags = FLAMMABLE
max_integrity = 40
flags_2 = RANDOM_BLOCKER_2
+ new_attack_chain = TRUE
/// Has the pin been pulled?
var/active = FALSE
/// Time between the pin being pulled and detonation.
@@ -21,6 +22,8 @@
var/display_timer = TRUE
/// Can the grenade's fuze time be changed?
var/modifiable_timer = TRUE
+ /// Allows the default `activate_self()` behavour to be fully overriden.
+ var/custom_activation = FALSE
/obj/item/grenade/examine(mob/user)
. = ..()
@@ -62,11 +65,18 @@
return FALSE
return TRUE
-/obj/item/grenade/attack_self__legacy__attackchain(mob/user as mob)
+/obj/item/grenade/activate_self(mob/user)
+ if(..())
+ return ITEM_INTERACT_COMPLETE
+
+ if(custom_activation)
+ return // Let the child proc cook.
+
if(active)
- return
+ return ITEM_INTERACT_COMPLETE
+
if(!clown_check(user))
- return
+ return ITEM_INTERACT_COMPLETE
to_chat(user, SPAN_DANGER("You prime [src]! [det_time / 10] seconds!"))
active = TRUE
@@ -83,6 +93,7 @@
C.throw_mode_on()
spawn(det_time)
prime()
+ return ITEM_INTERACT_COMPLETE
/obj/item/grenade/proc/prime()
return
diff --git a/code/game/objects/items/weapons/grenades/syndieminibomb.dm b/code/game/objects/items/weapons/grenades/syndieminibomb.dm
index 03b0dcf6342..a0326c65fe6 100644
--- a/code/game/objects/items/weapons/grenades/syndieminibomb.dm
+++ b/code/game/objects/items/weapons/grenades/syndieminibomb.dm
@@ -19,12 +19,12 @@
if(HAS_TRAIT(user, TRAIT_CLUMSY))
. += SPAN_SANS("There are small glue ejectors all over the bomb.")
-/obj/item/grenade/syndieminibomb/fake/attack_self__legacy__attackchain(mob/user)
+/obj/item/grenade/syndieminibomb/fake/activate_self(mob/user)
if(!active)
set_nodrop(TRUE, user)
to_chat(user, SPAN_USERDANGER("As you activate the bomb, it emits a substance that sticks to your hand! It won't come off!"))
to_chat(user, SPAN_SANS("Uh oh."))
- . = ..()
+ return ..()
/obj/item/grenade/syndieminibomb/pen
name = "pen"
@@ -35,7 +35,8 @@
inhand_icon_state = "pen"
explosion_cause = "Syndicate minibomb (disguised as a black pen)"
-/obj/item/grenade/syndieminibomb/pen/attack_self__legacy__attackchain(mob/user)
+/obj/item/grenade/syndieminibomb/pen/activate_self(mob/user)
if(!active)
+ ..()
visible_message(SPAN_NOTICE("[user] fumbles with [src]!"))
- . = ..()
+ return ITEM_INTERACT_COMPLETE
diff --git a/code/modules/mining/equipment/mining_charges.dm b/code/modules/mining/equipment/mining_charges.dm
index 602014a86cc..f2f20ef285d 100644
--- a/code/modules/mining/equipment/mining_charges.dm
+++ b/code/modules/mining/equipment/mining_charges.dm
@@ -26,47 +26,52 @@
if(timer_off)
. += SPAN_NOTICE("The mining charge is connected to a detonator.")
-/obj/item/grenade/plastic/miningcharge/attack_self__legacy__attackchain(mob/user)
- if(nadeassembly)
- nadeassembly.attack_self__legacy__attackchain(user)
+/obj/item/grenade/plastic/miningcharge/interact_with_atom(atom/target, mob/living/user, list/modifiers)
+ if(!ismineralturf(target) && !hacked)
+ return ITEM_INTERACT_COMPLETE
-/obj/item/grenade/plastic/miningcharge/afterattack__legacy__attackchain(atom/movable/AM, mob/user, flag)
- if(!ismineralturf(AM) && !hacked)
- return
- if(is_ancient_rock(AM) && !hacked)
- to_chat(user, SPAN_NOTICE("This rock appears to be resistant to all mining tools except pickaxes!"))
- return
- if(!timer_off) //override original proc for plastic explosions
+ if(is_ancient_rock(target) && !hacked)
+ to_chat(user, SPAN_WARNING("This rock appears to be resistant to all mining tools except pickaxes!"))
+ return ITEM_INTERACT_COMPLETE
+
+ // Override original proc for plastic explosives.
+ if(!timer_off)
return ..()
- if(!flag)
- return
- if(iscarbon(AM))
- return
+
+ if(iscarbon(target))
+ return ITEM_INTERACT_COMPLETE
+
to_chat(user, SPAN_NOTICE("You start planting [src]."))
- if(!do_after(user, (2.5 SECONDS) * toolspeed, target = AM))
- return
+ if(!do_after(user, (2.5 SECONDS) * toolspeed, target = target))
+ return ITEM_INTERACT_COMPLETE
+
if(!user.unequip(src))
- return
- target = AM
- forceMove(AM)
+ to_chat(user, SPAN_DANGER("[src] is stuck to your hand!"))
+ return ITEM_INTERACT_COMPLETE
+
+ forceMove(target)
if(hacked)
message_admins("[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at [ADMIN_COORDJMP(target)]")
log_game("planted [name] on [target.name] at [COORD(target)]", user)
installed = TRUE
target.overlays += image_overlay
+ return ITEM_INTERACT_COMPLETE
-/obj/item/grenade/plastic/miningcharge/attackby__legacy__attackchain(obj/item/I, mob/user, params)
- if(!istype(I, /obj/item/detonator))
- return
- var/obj/item/detonator/detonator = I
+/obj/item/grenade/plastic/miningcharge/item_interaction(mob/living/user, obj/item/used, list/modifiers)
+ if(!istype(used, /obj/item/detonator))
+ return NONE
+
+ var/obj/item/detonator/detonator = used
if((src in detonator.bombs) || timer_off)
to_chat(user, SPAN_WARNING("[src] was already synchronized to a existing detonator!"))
- return
+ return ITEM_INTERACT_COMPLETE
+
detonator.bombs += src
timer_off = TRUE
- to_chat(user, SPAN_NOTICE("You synchronize [src] to [I]."))
+ to_chat(user, SPAN_NOTICE("You synchronize [src] to [used]."))
playsound(src, 'sound/machines/twobeep.ogg', 50)
detonator.update_icon()
+ return ITEM_INTERACT_COMPLETE
/obj/item/grenade/plastic/miningcharge/proc/detonate()
addtimer(CALLBACK(src, PROC_REF(prime)), 3 SECONDS)
@@ -75,7 +80,7 @@
if(hacked) //try not to blow your fingers off
explode()
return
- var/turf/simulated/mineral/location = get_turf(target)
+ var/turf/simulated/mineral/location = get_turf(target_atom)
var/datum/effect_system/smoke_spread/S = new
S.set_up(smoke_amount, 0, location, null)
S.start()
@@ -99,18 +104,18 @@
/obj/item/grenade/plastic/miningcharge/proc/explode()
var/turf/location
- if(target)
- if(!QDELETED(target))
- if(isturf(target))
- location = get_turf(target)
+ if(target_atom)
+ if(!QDELETED(target_atom))
+ if(isturf(target_atom))
+ location = get_turf(target_atom)
else
- location = get_atom_on_turf(target)
- target.overlays -= image_overlay
+ location = get_atom_on_turf(target_atom)
+ target_atom.overlays -= image_overlay
else
location = get_atom_on_turf(src)
if(location)
explosion(location, boom_sizes[1], boom_sizes[2], boom_sizes[3], cause = name)
- location.ex_act(EXPLODE_HEAVY, target)
+ location.ex_act(EXPLODE_HEAVY, target_atom)
qdel(src)
/obj/item/grenade/plastic/miningcharge/proc/override_safety()
@@ -161,13 +166,16 @@
/obj/item/t_scanner/adv_mining_scanner/syndicate/afterattack__legacy__attackchain(atom/target, mob/user, proximity_flag, click_parameters)
if(!istype(target, /obj/item/grenade/plastic/miningcharge))
return
+
var/obj/item/grenade/plastic/miningcharge/charge = target
if(charge.hacked)
to_chat(user, SPAN_NOTICE("[src] is already overridden!"))
return
+
if(charges <= 0)
to_chat(user, SPAN_NOTICE("Its overriding function is depleted."))
return
+
charge.override_safety()
visible_message(SPAN_WARNING("Sparks fly out of [src]!"))
playsound(src, "sparks", 50, TRUE)
diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm
index a5798a95555..4057a3a0c17 100644
--- a/code/modules/mining/equipment/wormhole_jaunter.dm
+++ b/code/modules/mining/equipment/wormhole_jaunter.dm
@@ -197,9 +197,9 @@ GLOBAL_LIST_EMPTY(wormhole_effect)
thrower = null
return ..()
-/obj/item/grenade/jaunter_grenade/attack_self__legacy__attackchain(mob/user)
- . = ..()
+/obj/item/grenade/jaunter_grenade/activate_self(mob/user)
thrower = user
+ return ..()
/obj/item/grenade/jaunter_grenade/prime()
var/area/our_area = get_area(src)
diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm
index d4fc08dfdb2..4393ab68c6a 100644
--- a/code/modules/mod/modules/modules_security.dm
+++ b/code/modules/mod/modules/modules_security.dm
@@ -66,7 +66,7 @@
if(!.)
return
var/obj/item/grenade/mirage/grenade = .
- grenade.attack_self__legacy__attackchain(mod.wearer)
+ grenade.activate_self(mod.wearer)
/obj/item/grenade/mirage
name = "mirage grenade"
@@ -76,14 +76,13 @@
/// Mob that threw the grenade.
var/mob/living/thrower
-
/obj/item/grenade/mirage/Destroy()
thrower = null
return ..()
-/obj/item/grenade/mirage/attack_self__legacy__attackchain(mob/user)
- . = ..()
+/obj/item/grenade/mirage/activate_self(mob/user)
thrower = user
+ return ..()
/obj/item/grenade/mirage/prime()
do_sparks(rand(3, 6), FALSE, src)
@@ -191,7 +190,7 @@
playsound(src, 'sound/machines/click.ogg', 100, TRUE)
drain_power(use_power_cost)
var/obj/item/grenade/grenade = dispensed
- grenade.attack_self__legacy__attackchain(mod.wearer)
+ grenade.activate_self(mod.wearer)
return grenade
/obj/item/mod/module/anomaly_locked/firewall/prebuilt
@@ -245,7 +244,7 @@
playsound(src, 'sound/machines/click.ogg', 100, TRUE)
drain_power(use_power_cost)
var/obj/item/grenade/grenade = dispensed
- grenade.attack_self__legacy__attackchain(mod.wearer)
+ grenade.activate_self(mod.wearer)
return grenade
/obj/item/mod/module/anomaly_locked/cryogrenade/prebuilt
@@ -267,9 +266,9 @@
thrower = null
return ..()
-/obj/item/grenade/cryogrenade_mod/attack_self__legacy__attackchain(mob/user)
- . = ..()
+/obj/item/grenade/cryogrenade_mod/activate_self(mob/user)
thrower = user
+ return ..()
/obj/item/grenade/cryogrenade_mod/prime()
update_mob()
@@ -302,4 +301,4 @@
var/obj/item/grenade/smokebomb/grenade = ..()
if(!grenade)
return
- grenade.attack_self__legacy__attackchain(mod.wearer)
+ grenade.activate_self(mod.wearer)