Files
Leland KembleandGitHub 06608081d2 Moves a greater manyer morer things from attackby() to item_interaction() (#96739)
## About The Pull Request

50 files, plus additonal file that was necessary because I slightly
refactored windoor construction. This ended up like three and a half
times larger than most of the other ones, I really wasn't meaning for
that to happen. Maybe its because I more vigorously enforced the empty
line after every return thing. The only way to find out is to read 1700
lines of changes, and I don't feel like doing that again. I pinky
promise it all works, and I've tested every item changed individually.

Changes beyond conversion:
You can't welder down reinforced falsewalls anymore, pretty sure it was
an oversight because they're supposed to be taken down by wirecutters
You can right click to close gun lockers with an empty hand, because
otherwise you can't close the lockers at all if there's a gun in them
Meatspikes no longer runtime on construction due to the old trick of
balloon alert + qdel
Windoor assembly no longer SUCKS DICK!!, it's no longer storing
essentially a boolean in an undocumented number in a string, it no
longer requires a VERB to flip its direction.
on a related note, the creator of the windoor assembly construction
steps has been sent to live on a farm far out in the country

Also, a quick note about how these prs are gonna fuck everything up
until they're all together. There's a lot more places where `attackby()`
is directly called than I would have assumed, and given as those are
being changed to call `item_interaction()` potentially(usually) in a
different pr than the pr in which that atom's `attackby()` is actually
converted, that function's not going to work at all until both are
merged. The good news is that almost every instance this is happening,
it's pure convenience, where the user would have access to both items
anyway and could just manually call the attack chain by clicking them
together. Instances where this is not the case are being skipped over
until they can be packaged together to avoid the issue, but I'm not
bothering to do this on ones where the desync won't make an interaction
actually unusable, because that would require me to turn a 1700 line pr
into a 3500 line pr and I really was aiming for like 500

## Why It's Good For The Game

Ignore the paragraph about how I expect this to create a hostage
situation where the only fix to the bugs I make is to merge my other
prs, and instead think about how cool swing combat would be and how much
you want it

## Changelog
🆑
fix: you now can only use a wirecutter to take down a reinforced
falsewall
fix: meatspikes no longer runtime on construction
fix: you no longer have to use a verb that you can't use to flip windoor
assemblies

qol: you can right click a gun locker to close it

code: 50 files have been moved from attackby() to item_interaction()
/🆑
2026-07-16 15:07:43 +02:00

354 lines
15 KiB
Plaintext

//Items for nuke theft, supermatter theft traitor objective
// STEALING THE NUKE
//the nuke core - objective item
/obj/item/nuke_core
name = "plutonium core"
desc = "Extremely radioactive. Wear goggles."
icon = 'icons/obj/antags/syndicate_tools.dmi'
icon_state = "plutonium_core"
inhand_icon_state = "plutoniumcore"
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/pulse = 0
var/cooldown = 0
var/pulseicon = "plutonium_core_pulse"
/obj/item/nuke_core/Initialize(mapload)
. = ..()
START_PROCESSING(SSobj, src)
/obj/item/nuke_core/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/nuke_core/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(!istype(tool, /obj/item/nuke_core_container))
return NONE
astype(tool, /obj/item/nuke_core_container).load(src, user)
return ITEM_INTERACT_SUCCESS
/obj/item/nuke_core/process()
if(cooldown < world.time - 60)
cooldown = world.time
flick(pulseicon, src)
radiation_pulse(get_turf(src), max_range = 2, threshold = RAD_EXTREME_INSULATION)
/obj/item/nuke_core/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is rubbing [src] against [user.p_them()]self! It looks like [user.p_theyre()] trying to commit suicide!"))
return TOXLOSS
//nuke core box, for carrying the core
/obj/item/nuke_core_container
name = "nuke core container"
desc = "Solid container for radioactive objects."
icon = 'icons/obj/antags/syndicate_tools.dmi'
icon_state = "core_container_empty"
inhand_icon_state = "tile"
lefthand_file = 'icons/mob/inhands/items/tiles_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/tiles_righthand.dmi'
var/obj/item/nuke_core/core
/obj/item/nuke_core_container/Destroy()
QDEL_NULL(core)
return ..()
/obj/item/nuke_core_container/proc/load(obj/item/nuke_core/ncore, mob/user)
if(core || !istype(ncore))
return FALSE
ncore.forceMove(src)
core = ncore
icon_state = "core_container_loaded"
to_chat(user, span_warning("Container is sealing..."))
addtimer(CALLBACK(src, PROC_REF(seal)), 5 SECONDS)
return TRUE
/obj/item/nuke_core_container/proc/seal()
if(istype(core))
STOP_PROCESSING(SSobj, core)
icon_state = "core_container_sealed"
playsound(src, 'sound/items/deconstruct.ogg', 60, TRUE)
if(ismob(loc))
to_chat(loc, span_warning("[src] is sealed, [core]'s radiation is contained."))
/obj/item/nuke_core_container/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(!istype(tool, /obj/item/nuke_core))
return NONE
if(!user.temporarilyRemoveItemFromInventory(tool))
to_chat(user, span_warning("The [tool] is stuck to your hand!"))
return ITEM_INTERACT_BLOCKING
load(tool, user)
return ITEM_INTERACT_SUCCESS
//snowflake screwdriver, works as a key to start nuke theft, traitor only
/obj/item/screwdriver/nuke
name = "screwdriver"
desc = "A screwdriver with an ultra thin tip that's carefully designed to boost screwing speed."
icon = 'icons/obj/antags/syndicate_tools.dmi'
icon_state = "screwdriver_nuke"
post_init_icon_state = null
inhand_icon_state = "screwdriver_nuke"
toolspeed = 0.5
random_color = FALSE
greyscale_config_inhand_left = null
greyscale_config_inhand_right = null
greyscale_colors = null
/obj/item/screwdriver/nuke/get_belt_overlay()
return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "screwdriver_nuke")
/obj/item/paper/guides/antag/nuke_instructions
default_raw_text = "How to break into a Nanotrasen self-destruct terminal and remove its plutonium core:<br>\
<ul>\
<li>Use a screwdriver with a very thin tip (provided) to unscrew the terminal's front panel</li>\
<li>Dislodge and remove the front panel with a crowbar</li>\
<li>Cut the inner metal plate with a welding tool</li>\
<li>Pry off the inner plate with a crowbar to expose the radioactive core</li>\
<li>Use the core container to remove the plutonium core; the container will take some time to seal</li>\
<li>???</li>\
</ul>"
/obj/item/paper/guides/antag/hdd_extraction
default_raw_text = "<h1>Source Code Theft & You - The Idiot's Guide to Crippling Nanotrasen Research & Development</h1><br>\
Rumour has it that Nanotrasen are using their R&D Servers to create something awful! They've codenamed it Project Goon, whatever that means.<br>\
This cannot be allowed to stand. Below is all our intel for stealing their source code and crippling their research efforts:<br>\
<ul>\
<li>Locate the physical R&D Server mainframes. Intel suggests these are stored in specially cooled rooms deep within their Science department.</li>\
<li>Nanotrasen is a corporation not known for subtlety in design. You should be able to identify the master server by any distinctive markings.</li>\
<li>Tools are on-site procurement. Screwdriver, crowbar and wirecutters should be all you need to do the job.<li>\
<li>The front panel screws are hidden in recesses behind stickers. Easily removed once you know they're there.</li>\
<li>You'll probably find the hard drive in secure housing. You may need to pry it loose with a crowbar, shouldn't do too much damage.</li>\
<li>Finally, carefully cut all of the hard drive's connecting wires. Don't rush this, snipping the wrong wire could wipe all data!</li>\
</ul>\
Removing this drive is guaranteed to cripple research efforts regardless of what data is contained on it.<br>\
The thing's probably hardwired. No putting it back once you've extracted it. The crew are likely to be as mad as bees if they find out!<br>\
Survive the shift and extract the hard drive safely.<br>\
Succeed and you will receive a coveted green highlight on your record for this assignment. Fail us and red's the last colour you'll ever see.<br>\
Do not disappoint us.<br>"
/obj/item/disk/computer/hdd_theft
name = "r&d server hard disk drive"
desc = "For some reason, people really seem to want to steal this. The source code on this drive is probably used for something awful!"
max_capacity = 512
w_class = WEIGHT_CLASS_NORMAL
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
sticker_icon_state = "o_nt"
// STEALING SUPERMATTER
/obj/item/paper/guides/antag/supermatter_sliver
default_raw_text = "How to safely extract a supermatter sliver:<br>\
<ul>\
<li>You must have active magnetic anchoring at all times near an active supermatter crystal.</li>\
<li>Approach an active supermatter crystal with radiation shielded personal protective equipment. DO NOT MAKE PHYSICAL CONTACT.</li>\
<li>Use a supermatter scalpel (provided) to slice off a sliver of the crystal.</li>\
<li>Use supermatter extraction tongs (also provided) to safely pick up the sliver you sliced off.</li>\
<li>Physical contact of any object with the sliver will dust the object, as well as yourself.</li>\
<li>Use the tongs to place the sliver into the provided container, which will take some time to seal.</li>\
<li>Get the hell out before the crystal delaminates.</li>\
<li>???</li>\
</ul>"
/obj/item/nuke_core/supermatter_sliver
name = "supermatter sliver"
desc = "A tiny, highly volatile sliver of a supermatter crystal. Do not handle without protection!"
icon_state = "supermatter_sliver"
inhand_icon_state = null //touching it dusts you, so no need for an inhand icon.
pulseicon = "supermatter_sliver_pulse"
layer = ABOVE_MOB_LAYER
/obj/item/nuke_core/supermatter_sliver/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_FISHING_ROD_CAST, PROC_REF(on_hook))
/obj/item/nuke_core/supermatter_sliver/proc/on_hook(obj/item/nuke_core/supermatter_sliver/source, obj/item/fishing_rod/rod, mob/user)
SIGNAL_HANDLER
//hook gets dusted but the rod remains intact
attackby(rod.hook, user)
return FISHING_ROD_CAST_HANDLED
/obj/item/nuke_core/supermatter_sliver/attack_tk(mob/user) // no TK dusting memes
return
/obj/item/nuke_core/supermatter_sliver/can_be_pulled(user, force) // no drag memes
return FALSE
/obj/item/nuke_core/supermatter_sliver/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(istype(tool, /obj/item/hemostat/supermatter))
var/obj/item/hemostat/supermatter/tongs = tool
if (tongs.sliver)
to_chat(user, span_warning("\The [tongs] is already holding a supermatter sliver!"))
return ITEM_INTERACT_BLOCKING
forceMove(tongs)
tongs.sliver = src
tongs.update_appearance()
to_chat(user, span_notice("You carefully pick up [src] with [tongs]."))
return ITEM_INTERACT_SUCCESS
if(istype(tool, /obj/item/scalpel/supermatter) || istype(tool, /obj/item/nuke_core_container/supermatter/)) // we don't want it to dust
return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("As it touches \the [src], both \the [src] and \the [tool] burst into dust!"))
radiation_pulse(user, max_range = 2, threshold = RAD_EXTREME_INSULATION, chance = 40)
playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE)
qdel(tool)
qdel(src)
return ITEM_INTERACT_SUCCESS
/obj/item/nuke_core/supermatter_sliver/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!isliving(hit_atom))
return ..()
var/mob/living/victim = hit_atom
if(victim.incorporeal_move || HAS_TRAIT(victim, TRAIT_GODMODE)) //try to keep this in sync with supermatter's consume fail conditions
return ..()
var/mob/thrower = throwingdatum?.get_thrower()
if(istype(thrower))
log_combat(thrower, hit_atom, "consumed", src)
message_admins("[src] has consumed [key_name_admin(victim)] [ADMIN_JMP(src)], thrown by [key_name_admin(thrower)].")
investigate_log("has consumed [key_name(victim)], thrown by [key_name(thrower)]", INVESTIGATE_ENGINE)
else
message_admins("[src] has consumed [key_name_admin(victim)] [ADMIN_JMP(src)] via throw impact.")
investigate_log("has consumed [key_name(victim)] via throw impact.", INVESTIGATE_ENGINE)
victim.visible_message(span_danger("As [victim] is hit by [src], both flash into dust and silence fills the room..."),\
span_userdanger("You're hit by [src] and everything suddenly goes silent.\n[src] flashes into dust, and soon as you can register this, you do as well."),\
span_hear("Everything suddenly goes silent."))
victim.investigate_log("has been dusted by [src].", INVESTIGATE_DEATHS)
victim.dust()
radiation_pulse(src, max_range = 2, threshold = RAD_EXTREME_INSULATION, chance = 40)
playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE)
qdel(src)
/obj/item/nuke_core/supermatter_sliver/pickup(mob/living/user)
..()
if(!isliving(user) || HAS_TRAIT(user, TRAIT_GODMODE)) //try to keep this in sync with supermatter's consume fail conditions
return FALSE
user.visible_message(span_danger("[user] reaches out and tries to pick up [src]. [user.p_their()] body starts to glow and bursts into flames before flashing into dust!"),\
span_userdanger("You reach for [src] with your hands. That was dumb."),\
span_hear("Everything suddenly goes silent."))
radiation_pulse(user, max_range = 2, threshold = RAD_EXTREME_INSULATION, chance = 40)
playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE)
user.investigate_log("has been dusted by [src].", INVESTIGATE_DEATHS)
user.dust()
/obj/item/nuke_core_container/supermatter
name = "supermatter bin"
desc = "A tiny receptacle that releases an inert hyper-noblium mix upon sealing, allowing a sliver of a supermatter crystal to be safely stored."
var/obj/item/nuke_core/supermatter_sliver/sliver
/obj/item/nuke_core_container/supermatter/Destroy()
QDEL_NULL(sliver)
return ..()
/obj/item/nuke_core_container/supermatter/load(obj/item/hemostat/supermatter/T, mob/user)
if(!istype(T) || !T.sliver)
return FALSE
T.sliver.forceMove(src)
sliver = T.sliver
T.sliver = null
T.icon_state = "supermatter_tongs"
icon_state = "core_container_loaded"
to_chat(user, span_warning("Container is sealing..."))
addtimer(CALLBACK(src, PROC_REF(seal)), 5 SECONDS)
return TRUE
/obj/item/nuke_core_container/supermatter/seal()
if(istype(sliver))
STOP_PROCESSING(SSobj, sliver)
icon_state = "core_container_sealed"
playsound(src, 'sound/items/Deconstruct.ogg', 60, TRUE)
if(ismob(loc))
to_chat(loc, span_warning("[src] is permanently sealed, [sliver] is safely contained."))
/obj/item/scalpel/supermatter
name = "supermatter scalpel"
desc = "A scalpel with a fragile tip of condensed hyper-noblium gas, searingly cold to the touch, that can safely shave a sliver off a supermatter crystal."
icon = 'icons/obj/antags/syndicate_tools.dmi'
icon_state = "supermatter_scalpel"
toolspeed = 0.5
damtype = BURN
usesound = 'sound/items/weapons/bladeslice.ogg'
var/usesLeft
/obj/item/scalpel/supermatter/Initialize(mapload)
. = ..()
usesLeft = rand(2, 4)
/obj/item/hemostat/supermatter
name = "supermatter extraction tongs"
desc = "A pair of tongs made from condensed hyper-noblium gas, searingly cold to the touch, that can safely grip a supermatter sliver."
icon = 'icons/obj/antags/syndicate_tools.dmi'
icon_state = "supermatter_tongs"
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
inhand_icon_state = "supermatter_tongs"
toolspeed = 0.75
damtype = BURN
var/obj/item/nuke_core/supermatter_sliver/sliver
/obj/item/hemostat/supermatter/Initialize(mapload)
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
/obj/item/hemostat/supermatter/Destroy()
QDEL_NULL(sliver)
return ..()
/obj/item/hemostat/supermatter/update_icon_state()
icon_state = "supermatter_tongs[sliver ? "_loaded" : null]"
inhand_icon_state = "supermatter_tongs[sliver ? "_loaded" : null]"
return ..()
/obj/item/hemostat/supermatter/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!sliver)
return ..()
if (istype(interacting_with, /obj/item/nuke_core_container/supermatter))
var/obj/item/nuke_core_container/supermatter/container = interacting_with
container.load(src, user)
return ITEM_INTERACT_SUCCESS
if(ismovable(interacting_with) && interacting_with != sliver)
Consume(interacting_with, user)
return ITEM_INTERACT_SUCCESS
return ..()
/obj/item/hemostat/supermatter/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) // no instakill supermatter javelins
if(sliver)
sliver.forceMove(loc)
visible_message(span_notice("\The [sliver] falls out of \the [src] as it hits the ground."))
sliver = null
update_appearance()
return ..()
/obj/item/hemostat/supermatter/proc/Consume(atom/movable/AM, mob/living/user)
if(ismob(AM))
if(!isliving(AM))
return
var/mob/living/victim = AM
if(victim.incorporeal_move || HAS_TRAIT(victim, TRAIT_GODMODE)) //try to keep this in sync with supermatter's consume fail conditions
return
victim.investigate_log("has been dusted by [src].", INVESTIGATE_DEATHS)
victim.dust()
message_admins("[src] has consumed [key_name_admin(victim)] [ADMIN_JMP(src)].")
investigate_log("has consumed [key_name(victim)].", INVESTIGATE_ENGINE)
else if(istype(AM, /obj/singularity))
return
else
investigate_log("has consumed [AM].", INVESTIGATE_ENGINE)
qdel(AM)
if (user)
log_combat(user, AM, "consumed", sliver, "via [src]")
user.visible_message(span_danger("As [user] touches [AM] with \the [src], both flash into dust and silence fills the room..."),\
span_userdanger("You touch [AM] with [src], and everything suddenly goes silent.\n[AM] and [sliver] flash into dust, and soon as you can register this, you do as well."),\
span_hear("Everything suddenly goes silent."))
user.investigate_log("has been dusted by [src].", INVESTIGATE_DEATHS)
user.dust()
radiation_pulse(src, max_range = 2, threshold = RAD_EXTREME_INSULATION, chance = 40)
playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE)
QDEL_NULL(sliver)
update_appearance()