Files
Paradise/code/game/objects/items/weapons/legcuffs.dm
T
79bad427c8 Movement cross/uncross implementation. (#26762)
* refactor: Movement cross/uncross implementation.

* wrong var name

* fix unit tests dropping PDAs into nowhere

* Add documentation.

* remove unused constants

* say which procs are off limits

* fix simpleanimal z change runtime

* helps not to leave merge conflicts

* kill me

* fix typecast

* fix projectile/table collision

* treadmills don't cause MC to crash anymore

* connect_loc is appropriate here

* fix windoors and teleporters

* fix bonfires and clarify docs

* fix proximity sensors

Tested with sensors in crates, sensors in modsuits
Tested new proximity component with firing projectiles at singularity
Tested new proximity component with portable flashes
Tested new proximity component with facehuggers

* lint

* fix: polarized access helper false positives

* Revert "fix: polarized access helper false positives"

This reverts commit 9814f98cf6.

* hopefully the right change for mindflayer steam

* Changes following cameras

* fix glass table collision

* appears to fix doorspam

* fix ore bags not picking up ore

* fix signatures of /Exited

* remove debug log

* remove duplicate signal registrar

* fix emptying bags into locations

* I don't trust these nested Move calls

* use connect_loc for upgraded resonator fields

* use moveToNullspace

* fix spiderweb crossing

* fix pass checking for windows from a tile off

* fix bluespace closet/transparency issues

* fix mechs not interacting with doors and probably other things

* fix debug

* fix telepete

* add some docs

* stop trying to shoehorn prox monitor into cards

* I should make sure things build

* kill override signal warning

* undef signal

* not many prox monitors survive going off like this

* small fixes to storage

* make moving wormholes respect signals

* use correct signals for pulse demon

* fix pulse heart too

* fix smoke signals

* may have fucked singulo projectile swerve

* fix singulo projectile arcing

* remove duplicate define

* just look at it

* hopefully last cleanups of incorrect signal usage

* fix squeaking

* may god have mercy on my soul

* Apply suggestions from code review

Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
Signed-off-by: warriorstar-orion <orion@snowfrost.garden>

* lewc review

* Apply suggestions from code review

Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
Signed-off-by: warriorstar-orion <orion@snowfrost.garden>

* burza review

* fix bad args for grenade assemblies

* Update code/__DEFINES/is_helpers.dm

Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
Signed-off-by: warriorstar-orion <orion@snowfrost.garden>

---------

Signed-off-by: warriorstar-orion <orion@snowfrost.garden>
Co-authored-by: DGamerL <daan.lyklema@gmail.com>
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
2024-12-21 08:07:44 +00:00

301 lines
10 KiB
Plaintext

/obj/item/restraints/legcuffs
name = "leg cuffs"
desc = "Use this to keep prisoners in line."
gender = PLURAL
icon_state = "handcuff"
cuffed_state = "legcuff"
flags = CONDUCT
throwforce = 0
w_class = WEIGHT_CLASS_NORMAL
origin_tech = "engineering=3;combat=3"
slowdown = 7
breakouttime = 30 SECONDS
/obj/item/restraints/legcuffs/beartrap
name = "bear trap"
throw_speed = 1
throw_range = 1
icon_state = "beartrap0"
desc = "A trap used to catch bears and other legged creatures."
origin_tech = "engineering=4"
breakouttime = 20 SECONDS
var/armed = FALSE
var/trap_damage = 20
///Do we want the beartrap not to make a visable message on arm? Use when a beartrap is applied by something else.
var/silent_arming = FALSE
var/obj/item/grenade/iedcasing/IED = null
var/obj/item/assembly/signaler/sig = null
/obj/item/restraints/legcuffs/beartrap/Initialize(mapload)
. = ..()
var/static/list/loc_connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_atom_entered),
)
AddElement(/datum/element/connect_loc, loc_connections)
/obj/item/restraints/legcuffs/beartrap/update_icon_state()
icon_state = "beartrap[armed]"
/obj/item/restraints/legcuffs/beartrap/Destroy()
QDEL_NULL(IED)
QDEL_NULL(sig)
return ..()
/obj/item/restraints/legcuffs/beartrap/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is sticking [user.p_their()] head in [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
playsound(loc, 'sound/weapons/bladeslice.ogg', 50, TRUE, -1)
return BRUTELOSS
/obj/item/restraints/legcuffs/beartrap/attack_self__legacy__attackchain(mob/user)
..()
if(!ishuman(user) || user.restrained())
return
if(do_after(user, 2 SECONDS, target = user))
armed = !armed
update_icon(UPDATE_ICON_STATE)
to_chat(user, "<span class='notice'>[src] is now [armed ? "armed" : "disarmed"]</span>")
/obj/item/restraints/legcuffs/beartrap/attackby__legacy__attackchain(obj/item/I, mob/user) //Let's get explosive.
if(istype(I, /obj/item/grenade/iedcasing))
if(IED)
to_chat(user, "<span class='warning'>This beartrap already has an IED hooked up to it!</span>")
return
if(sig)
to_chat(user, "<span class='warning'>This beartrap already has a signaler hooked up to it!</span>")
return
user.drop_item()
I.forceMove(src)
IED = I
message_admins("[key_name_admin(user)] has rigged a beartrap with an IED.")
log_game("[key_name(user)] has rigged a beartrap with an IED.")
to_chat(user, "<span class='notice'>You sneak [IED] underneath the pressure plate and connect the trigger wire.</span>")
desc = "A trap used to catch bears and other legged creatures. <span class='warning'>There is an IED hooked up to it.</span>"
if(istype(I, /obj/item/assembly/signaler))
if(IED)
to_chat(user, "<span class='warning'>This beartrap already has an IED hooked up to it!</span>")
return
if(sig)
to_chat(user, "<span class='warning'>This beartrap already has a signaler hooked up to it!</span>")
return
sig = I
if(sig.secured)
to_chat(user, "<span class='warning'>The signaler is secured.</span>")
sig = null
return
user.drop_item()
I.forceMove(src)
to_chat(user, "<span class='notice'>You sneak [sig] underneath the pressure plate and connect the trigger wire.</span>")
desc = "A trap used to catch bears and other legged creatures. <span class='warning'>There is a remote signaler hooked up to it.</span>"
..()
/obj/item/restraints/legcuffs/beartrap/screwdriver_act(mob/living/user, obj/item/I)
if(!IED && !sig)
return
if(IED)
IED.forceMove(get_turf(src))
IED = null
to_chat(user, "<span class='notice'>You remove the IED from [src].</span>")
if(sig)
sig.forceMove(get_turf(src))
sig = null
to_chat(user, "<span class='notice'>You remove the signaler from [src].</span>")
return TRUE
/obj/item/restraints/legcuffs/beartrap/proc/on_atom_entered(datum/source, mob/living/entered)
if(!armed || !isturf(loc) || !istype(entered))
return
if((iscarbon(entered) || isanimal(entered)) && !HAS_TRAIT(entered, TRAIT_FLYING))
spring_trap(entered)
if(ishuman(entered))
var/mob/living/carbon/H = entered
if(IS_HORIZONTAL(H))
H.apply_damage(trap_damage, BRUTE, "chest")
else
H.apply_damage(trap_damage, BRUTE, pick("l_leg", "r_leg"))
if(!H.legcuffed && H.get_num_legs() >= 2) //beartrap can't cuff you leg if there's already a beartrap or legcuffs.
H.legcuffed = src
forceMove(H)
H.update_inv_legcuffed()
SSblackbox.record_feedback("tally", "handcuffs", 1, type)
else
if(istype(entered, /mob/living/simple_animal/hostile/bear))
entered.apply_damage(trap_damage * 2.5, BRUTE)
else
entered.apply_damage(trap_damage * 1.75, BRUTE)
/obj/item/restraints/legcuffs/beartrap/on_found(mob/finder)
if(!armed)
return FALSE
spring_trap(finder)
if(ishuman(finder))
var/mob/living/carbon/H = finder
H.apply_damage(trap_damage, BRUTE, pick("l_hand", "r_hand"))
return TRUE
/obj/item/restraints/legcuffs/beartrap/proc/spring_trap(mob/user)
armed = FALSE
update_icon()
playsound(loc, 'sound/effects/snap.ogg', 50, TRUE)
if(!silent_arming)
user.visible_message("<span class='danger'>[user] triggers [src].</span>", "<span class='userdanger'>You trigger [src].</span>")
if(sig)
sig.signal()
if(IED)
IED.active = TRUE
message_admins("[key_name_admin(usr)] has triggered an IED-rigged [name].")
log_game("[key_name(usr)] has triggered an IED-rigged [name].")
spawn(IED.det_time)
IED.prime()
/obj/item/restraints/legcuffs/beartrap/energy
name = "energy snare"
armed = TRUE
icon_state = "e_snare1"
trap_damage = 0
flags = DROPDEL
breakouttime = 6 SECONDS
/obj/item/restraints/legcuffs/beartrap/energy/New()
..()
addtimer(CALLBACK(src, PROC_REF(dissipate)), 100)
/obj/item/restraints/legcuffs/beartrap/energy/proc/dissipate()
if(!ismob(loc))
do_sparks(1, 1, src)
qdel(src)
/obj/item/restraints/legcuffs/beartrap/energy/attack_hand(mob/user)
Crossed(user) //honk
/obj/item/restraints/legcuffs/beartrap/energy/cyborg
breakouttime = 20 // Cyborgs shouldn't have a strong restraint
/obj/item/restraints/legcuffs/bola
name = "bola"
desc = "A restraining device designed to be thrown at the target. Upon connecting with said target, it will wrap around their legs, making it difficult for them to move quickly."
lefthand_file = 'icons/mob/inhands/weapons_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons_righthand.dmi'
icon_state = "bola"
item_state = "bola"
breakouttime = 3.5 SECONDS
gender = NEUTER
origin_tech = "engineering=3;combat=1"
hitsound = 'sound/effects/snap.ogg'
throw_range = 0 // increased when throw mode is enabled
/// is the bola reuseable?
var/reuseable = TRUE
///the duration of the knockdown in seconds
var/knockdown_duration = 0
/// the number of spins till the bola gets the maximum throw distance. each spin takes 1 second
var/max_spins = 3
/// the max range after the bola fully spins up. if your value for this isn't divisable by the value of `max_spins` it will be lower than the max
var/max_range = 7
/// the max speed after the bola fully spins up. if your value for this isn't divisable by the value of `max_spins` it will be lower than the max
var/max_speed = 2
/// are we currently spinning the bola
var/spinning = FALSE
/obj/item/restraints/legcuffs/bola/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_CARBON_TOGGLE_THROW, PROC_REF(spin_up_wrapper))
/obj/item/restraints/legcuffs/bola/proc/spin_up_wrapper(datum/source, throw_mode_state) // so that signal handler works
SIGNAL_HANDLER
if(throw_mode_state) // if we actually turned throw mode on
INVOKE_ASYNC(src, PROC_REF(spin_up))
/obj/item/restraints/legcuffs/bola/proc/spin_up()
if(spinning)
return
var/mob/living/L = loc // can only be called if the mob is holding the bola.
var/range_increment = round(max_range / max_spins)
var/speed_increment = round(max_speed / max_spins)
RegisterSignal(L, COMSIG_CARBON_SWAP_HANDS, PROC_REF(reset_values), override = TRUE)
item_state = "[initial(item_state)]_spin"
L.update_inv_r_hand()
L.update_inv_l_hand()
spinning = TRUE
for(var/i in 1 to max_spins)
if(!do_mob(L, L, 1 SECONDS, only_use_extra_checks = TRUE, extra_checks = list(CALLBACK(src, PROC_REF(can_spin_check), L))))
reset_values(L)
break
throw_range += range_increment
throw_speed += speed_increment
/obj/item/restraints/legcuffs/bola/end_throw()
reset_values()
/obj/item/restraints/legcuffs/bola/equipped(mob/user, slot, initial) // switching hands with it or putting it into/out of a bag resets it.
. = ..()
reset_values()
/obj/item/restraints/legcuffs/bola/proc/reset_values(mob/living/user)
throw_range = initial(throw_range)
throw_speed = initial(throw_speed)
item_state = initial(item_state)
spinning = FALSE
if(user)
user.update_inv_r_hand()
user.update_inv_l_hand()
/// if it returns TRUE, it breaks the loop, returning FALSE, continues the loop
/obj/item/restraints/legcuffs/bola/proc/can_spin_check(mob/living/user)
if(user.get_active_hand() != src)
return TRUE
if(!user.in_throw_mode)
return TRUE
return FALSE
/obj/item/restraints/legcuffs/bola/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
playsound(loc,'sound/weapons/bolathrow.ogg', 50, TRUE)
if(!..())
return
/obj/item/restraints/legcuffs/bola/throw_impact(atom/hit_atom)
reset_values()
if(..() || !iscarbon(hit_atom))//if it gets caught or the target can't be cuffed,
return//abort
var/mob/living/carbon/C = hit_atom
if(!C.legcuffed && C.get_num_legs() >= 2)
visible_message("<span class='danger'>[src] ensnares [C]!</span>")
C.legcuffed = src
forceMove(C)
C.update_inv_legcuffed()
SSblackbox.record_feedback("tally", "handcuffs", 1, type)
to_chat(C, "<span class='userdanger'>[src] ensnares you!</span>")
C.KnockDown(knockdown_duration)
playsound(loc, hitsound, 50, TRUE)
if(!reuseable)
flags |= DROPDEL
/// traitor variant
/obj/item/restraints/legcuffs/bola/tactical
name = "reinforced bola"
desc = "A strong bola, made with a long steel chain. It looks heavy, enough so that it could trip somebody."
icon_state = "bola_r"
item_state = "bola_r"
breakouttime = 7 SECONDS
origin_tech = "engineering=4;combat=3"
knockdown_duration = 2 SECONDS
/// For Security
/obj/item/restraints/legcuffs/bola/energy
name = "energy bola"
desc = "A specialized hard-light bola designed to ensnare fleeing criminals and aid in arrests."
icon_state = "ebola"
item_state = "ebola"
hitsound = 'sound/weapons/tase.ogg'
w_class = WEIGHT_CLASS_SMALL
breakouttime = 4 SECONDS
reuseable = FALSE