/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' icon_state = "beartrap" randpixel = 0 center_of_mass = null throwforce = 0 w_class = WEIGHT_CLASS_NORMAL origin_tech = list(TECH_ENGINEERING = 2) matter = list(DEFAULT_WALL_MATERIAL = 18750) can_buckle = list(/mob/living) update_icon_on_init = TRUE /// This boolean indicates that the trap is deployed and ready to trap a mob. It can only be deployed after being secured. var/deployed = FALSE /// This boolean determines whether the trap will unanchor itself after being disarmed var/unsecure_on_disarm = TRUE /// Time in deciseconds needed to escape from the trap var/time_to_escape = 1 MINUTE /// When the trap triggers and does damage, this will be the armor penetration value var/activated_armor_penetration = 0 /obj/item/trap/Initialize() . = ..() update_icon() var/static/list/loc_connections = list( COMSIG_ATOM_ENTERED = PROC_REF(on_entered), ) AddElement(/datum/element/connect_loc, loc_connections) /obj/item/trap/get_examine_text(mob/user, distance, is_adjacent, infix, suffix) . = ..() . += get_trap_examine_text(user, distance, is_adjacent, infix, suffix) /obj/item/trap/proc/get_trap_examine_text(mob/user, distance, is_adjacent, infix, suffix) . = list() if(buckled) . += SPAN_NOTICE("You can free the creature inside the trap by clicking on it.") else if(deployed) . += SPAN_NOTICE("You can disarm the trap by clicking on it.") else . += SPAN_NOTICE("You can deploy the trap by using it in-hand.") /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_BOLD("[user]")] starts deploying \the [src]...", SPAN_NOTICE("You begin deploying \the [src]!"), SPAN_WARNING("You hear the slow creaking of a spring.")) if(do_after(user, 5 SECONDS)) playsound(src, 'sound/items/crank.ogg', 50, TRUE) user.visible_message("[SPAN_BOLD("[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)) return user.visible_message("[SPAN_BOLD("[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_BOLD("[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_BOLD("[user]")] starts disarming \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_BOLD("[user]")] disarms \the [src]!", SPAN_NOTICE("You disarm \the [src]!")) deployed = FALSE if(unsecure_on_disarm) anchored = FALSE update_icon() /obj/item/trap/proc/attack_mob(mob/living/L) var/target_zone = L.lying ? ran_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("You hear a loud metallic snap!")) 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 buckle(L) 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/proc/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) SIGNAL_HANDLER if(ishuman(arrived)) var/mob/living/carbon/human/H = arrived if(H.shoes?.item_flags & ITEM_FLAG_LIGHT_STEP) return if(deployed && isliving(arrived)) var/mob/living/L = arrived if(L.pass_flags & PASSTABLE) return INVOKE_ASYNC(src, PROC_REF(attack_mob), L) update_icon() shake_animation() /obj/item/trap/update_icon() icon_state = "[initial(icon_state)][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" activated_armor_penetration = 100 /obj/item/trap/sharpened/antagonist_hints(mob/user, distance, is_adjacent) . += ..() . += "This device has an even higher chance of penetrating armor and locking foes in place." /** * # 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_state = "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 = "[initial(icon_state)][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)) playsound(src, 'sound/items/crank.ogg', 50, TRUE) 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 if(unsecure_on_disarm) 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_state = "punji" var/message = null /obj/item/trap/punji/feedback_hints(mob/user, distance, is_adjacent) . += ..() if(src.message && distance < 3) . += SPAN_ALERT("You notice something written on a plate inside the trap:") . += SPAN_BAD(message) /obj/item/trap/punji/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) if(deployed && isliving(arrived)) var/mob/living/L = arrived attack_mob(L) update_icon() /obj/item/trap/punji/attack_mob(mob/living/L) //Reveal the trap, if not already visible invisibility = 0 //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) //Apply weakness, so the victim doesn't walk immediately back out of the trap L.Weaken(10) //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("[L] steps on \the [src]!")) return var/mob/living/carbon/human/human = L var/obj/item/organ/organ = human.get_organ(target_zone) if(isipc(L) || isrobot(L)) playsound(src, 'sound/weapons/smash.ogg', 100, TRUE) else playsound(src, 'sound/weapons/heavysmash.ogg', 100, TRUE) 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("You feel your body fall, and something sharp penetrate your [organ.name]!")) //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 //Also, don't infect robotic limbs with infections!!!!!!!!!!! //Something something the certainty of steel if(isvaurca(L) && prob(50) || organ.robotic == ROBOTIC_MECHANICAL) 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:
")+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 /obj/item/trap/punji/deployed/hidden invisibility = INVISIBILITY_MAXIMUM /obj/item/trap/jagged_rock name = "treacherous rock" desc = "A jagged and dangerous outcropping." icon = 'icons/obj/flora/rocks_grey.dmi' icon_state = "basalt" anchored = TRUE invisibility = 0 /obj/item/trap/jagged_rock/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) if(isliving(arrived)) var/mob/living/L = arrived attack_mob(L) update_icon() /obj/item/trap/jagged_rock/attack_mob(mob/living/L) //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) //Apply weakness, so the victim doesn't walk immediately back out of the trap L.Weaken(10) //If successfully applied, give the message if(success) //Give a simple message and return if it's not a human if(!ishuman(L)) L.visible_message(SPAN_DANGER("[L] slams into \the [src]!")) return var/mob/living/carbon/human/human = L var/obj/item/organ/organ = human.get_organ(target_zone) if(isipc(L) || isrobot(L)) playsound(src, 'sound/weapons/smash.ogg', 100, TRUE) else playsound(src, 'sound/weapons/heavysmash.ogg', 100, TRUE) human.visible_message(SPAN_DANGER("\The [human] slams into \the [src]!"), SPAN_WARNING(FONT_LARGE(SPAN_DANGER("You crash on \the [src], feel your body crumble, and something sharp penetrate your [organ.name]!"))), SPAN_WARNING("You feel your body crumble, and something sharp penetrate your [organ.name]!")) /** * # 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_state = "small" throwforce = 2 force = 1 w_class = WEIGHT_CLASS_SMALL origin_tech = list(TECH_ENGINEERING = 1) matter = list(DEFAULT_WALL_MATERIAL = 1750) health = 100 can_astar_pass = CANASTARPASS_ALWAYS_PROC time_to_escape = 3 MINUTES unsecure_on_disarm = FALSE /// Whether someone is actively breaking out of this trap var/breakout = FALSE /// The time in deciseconds between shakes when a user is trying to escape var/shake_time = 5 SECONDS /// The world.time of when the last breakout shake callback happened successfully var/last_shake = 0 /// When a mob of this size crosses over the active trap, it'll be caught var/max_mob_size = MOB_MINISCULE /// When deconstructed, it will return these materials var/list/resources = list(/obj/item/stack/rods = 6) /// A weakref to the mob currently held inside the trap var/datum/weakref/captured = null /obj/item/trap/animal/get_trap_examine_text(mob/user, distance, is_adjacent, infix, suffix) . = list() if(captured) var/mob/captured_mob = captured.resolve() if(captured_mob) . += SPAN_NOTICE("You can free the creature inside by right clicking the trap and selecting \"Release Animal\".") if(deployed) . += SPAN_NOTICE("You can disarm the trap by clicking on it, or by right clicking the trap and selecting \"Deploy / Undeploy Trap\".") else if(anchored) . += get_securing_text(secure = FALSE) if(!captured) . += SPAN_NOTICE("You can deploy the trap by clicking on it, or by right clicking the trap and selecting \"Deploy / Undeploy Trap\".") else . += get_securing_text(secure = TRUE) . += SPAN_NOTICE("The trap can be deconstructed with a welding tool.") /obj/item/trap/animal/proc/get_securing_text(var/secure = TRUE) if(secure) return SPAN_NOTICE("You can secure the trap by using a screwdriver on it. This will anchor it to the floor, and ready it for deployment.") return SPAN_NOTICE("You can unsecure the trap by using a screwdriver on it. This will unanchor it from the floor, allowing it to be moved.") /obj/item/trap/animal/mouse_drop_receive(atom/dropped, mob/user, params) var/mob/living/capturing_mob = dropped if(!istype(capturing_mob)) return if(captured) to_chat(user, SPAN_WARNING("\The [src] is already full!")) return if(capturing_mob.mob_size > max_mob_size) to_chat(user, SPAN_WARNING("[capturing_mob] won't fit in there!")) return if(!do_mob(user, capturing_mob, 3 SECONDS, needhand = FALSE)) return capture(capturing_mob) /obj/item/trap/animal/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) if(!deployed || !anchored) return if(captured) // just in case but this shouldn't happen return capture(arrived) /obj/item/trap/animal/proc/capture(var/atom/movable/movable_atom, var/msg = 1) if(!isliving(movable_atom)) return var/mob/living/capturing_mob = movable_atom if(capturing_mob.mob_size > max_mob_size) return if(msg) capturing_mob.visible_message(SPAN_DANGER("[capturing_mob] enters \the [src], and it snaps shut with a clatter!"), SPAN_DANGER("You enter \the [src], and it snaps shut with a clatter!"), SPAN_DANGER("You hear a loud metallic snap!")) if(capturing_mob.loc != loc) capturing_mob.forceMove(loc) captured = WEAKREF(capturing_mob) INVOKE_ASYNC(src, PROC_REF(buckle), capturing_mob) layer = capturing_mob.layer + 0.1 playsound(src, 'sound/weapons/beartrap_shut.ogg', 100, 1) deployed = FALSE shake_animation() update_icon() /obj/item/trap/animal/proc/can_breakout() if(deployed || !captured) return FALSE // Trap-door is open, no one is captured. if(breakout) return FALSE //Already breaking out. return TRUE /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, TRUE) 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 (!can_breakout()) return escapee.next_move = world.time + 1 SECOND escapee.last_special = world.time + 1 SECOND to_chat(escapee, SPAN_WARNING("You begin to shake and bump the lock of \the [src]. (this will take about [time_to_escape / 600] minutes).")) visible_message(SPAN_DANGER("\The [src] begins to shake violently! Something is attempting to escape it!")) if (!do_after(escapee, time_to_escape, src, extra_checks = CALLBACK(src, PROC_REF(breakout_callback), escapee))) 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/bumped_atom) if(deployed) Crossed(bumped_atom) return return ..() /obj/item/trap/animal/verb/deploy_trap() set src in orange(1) set category = "Object" set name = "Deploy / Undeploy Trap" if(use_check_and_message(usr)) return if(!can_use(usr)) to_chat(usr, SPAN_WARNING("You cannot use \the [src].")) return if(deployed) if(captured) to_chat(usr, SPAN_WARNING("\The [src] already has something inside!")) return disarm_trap(usr) else if(!anchored) to_chat(usr, SPAN_WARNING("\The [src] needs to be secured first!")) return if(captured) to_chat(usr, SPAN_WARNING("\The [src] already has something inside!")) return deploy(usr) /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/mob/captured_mob = captured ? captured.resolve() : null if(captured_mob) if(tgui_alert(usr, "Do you want to open the cage and free \the [captured_mob]?", src.name, list("Yes", "No")) == "No") return if(!can_use(usr)) to_chat(usr, SPAN_WARNING("You cannot use \the [src].")) return if(usr == captured_mob) 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(obj/projectile/hitting_projectile, def_zone, piercing_hit) . = ..() if(. != BULLET_ACT_HIT) return . var/mob/living/captured_mob = captured ? captured.resolve() : null if(captured_mob) captured_mob.bullet_act(arglist(args)) /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/mob/captured_mob = captured ? captured.resolve() : null if (!captured_mob) captured = null return var/msg if (isliving(captured_mob)) var/mob/living/living_mob = captured_mob msg = SPAN_WARNING("[living_mob] runs out of \the [src].") unbuckle() captured = null visible_message(msg) shake_animation() update_icon() 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/grab = attacking_item var/mob/living/capturing_mob = grab.affecting if (grab.state == GRAB_PASSIVE || grab.state == GRAB_UPGRADING) to_chat(user, SPAN_NOTICE("You need a better grip on \the [capturing_mob]!")) return user.visible_message("[SPAN_BOLD("[user]")] starts putting \the [capturing_mob] into \the [src].", SPAN_NOTICE("You start putting \the [capturing_mob] into \the [src].")) if(capturing_mob.mob_size > max_mob_size) to_chat(user, SPAN_WARNING("\The [capturing_mob] won't fit in there!")) return if (do_mob(user, capturing_mob, 3 SECONDS, needhand = FALSE)) if(captured?.resolve()) return capture(capturing_mob) else if(attacking_item.tool_behaviour == TOOL_WELDER) 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, 6 SECONDS, volume = 50)) if(WT.use(2, user)) user.visible_message(SPAN_NOTICE("[user] slices \the [src] open!"), SPAN_NOTICE("You slice \the [src] open!")) for(var/resource_path in resources) new resource_path(loc, resources[resource_path]) release(user) qdel(src) else if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER) var/turf/T = get_turf(src) if(!T) to_chat(user, SPAN_WARNING("There is nothing to secure \the [src] to!")) return user.visible_message("[SPAN_BOLD("[user]")] starts [anchored ? "un" : "" ]securing \the [src]...", SPAN_NOTICE("You start [anchored ? "un" : "" ]securing \the [src]...")) if(attacking_item.use_tool(src, user, 3 SECONDS, volume = 50)) density = !density anchored = !anchored if(!anchored) deployed = FALSE user.visible_message("[SPAN_BOLD("[user]")] [anchored ? "" : "un" ]secures \the [src]!", SPAN_NOTICE("You [anchored ? "" : "un" ]secure \the [src]!")) update_icon() 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(deployed) disarm_trap(user) else if(anchored) deploy(user) else ..() /obj/item/trap/animal/proc/pass_without_trace(var/mob/user, var/chance_to_trigger = 0) user.visible_message("[SPAN_BOLD("[user]")] tries moving around \the [src] without triggering it.", SPAN_NOTICE("You try to carefully move around \the [src] without triggering it.")) if(do_after(user, 2 SECONDS, src)) if(chance_to_trigger && prob(chance_to_trigger)) user.forceMove(loc) user.visible_message(SPAN_WARNING("[user] accidentally triggers \the [src]!"), SPAN_WARNING("You accidentally trigger \the [src]!")) capture(user) else user.forceMove(loc) user.visible_message("[SPAN_BOLD("[user]")] successfully moves around \the [src] without triggering it.", SPAN_NOTICE("You successfully move around \the [src] without triggering it.")) /obj/item/trap/animal/mouse_drop_dragged(atom/over, mob/user, src_location, over_location, params) if(!isliving(user) || !src.Adjacent(user)) return if(captured) pass_without_trace(user) // It's full return else if(iscarbon(user)) pass_without_trace(user) return return ..() /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(mob/living/target_mob, mob/living/user, target_zone) if(!deployed) return if(captured) // It is full return if(isliving(target_mob)) var/mob/living/capturing_mob = target_mob if(capturing_mob.mob_size > max_mob_size) to_chat(user, SPAN_WARNING("\The [capturing_mob] doesn't fit in \the [src]!")) return user.visible_message(SPAN_WARNING("[user] traps \the [capturing_mob] inside of \the [src]."), SPAN_WARNING("You trap [capturing_mob] inside of the \the [src]!"), SPAN_DANGER("You hear a loud metallic snap!")) capture(capturing_mob, FALSE) 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_state = "medium" throwforce = 4 force = 11 w_class = WEIGHT_CLASS_BULKY origin_tech = list(TECH_ENGINEERING = 3) matter = list(DEFAULT_WALL_MATERIAL = 5750) max_mob_size = MOB_SMALL resources = list(/obj/item/stack/rods = 12) /** * # 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_state = "large" throwforce = 6 force = 10 w_class = 6 density = TRUE origin_tech = list(TECH_ENGINEERING = 3) matter = list(DEFAULT_WALL_MATERIAL = 15750) max_mob_size = 20 resources = list(/obj/item/stack/rods = 12, /obj/item/stack/material/steel = 4) /obj/item/trap/animal/large/get_securing_text(var/secure = TRUE) if(secure) return SPAN_NOTICE("You can secure the trap by using a wrench on it. This will anchor it to the floor, and ready it for deployment.") return SPAN_NOTICE("You can unsecure the trap by using a wrench on it. This will unanchor it from the floor, allowing it to be moved.") /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.tool_behaviour == TOOL_WRENCH) var/turf/T = get_turf(src) if(!T) to_chat(user, SPAN_WARNING("There is nothing to secure \the [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.tool_behaviour == TOOL_SCREWDRIVER) // Unlike smaller traps, screwdriver shouldn't work on this. return else ..() /obj/item/trap/animal/large/mouse_drop_dragged(atom/over, mob/user, src_location, over_location, params) if(captured) to_chat(user, SPAN_WARNING("The trap door's down, you can't get through there!")) return if(!src.Adjacent(user)) return if(!ishuman(user)) ..() return var/trigger_chance = 0 if(user.a_intent == I_HELP) trigger_chance = 100 else if(user.a_intent != I_HURT) trigger_chance = 50 pass_without_trace(user, trigger_chance) /obj/item/trap/animal/large/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(deployed) return TRUE if(mover?.movement_type & PHASING) 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 = WEIGHT_CLASS_HUGE /obj/item/large_trap_foundation/feedback_hints(mob/user, distance, is_adjacent) . += ..() . += SPAN_NOTICE("\The [src] can be turned into a large trap by attaching twelve metal rods to it.") /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) user.visible_message("[SPAN_BOLD("[user]")] starts adding metal bars to \the [src]...", SPAN_NOTICE("You start adding metal bars to \the [src]...")) if (!do_after(user, 2 SECONDS, src)) return O.use(12) var/obj/item/trap/animal/large/new_trap = new /obj/item/trap/animal/large(src.loc) user.visible_message("[SPAN_BOLD("[user]")] finishes constructing \the [new_trap].", SPAN_NOTICE("You finish constructing \the [new_trap].")) qdel(src) return else to_chat(user, SPAN_WARNING("You need at least twelve rods to complete \the [src].")) return else if(istype(attacking_item, /obj/item/screwdriver)) return else ..()