diff --git a/beestation.dme b/beestation.dme index 9c0e244b937c7..b7ca356d20019 100644 --- a/beestation.dme +++ b/beestation.dme @@ -3719,6 +3719,7 @@ #include "monkestation\code\datums\votesounds.dm" #include "monkestation\code\datums\announcers\duke_announcer.dm" #include "monkestation\code\datums\brain_damage\mild.dm" +#include "monkestation\code\datums\components\chain.dm" #include "monkestation\code\datums\components\hot_ice.dm" #include "monkestation\code\datums\components\pricetag.dm" #include "monkestation\code\datums\components\strong_pull.dm" diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 911e2d2057c32..5b34fe1f5859e 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -512,6 +512,10 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai full_w_class = WEIGHT_CLASS_SMALL grind_results = list(/datum/reagent/copper = 2) //2 copper per cable in the coil usesound = 'sound/items/deconstruct.ogg' + //MONKESTATION EDIT: The target when tethering two things together + var/atom/movable/tether_target + //MONKESTATION EDIT: A temporary tether before they attach the vehicle to the second thing + var/datum/component/chain/temp_tether /obj/item/stack/cable_coil/cyborg is_cyborg = 1 @@ -589,6 +593,46 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai amount += extra update_icon() +//MONKESTATION EDIT: Tethering people to vehicles +/obj/item/stack/cable_coil/afterattack(atom/movable/target, mob/user, proximity_flag) + if(!proximity_flag) + return + + if(!istype(target)) + return ..() + + if(QDELETED(temp_tether)) + tether_target = null + temp_tether = null + + if(target == tether_target) + to_chat(user,"You untie the cable from [target].") + qdel(temp_tether) + tether_target = null + temp_tether = null + return + + if(!tether_target) + if(istype(target, /obj/vehicle)) + to_chat(user,"You tie one end of the cable around [target]") + tether_target = target + temp_tether = target.AddComponent(/datum/component/chain, user, 4) + return + + user.visible_message("[user] begins tying the other end of the cable [target]","You begin tying the other end of the cable [target]") + if(do_after(user, 8 SECONDS, target=target)) + target.AddComponent(/datum/component/chain, tether_target, 4) + use(1) + qdel(temp_tether) + temp_tether = null + tether_target = null + +/obj/item/stack/cable_coil/dropped(mob/user) + . = ..() + if(temp_tether) + qdel(temp_tether) + temp_tether = null + tether_target = null /////////////////////////////////////////////// diff --git a/monkestation/code/datums/components/chain.dm b/monkestation/code/datums/components/chain.dm new file mode 100644 index 0000000000000..1403643b7671a --- /dev/null +++ b/monkestation/code/datums/components/chain.dm @@ -0,0 +1,124 @@ + +/* +This component attaches to things that'll follow another object +Like connecting a person to a wheelchair so they get dragged behind it +*/ +/datum/component/chain + //The thing the parent will follow + var/atom/movable/attachment_point + + var/atom/movable/owner + var/max_dist + var/equal_force + + var/datum/beam/tether_beam + +/datum/component/chain/Initialize(target, max_dist=3, equal_force = TRUE, draw_beam = TRUE) + if(!ismovableatom(parent) || !ismovableatom(target)) + return COMPONENT_INCOMPATIBLE + + owner = parent + attachment_point = target + src.max_dist = max_dist + src.equal_force = equal_force + + if(draw_beam) + tether_beam = owner.Beam(target, "usb_cable_beam", 'icons/obj/wiremod.dmi', maxdistance = max_dist+1) + + RegisterSignal(target, COMSIG_MOVABLE_PRE_MOVE, .proc/on_attachment_move) + RegisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE, .proc/on_parent_move) + RegisterSignal(owner, COMSIG_ATOM_ATTACK_HAND, .proc/on_parent_touched) + RegisterSignal(owner, COMSIG_ATOM_TOOL_ACT(TOOL_WIRECUTTER), .proc/on_parent_wirecutters) + + if(draw_beam) + RegisterSignal(owner, COMSIG_MOVABLE_MOVED, .proc/on_atom_moved) + RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/on_atom_moved) + +/datum/component/chain/Destroy(force, silent) + . = ..() + if(tether_beam) + qdel(tether_beam) + tether_beam = null + owner = null + attachment_point = null + +/datum/component/chain/proc/on_atom_moved(atom/movable/mover, old_loc, movement_dir, forced, old_locs, momentum_change) + SIGNAL_HANDLER + + spawn(0) + tether_beam.recalculate() + +/datum/component/chain/proc/on_attachment_move(atom/movable/mover, newloc) + SIGNAL_HANDLER + + if(!owner) + qdel(src) + return + + var/dist = get_dist(owner,newloc) + if(dist < max_dist) + return + + if(!owner.anchored) + owner.Move(get_step_towards(owner,mover)) + + if(isliving(owner)) + var/mob/living/living_owner = owner + living_owner.Knockdown(1 SECONDS) + + if(dist > max_dist) + owner.visible_message("The tether snaps!") + qdel(src) + return + +/datum/component/chain/proc/on_parent_move(atom/movable/mover, newloc) + SIGNAL_HANDLER + + if(!attachment_point) + qdel(src) + return + + var/dist = get_dist(attachment_point,newloc) + if(dist < max_dist) + return + + if(dist > max_dist) + qdel(src) + return + + if(attachment_point.anchored) + return COMPONENT_MOVABLE_BLOCK_PRE_MOVE + + attachment_point.Move(get_step_towards(attachment_point,mover)) + + if(equal_force) + return + + if(isliving(owner)) + var/mob/living/living_owner = owner + living_owner.Knockdown(1 SECONDS) + to_chat(owner,"You trip on the tether!") + return COMPONENT_MOVABLE_BLOCK_PRE_MOVE + +/datum/component/chain/proc/on_parent_touched(datum/source, mob/user) + SIGNAL_HANDLER + + INVOKE_ASYNC(src, .proc/untie_parent, user) + +/datum/component/chain/proc/untie_parent(mob/user) + if(user == owner) + user.visible_message("[user] begins untying the cable from \himself.","You begin untying the cable from yourself.") + else + user.visible_message("[user] begins untying the cable from [owner].","You begin untying the cable from [owner].") + if(do_mob(user, owner, 10 SECONDS)) + qdel(src) + +/datum/component/chain/proc/on_parent_wirecutters(datum/source, mob/user) + SIGNAL_HANDLER + + if(user == owner) + user.visible_message("[user] cuts \himself free.","You cut yourself free.") + else + user.visible_message("[user] cuts [owner] free.","[user] cuts you free] free.") + qdel(src) + return COMPONENT_BLOCK_TOOL_ATTACK