At first i thought that i was being forced to add a feature 🤮 but then i realized i was being encouraged to refactor 😄. Electrified chair is now a component instead of a failure (#57117)

This commit is contained in:
Kylerace
2021-03-03 05:05:52 -08:00
committed by GitHub
parent c03d3fa4cf
commit 01f899c946
12 changed files with 303 additions and 79 deletions
+3
View File
@@ -1097,3 +1097,6 @@
#define COMSIG_AQUARIUM_BEFORE_INSERT_CHECK "aquarium_about_to_be_inserted"
#define COMSIG_AQUARIUM_SURFACE_CHANGED "aquarium_surface_changed"
#define COMSIG_AQUARIUM_FLUID_CHANGED "aquarium_fluid_changed"
///from /obj/item/assembly/proc/pulsed()
#define COMSIG_ASSEMBLY_PULSED "assembly_pulsed"
+14
View File
@@ -0,0 +1,14 @@
///electrified_buckle requires a shock kit attached to it in order to shock
#define SHOCK_REQUIREMENT_ITEM (1<<0)
///electrified_buckle requires a live cable to work, and draws power from it
#define SHOCK_REQUIREMENT_LIVE_CABLE (1<<1)
///electrified_buckle requires to be turned on with a signal in order to shock the buckled mob
#define SHOCK_REQUIREMENT_ON_SIGNAL_RECEIVED (1<<2)
///electrified_buckle requires the parent to be alive in order to shock (if parent is a mob)
#define SHOCK_REQUIREMENT_PARENT_MOB_ISALIVE (1<<3)
///a signal can toggle the ability to shock on a timer
#define SHOCK_REQUIREMENT_SIGNAL_RECEIVED_TOGGLE (1<<4)
///This trait signifies that the object can be used to electrify things buckled to it
#define TRAIT_ELECTRIFIED_BUCKLE "electrified buckle"
@@ -0,0 +1,203 @@
///divide the power in the cable net under parent by this to determine the shock damage
#define ELECTRIC_BUCKLE_SHOCK_STRENGTH_DIVISOR 5000
///it will not shock the mob buckled to parent if its required to use a cable to shock and the cable has less than this power availaible
#define ELECTRIC_BUCKLE_MINUMUM_POWERNET_STRENGTH 10
/**
* # electrified_buckle component:
* attach it to any atom/movable that can be buckled to in order to have it shock mobs buckled to it. by default it shocks mobs buckled to parent every shock_loop_time.
* the parent is supposed to define its behavior with arguments in AddComponent
*/
/datum/component/electrified_buckle
///if usage_flags has SHOCK_REQUIREMENT_ITEM, this is the item required to be inside parent in order for it to shock buckled mobs
var/obj/item/required_object
///this is casted to the overlay we put on parent_chair
var/list/requested_overlays
///it will only shock once every shock_loop_time
COOLDOWN_DECLARE(electric_buckle_cooldown)
///these flags tells this instance what is required in order to allow shocking
var/usage_flags
///if true, this will shock the buckled mob every shock_loop_time in process()
var/shock_on_loop = TRUE
///how long the component waits before shocking the mob buckled to parent again
var/shock_loop_time = 5 SECONDS
///how much damage is done per shock iff usage_flags doesnt have SHOCK_REQUIREMENT_LIVE_CABLE
var/shock_damage = 50
///this signal was given as an argument to register for parent to emit, if its emitted to parent then shock_on_demand is called. var is so it can be unregistered
var/requested_signal_parent_emits = null
/**
* Initialize args:
*
* * input_requirements - bitflag that defines how the component is supposed to act, see __DEFINES/electrified_buckle.dm for the options. sets usage_flags
* * input_item - if set to an item and input_requirements has SHOCK_REQUIREMENT_ITEM, moves that item inside parent and the component will delete itself if input_item no longer exists/moves out of parent. sets required_object
* * overlays_to_add - pass in a list of images and the component will add them to parent as well as remove them in UnregisterFromParent(). sets requested_overlays
* * override_buckle - if TRUE, sets parent.can_buckle = TRUE and resets it on UnregisterFromParent(), usually objects that have need to be overridden will look janky on buckle
* * damage_on_shock - if SHOCK_REQUIREMENT_LIVE_CABLE is not set in input_requirements, then this is how much damage each shock does. sets shock_damage
* * signal_to_register_from_parent - if set, the component registers to listen for this signal targeting parent to manually shock. sets requested_signal_parent_emits
*/
/datum/component/electrified_buckle/Initialize(input_requirements, obj/item/input_item, list/overlays_to_add, override_buckle, damage_on_shock = 50, signal_to_register_from_parent, loop_length)
var/atom/movable/parent_as_movable = parent
if(!istype(parent_as_movable))
return COMPONENT_INCOMPATIBLE
usage_flags = input_requirements
if(!parent_as_movable.can_buckle && !override_buckle)
return COMPONENT_INCOMPATIBLE
else if (override_buckle)
parent_as_movable.can_buckle = TRUE
if((usage_flags & SHOCK_REQUIREMENT_ITEM) && QDELETED(input_item))
return COMPONENT_INCOMPATIBLE
if(HAS_TRAIT(parent_as_movable, TRAIT_ELECTRIFIED_BUCKLE))
return COMPONENT_INCOMPATIBLE
if(usage_flags & SHOCK_REQUIREMENT_ITEM)
required_object = input_item
required_object.Move(parent_as_movable)
RegisterSignal(required_object, COMSIG_PARENT_PREQDELETED, .proc/delete_self)
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER), .proc/move_required_object_from_contents)
if(usage_flags & SHOCK_REQUIREMENT_ON_SIGNAL_RECEIVED)
shock_on_loop = FALSE
RegisterSignal(required_object, COMSIG_ASSEMBLY_PULSED, .proc/shock_on_demand)
else if(usage_flags & SHOCK_REQUIREMENT_SIGNAL_RECEIVED_TOGGLE)
RegisterSignal(required_object, COMSIG_ASSEMBLY_PULSED, .proc/toggle_shock_loop)
if((usage_flags & SHOCK_REQUIREMENT_PARENT_MOB_ISALIVE) && ismob(parent))
RegisterSignal(parent, COMSIG_LIVING_DEATH, .proc/delete_self)
RegisterSignal(parent, COMSIG_MOVABLE_BUCKLE, .proc/on_buckle)
ADD_TRAIT(parent_as_movable, TRAIT_ELECTRIFIED_BUCKLE, INNATE_TRAIT)
//if parent wants us to manually shock on some specified action
if(signal_to_register_from_parent)
RegisterSignal(parent, signal_to_register_from_parent, .proc/shock_on_demand)
requested_signal_parent_emits = signal_to_register_from_parent
if(overlays_to_add)
requested_overlays = overlays_to_add
parent_as_movable.add_overlay(requested_overlays)
parent_as_movable.name = "electrified [initial(parent_as_movable.name)]"
shock_damage = damage_on_shock
if(loop_length)
shock_loop_time = loop_length
if(parent_as_movable.has_buckled_mobs())
for(var/mob/living/possible_guinea_pig as anything in parent_as_movable.buckled_mobs)
if(on_buckle(src, possible_guinea_pig))
break
/datum/component/electrified_buckle/UnregisterFromParent()
var/atom/movable/parent_as_movable = parent
parent_as_movable.cut_overlay(requested_overlays)
parent_as_movable.name = initial(parent_as_movable.name)
parent_as_movable.can_buckle = initial(parent_as_movable.can_buckle)
if(parent)
REMOVE_TRAIT(parent_as_movable, TRAIT_ELECTRIFIED_BUCKLE, INNATE_TRAIT)
UnregisterSignal(parent, list(COMSIG_MOVABLE_BUCKLE, COMSIG_MOVABLE_UNBUCKLE, COMSIG_ATOM_EXIT, COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER)))
if(requested_signal_parent_emits)
UnregisterSignal(parent, requested_signal_parent_emits)
if(required_object)
UnregisterSignal(required_object, list(COMSIG_PARENT_PREQDELETED, COMSIG_ASSEMBLY_PULSED))
if(parent_as_movable && (required_object in parent_as_movable.contents))
required_object.Move(parent_as_movable.loc)
required_object = null
STOP_PROCESSING(SSprocessing, src)
/datum/component/electrified_buckle/proc/delete_self()
SIGNAL_HANDLER
qdel(src)
/datum/component/electrified_buckle/proc/move_required_object_from_contents(datum/source, mob/living/user, obj/item/tool, tool_type)
SIGNAL_HANDLER
var/atom/movable/parent_as_movable = parent
if(!QDELETED(parent_as_movable))
tool.play_tool_sound(parent_as_movable)
required_object.Move(parent_as_movable.loc)
qdel(src)
/datum/component/electrified_buckle/proc/on_buckle(datum/source, mob/living/mob_to_buckle, _force)
SIGNAL_HANDLER
if(!istype(mob_to_buckle))
return FALSE
COOLDOWN_START(src, electric_buckle_cooldown, shock_loop_time)
if(!(usage_flags & SHOCK_REQUIREMENT_ON_SIGNAL_RECEIVED) && shock_on_loop)
START_PROCESSING(SSprocessing, src)
return TRUE
///where the guinea pig is actually shocked if possible
/datum/component/electrified_buckle/process(delta_time)
var/atom/movable/parent_as_movable = parent
if(QDELETED(parent_as_movable) || !parent_as_movable.has_buckled_mobs())
return PROCESS_KILL
if(!shock_on_loop)
return PROCESS_KILL
if(!COOLDOWN_FINISHED(src, electric_buckle_cooldown))
return
COOLDOWN_START(src, electric_buckle_cooldown, shock_loop_time)
var/turf/our_turf = get_turf(parent_as_movable)
var/obj/structure/cable/live_cable = our_turf.get_cable_node()
if(usage_flags & SHOCK_REQUIREMENT_LIVE_CABLE)
if((!live_cable || !live_cable.powernet || live_cable.powernet.avail < ELECTRIC_BUCKLE_MINUMUM_POWERNET_STRENGTH))
return
for(var/mob/living/guinea_pig as anything in parent_as_movable.buckled_mobs)
guinea_pig.electrocute_act(round(live_cable.powernet.avail / ELECTRIC_BUCKLE_SHOCK_STRENGTH_DIVISOR), parent_as_movable)
break
else
for(var/mob/living/guinea_pig as anything in parent_as_movable.buckled_mobs)
guinea_pig.electrocute_act(shock_damage, parent_as_movable)
break
parent_as_movable.visible_message("<span class='danger'>The electric chair went off!</span>", "<span class='hear'>You hear a deep sharp shock!</span>")
///a shock that is toggled manually
/datum/component/electrified_buckle/proc/shock_on_demand()
SIGNAL_HANDLER
if((usage_flags & SHOCK_REQUIREMENT_ITEM) && QDELETED(required_object))
return
var/atom/movable/parent_as_movable = parent
if(usage_flags & SHOCK_REQUIREMENT_LIVE_CABLE)
var/turf/our_turf = get_turf(parent_as_movable)
var/obj/structure/cable/live_cable = our_turf.get_cable_node()
if(!live_cable || !live_cable.powernet || live_cable.powernet.avail < ELECTRIC_BUCKLE_MINUMUM_POWERNET_STRENGTH)
return
for(var/mob/living/guinea_pig as anything in parent_as_movable.buckled_mobs)
var/shock_damage = round(live_cable.powernet.avail / ELECTRIC_BUCKLE_SHOCK_STRENGTH_DIVISOR)
guinea_pig.electrocute_act(shock_damage, parent_as_movable)
break
/datum/component/electrified_buckle/proc/toggle_shock_loop()
SIGNAL_HANDLER
var/atom/movable/parent_as_movable = parent
if(shock_on_loop)
shock_on_loop = FALSE
STOP_PROCESSING(SSprocessing, src)
parent_as_movable.visible_message("<span class='notice'>The electric chair emits a snap as its circuit opens, making it safe for now.</span>")
else
shock_on_loop = TRUE
START_PROCESSING(SSprocessing, src)
parent_as_movable.visible_message("<span class='notice'>You hear the sound of an electric circuit closing coming from the electric chair!</span>")
#undef ELECTRIC_BUCKLE_SHOCK_STRENGTH_DIVISOR
#undef ELECTRIC_BUCKLE_MINUMUM_POWERNET_STRENGTH
@@ -46,11 +46,11 @@
to_chat(user, "<span class='warning'>[W] is stuck to your hand, you cannot attach it to [src]!</span>")
return
W.master = A
A.part1 = W
A.helmet_part = W
user.transferItemToLoc(src, A, TRUE)
master = A
A.part2 = src
A.electropack_part = src
user.put_in_hands(A)
A.add_fingerprint(user)
@@ -60,7 +60,6 @@
/obj/item/electropack/receive_signal(datum/signal/signal)
if(!signal || signal.data["code"] != code)
return
if(isliving(loc) && on)
if(shock_cooldown)
return
@@ -77,6 +76,9 @@
L.Paralyze(100)
if(master)
if(isassembly(master))
var/obj/item/assembly/master_as_assembly = master
master_as_assembly.pulsed()
master.receive_signal()
/obj/item/electropack/proc/set_frequency(new_frequency)
@@ -75,23 +75,35 @@
qdel(src)
/obj/structure/chair/attackby(obj/item/W, mob/user, params)
if(W.tool_behaviour == TOOL_WRENCH && !(flags_1&NODECONSTRUCT_1))
W.play_tool_sound(src)
deconstruct()
else if(istype(W, /obj/item/assembly/shock_kit))
if(!user.temporarilyRemoveItemFromInventory(W))
return
var/obj/item/assembly/shock_kit/SK = W
var/obj/structure/chair/e_chair/E = new /obj/structure/chair/e_chair(src.loc)
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE)
E.setDir(dir)
E.part = SK
SK.forceMove(E)
SK.master = E
qdel(src)
else
return ..()
if(flags_1 & NODECONSTRUCT_1)
return . = ..()
if(istype(W, /obj/item/assembly/shock_kit) && !HAS_TRAIT(src, TRAIT_ELECTRIFIED_BUCKLE))
electrify_self(W, user)
return
. = ..()
///allows each chair to request the electrified_buckle component with overlays that dont look ridiculous
/obj/structure/chair/proc/electrify_self(obj/item/assembly/shock_kit/input_shock_kit, mob/user, list/overlays_from_child_procs)
SHOULD_CALL_PARENT(TRUE)
if(!user.temporarilyRemoveItemFromInventory(input_shock_kit))
return
if(!overlays_from_child_procs || overlays_from_child_procs.len == 0)
var/image/echair_over_overlay = image('icons/obj/chairs.dmi', loc, "echair_over")
AddComponent(/datum/component/electrified_buckle, (SHOCK_REQUIREMENT_ITEM | SHOCK_REQUIREMENT_LIVE_CABLE | SHOCK_REQUIREMENT_SIGNAL_RECEIVED_TOGGLE), input_shock_kit, list(echair_over_overlay), FALSE)
else
AddComponent(/datum/component/electrified_buckle, (SHOCK_REQUIREMENT_ITEM | SHOCK_REQUIREMENT_LIVE_CABLE | SHOCK_REQUIREMENT_SIGNAL_RECEIVED_TOGGLE), input_shock_kit, overlays_from_child_procs, FALSE)
if(HAS_TRAIT(src, TRAIT_ELECTRIFIED_BUCKLE))
to_chat(user, "<span class='notice'>You connect the shock kit to the [name], electrifying it </span>")
else
user.put_in_active_hand(input_shock_kit)
to_chat(user, "<span class='notice'> You cannot fit the shock kit onto the [name]!")
/obj/structure/chair/wrench_act(mob/living/user, obj/item/I)
. = ..()
I.play_tool_sound(src)
deconstruct()
/obj/structure/chair/attack_tk(mob/user)
if(!anchored || has_buckled_mobs() || !isturf(user.loc))
@@ -212,6 +224,11 @@
/obj/structure/chair/comfy/shuttle/GetArmrest()
return mutable_appearance('icons/obj/chairs.dmi', "shuttle_chair_armrest")
/obj/structure/chair/comfy/shuttle/electrify_self(obj/item/assembly/shock_kit/input_shock_kit, mob/user, list/overlays_from_child_procs)
if(!overlays_from_child_procs)
overlays_from_child_procs = list(image('icons/obj/chairs.dmi', loc, "echair_over", pixel_x = -1))
. = ..()
/obj/structure/chair/office
anchored = FALSE
buildstackamount = 5
@@ -224,6 +241,11 @@
if(has_gravity())
playsound(src, 'sound/effects/roll.ogg', 100, TRUE)
/obj/structure/chair/office/electrify_self(obj/item/assembly/shock_kit/input_shock_kit, mob/user, list/overlays_from_child_procs)
if(!overlays_from_child_procs)
overlays_from_child_procs = list(image('icons/obj/chairs.dmi', loc, "echair_over", pixel_x = -1))
. = ..()
/obj/structure/chair/office/light
icon_state = "officechair_white"
@@ -10,6 +10,11 @@
armrest = mutable_appearance(icon, "[icon_state]_armrest", ABOVE_MOB_LAYER)
return ..()
/obj/structure/chair/sofa/electrify_self(obj/item/assembly/shock_kit/input_shock_kit, mob/user, list/overlays_from_child_procs)
if(!overlays_from_child_procs)
overlays_from_child_procs = list(image('icons/obj/chairs.dmi', loc, "echair_over", pixel_x = -1))
. = ..()
/obj/structure/chair/sofa/post_buckle_mob(mob/living/M)
. = ..()
update_armrest()
+5 -35
View File
@@ -1,52 +1,22 @@
/obj/structure/chair/e_chair
name = "electric chair"
desc = "Looks absolutely SHOCKING!"
icon_state = "echair0"
var/obj/item/assembly/shock_kit/part = null
var/last_time = 1
item_chair = null
/obj/structure/chair/e_chair/Initialize()
. = ..()
add_overlay(mutable_appearance('icons/obj/chairs.dmi', "echair_over", MOB_LAYER + 1))
var/obj/item/assembly/shock_kit/stored_kit = new(contents)
var/image/export_to_component = image('icons/obj/chairs.dmi', loc, "echair_over")
AddComponent(/datum/component/electrified_buckle, (SHOCK_REQUIREMENT_ITEM | SHOCK_REQUIREMENT_LIVE_CABLE | SHOCK_REQUIREMENT_SIGNAL_RECEIVED_TOGGLE), stored_kit, list(export_to_component))
/obj/structure/chair/e_chair/attackby(obj/item/W, mob/user, params)
if(W.tool_behaviour == TOOL_WRENCH)
var/obj/structure/chair/C = new /obj/structure/chair(loc)
W.play_tool_sound(src)
C.setDir(dir)
part.forceMove(loc)
part.master = null
part = null
qdel(src)
/obj/structure/chair/e_chair/proc/shock()
if(last_time + 50 > world.time)
return
last_time = world.time
// special power handling
var/area/A = get_area(src)
if(!isarea(A))
return
if(!A.powered(AREA_USAGE_EQUIP))
return
A.use_power(AREA_USAGE_EQUIP, 5000)
flick("echair_shock", src)
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(12, 1, src)
s.start()
if(has_buckled_mobs())
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
buckled_mob.electrocute_act(85, src, 1)
to_chat(buckled_mob, "<span class='userdanger'>You feel a deep shock course through your body!</span>")
addtimer(CALLBACK(buckled_mob, /mob/living.proc/electrocute_act, 85, src, 1), 1)
visible_message("<span class='danger'>The electric chair went off!</span>", "<span class='hear'>You hear a deep sharp shock!</span>")
/obj/structure/chair/e_chair/post_buckle_mob(mob/living/L)
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "dying", /datum/mood_event/deaths_door)
/obj/structure/chair/e_chair/post_unbuckle_mob(mob/living/L)
SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "dying")
. = ..()
+1 -2
View File
@@ -127,8 +127,7 @@
var/obj/item/reagent_containers/RG = I
RG.reagents.add_reagent(/datum/reagent/water, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
to_chat(user, "<span class='notice'>You fill [RG] from [src]. Gross.</span>")
else
return ..()
. = ..()
/obj/structure/toilet/secret
var/obj/item/secret
+4 -3
View File
@@ -58,15 +58,16 @@
return FALSE
return TRUE
//Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs
///Called when another assembly acts on this one, var/radio will determine where it came from for wire calcs
/obj/item/assembly/proc/pulsed(radio = FALSE)
if(wire_type & WIRE_RECEIVE)
INVOKE_ASYNC(src, .proc/activate)
if(radio && (wire_type & WIRE_RADIO_RECEIVE))
INVOKE_ASYNC(src, .proc/activate)
SEND_SIGNAL(src, COMSIG_ASSEMBLY_PULSED)
return TRUE
//Called when this device attempts to act on another device, var/radio determines if it was sent via radio or direct
///Called when this device attempts to act on another device, var/radio determines if it was sent via radio or direct
/obj/item/assembly/proc/pulse(radio = FALSE)
if(connected && wire_type)
connected.pulse_assembly(src)
@@ -77,7 +78,7 @@
holder.process_activation(src, 0, 1)
return TRUE
// What the device does when turned on
/// What the device does when turned on
/obj/item/assembly/proc/activate()
if(QDELETED(src) || !secured || (next_activate > world.time))
return FALSE
+23 -20
View File
@@ -3,38 +3,41 @@
desc = "This appears to be made from both an electropack and a helmet."
icon = 'icons/obj/assemblies.dmi'
icon_state = "shock_kit"
var/obj/item/clothing/head/helmet/part1 = null
var/obj/item/electropack/part2 = null
var/obj/item/clothing/head/helmet/helmet_part = null
var/obj/item/electropack/electropack_part = null
w_class = WEIGHT_CLASS_HUGE
flags_1 = CONDUCT_1
/obj/item/assembly/shock_kit/Destroy()
qdel(part1)
qdel(part2)
QDEL_NULL(helmet_part)
QDEL_NULL(electropack_part)
return ..()
/obj/item/assembly/shock_kit/Initialize()
. = ..()
if(!helmet_part)
helmet_part = new(src)
helmet_part.master = src
if(!electropack_part)
electropack_part = new(src)
electropack_part.master = src
/obj/item/assembly/shock_kit/wrench_act(mob/living/user, obj/item/I)
..()
to_chat(user, "<span class='notice'>You disassemble [src].</span>")
if(part1)
part1.forceMove(drop_location())
part1.master = null
part1 = null
if(part2)
part2.forceMove(drop_location())
part2.master = null
part2 = null
if(helmet_part)
helmet_part.forceMove(drop_location())
helmet_part.master = null
helmet_part = null
if(electropack_part)
electropack_part.forceMove(drop_location())
electropack_part.master = null
electropack_part = null
qdel(src)
return TRUE
/obj/item/assembly/shock_kit/attack_self(mob/user)
part1.attack_self(user)
part2.attack_self(user)
helmet_part.attack_self(user)
electropack_part.attack_self(user)
add_fingerprint(user)
return
/obj/item/assembly/shock_kit/receive_signal()
if(istype(loc, /obj/structure/chair/e_chair))
var/obj/structure/chair/e_chair/C = loc
C.shock()
return
Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 36 KiB

+2
View File
@@ -53,6 +53,7 @@
#include "code\__DEFINES\dye_keys.dm"
#include "code\__DEFINES\dynamic.dm"
#include "code\__DEFINES\economy.dm"
#include "code\__DEFINES\electrified_buckle.dm"
#include "code\__DEFINES\events.dm"
#include "code\__DEFINES\exosuit_fab.dm"
#include "code\__DEFINES\experisci.dm"
@@ -462,6 +463,7 @@
#include "code\datums\components\dejavu.dm"
#include "code\datums\components\earprotection.dm"
#include "code\datums\components\edit_complainer.dm"
#include "code\datums\components\electrified_buckle.dm"
#include "code\datums\components\embedded.dm"
#include "code\datums\components\explodable.dm"
#include "code\datums\components\footstep.dm"