Skip to content

Commit

Permalink
Refactor APCs interaction chain from attackby to item_interaction (tg…
Browse files Browse the repository at this point in the history
…station#82390)

## About The Pull Request

For how many lines this is, there's not a lot to really say.
In general, we simply move all item interactions from `attackby(...)` to
`item_interaction(...)`, split each item interaction off into a separate
proc, and make them all return the proper item interaction flags.
We _do_ kill some probably dead code, and remove a call to
`attackby(...)` elsewhere. Then, for clarity, we move the cell check
below the ID check so it can be next to the other item type checks, as
the priority between cell and ID is unlikely to matter anyway.
Other than what's described above and detailed below, each section's
functionality should be the same.

Now, for the parts that _do_ need to be explained more.

### Killing Probably Dead Code

Alright, so, the first part that does not have the cleanest transition.

https://github.com/tgstation/tgstation/blob/d38f9385b863e49f83455a227764d302629e2867/code/modules/power/apc/apc_attack.dm#L22-L23
Whatever the fuck this is.

Asking around, this seems to just be dead code.
For sanity's sake removing it and testing, silicon interactions with it
seem to work just fine.
So we kill it. We just kill it. We Just Kill It.

Closest we could find requires the distance check there to be false, so
it wouldn't apply. But it _does_ bring us to the second bit of weird
code.

### Calling APC Attackby Elsewhere?
So wallframes let you screwdriver them to put them up, which from a
comment seems to be because of cyborgs.
APC wallframes of course override this with their own implementation,
that allows you to also replace a damaged cover or frame like that!

https://github.com/tgstation/tgstation/blob/d38f9385b863e49f83455a227764d302629e2867/code/game/objects/items/apc_frame.dm#L29-L39
...By just calling the wholeass `attackby(...)` proc on the APC and
calling it a day.

But hey, this is where our previous splitting up comes in handy, because
we just have a `wallframe_act(...)` proc!
So we just call that instead.
```dm
var/obj/machinery/power/apc/mounted_apc = locate(/obj/machinery/power/apc) in get_turf(user)
mounted_apc.wallframe_act(user, src)
return ITEM_INTERACT_SUCCESS
```
...And not use single letter variables, while we're at it.

That should be all.
Remember to get snacks and drinks.
## Why It's Good For The Game

Split off 178 line `attackby(...)` item interaction chain into separate
procs called in `item_interaction(...)`.
Screwdrivering APC wallframes no longer calls the wholeass
`attackby(...)` on the APC, but just call the new sub-proc for the
specific interaction it cares about.
## Changelog
:cl:
refactor: APCs have had their item interaction chain refactored. This
should functionally be the same, but please report any issues.
/:cl:
  • Loading branch information
00-Steven authored Apr 3, 2024
1 parent 59ca0f5 commit 6f68fa4
Show file tree
Hide file tree
Showing 3 changed files with 225 additions and 183 deletions.
8 changes: 4 additions & 4 deletions code/game/objects/items/apc_frame.dm
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@
/obj/item/wallframe/apc/screwdriver_act(mob/living/user, obj/item/tool)
//overriding the wallframe parent screwdriver act with this one which allows applying to existing apc frames.

var/turf/T = get_step(get_turf(user), user.dir)
if(iswallturf(T))
var/turf/turf = get_step(get_turf(user), user.dir)
if(iswallturf(turf))
if(locate(/obj/machinery/power/apc) in get_turf(user))
var/obj/machinery/power/apc/mounted_apc = locate(/obj/machinery/power/apc) in get_turf(user)
mounted_apc.attackby(src, user)
mounted_apc.wallframe_act(user, src)
return ITEM_INTERACT_SUCCESS
T.attackby(src, user)
turf.attackby(src, user)
return ITEM_INTERACT_SUCCESS
179 changes: 0 additions & 179 deletions code/modules/power/apc/apc_attack.dm
Original file line number Diff line number Diff line change
@@ -1,182 +1,3 @@
/obj/machinery/power/apc/attackby(obj/item/attacking_object, mob/living/user, params)
if(HAS_TRAIT(attacking_object, TRAIT_APC_SHOCKING))
var/metal = 0
var/shock_source = null
metal += LAZYACCESS(attacking_object.custom_materials, GET_MATERIAL_REF(/datum/material/iron))//This prevents wooden rolling pins from shocking the user

if(cell || terminal) //The mob gets shocked by whichever powersource has the most electricity
if(cell && terminal)
shock_source = cell.charge > terminal.powernet.avail ? cell : terminal.powernet
else
shock_source = terminal?.powernet || cell

if(shock_source && metal && (panel_open || opened)) //Now you're cooking with electricity
if(!electrocute_mob(user, shock_source, src, siemens_coeff = 1, dist_check = TRUE))//People with insulated gloves just attack the APC normally. They're just short of magical anyway
return
do_sparks(5, TRUE, src)
user.visible_message(span_notice("[user.name] shoves [attacking_object] into the internal components of [src], erupting into a cascade of sparks!"))
if(shock_source == cell)//If the shock is coming from the cell just fully discharge it, because it's funny
cell.use(cell.charge)
return

if(issilicon(user) && get_dist(src,user) > 1)
return attack_hand(user)

if(istype(attacking_object, /obj/item/stock_parts/cell) && opened)
if(cell)
balloon_alert(user, "cell already installed!")
return
if(machine_stat & MAINT)
balloon_alert(user, "no connector for a cell!")
return
if(!user.transferItemToLoc(attacking_object, src))
return
cell = attacking_object
user.visible_message(span_notice("[user.name] inserts the power cell to [src.name]!"))
balloon_alert(user, "cell inserted")
update_appearance()
return

if(attacking_object.GetID())
togglelock(user)
return

if(istype(attacking_object, /obj/item/stack/cable_coil) && opened)
var/turf/host_turf = get_turf(src)
if(!host_turf)
CRASH("attackby on APC when it's not on a turf")
if(host_turf.underfloor_accessibility < UNDERFLOOR_INTERACTABLE)
balloon_alert(user, "remove the floor plating!")
return
if(terminal)
balloon_alert(user, "already wired!")
return
if(!has_electronics)
balloon_alert(user, "no board to wire!")
return

var/obj/item/stack/cable_coil/installing_cable = attacking_object
if(installing_cable.get_amount() < 10)
balloon_alert(user, "need ten lengths of cable!")
return

var/terminal_cable_layer = cable_layer // Default to machine's cable layer
if(LAZYACCESS(params2list(params), RIGHT_CLICK))
var/choice = tgui_input_list(user, "Select Power Input Cable Layer", "Select Cable Layer", GLOB.cable_name_to_layer)
if(isnull(choice))
return
terminal_cable_layer = GLOB.cable_name_to_layer[choice]

user.visible_message(span_notice("[user.name] adds cables to the APC frame."))
balloon_alert(user, "adding cables to the frame...")
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)

