Files
Aurora.3/code/game/objects/items/weapons/traps.dm
Fluffy ec194f9988 Tyrant tweaks (#19371)
Added some notifications of proximity to the plains tyrant.
Reduced health and auto-brute-healing of the plains tyrant.
Fixed traps pathing so that mobs should now pass in them.
Optimized SA_attackable proc.
Mechs are no longer opaque, this fixes the simplemobs not attacking them
(because the line of sight check fails as the turf they stand on is
opaque if they are opaque too) as well as avoid lighting recomputing on
every step.

---------

Signed-off-by: Fluffy <65877598+FluffyGhoster@users.noreply.github.com>
Co-authored-by: Matt Atlas <mattiathebest2000@hotmail.it>
2024-06-09 17:08:04 +00:00

853 lines
25 KiB
Plaintext

/obj/item/trap
name = "mechanical trap"
desc = "A mechanically activated leg trap. Low-tech, but reliable. Looks like it could really hurt if you set it off."
throw_speed = 2
throw_range = 1
gender = PLURAL
icon = 'icons/obj/item/traps/traps.dmi'
var/icon_base = "beartrap"
icon_state = "beartrap0"
randpixel = 0
center_of_mass = null
throwforce = 0
w_class = ITEMSIZE_NORMAL
origin_tech = list(TECH_ENGINEERING = 2)
matter = list(DEFAULT_WALL_MATERIAL = 18750)
var/deployed = FALSE
var/time_to_escape = 60
var/activated_armor_penetration = 0
/obj/item/trap/Initialize()
. = ..()
update_icon()
/obj/item/trap/proc/can_use(mob/user)
return (user.IsAdvancedToolUser() && !issilicon(user) && !user.stat && !user.restrained())
/obj/item/trap/attack_self(mob/user)
..()
if(!deployed && can_use(user))
if(deploy(user))
user.drop_from_inventory(src)
anchored = TRUE
/obj/item/trap/proc/deploy(mob/user)
user.visible_message(
SPAN_WARNING("\The [user] starts to deploy \the [src]."),
SPAN_WARNING("You begin deploying \the [src]!"),
SPAN_WARNING("You hear the slow creaking of a spring.")
)
if(do_after(user, 5 SECONDS))
user.visible_message(
SPAN_WARNING("\The [user] deploys \the [src]."),
SPAN_WARNING("You deploy \the [src]!"),
SPAN_WARNING("You hear a latch click loudly.")
)
deployed = TRUE
update_icon()
return TRUE
return FALSE
/obj/item/trap/user_unbuckle(mob/user)
if(buckled && can_use(user))
user.visible_message(
SPAN_NOTICE("\The [user] begins freeing \the [buckled] from \the [src]..."),
SPAN_NOTICE("You carefully begin to free \the [buckled] from \the [src]..."),
SPAN_NOTICE("You hear metal creaking.")
)
if(do_after(user, time_to_escape))
user.visible_message(
SPAN_NOTICE("\The [user] frees \the [buckled] from \the [src]."),
SPAN_NOTICE("You free \the [buckled] from \the [src].")
)
unbuckle()
anchored = FALSE
/obj/item/trap/attack_hand(mob/user)
if(can_use(user))
if(buckled)
user_unbuckle(user)
return
else if(deployed)
disarm_trap(user)
return
..()
/obj/item/trap/proc/disarm_trap(var/mob/user)
user.visible_message(SPAN_NOTICE("\The [user] starts to disarm \the [src]..."), SPAN_NOTICE("You begin disarming \the [src]..."), SPAN_WARNING("You hear a latch click followed by the slow creaking of a spring."))
if(do_after(user, 6 SECONDS))
user.visible_message(SPAN_NOTICE("\The [user] disarms \the [src]!"), SPAN_NOTICE("You disarm \the [src]!"))
deployed = FALSE
anchored = FALSE
update_icon()
/obj/item/trap/proc/attack_mob(mob/living/L)
var/target_zone
if(L.lying)
target_zone = ran_zone()
else
target_zone = pick(BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG)
var/success = L.apply_damage(30, DAMAGE_BRUTE, target_zone, used_weapon = src, armor_pen = activated_armor_penetration)
if(!success)
return FALSE
L.visible_message(SPAN_DANGER("\The [L] steps on \the [src]!"), FONT_LARGE(SPAN_DANGER("You step on \the [src]!")), SPAN_WARNING("<b>You hear a loud metallic snap!</b>"))
var/did_trap = TRUE
if(ishuman(L))
var/mob/living/carbon/human/H = L
var/obj/item/organ/external/limb = H.get_organ(check_zone(target_zone))
if(!limb || limb.is_stump()) // oops, we took the limb clean off
did_trap = FALSE
if(did_trap)
//trap the victim in place
can_buckle = list(/mob/living)
buckle(L)
can_buckle = initial(can_buckle)
deployed = FALSE
to_chat(L, FONT_LARGE(SPAN_DANGER("The steel jaws of \the [src] bite into you, [did_trap ? "trapping you in place" : "cleaving your limb clean off"]!")))
playsound(src, 'sound/weapons/beartrap_shut.ogg', 100, TRUE) //Really loud snapping sound
if (istype(L, /mob/living/simple_animal/hostile/bear))
var/mob/living/simple_animal/hostile/bear/bear = L
bear.anger += 15//traps make bears really angry
bear.instant_aggro()
if(!buckled)
anchored = FALSE
deployed = FALSE
/obj/item/trap/Crossed(atom/movable/AM)
if(ishuman(AM))
var/mob/living/carbon/human/H = AM
if(H.shoes?.item_flags & ITEM_FLAG_LIGHT_STEP)
return
if(deployed && isliving(AM))
var/mob/living/L = AM
if(L.pass_flags & PASSTABLE)
return
attack_mob(L)
update_icon()
shake_animation()
/obj/item/trap/update_icon()
icon_state = "[icon_base][deployed]"
/*
##################
Subtypes
##################
*/
/**
* # Sharpened trap
*
* This device has an even higher chance of penetrating armor and locking foes in place
*/
/obj/item/trap/sharpened
name = "sharpened mechanical trap"
desc_antag = "This device has an even higher chance of penetrating armor and locking foes in place."
activated_armor_penetration = 100
/**
* # Animal trap
*
* Used to catch small animals like rats, lizards, and chicks
*/
/obj/item/trap/animal
name = "small trap"
desc = "A small mechanical trap that's used to catch small animals like rats, lizards, and chicks."
icon_base = "small"
icon_state = "small0"
throwforce = 2
force = 1
w_class = ITEMSIZE_SMALL
origin_tech = list(TECH_ENGINEERING = 1)
matter = list(DEFAULT_WALL_MATERIAL = 1750)
deployed = FALSE
time_to_escape = 3 // Minutes
can_buckle = list(/mob/living)
health = 100
can_astar_pass = CANASTARPASS_ALWAYS_PROC
var/breakout = FALSE
var/last_shake = 0
var/list/allowed_mobs = list(/mob/living/simple_animal/rat, /mob/living/simple_animal/chick, /mob/living/simple_animal/lizard)
var/release_time = 0
var/list/resources = list(rods = 6)
var/spider = TRUE
var/datum/weakref/captured = null
/obj/item/trap/animal/MouseDrop_T(atom/dropping, mob/user)
var/mob/living/M = dropping
if(!istype(M))
return
if(!captured)
if(!is_type_in_list(M, allowed_mobs))
to_chat(user, SPAN_WARNING("[M] won't fit in there!"))
else if(do_after(user, 5 SECONDS))
capture(M)
else
to_chat(user, SPAN_WARNING("\The [src] is already full!"))
/obj/item/trap/animal/update_icon()
icon_state = "[icon_base][deployed]"
/obj/item/trap/animal/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
. = ..()
if(captured)
var/datum/L = captured.resolve()
if (L)
. += SPAN_WARNING("[L] is trapped inside!")
return
else if(deployed)
. += SPAN_WARNING("It's set up and ready to capture something.")
else
. += SPAN_NOTICE("\The [src] is empty and un-deployed.")
/obj/item/trap/animal/Crossed(atom/movable/AM)
if(!deployed || !anchored)
return
if(captured) // just in case but this shouldn't happen
return
capture(AM)
/obj/item/trap/animal/proc/capture(var/mob/AM, var/msg = 1)
if(isliving(AM) && is_type_in_list(AM, allowed_mobs))
var/mob/living/L = AM
if(msg)
L.visible_message(
SPAN_DANGER("[L] enters \the [src], and it snaps shut with a clatter!"),
SPAN_DANGER("You enter \the [src], and it snaps shut with a clatter!"),
"<b>You hear a loud metallic snap!</b>"
)
if(AM.loc != loc)
AM.forceMove(loc)
captured = WEAKREF(L)
buckle(L)
layer = L.layer + 0.1
playsound(src, 'sound/weapons/beartrap_shut.ogg', 100, 1)
deployed = FALSE
src.shake_animation()
update_icon()
/obj/item/trap/animal/proc/req_breakout()
if(deployed || !captured)
return 0 // Trap-door is open, no one is captured.
if(breakout)
return -1 //Already breaking out.
return 1
/obj/item/trap/animal/proc/breakout_callback(var/mob/living/escapee)
if (QDELETED(escapee))
return FALSE
if ((world.time - last_shake) > 5 SECONDS)
playsound(loc, 'sound/effects/grillehit.ogg', 100, 1)
shake_animation()
last_shake = world.time
return TRUE
// If we are stuck, and need to get out
/obj/item/trap/animal/user_unbuckle(var/mob/living/escapee)
if (req_breakout() < 1)
return
escapee.next_move = world.time + 100
escapee.last_special = world.time + 100
to_chat(escapee, SPAN_WARNING("You begin to shake and bump the lock of \the [src]. (this will take about [time_to_escape] minutes)."))
visible_message(SPAN_DANGER("\The [src] begins to shake violently! Something is attempting to escape it!"))
var/time = 360 * time_to_escape * 2
breakout = TRUE
if (!do_after(escapee, time, src))
breakout = FALSE
return
breakout = FALSE
to_chat(escapee, SPAN_WARNING("You successfully break out!"))
visible_message(SPAN_DANGER("\The [escapee] successfully breaks out of \the [src]!"))
playsound(loc, 'sound/effects/grillehit.ogg', 100, 1)
release()
/obj/item/trap/animal/CollidedWith(atom/AM)
if(deployed && is_type_in_list(AM, allowed_mobs))
Crossed(AM)
else
..()
/obj/item/trap/animal/verb/release_animal()
set src in orange(1)
set category = "Object"
set name = "Release animal"
if(!usr.canmove || usr.stat || usr.restrained())
return
if(!ishuman(usr))
to_chat(usr, SPAN_WARNING("This mob type can't use this verb."))
return
var/datum/M = captured ? captured.resolve() : null
if(M)
var/open = alert("Do you want to open the cage and free \the [M]?",,"No","Yes")
if(open == "No")
return
if(!can_use(usr))
to_chat(usr, SPAN_WARNING("You cannot use \the [src]."))
return
if(usr == M)
to_chat(usr, SPAN_WARNING("You can't open \the [src] from the inside! You'll need to force it open."))
return
var/adj = src.Adjacent(usr)
if(!adj)
attack_self(src)
return
release(usr)
/obj/item/trap/animal/crush_act()
if(captured)
var/datum/L = captured ? captured.resolve() : null
if(L && isliving(L))
var/mob/living/LL = L
LL.gib()
new /obj/item/stack/material/steel(get_turf(src))
qdel(src)
/obj/item/trap/animal/ex_act(severity)
switch(severity)
if(1)
health -= rand(120, 240)
if(2)
health -= rand(60, 120)
if(3)
health -= rand(30, 60)
if (health <= 0)
if(captured)
release()
new /obj/item/stack/material/steel(get_turf(src))
qdel(src)
/obj/item/trap/animal/bullet_act(var/obj/item/projectile/Proj)
for (var/atom/movable/A in src)
if(istype(A, /mob/living))
var/mob/living/M = A
M.bullet_act(Proj)
/obj/item/trap/animal/proc/release(var/mob/user, var/turf/target)
if(!target)
target = src.loc
if(user)
visible_message(SPAN_NOTICE("[user] opens \the [src]."))
var/datum/L = captured ? captured.resolve() : null
if (!L)
captured = null
release_time = world.time
return
var/msg
if (isliving(L))
var/mob/living/ll = L
msg = SPAN_WARNING("[ll] runs out of \the [src].")
unbuckle()
captured = null
visible_message(msg)
shake_animation()
update_icon()
release_time = world.time
layer = initial(layer)
/obj/item/trap/animal/attackby(obj/item/attacking_item, mob/user)
if(istype(attacking_item, /obj/item/grab))
var/obj/item/grab/G = attacking_item
var/mob/living/M = G.affecting
if (G.state == GRAB_PASSIVE || G.state == GRAB_UPGRADING)
to_chat(user, SPAN_NOTICE("You need a better grip on \the [M]!"))
return
user.visible_message(SPAN_NOTICE("[user] starts putting [M] into \the [src]."),
SPAN_NOTICE("You start putting [M] into \the [src]."))
if (!is_type_in_list(M, allowed_mobs))
to_chat(user, SPAN_WARNING("[M] won't fit in there!"))
return
if (do_mob(user, M, 3 SECONDS, needhand = 0))
if(captured?.resolve())
return
capture(M)
else if(attacking_item.iswelder())
var/obj/item/weldingtool/WT = attacking_item
if(!WT.isOn())
to_chat(user, SPAN_WARNING("\The [WT] is off!"))
return
user.visible_message(SPAN_NOTICE("[user] is trying to slice \the [src] open!"),
SPAN_NOTICE("You are trying to slice \the [src] open!"))
if(WT.use_tool(src, user, 60, volume = 50))
if(WT.use(2, user))
user.visible_message(SPAN_NOTICE("[user] slices \the [src] open!"),
SPAN_NOTICE("You slice \the [src] open!"))
new /obj/item/stack/rods(src.loc, resources["rods"])
if(resources.len == 2)
new /obj/item/stack/material/steel(src.loc, resources["metal"])
release(user)
qdel(src)
else if(attacking_item.isscrewdriver())
var/turf/T = get_turf(src)
if(!T)
to_chat(user, SPAN_WARNING("There is nothing to secure [src] to!"))
return
user.visible_message(SPAN_NOTICE("[user] is trying to [anchored ? "un" : "" ]secure \the [src]!"),
SPAN_NOTICE("You are trying to [anchored ? "un" : "" ]secure \the [src]!"))
var/sound_to_play = pick(list('sound/items/Screwdriver.ogg', 'sound/items/Screwdriver2.ogg'))
playsound(src.loc, sound_to_play, 50, 1)
if(attacking_item.use_tool(src, user, 30, volume = 50))
density = !density
anchored = !anchored
user.visible_message(SPAN_NOTICE("[user] [anchored ? "" : "un" ]secures \the [src]!"),
SPAN_NOTICE("You [anchored ? "" : "un" ]secure \the [src]!"))
else
..()
/obj/item/trap/animal/Move()
..()
if(captured)
var/datum/M = captured.resolve()
if(isliving(M))
var/mob/living/L = M
if(L && buckled.buckled_to == src)
L.forceMove(loc)
else if(L)
captured = null
else
captured = null
/obj/item/trap/animal/attack_hand(mob/user)
if(user.loc == src || captured)
return
if(anchored && deployed)
to_chat(user, SPAN_NOTICE("\The [src] is already anchored and set!"))
else if(anchored)
deploy(user)
else
..()
/obj/item/trap/animal/proc/pass_without_trace(mob/user, pct = 100)
if(!is_type_in_list(user, allowed_mobs))
user.forceMove(loc)
user.visible_message(SPAN_NOTICE("[user] passes over \the [src] without triggering it."),
SPAN_NOTICE("You pass over \the [src] without triggering it.")
)
else
user.visible_message(SPAN_NOTICE("[user] attempts to pass through \the [src] without triggering it."),
SPAN_NOTICE("You attempt to pass through \the [src] without triggering it. ")
)
if(do_after(user, 2 SECONDS, src))
if(prob(pct))
user.forceMove(loc)
user.visible_message(SPAN_NOTICE("[user] passes through \the [src] without triggering it."),
SPAN_NOTICE("You pass through \the [src] without triggering it.")
)
else
user.forceMove(loc)
user.visible_message(SPAN_WARNING("[user] accidentally triggers \the [src]!"),
SPAN_WARNING("You accidentally trigger \the [src]!")
)
capture(user)
/obj/item/trap/animal/MouseDrop(over_object, src_location, over_location)
if(!isliving(usr) || !src.Adjacent(usr))
return
if(captured)
pass_without_trace(usr) // It's full
if((usr.isMonkey() && (/mob/living/carbon/human/monkey in allowed_mobs)) || is_type_in_list(usr, allowed_mobs)) // Because monkeys can be of type of just human.
pass_without_trace(usr, 50)
return
else if(iscarbon(usr))
pass_without_trace(usr)
else
..()
/obj/item/trap/animal/attack_self(mob/user)
if(!can_use(user))
to_chat(user, SPAN_WARNING("You cannot use \the [src]."))
return
if(captured)
release(user, user.loc)
/obj/item/trap/animal/attack(var/target, mob/living/user)
if(!deployed)
return
if(captured) // It is full
return
if(isliving(target))
var/mob/living/M = target
if(is_type_in_list(M, allowed_mobs))
user.visible_message(
SPAN_WARNING("[user] traps [M] inside of \the [src]."),
SPAN_WARNING("You trap [M] inside of the \the [src]!"),
"<b>You hear a loud metallic snap!</b>"
)
capture(M, msg = 0)
else
..()
/obj/item/trap/animal/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
return TRUE
/obj/item/trap/animal/CanAStarPass(to_dir, datum/can_pass_info/pass_info)
return TRUE
/**
* # Animal trap (Medium)
*
* Used to catch medium animals like cats, monkeys, nymphs, and wayward maintenance drones
*/
/obj/item/trap/animal/medium
name = "medium trap"
desc = "A medium mechanical trap that is used to catch moderately-sized animals like cats, monkeys, nymphs, and wayward maintenance drones."
icon_base = "medium"
icon_state = "medium0"
throwforce = 4
force = 11
w_class = ITEMSIZE_LARGE
origin_tech = list(TECH_ENGINEERING = 3)
matter = list(DEFAULT_WALL_MATERIAL = 5750)
deployed = FALSE
resources = list(rods = 12)
spider = FALSE
/obj/item/trap/animal/medium/Initialize()
. = ..()
allowed_mobs = list(
/mob/living/simple_animal/cat, /mob/living/simple_animal/corgi, /mob/living/simple_animal/hostile/retaliate/diyaab, /mob/living/carbon/human/monkey, /mob/living/simple_animal/penguin, /mob/living/simple_animal/crab,
/mob/living/simple_animal/chicken, /mob/living/simple_animal/yithian, /mob/living/carbon/alien/diona, /mob/living/silicon/robot/drone, /mob/living/silicon/pai,
/mob/living/simple_animal/spiderbot, /mob/living/simple_animal/hostile/tree)
/**
* # Animal trap (Large)
*
* Used to catch larger animals, from spiders and dogs to bears and even larger mammals
*/
/obj/item/trap/animal/large
name = "large trap"
desc = "A large mechanical trap that is used to catch larger animals, from spiders and dogs to bears and even larger mammals."
icon_base = "large"
icon_state = "large0"
throwforce = 6
force = 10
w_class = 6
density = 1
origin_tech = list(TECH_ENGINEERING = 3)
matter = list(DEFAULT_WALL_MATERIAL = 15750)
deployed = FALSE
resources = list(rods = 12, metal = 4)
spider = FALSE
/obj/item/trap/animal/large/Initialize()
. = ..()
allowed_mobs = list(
/mob/living/simple_animal/hostile/retaliate/goat, /mob/living/simple_animal/cow, /mob/living/simple_animal/corgi/fox,
/mob/living/simple_animal/hostile/carp, /mob/living/simple_animal/hostile/bear, /mob/living/simple_animal/hostile/giant_spider,
/mob/living/simple_animal/hostile/commanded/dog, /mob/living/simple_animal/hostile/retaliate/cavern_dweller, /mob/living/carbon/human,
/mob/living/simple_animal/pig)
/obj/item/trap/animal/large/attack_hand(mob/user)
if(user == buckled)
return
else if(!anchored)
to_chat(user, SPAN_WARNING("You need to anchor \the [src] first!"))
else if(captured)
to_chat(user, SPAN_WARNING("You can't deploy \the [src] with something caught!"))
else
..()
/obj/item/trap/animal/large/attackby(obj/item/attacking_item, mob/user)
if(attacking_item.iswrench())
var/turf/T = get_turf(src)
if(!T)
to_chat(user, SPAN_WARNING("There is nothing to secure [src] to!"))
return
if(anchored && deployed)
to_chat(user, SPAN_WARNING("You can't do that while \the [src] is deployed! Undeploy it first."))
return
user.visible_message(SPAN_NOTICE("[user] begins [anchored ? "un" : "" ]securing \the [src]!"),
SPAN_NOTICE("You begin [anchored ? "un" : "" ]securing \the [src]!"))
if(attacking_item.use_tool(src, user, 30, volume = 50))
anchored = !anchored
user.visible_message(SPAN_NOTICE("[user] [anchored ? "" : "un" ]secures \the [src]!"),
SPAN_NOTICE("You [anchored ? "" : "un" ]secure \the [src]!"))
else if(attacking_item.isscrewdriver())
// Unlike smaller traps, screwdriver shouldn't work on this.
return
else
..()
/obj/item/trap/animal/large/MouseDrop(over_object, src_location, over_location)
if(captured)
to_chat(usr, SPAN_WARNING("The trap door's down, you can't get through there!"))
return
if(!src.Adjacent(usr))
return
if(!ishuman(usr))
..()
return
var/pct = 0
if(usr.a_intent == I_HELP)
pct = 100
else if(usr.a_intent != I_HURT)
pct = 50
pass_without_trace(usr, pct)
/obj/item/trap/animal/large/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(deployed)
return TRUE
return FALSE
/obj/item/large_trap_foundation
name = "large trap foundation"
desc = "A metal foundation for large trap, it is missing metals rods to hold the prey."
icon = 'icons/obj/item/traps/traps.dmi'
icon_state = "large_foundation"
throwforce = 4
force = 11
w_class = ITEMSIZE_HUGE
/obj/item/large_trap_foundation/attackby(obj/item/attacking_item, mob/user)
if(istype(attacking_item, /obj/item/stack/rods))
var/obj/item/stack/rods/O = attacking_item
if(O.get_amount() >= 12)
to_chat(user, SPAN_NOTICE("You are trying to add metal bars to \the [src]."))
if (!do_after(user, 2 SECONDS, src))
return
to_chat(user, SPAN_NOTICE("You add metal bars to \the [src]."))
O.use(12)
new /obj/item/trap/animal/large(src.loc)
qdel(src)
return
else
to_chat(user, SPAN_WARNING("You need at least 12 rods to complete \the [src]."))
else if(istype(attacking_item, /obj/item/screwdriver))
return
else
..()
/**
* # Tripwire trap
*
* A trap that makes you fall over
*/
/obj/item/trap/tripwire
name = "tripwire trap"
desc = "A piece of cable coil strung between two metal rods. Low-tech, but reliable."
icon_base = "tripwire"
color = COLOR_RED
layer = UNDERDOOR // so you can't cover it with items
/obj/item/trap/tripwire/Initialize(mapload, var/new_cable_color)
. = ..()
if(!new_cable_color)
new_cable_color = COLOR_RED
color = new_cable_color
/obj/item/trap/tripwire/update_icon()
underlays = null
icon_state = "[icon_base][deployed]"
var/image/I = image(icon, null, "[icon_state]_base")
I.appearance_flags = RESET_COLOR
underlays = list(I)
/obj/item/trap/tripwire/deploy(mob/user)
user.visible_message(SPAN_WARNING("\The [user] starts to deploy \the [src]."), SPAN_WARNING("You begin deploying \the [src]!"))
if(do_after(user, 5 SECONDS))
user.visible_message(SPAN_WARNING("\The [user] deploys \the [src]."), SPAN_WARNING("You deploy \the [src]!"))
deployed = TRUE
update_icon()
return TRUE
return FALSE
/obj/item/trap/tripwire/disarm_trap(var/mob/user)
user.visible_message(SPAN_NOTICE("\The [user] starts to take \the [src] down..."), SPAN_NOTICE("You begin taking \the [src] down..."), SPAN_WARNING("You hear a latch click followed by the slow creaking of a spring."))
if(do_after(user, 6 SECONDS))
deployed = FALSE
anchored = FALSE
update_icon()
/obj/item/trap/tripwire/attack_mob(mob/living/L)
if(!ishuman(L))
return
var/mob/living/carbon/human/H = L
if(!H.organs_by_name[BP_L_LEG] && !H.organs_by_name[BP_R_LEG]) // tripwires are triggered by shin, so if you don't have legs, assume you fly or crawl
return
if(!L.lying && (L.m_intent == M_RUN) || prob(5))
L.visible_message(SPAN_DANGER("\The [L] trips over \the [src]!"), FONT_LARGE(SPAN_DANGER("You trip over \the [src]!")))
L.Weaken(3)
/**
* # Punji trap
*
* A trap that damages and gives an infection to the victim, can have a message attached
*/
/obj/item/trap/punji
name = "punji trap"
desc = "An horrendous trap."
icon = 'icons/obj/item/traps/punji.dmi'
icon_base = "punji"
icon_state = "punji0"
var/message = null
/obj/item/trap/punji/Crossed(atom/movable/AM)
if(deployed && isliving(AM))
var/mob/living/L = AM
attack_mob(L)
update_icon()
/obj/item/trap/punji/attack_mob(mob/living/L)
//Reveal the trap, if not already visible
hide(FALSE)
//Select a target zone
var/target_zone
if(L.lying)
target_zone = pick(BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG, BP_L_HAND, BP_L_ARM, BP_R_HAND, BP_R_ARM)
else
target_zone = pick(BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG)
//Try to apply the damage
var/success = L.apply_damage(50, DAMAGE_BRUTE, target_zone, used_weapon = src, armor_pen = activated_armor_penetration)
//If successfully applied, give the message
if(success)
//Show the leftover message, if any, after a little
addtimer(CALLBACK(src, PROC_REF(reveal_message), L), 3 SECONDS)
//Give a simple message and return if it's not a human
if(!ishuman(L))
L.visible_message(SPAN_DANGER("You step on \the [src]!"))
return
var/mob/living/carbon/human/human = L
var/obj/item/organ/organ = human.get_organ(target_zone)
human.visible_message(SPAN_DANGER("\The [human] steps on \the [src]!"),
SPAN_WARNING(FONT_LARGE(SPAN_DANGER("You step on \the [src], feel your body fall, and something sharp penetrate your [organ.name]!"))),
SPAN_WARNING("<b>You feel your body fall, and something sharp penetrate your [organ.name]!</b>"))
//If it's a human and not an IPC, apply an infection
//We are returning early before this step in case something isn't a human, so this should be fine not to catch borgs/bot/exosuits/whatever
if(!isipc(L))
//If it's a Vaurca, there's a chance the spear wouldn't go in deep enough to apply an infection
//You're still damaged by falling on it though, which happens above, but at least you're spared the infection
//Glory to your carapace
if(isvaurca(L) && prob(50))
return
organ.germ_level += INFECTION_LEVEL_TWO
/obj/item/trap/punji/proc/reveal_message(mob/living/victim)
if(!message)
return
//If the mob moved away and/or no longer sees the trap, do not show the message
if(!(src in oview(world.view, victim)))
return
victim.visible_message(SPAN_ALERT("You notice something written on a plate inside the trap: <br>")+SPAN_BAD(message))
/obj/item/trap/punji/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
. = ..()
if(src.message && distance < 3)
. += SPAN_ALERT("You notice something written on a plate inside the trap:")
. += SPAN_BAD(message)
/obj/item/trap/punji/verb/hide_under()
set src in oview(1)
set name = "Hide"
set desc = "Hide the trap under the cover."
set category = "Object"
if(use_check_and_message(usr, USE_DISALLOW_SILICONS))
return
to_chat(usr, SPAN_NOTICE("You begin hiding the trap..."))
if(!do_after(usr, 15 SECONDS))
return
hide(TRUE)
to_chat(usr, SPAN_ALERT("You hide \the [src], remember where you left it or suffer the very same warcrime you wanted to inflict!"))
/obj/item/trap/punji/verb/set_message()
set src in oview(1)
set name = "Set Message"
set desc = "Set a message for the victim of the trap."
set category = "Object"
if(src.message)
to_chat(usr, SPAN_NOTICE("There is already a carved message inside the trap, can't make more..."))
return
var/added_message = tgui_input_text(usr, "Leave your message here...", "Punji trap message", multiline = TRUE, encode = FALSE)
if(added_message)
to_chat(usr, SPAN_NOTICE("You begin carving the message inside the trap..."))
if(do_after(usr, 10 SECONDS))
src.message = strip_html_readd_newlines(added_message)
/obj/item/trap/punji/deployed
deployed = TRUE
anchored = TRUE
icon_state = "punji1"