Files
ShadowandGitHub af05eae20a Saw traps no longer automatically chop off legs and feet (#7585)
## About The Pull Request

Changed the saw traps to apply their damage directly to their targeted
limb instead of immediately severing it.

This PR has been tested locally.

## Why It's Good For The Game

The saw traps in some exploration areas, for some reason, automatically
sever your feet/legs when stepped on, on top of applying their actual
damage. This seems overly harsh especially given the chaotic nature of
exploration, so I have changed them to simply apply their damage to a
leg/foot when stepped on. Their damage is enough to significantly injure
someone with even a couple steps, and repeatedly walking into them if
you are careless will eventually break/sever the limb anyway.

## Changelog
🆑
balance: Saw traps will no longer immediately sever limbs when stepped
on.
/🆑
2026-05-29 02:46:21 -04:00

828 lines
27 KiB
Plaintext

//////////////////////////////
// Traps Readme
//////////////////////////////
/*
Hello! Below you will find a variety of traps designed for map placement.
Many of these traps were created with a sort of "Tomb" or "Ruins" vibe in mind, but there is always room to expand!
All traps are able to be networked together through the ID variable.
Most traps are designed to work in conjunction with Pressure Plates, which may be located in 'code/game/turfs/flooring/flooring_traps.dm'.
Certain traps, like the Falling Log, are designed to trigger when crossed, instead of relying on a pressure plate system to trip.
Some traps necessarily possess vestigial variables, so make sure to read through them and factor in the nuances of each model!
Traps are split into a couple categories:
- Pit
- Launcher
- Pop-Up
- Falling
Pit Traps:
An undeniable classic. Pit traps are those traps which cause the floor to give way and drop an unsuspecting victim into a hazard.
Exactly how this works necessarily varies between each form of trap. Acid pits have to replace the entire turf, whereas punji pits simply lay over the floor.
Be sure to take this into consideration when laying out traps. For some undetermined reason, pit traps do not activate simultaneously, either.
That is to say, a pressure plate being tripped will only trigger one trap at a time. This is a bug and I have not yet found a solution.
Pit traps may be temporarily circumvented by laying down wooden planks to form a bridge, but be careful! These planks may not be that sturdy.
Pit traps may be closed over/reset by using floor tiles on them. This system probably needs more refinement, but it is baseline functional.
Launcher Traps:
Another Temple Delver favorite, launcher traps fire projectiles in a set direction when set off by a pressure plate.
These projectiles CAN destroy walls across from them, so be mindful of your placement when designing these, so that they don't undercut other portions of your dungeon.
Launchers may be jammed by shoving rods into the holes, and unjammed/reset by crowbarring out obstructions.
More icon variants for launchers are planned.
Pop-Up Traps:
WARNING! A debug variant exists for pop-up traps. The basic Pop-Up trap (obj/effect/trap/pop_up) is not intended for use.
These traps hide under the floor, and trigger when set off by a pressure plate.
They can be incredibly deadly, and must be destroyed to neutralize their threat. Some may be repaired with a welder.
Some, like the thrower trap, can be jammed with rods, or unjammed with wirecutters. Use throwers to catapult hapless victims into other hazards for maximum carnage!
A way to repair and/or reset every variant of Pop-Up would be nice eventually.
Falling Traps:
WARNING! A debug variant exists for falling traps. The basic Falling trap (obj/effect/trap/falling) is not intended for use.
Remember that scene with the AT-ST in Star Wars Ep. VI? I do! These traps plummet from above to totally ruin your day!
Currently only the falling log exists, but eventually I have plans for wrecking balls, dual logs, pendulum axes, and so on!
These traps not only smack you with damage flat out, but they can throw you in a random direction, allowing you to potentially send victims into other traps!
The falling log (and potentially all falling traps) can be broken by using wirecutters on the ropes, and can be repaired/reset using cables.
That about covers it! If you get an idea for a trap, swing it by me, or try your hand at implementing it yourself! If you have any questions, I'm always happy to answer them!
- Kat
General To-Do/Wants:
Solve pressure plate multi-signal issue for acid pits? Everything else pops correctly.
Make more Launcher sprites - sculpture, recessed holes, etc.
Make Laser sci-fi flavored Launchers - energy beam wall mounts, magical spinning crystals, etc.
Make it so pop-ups can be damaged by weapon attacks, and not just projectiles?
Make it so swinging ropes can be cut by knives/swords, and not just wirecutters.
Add those other swinging traps you mentioned above!
*/
/obj/effect/trap
name = "strange area"
desc = "The dust hangs strangely in the air here."
icon = 'icons/turf/flooring/trap.dmi'
icon_state = "trap_frame"
anchored = TRUE
density = FALSE
integrity_flags = INTEGRITY_NO_DECONSTRUCT
//invisibility = INVISIBILITY_MAXIMUM - Commented this invis variant out due to balancing issues/its blocking of warning text and effect icons.
//mouse_opacity = MOUSE_OPACITY_TRANSPARENT - Commented out for admin QOL and cleanup.
var/trap_floor_type = /turf/simulated/floor/water/acid
var/tripped = FALSE
var/id = "trap_debug_controller"
/obj/effect/trap/Initialize(mapload)
. = ..()
simple_network_register(id)
/obj/effect/trap/simple_network_receive(id, message, list/data, datum/sender)
. = ..()
trip()
/obj/effect/trap/proc/trip()
if(tripped)
return
if(!tripped)
tripped = TRUE
fire()
/obj/effect/trap/proc/fire()
update_icon()
visible_message("<span class='danger'>The floor crumbles away!</span>")
playsound(src, 'sound/effects/slosh.ogg', 100, 1)
var/turf/deploy_location = get_turf(src)
deploy_location.ChangeTurf(trap_floor_type)
/obj/effect/trap/examine_integrity(mob/user)
. = list()
if(atom_flags & ATOM_BROKEN)
. += SPAN_WARNING("Whatever nefarious purpose this one once had, it's broken now.")
/obj/effect/trap/atom_break()
. = ..()
update_icon()
/obj/effect/trap/atom_fix()
. = ..()
update_icon()
/obj/effect/trap/update_icon_state()
if(!tripped)
icon_state = "[initial(icon_state)]"
else if (tripped)
icon_state = "[initial(icon_state)]_visible"
return ..()
//////////////////
/// Pit Traps
//////////////////
//Acid Pits
/obj/effect/trap/pit
name = "strange area"
desc = "The dust hangs strangely in the air here."
/obj/effect/trap/pit/attackby(obj/item/W, mob/user)
if(istype(W,/obj/item/stack/material/wood))
var/obj/item/stack/material/wood/M = W
if(M.amount >= 3)
M.use(3)
var/turf/T = get_turf(src)
new /obj/structure/catwalk/plank(T)
to_chat(user, "<span class='notice'>You carefully lay the planks over the trap, creating a bridge.</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need three planks of wood to construct a bridge.</span>")
else if(istype(W,/obj/item/stack/tile))
var/obj/item/stack/tile/M = W
var/rearm_type = /turf/simulated/floor/plating
if(M.amount >= 2)
M.use(2)
var/turf/T = get_turf(src)
T.ChangeTurf(rearm_type)
tripped = 0
update_icon()
to_chat(user, "<span class='notice'>You patch over the hole, rearming the trap.</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need two tiles to rearm the trap.</span>")
/obj/effect/trap/pit/deep
trap_floor_type = /turf/simulated/floor/water/acid/deep
/obj/effect/trap/pit/blood
trap_floor_type = /turf/simulated/floor/water/blood
/obj/effect/trap/pit/blood/deep
trap_floor_type = /turf/simulated/floor/water/blood/deep
/obj/effect/trap/pit/open_space
trap_floor_type = /turf/simulated/open
//Punji Spear Traps
/obj/effect/trap/pit/punji
icon_state = "punji"
trap_floor_type = null
var/min_damage = 15
var/max_damage = 25
/obj/effect/trap/pit/punji/fire()
name = "punji pit"
desc = "This pit is filled with sharpened punji stakes!"
update_icon()
visible_message("<span class='danger'>The floor crumbles away!</span>")
playsound(src, 'sound/weapons/slice.ogg', 100, 1)
/obj/effect/trap/pit/punji/Crossed(atom/AM as mob|obj)
. = ..()
if(AM.is_incorporeal())
return
if(!tripped)
return
else if(istype(AM, /mob/living))
var/mob/living/M = AM
if(M.is_avoiding_ground())
return
var/damage = rand(min_damage, max_damage)
M.apply_damage(damage, DAMAGE_TYPE_BRUTE)
M.visible_message("<span class='danger'>[M] falls onto a punji stake!</span>", \
"<span class='userdanger'>You slide onto a punji stake!</span>")
/obj/effect/trap/pit/punji/attackby(obj/item/W, mob/user)
..()
if(istype(W,/obj/item/stack/tile))
var/obj/item/stack/tile/M = W
if(M.amount >= 2)
M.use(2)
tripped = 0
update_icon()
to_chat(user, "<span class='notice'>You conceal the pit, rearming the trap.</span>")
qdel(src)
else
to_chat(user, "<span class='warning'>You need two tiles to rearm the trap.</span>")
//Bone Breaking Traps
/obj/effect/trap/pit/bone_breaker
icon_state = "bone"
trap_floor_type = null
/obj/effect/trap/pit/bone_breaker/fire(atom/A)
update_icon()
visible_message("<span class='danger'>The floor crumbles away!</span>")
playsound(src, 'sound/effects/bang.ogg', 100, 1)
/obj/effect/trap/pit/bone_breaker/Crossed(atom/AM as mob|obj)
. = ..()
if(AM.is_incorporeal())
return
if(!tripped)
return
else if(istype(AM, /mob/living))
var/mob/living/M = AM
if(M.is_avoiding_ground())
return
break_legs(AM)
AM.visible_message("<span class='danger'>[AM] falls into the path of the piston!</span>", \
"<span class='userdanger'>Your leg is crushed by the piston!</span>")
/obj/effect/trap/pit/bone_breaker/proc/break_legs(mob/victim as mob)
var/broken_legs = 0
var/mob/living/carbon/human/target = victim
var/obj/item/organ/external/left_leg = target.get_organ(BP_L_LEG)
var/obj/item/organ/external/right_leg = target.get_organ(BP_R_LEG)
playsound(src, 'sound/effects/bang.ogg', 100, 1)
if(left_leg && left_leg.fracture())
broken_legs++
if(right_leg && right_leg.fracture())
broken_legs++
if(!broken_legs)
return
/obj/effect/trap/pit/bone_breaker/attackby(obj/item/W, mob/user)
..()
if(istype(W,/obj/item/stack/tile))
var/obj/item/stack/tile/M = W
if(M.amount >= 2)
M.use(2)
tripped = 0
update_icon()
to_chat(user, "<span class='notice'>You conceal the pit, rearming the trap.</span>")
else
to_chat(user, "<span class='warning'>You need two tiles to rearm the trap.</span>")
//Pitfall Traps (These are chasms, so only use these if you're okay with permakilling someone for the round.)
//It's currently acting as if chasms don't exist. Investigate.
/*
/obj/effect/trap/pit/chasm
trap_floor_type = /turf/open/chasm
*/
//Tentacle Pits
/obj/effect/trap/pit/tentacle
icon_state = "tentacle"
trap_floor_type = null
var/min_damage = 15
var/max_damage = 25
/obj/effect/trap/pit/tentacle/fire(atom/A)
update_icon()
visible_message("<span class='danger'>The floor crumbles away!</span>")
playsound(src, 'sound/effects/blobattack.ogg', 100, 1)
/obj/effect/trap/pit/tentacle/Crossed(atom/AM as mob|obj)
. = ..()
if(AM.is_incorporeal())
return
if(!tripped)
return
else if(istype(AM, /mob/living))
var/mob/living/M = AM
if(M.is_avoiding_ground())
return
var/damage = rand(min_damage, max_damage)
M.apply_damage(damage, DAMAGE_TYPE_TOX)
M.set_stunned(20 * 15)
M.visible_message("<span class='danger'>[M] falls into a writhing mass of tentacles!</span>", \
"<span class='userdanger'>You are entwined by a writhing mass of tentacles!</span>")
/obj/effect/trap/pit/tentacle/attackby(obj/item/W, mob/user)
..()
if(istype(W,/obj/item/stack/tile))
var/obj/item/stack/tile/M = W
if(M.amount >= 2)
M.use(2)
tripped = 0
update_icon()
to_chat(user, "<span class='notice'>You conceal the pit, rearming the trap.</span>")
else
to_chat(user, "<span class='warning'>You need two tiles to rearm the trap.</span>")
/obj/effect/trap/pit/tentacle/safe //C'mon, you know why.
min_damage = 0
max_damage = 0
//////////////////
// Launcher Traps
//////////////////
//Crossbow Launcher
/obj/effect/trap/launcher
name = "odd sculpture"
desc = "This sculpture on the wall seems vaguely threatening."
icon_state = "launcher"
anchored = 1
density = 1
dir = 2
trap_floor_type = null
var/projectile_type
var/projectile_sound
var/fire_delay = 5
var/max_burst_delay = 10
var/min_burst_delay = 2
var/burst_shots = 3
var/last_shot = 0
var/shot_number = 0
var/burst_delay = 2
var/initial_fire_delay = 5
var/ammo_count = 0
var/ammo_store = 0 //How many shots the trap has stored before it runs out. This seems to work out to the value + 1.
//This needs to check dirs, projectiles, accuracy, reload/recharge. It's kinda gonna suck. Consult Turret code.
/obj/effect/trap/launcher/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/effect/trap/launcher/fire()
update_icon()
visible_message("<span class='danger'>The sculpture's eyes snap open!</span>")
playsound(src, 'sound/effects/stonedoor_openclose.ogg', 100, 1)
/obj/effect/trap/launcher/process(delta_time)
if(!tripped)
return
if(atom_flags & ATOM_BROKEN)
return
if(ammo_count)
if(src.shot_number > src.ammo_store)
return
if(((src.last_shot + src.fire_delay) <= world.time) && src.tripped)
src.last_shot = world.time
if(src.shot_number < burst_shots)
src.fire_delay = get_burst_delay()
src.shot_number ++
else
src.fire_delay = get_rand_burst_delay()
src.shot_number = 0
playsound(src.loc, projectile_sound, 25, 1)
var/obj/projectile/bullet/shotgun/stake/P = get_projectile()
//P.firer = src
P.fire(dir2angle(dir))
/obj/effect/trap/launcher/proc/get_initial_fire_delay()
return initial_fire_delay
/obj/effect/trap/launcher/proc/get_rand_burst_delay()
return rand(min_burst_delay, max_burst_delay)
/obj/effect/trap/launcher/proc/get_burst_delay()
return burst_delay
/obj/effect/trap/launcher/proc/get_projectile()
return new projectile_type(get_turf(src))
/obj/effect/trap/launcher/attackby(var/obj/item/W, var/mob/user)
if(istype(W,/obj/item/stack/rods))
var/obj/item/stack/rods/M = W
if(M.amount >= 5)
M.use(5)
atom_break()
to_chat(user, "<span class='notice'>You slip the rods into the firing mechanism, jamming it.</span>")
else
to_chat(user, "<span class='warning'>You need five rods to jam the mechanism.</span>")
if(istype(W,/obj/item/tool/crowbar))
if((atom_flags & ATOM_BROKEN))
to_chat(user, "<span class='notice'>You pry the obstruction out, resetting the trap.</span>")
atom_fix()
else
to_chat(user, "<span class='warning'>You can't pry this sculpture off of the wall.</span>")
/obj/effect/trap/launcher/update_icon_state()
if(!tripped)
icon_state = "[initial(icon_state)]"
else if (tripped && !(atom_flags & ATOM_BROKEN))
icon_state = "[initial(icon_state)]_visible"
else if (tripped && (atom_flags & ATOM_BROKEN))
icon_state = "[initial(icon_state)]_jammed"
return ..()
//Stake Launcher
/obj/effect/trap/launcher/stake
projectile_type = /obj/projectile/bullet/shotgun/stake
projectile_sound = 'sound/weapons/punchmiss.ogg'
//Dart Launcher
/obj/effect/trap/launcher/dart
projectile_type = /obj/projectile/energy/bolt
projectile_sound = 'sound/weapons/slice.ogg'
//Fireball Launcher
/obj/effect/trap/launcher/fireball
projectile_type = /obj/projectile/bullet/incendiary/flamethrower/large
projectile_sound = 'sound/effects/bamf.ogg'
//Heavy Fireball Launcher
/obj/effect/trap/launcher/fireball_aoe
projectile_type = /obj/projectile/magic/aoe/fireball
projectile_sound = 'sound/weapons/cannon.ogg'
/obj/effect/trap/launcher/fireball_aoe/finite //Finite variant
ammo_count = 1
ammo_store = 1
//Web Launcher
/obj/effect/trap/launcher/web
projectile_type = /obj/projectile/webball
projectile_sound = 'sound/effects/splat.ogg'
//Flesh Launcher
/obj/effect/trap/launcher/flesh
projectile_type = /obj/projectile/bullet/organic
projectile_sound = 'sound/effects/squelch1.ogg'
//////////////////
// Pop-Up Traps
//////////////////
//Debug
/obj/effect/trap/pop_up
name = "pop up trap"
desc = "You shouldn't be seeing this! Contact an admin!"
icon_state = "popup_spear"
anchored = 1
density = 0
trap_floor_type = null
integrity = 200
integrity_max = 200
var/min_damage = 15
var/max_damage = 25
/obj/effect/trap/pop_up/attackby(var/obj/item/W, var/mob/user)
if(istype(W, /obj/item/weldingtool))
var/obj/item/weldingtool/WT = W
if(WT.remove_fuel(0, user))
if(integrity < integrity_max)
to_chat(user, SPAN_NOTICE("You begin repairing \the [src.name] with \the [WT].>"))
if(do_after(user, 20, src))
set_integrity(integrity_max)
return
return ..()
/obj/effect/trap/pop_up/atom_break()
. = ..()
visible_message(SPAN_DANGER("\The [src] breaks! It was a trap!"))
/obj/effect/trap/pop_up/update_icon_state()
if(!tripped)
icon_state = "[initial(icon_state)]"
else if(tripped && !(atom_flags & ATOM_BROKEN))
icon_state = "[initial(icon_state)]_visible"
else if (tripped && (atom_flags & ATOM_BROKEN))
icon_state = "[initial(icon_state)]_broken"
return ..()
//Spear Trap
/obj/effect/trap/pop_up/spear
name = "loose tile"
desc = "The edges of this tile are angled strangely."
icon_state = "popup_spear"
/obj/effect/trap/pop_up/spear/fire()
update_icon()
visible_message("<span class='danger'>Blades erupt from concealed holes in the floor!</span>")
playsound(src, 'sound/effects/holster/holsterout.ogg', 100, 1) //Sound is too quiet, same issue as pillar.
name = "spear trap"
desc = "These knee-high blades look dangerous!"
/obj/effect/trap/pop_up/spear/Crossed(atom/AM as mob|obj)
. = ..()
if(AM.is_incorporeal())
return
if((atom_flags & ATOM_BROKEN))
return
if(!tripped)
return
else if(istype(AM, /mob/living))
var/mob/living/M = AM
var/damage = rand(min_damage, max_damage)
M.apply_damage(damage, DAMAGE_TYPE_BRUTE)
M.visible_message("<span class='danger'>[M] is stabbed by the rising spears!</span>", \
"<span class='userdanger'>You are impaled by a thrusting spear!</span>")
//Spinning Blade Column
/obj/effect/trap/pop_up/pillar
name = "loose tile"
desc = "The edges of this tile are bent strangely."
icon_state = "popup_pillar"
min_damage = 10
max_damage = 30
/obj/effect/trap/pop_up/pillar/fire()
update_icon()
visible_message("<span class='danger'>A bladed pillar pops up from a concealed pit in the floor!</span>")
playsound(src, 'sound/effects/holster/holsterout.ogg', 100, 1) //Fix sound. It's the gun draw sound, not the blade draw.
name = "spinning blade trap"
desc = "The blades on this waist-high pillar are spinning violently!"
/obj/effect/trap/pop_up/pillar/Crossed(atom/AM as mob|obj)
. = ..()
if(AM.is_incorporeal())
return
if((atom_flags & ATOM_BROKEN))
return
if(!tripped)
return
else if(istype(AM, /mob/living))
var/mob/living/M = AM
var/damage = rand(min_damage, max_damage)
var/list/target_limbs = list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)
var/selected = pick(target_limbs)
var/obj/item/organ/external/target = M.get_organ(selected)
target.inflict_bodypart_damage(damage, 0, DAMAGE_MODE_SHARP | DAMAGE_MODE_SHRED, "spinning saw blade")
M.visible_message("<span class='danger'>[M] is slashed by the spinning blades!</span>", \
"<span class='userdanger'>You are slashed by the spinning blades!</span>")
/* This is all per-tick processing stuff. It isn't working the way I want, so I'm reverting it.
if (istype(AM, /mob/living))
START_PROCESSING(SSprocess_5fps, src)
var/mob/living/M = AM
M.visible_message("<span class='danger'>[M] is slashed by the spinning blades!</span>", \
"<span class='userdanger'>You are slashed by the spinning blades!</span>")
/obj/effect/trap/pop_up/pillar/process(atom/AM as mob|obj)
var/mob/living/M = AM
var/damage = rand(min_damage, max_damage)
M.apply_damage(damage, DAMAGE_TYPE_BRUTE)
/obj/effect/trap/pop_up/pillar/Destroy()
STOP_PROCESSING(SSprocess_5fps, src)
return ..()
*/
//Springtrap Buzzsaw
/obj/effect/trap/pop_up/buzzsaw
icon_state = "popup_saw"
name = "loose tile"
desc = "This tile has straight slits running along it."
min_damage = 25
max_damage = 45
/obj/effect/trap/pop_up/buzzsaw/fire()
update_icon()
visible_message("<span class='danger'>Sawblades erupt from concealed slats in the floor!</span>")
playsound(src, 'sound/weapons/circsawhit.ogg', 100, 1)
name = "spinning saw trap"
desc = "These buzzsaw blades are spinning incredibly quickly!"
/obj/effect/trap/pop_up/buzzsaw/Crossed(atom/AM as mob|obj)
. = ..()
if(AM.is_incorporeal())
return
if((atom_flags & ATOM_BROKEN))
return
if(!tripped)
return
else if(istype(AM, /mob/living))
var/mob/living/M = AM
var/damage = rand(min_damage, max_damage)
var/list/target_limbs = list(BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)
var/selected = pick(target_limbs)
var/obj/item/organ/external/target = M.get_organ(selected)
target.inflict_bodypart_damage(damage, 0, DAMAGE_MODE_SHARP | DAMAGE_MODE_SHRED, "spinning saw blade")
M.visible_message("<span class='danger'>[M] is ripped by the whirling sawblades!</span>", \
"<span class='userdanger'>You are ripped open by the whirling sawblades!</span>")
//Flame Trap
/obj/effect/trap/pop_up/flame
name = "loose tile"
desc = "The edges of this tile shine strangely."
icon_state = "popup_flame"
min_damage = 5
max_damage = 15
/obj/effect/trap/pop_up/flame/fire()
update_icon()
visible_message("<span class='danger'>Flames gush from a hidden nozzle in the floor!</span>")
playsound(src, 'sound/effects/bamf.ogg', 100, 1)
name = "flame geyser trap"
desc = "The flames bursting out of this are extremely hot!"
/obj/effect/trap/pop_up/flame/Crossed(atom/AM as mob|obj)
. = ..()
if(AM.is_incorporeal())
return
if((atom_flags & ATOM_BROKEN))
return
if(!tripped)
return
else if(istype(AM, /mob/living))
var/mob/living/M = AM
var/damage = rand(min_damage, max_damage)
M.apply_damage(damage, DAMAGE_TYPE_BURN)
M.adjust_fire_stacks(2)
M.IgniteMob()
M.visible_message("<span class='danger'>[M] is engulfed in flames!</span>", \
"<span class='userdanger'>You are engulfed in ravenous flames!</span>")
//Tossing Piston Plate
/obj/effect/trap/pop_up/thrower
name = "crooked tile"
desc = "The edges of this tile are lifted slightly."
icon_state = "thrower"
trap_floor_type = null
/obj/effect/trap/pop_up/thrower/fire()
update_icon()
visible_message("<span class='danger'>The floor tile pistons upwards violently!</span>")
playsound(src, 'sound/effects/bang.ogg', 100, 1)
name = "piston trap"
desc = "This concealed piston rockets upwards with great force."
/obj/effect/trap/pop_up/thrower/Crossed(atom/AM as mob|obj)
. = ..()
if(AM.is_incorporeal())
return
if((atom_flags & ATOM_BROKEN))
return
if (!tripped)
return
else if(istype(AM, /mob/living))
var/mob/living/M = AM
var/list/throw_dirs = list(1, 2, 4, 8, 5, 6, 9, 10)
var/turf/T2 = get_step(AM, pick(throw_dirs))
M.throw_at_old(T2, 1, 1, src)
var/head_slot = SLOT_HEAD
if(!head_slot || !(istype(head_slot,/obj/item/clothing/head/helmet) || istype(head_slot,/obj/item/clothing/head/hardhat)))
M.setBrainLoss(2,5)
M.update_health()
update_icon()
playsound(src, 'sound/effects/bang.ogg', 100, 1)
visible_message("<span class='danger'>[src] slams into [M], sending them flying!</span>")
M.afflict_paralyze(20 * 12)
/obj/effect/trap/pop_up/thrower/attackby(var/obj/item/W, var/mob/user)
if(istype(W,/obj/item/stack/rods))
var/obj/item/stack/rods/M = W
if(M.amount >= 3)
M.use(3)
atom_break()
to_chat(user, "<span class='notice'>You slip the rods between the plate and its base, jamming it.</span>")
else
to_chat(user, "<span class='warning'>You need three rods to jam the mechanism.</span>")
if(istype(W,/obj/item/tool/wirecutters))
if((atom_flags & ATOM_BROKEN))
atom_fix()
to_chat(user, "<span class='notice'>You slice the rods and remove them, resetting the trap.</span>")
else
to_chat(user, "<span class='warning'>You can't disarm the trap this way!</span>")
/obj/effect/trap/pop_up/thrower/atom_fix()
. = ..()
update_icon()
set_integrity(integrity_max)
tripped = FALSE
name = "crooked tile"
desc = "The edges of this tile are lifted slightly."
/obj/effect/trap/pop_up/thrower/update_icon_state()
if(!tripped)
icon_state = "[initial(icon_state)]"
else if (tripped && !(atom_flags & ATOM_BROKEN))
icon_state = "[initial(icon_state)]_visible"
else if (tripped && (atom_flags & ATOM_BROKEN))
icon_state = "[initial(icon_state)]_jammed"
return ..()
//////////////////
// Falling Traps
//////////////////
//Falling Log
/obj/effect/trap/falling
name = "falling trap"
desc = "You shouldn't be seeing this! Contact an admin!"
icon_state = "log"
trap_floor_type = null
var/min_damage = 20
var/max_damage = 40
/obj/effect/trap/falling/attackby(var/obj/item/W, var/mob/user)
if(istype(W,/obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/M = W
if(M.amount >= 5 && (atom_flags & ATOM_BROKEN))
M.use(5)
atom_fix()
to_chat(user, "<span class='notice'>You use the coils to raise the [src] back up, resetting it.</span>")
if(istype(W,/obj/item/tool/wirecutters) || is_sharp(W))
if(!(atom_flags & ATOM_BROKEN))
atom_break()
to_chat(user, "<span class='notice'>You cut the ropes suspending the [src], breaking it.</span>")
update_icon()
/obj/effect/trap/falling/update_icon_state()
if(!tripped)
icon_state = "[initial(icon_state)]"
else if (tripped && !(atom_flags & ATOM_BROKEN))
icon_state = "[initial(icon_state)]_visible"
else if (tripped && (atom_flags & ATOM_BROKEN))
icon_state = "[initial(icon_state)]_jammed"
return ..()
//Falling Log
/obj/effect/trap/falling/log
name = "wavering tile"
desc = "There's something strange about the lighting around this tile."
icon_state = "log"
trap_floor_type = null
id = "self_triggering"
min_damage = 20
max_damage = 40
/obj/effect/trap/falling/log/fire()
visible_message("<span class='danger'>A log swings down from overhead!</span>")
tripped = TRUE
name = "falling log trap"
desc = "A heavy wooden log suspended by ropes. Primitive, but effective."
/obj/effect/trap/falling/log/Crossed(atom/AM as mob|obj)
. = ..()
if(AM.is_incorporeal())
return
if((atom_flags & ATOM_BROKEN))
return
if(tripped)
return
if(istype(AM, /mob/living))
fire()
update_icon()
var/mob/living/M = AM
var/list/throw_dirs = list(1, 2, 4, 8, 5, 6, 9, 10)
var/turf/T2 = get_step(AM, pick(throw_dirs))
var/damage = rand(min_damage, max_damage)
var/list/bone_sites = list(BP_HEAD, BP_TORSO, BP_GROIN, BP_L_ARM, BP_L_HAND, BP_R_ARM, BP_R_HAND, BP_L_LEG, BP_L_FOOT, BP_R_LEG, BP_R_FOOT)
var/selected = pick(bone_sites)
var/obj/item/organ/external/target = M.get_organ(selected)
var/head_slot = SLOT_HEAD
M.apply_damage(damage, DAMAGE_TYPE_BRUTE)
target.fracture()
M.throw_at_old(T2, 1, 1, src)
if(!head_slot || !(istype(head_slot,/obj/item/clothing/head/helmet) || istype(head_slot,/obj/item/clothing/head/hardhat)))
M.setBrainLoss(2,5)
M.update_health()
playsound(src, 'sound/effects/bang.ogg', 100, 1)
visible_message("<span class='danger'>The falling log slams into [M], sending them flying!</span>")
M.afflict_paralyze(20 * 12)
/obj/effect/trap/falling/log/atom_fix()
. = ..()
set_integrity(integrity_max)
tripped = FALSE
name = "wavering tile"
desc = "There's something strange about the lighting around this tile."
update_icon()
/obj/effect/trap/falling/log/update_icon_state()
if(!tripped)
icon_state = "[initial(icon_state)]"
else if (tripped && !(atom_flags & ATOM_BROKEN))
icon_state = "[initial(icon_state)]_visible"
else if (tripped && (atom_flags & ATOM_BROKEN))
icon_state = "[initial(icon_state)]_jammed"
return ..()