if(!do_after(user, 20, target = src))
return
if(installing_cable.get_amount() < 10 || !installing_cable)
return
if(terminal || !opened || !has_electronics)
return
var/turf/our_turf = get_turf(src)
var/obj/structure/cable/cable_node = our_turf.get_cable_node(terminal_cable_layer)
if(prob(50) && electrocute_mob(usr, cable_node, cable_node, 1, TRUE))
do_sparks(5, TRUE, src)
return
installing_cable.use(10)
balloon_alert(user, "cables added to the frame")
make_terminal(terminal_cable_layer)
terminal.connect_to_network()
return

if(istype(attacking_object, /obj/item/electronics/apc) && opened)
if(has_electronics)
balloon_alert(user, "there is already a board!")
return

if(machine_stat & BROKEN)
balloon_alert(user, "the frame is damaged!")
return

user.visible_message(span_notice("[user.name] inserts the power control board into [src]."))
balloon_alert(user, "you start to insert the board...")
playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)

if(!do_after(user, 10, target = src) || has_electronics)
return

has_electronics = APC_ELECTRONICS_INSTALLED
locked = FALSE
balloon_alert(user, "board installed")
qdel(attacking_object)
return

if(istype(attacking_object, /obj/item/electroadaptive_pseudocircuit) && opened)
var/obj/item/electroadaptive_pseudocircuit/pseudocircuit = attacking_object
if(!has_electronics)
if(machine_stat & BROKEN)
balloon_alert(user, "frame is too damaged!")
return
if(!pseudocircuit.adapt_circuit(user, circuit_cost = 50 KILO JOULES))
return
user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \
span_notice("You adapt a power control board and click it into place in [src]'s guts."))
has_electronics = APC_ELECTRONICS_INSTALLED
locked = FALSE
return

if(!cell)
if(machine_stat & MAINT)
balloon_alert(user, "no board for a cell!")
return
if(!pseudocircuit.adapt_circuit(user, circuit_cost = 500 KILO JOULES))
return
var/obj/item/stock_parts/cell/crap/empty/bad_cell = new(src)
bad_cell.forceMove(src)
cell = bad_cell
user.visible_message(span_notice("[user] fabricates a weak power cell and places it into [src]."), \
span_warning("Your [pseudocircuit.name] whirrs with strain as you create a weak power cell and place it into [src]!"))
update_appearance()
return

balloon_alert(user, "has both board and cell!")
return

if(istype(attacking_object, /obj/item/wallframe/apc) && opened)
if(!(machine_stat & BROKEN || opened == APC_COVER_REMOVED || atom_integrity < max_integrity)) // There is nothing to repair
balloon_alert(user, "no reason for repairs!")
return
if((machine_stat & BROKEN) && opened == APC_COVER_REMOVED && has_electronics && terminal) // Cover is the only thing broken, we do not need to remove elctronicks to replace cover
user.visible_message(span_notice("[user.name] replaces missing APC's cover."))
balloon_alert(user, "replacing APC's cover...")
if(do_after(user, 20, target = src)) // replacing cover is quicker than replacing whole frame
balloon_alert(user, "cover replaced")
qdel(attacking_object)
update_integrity(30) //needs to be welded to fully repair but can work without
set_machine_stat(machine_stat & ~(BROKEN|MAINT))
opened = APC_COVER_OPENED
update_appearance()
return
if(has_electronics)
balloon_alert(user, "remove the board inside!")
return
user.visible_message(span_notice("[user.name] replaces the damaged APC frame with a new one."))
balloon_alert(user, "replacing damaged frame...")
if(do_after(user, 50, target = src))
balloon_alert(user, "replaced frame")
qdel(attacking_object)
set_machine_stat(machine_stat & ~BROKEN)
atom_integrity = max_integrity
if(opened == APC_COVER_REMOVED)
opened = APC_COVER_OPENED
update_appearance()
return

if(panel_open && !opened && is_wire_tool(attacking_object))
wires.interact(user)
return

return ..()

/obj/machinery/power/apc/attack_hand_secondary(mob/user, list/modifiers)
. = ..()
if(!can_interact(user))
Expand Down
Loading

0 comments on commit 6f68fa4

Please sign in to comment.