From 7989a15746a0c9a1719ee978d6247ea7583cbcef Mon Sep 17 00:00:00 2001 From: emmanuelbassil <6874235+emmanuelbassil@users.noreply.github.com> Date: Tue, 7 Nov 2023 05:46:50 +0300 Subject: [PATCH] [MIRROR] Adds ability to resist out of gift-wrapped mob --- code/game/objects/buckling.dm | 1 + code/game/objects/items/weapons/gifts.dm | 60 +++++++++++++++---- code/game/objects/items/weapons/handcuffs.dm | 29 +++++---- .../objects/items/weapons/wrapping_paper.dm | 2 +- code/game/objects/structures.dm | 1 + .../crates_lockers/closets/__closet.dm | 47 +++++++++------ .../spreading/spreading_response.dm | 4 +- code/modules/mob/living/carbon/resist.dm | 45 +++++++------- .../spells/targeted/projectile/stuncuff.dm | 3 +- 9 files changed, 124 insertions(+), 68 deletions(-) diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 52a2db5c03e53..60e04e9ae7618 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -9,6 +9,7 @@ var/buckle_require_restraints = FALSE //require people to be handcuffed before being able to buckle. eg: pipes var/mob/living/buckled_mob var/buckle_sound = 'sound/effects/buckle.ogg' + var/breakout_time /** * A list of (x, y, z) to offset buckled_mob by, or null. diff --git a/code/game/objects/items/weapons/gifts.dm b/code/game/objects/items/weapons/gifts.dm index e57a4b42d9cda..6d594396e44b3 100644 --- a/code/game/objects/items/weapons/gifts.dm +++ b/code/game/objects/items/weapons/gifts.dm @@ -76,16 +76,17 @@ * Special item for wrapped mobs */ -/obj/mobpresent +/obj/structure/mobpresent name = "strange gift" desc = "It's a ... gift?" icon = 'icons/obj/parcels.dmi' icon_state = "strangegift" density = TRUE anchored = FALSE + breakout_time = 30 SECONDS var/package_type = "parcel" -/obj/mobpresent/Initialize(mapload, target, wrap_type) +/obj/structure/mobpresent/Initialize(mapload, target, wrap_type) . = ..(mapload) if (!target || !ishuman(target) || !wrap_type) return INITIALIZE_HINT_QDEL @@ -100,32 +101,65 @@ package_type = wrap_type update_icon() -/obj/mobpresent/on_update_icon() +/obj/structure/mobpresent/on_update_icon() icon_state = "strange[package_type]" -/obj/mobpresent/relaymove(mob/user) +/obj/structure/mobpresent/relaymove(mob/user) if (user.stat) return to_chat(user, SPAN_WARNING("You can't move.")) +/obj/structure/mobpresent/proc/unwrap() + for (var/mob/M in src) //Should only be one but whatever. + M.dropInto(loc) + if (M.client) + M.client.eye = M.client.mob + M.client.perspective = MOB_PERSPECTIVE + qdel(src) -/obj/mobpresent/use_tool(obj/item/tool, mob/user, list/click_params) +/obj/structure/mobpresent/mob_breakout(mob/living/escapee) + . = ..() + if (!breakout_time) + breakout_time = 30 SECONDS + if (breakout) + return FALSE + + . = TRUE + escapee.setClickCooldown(100) + + to_chat(escapee, SPAN_WARNING("You start squirming inside \the [src] and start weakening the wrapping paper. (this will take about [breakout_time/(1 SECOND)] second\s)")) + visible_message(SPAN_DANGER("\The [src] begins to shake violently!")) + shake_animation() + + var/stages = 3 + breakout = TRUE + for (var/i = 1 to stages) + if (do_after(escapee, breakout_time*(1/stages), do_flags = DO_DEFAULT | DO_USER_UNIQUE_ACT, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) + to_chat(escapee, SPAN_WARNING("You try to slip free of \the [src] ([i*100/stages]% done).")) + else + to_chat(escapee, SPAN_WARNING("You stop trying to slip free of \the [src].")) + breakout = FALSE + return + shake_animation() + + //Well then break it! + breakout = FALSE + to_chat(escapee, SPAN_WARNING("You successfully break out!")) + visible_message(SPAN_DANGER("\The [escapee] successfully broke out of \the [src]!")) + unwrap() + +/obj/structure/mobpresent/use_tool(obj/item/tool, mob/user, list/click_params) if (is_sharp(tool)) user.visible_message( SPAN_NOTICE("\The [user] cuts open \the [src] with \a [tool]."), SPAN_NOTICE("You cut open \the [src] with \the [tool].") ) - for (var/mob/M in src) //Should only be one but whatever. - M.dropInto(loc) - if (M.client) - M.client.eye = M.client.mob - M.client.perspective = MOB_PERSPECTIVE - qdel(src) + unwrap() return TRUE return ..() -/obj/mobpresent/attack_hand(mob/living/user) +/obj/structure/mobpresent/attack_hand(mob/living/user) to_chat(user, "You need a sharp tool to unwrap \the [src].") -/obj/mobpresent/attack_robot(mob/living/silicon/robot/user) +/obj/structure/mobpresent/attack_robot(mob/living/silicon/robot/user) to_chat(user, "You need a sharp tool to unwrap \the [src].") diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index b03b9800a5cdc..e86686ba5afd7 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -14,7 +14,7 @@ matter = list(MATERIAL_STEEL = 500) var/elastic var/dispenser = 0 - var/breakouttime = 1200 //Deciseconds = 120s = 2 minutes + breakout_time = 120 SECONDS var/cuff_sound = 'sound/weapons/handcuffs.ogg' var/cuff_type = "handcuffs" @@ -103,30 +103,39 @@ var/global/last_chew = 0 /mob/living/carbon/human/RestrainedClickOn(atom/A) if (A != src) return ..() - if (last_chew + 26 > world.time) return + if (last_chew + 26 > world.time) + to_chat(src, SPAN_WARNING("You need a break from chewing your own hand off, the pain is too much!")) + return var/mob/living/carbon/human/H = A if (!H.handcuffed) return - if (H.a_intent != I_HURT) return - if (H.zone_sel.selecting != BP_MOUTH) return - if (H.wear_mask) return - if (istype(H.wear_suit, /obj/item/clothing/suit/straight_jacket)) return + if (H.a_intent != I_HURT) + to_chat(src, SPAN_WARNING("You consider chewing your hands out of the restraints, but choose not to harm yourself.")) + return + if (H.zone_sel.selecting != BP_MOUTH) + to_chat(src, SPAN_WARNING("You need to target your mouth to start chewing through your restraints!")) + return + if (istype(H.wear_suit, /obj/item/clothing/suit/straight_jacket)) + to_chat(src, SPAN_WARNING("Try as you might, you cannot chew through \the [H.wear_suit.name].")) + return + if (H.wear_mask) + to_chat(src, SPAN_WARNING("Your mouth is covered, you cannot chew through your restraints!")) + return var/obj/item/organ/external/O = H.organs_by_name[(H.hand ? BP_L_HAND : BP_R_HAND)] if (!O) return - H.visible_message(SPAN_WARNING("\The [H] chews on \his [O.name]!"), SPAN_WARNING("You chew on your [O.name]!")) + H.visible_message(SPAN_DANGER("\The [H] chews on \his [O.name]!"), SPAN_DANGER("You chew on your [O.name]!")) admin_attacker_log(H, "chewed on their [O.name]!") O.take_external_damage(3,0, DAMAGE_FLAG_SHARP|DAMAGE_FLAG_EDGE ,"teeth marks") - last_chew = world.time /obj/item/handcuffs/cable name = "cable restraints" desc = "Looks like some cables tied together. Could be used to tie something up." icon_state = "cuff_white" - breakouttime = 300 //Deciseconds = 30s + breakout_time = 30 SECONDS cuff_sound = 'sound/weapons/cablecuff.ogg' cuff_type = "cable restraints" elastic = 1 @@ -165,6 +174,6 @@ var/global/last_chew = 0 icon_state = "tape_cross" item_state = null icon = 'icons/obj/bureaucracy.dmi' - breakouttime = 200 + breakout_time = 20 SECONDS cuff_type = "duct tape" health_max = 50 diff --git a/code/game/objects/items/weapons/wrapping_paper.dm b/code/game/objects/items/weapons/wrapping_paper.dm index 4163bad6c6a10..c6e871c1a6fcc 100644 --- a/code/game/objects/items/weapons/wrapping_paper.dm +++ b/code/game/objects/items/weapons/wrapping_paper.dm @@ -145,7 +145,7 @@ if (!do_after(user, ITEM_SIZE_LARGE SECONDS, target, DO_PUBLIC_UNIQUE) || !H.has_danger_grab(user) || !user.use_sanity_check(H, src)) return TRUE - var/obj/mobpresent/present = new (H.loc, H, package_type) + var/obj/structure/mobpresent/present = new (H.loc, H, package_type) use(a_used) if (user == target) diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 65173ec4520a8..a0b6a6ba02fcb 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -12,6 +12,7 @@ var/material/material = null var/footstep_type var/mob_offset = 0 //used for on_structure_offset mob animation + var/breakout //if someone is currently breaking out /obj/structure/damage_health(damage, damage_type, damage_flags, severity, skip_can_damage_check) if (damage && HAS_FLAGS(damage_flags, DAMAGE_FLAG_TURF_BREAKER)) diff --git a/code/game/objects/structures/crates_lockers/closets/__closet.dm b/code/game/objects/structures/crates_lockers/closets/__closet.dm index 23d1ad8bf50a7..687bfcbe66340 100644 --- a/code/game/objects/structures/crates_lockers/closets/__closet.dm +++ b/code/game/objects/structures/crates_lockers/closets/__closet.dm @@ -10,7 +10,6 @@ var/welded = 0 var/large = 1 var/wall_mounted = FALSE //equivalent to non-dense for air movement - var/breakout = 0 //if someone is currently breaking out. mutex var/storage_capacity = 2 * MOB_MEDIUM //This is so that someone can't pack hundreds of items in a locker/crate //then open it in a populated area to crash clients. var/open_sound = 'sound/effects/closet_open.ogg' @@ -20,6 +19,7 @@ var/setup = CLOSET_CAN_BE_WELDED var/closet_appearance = /singleton/closet_appearance material = MATERIAL_STEEL + breakout_time = 120 SECONDS // TODO: Turn these into flags. Skipped it for now because it requires updating 100+ locations... var/broken = FALSE @@ -448,39 +448,50 @@ return 0 //Door's open... wait, why are you in it's contents then? if((setup & CLOSET_HAS_LOCK) && locked) return 1 // Closed and locked - return (!welded) //closed but not welded... + return (welded) //closed but not welded... /obj/structure/closet/mob_breakout(mob/living/escapee) - . = ..() - var/breakout_time = 2 //2 minutes by default - if(breakout || !req_breakout()) + if (!breakout_time) + breakout_time = 120 SECONDS + if (breakout) + return FALSE + if (!req_breakout()) + breakout = FALSE + open() return FALSE . = TRUE escapee.setClickCooldown(100) - //okay, so the closet is either welded or locked... resist!!! - to_chat(escapee, SPAN_WARNING("You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time] minutes)")) - + to_chat(escapee, SPAN_WARNING("You lean on the back of \the [src] and start pushing the door open. (this will take about [breakout_time/(1 SECOND)] second\s)")) visible_message(SPAN_DANGER("\The [src] begins to shake violently!")) + shake_animation() - breakout = 1 //can't think of a better way to do this right now. - for(var/i in 1 to (6*breakout_time * 2)) //minutes * 6 * 5seconds * 2 - if(!do_after(escapee, 5 SECONDS, do_flags = DO_DEFAULT | DO_USER_UNIQUE_ACT, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) //5 seconds - breakout = 0 - return FALSE - //Perform the same set of checks as above for weld and lock status to determine if there is even still a point in 'resisting'... - if(!req_breakout()) - breakout = 0 - return FALSE + var/stages = 4 + breakout = TRUE + for (var/i = 1 to stages) + if (do_after(escapee, breakout_time*(1/stages), do_flags = DO_DEFAULT | DO_USER_UNIQUE_ACT, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) + if (!req_breakout()) + breakout = FALSE + open() + return + to_chat(escapee, SPAN_WARNING("You try to slip free of \the [src] ([i*100/stages]% done).")) + else + if (!req_breakout()) + breakout = FALSE + open() + return + to_chat(escapee, SPAN_WARNING("You stop trying to slip free of \the [src].")) + breakout = FALSE + return playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1) shake_animation() add_fingerprint(escapee) //Well then break it! - breakout = 0 + breakout = FALSE to_chat(escapee, SPAN_WARNING("You successfully break out!")) visible_message(SPAN_DANGER("\The [escapee] successfully broke out of \the [src]!")) playsound(src.loc, 'sound/effects/grillehit.ogg', 100, 1) diff --git a/code/modules/hydroponics/spreading/spreading_response.dm b/code/modules/hydroponics/spreading/spreading_response.dm index b8dfe79b050cc..5aec8f143f84f 100644 --- a/code/modules/hydroponics/spreading/spreading_response.dm +++ b/code/modules/hydroponics/spreading/spreading_response.dm @@ -53,14 +53,14 @@ unbuckle_mob() else user.setClickCooldown(100) - var/breakouttime = rand(600, 1200) //1 to 2 minutes. + var/escapetime = rand(600, 1200) //1 to 2 minutes. user.visible_message( "\The [user] attempts to get free from [src]!", SPAN_NOTICE("You attempt to get free from [src].") ) - if (do_after(user, breakouttime, src, DO_DEFAULT | DO_USER_UNIQUE_ACT | DO_PUBLIC_PROGRESS, INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED) && can_unbuckle(user)) + if (do_after(user, escapetime, src, DO_DEFAULT | DO_USER_UNIQUE_ACT | DO_PUBLIC_PROGRESS, INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED) && can_unbuckle(user)) if(unbuckle_mob()) user.visible_message( "\The [user] manages to escape [src]!", diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm index 0cf1f292366e4..4b4ddc38b264b 100644 --- a/code/modules/mob/living/carbon/resist.dm +++ b/code/modules/mob/living/carbon/resist.dm @@ -25,7 +25,6 @@ spawn() escape_handcuffs() /mob/living/carbon/proc/escape_handcuffs() - //if(!(last_special <= world.time)) return //This line represent a significant buff to grabs... // We don't have to check the click cooldown because /mob/living/verb/resist() has done it for us, we can simply set the delay @@ -37,25 +36,26 @@ var/obj/item/handcuffs/HC = handcuffed - //A default in case you are somehow handcuffed with something that isn't an obj/item/handcuffs type - var/breakouttime = istype(HC) ? HC.breakouttime : 2 MINUTES + //A default in case you are somehow handcuffed with something that does not have a breakouttime defined. + var/breakout_time = HC.breakout_time ? HC.breakout_time : 120 SECONDS var/mob/living/carbon/human/H = src if(istype(H) && H.gloves && istype(H.gloves,/obj/item/clothing/gloves/rig)) - breakouttime /= 2 + breakout_time /= 2 if(psi && psi.can_use()) var/psi_mod = (1 - (psi.get_rank(PSI_PSYCHOKINESIS)*0.2)) - breakouttime = max(5, breakouttime * psi_mod) + breakout_time = max(5, breakout_time * psi_mod) visible_message( SPAN_DANGER("\The [src] attempts to remove \the [HC]!"), - SPAN_WARNING("You attempt to remove \the [HC] (This will take around [breakouttime / (1 SECOND)] second\s and you need to stand still)."), range = 2 + SPAN_WARNING("You attempt to remove \the [HC] (This will take around [breakout_time/(1 SECOND)] second\s and you need to stand still)."), range = 2 ) var/stages = 4 for(var/i = 1 to stages) - if(do_after(src, breakouttime*0.25, do_flags = DO_DEFAULT | DO_USER_UNIQUE_ACT, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) + + if(do_after(src, breakout_time*(1/stages), do_flags = DO_DEFAULT | DO_USER_UNIQUE_ACT, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) if(!handcuffed || buckled) return to_chat(src, SPAN_WARNING("You try to slip free of \the [handcuffed] ([i*100/stages]% done).")) @@ -95,23 +95,24 @@ SPAN_WARNING("You attempt to break your [handcuffed.name]. (This will take around 5 seconds and you need to stand still)") ) - if(do_after(src, 5 SECONDS, do_flags = DO_DEFAULT | DO_USER_UNIQUE_ACT, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) - if(!handcuffed || buckled) - return + if (!do_after(src, 5 SECONDS, do_flags = DO_DEFAULT | DO_USER_UNIQUE_ACT, incapacitation_flags = INCAPACITATION_DEFAULT & ~INCAPACITATION_RESTRAINED)) + return + if (!handcuffed || buckled) + return - visible_message( - SPAN_DANGER("[src] manages to break \the [handcuffed]!"), - SPAN_WARNING("You successfully break your [handcuffed.name].") - ) + visible_message( + SPAN_DANGER("[src] manages to break \the [handcuffed]!"), + SPAN_WARNING("You successfully break your [handcuffed.name].") + ) - if(MUTATION_HULK in mutations) - say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) + if (MUTATION_HULK in mutations) + say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) - qdel(handcuffed) - handcuffed = null - if(buckled && buckled.buckle_require_restraints) - buckled.unbuckle_mob() - update_inv_handcuffed() + qdel(handcuffed) + handcuffed = null + if (buckled && buckled.buckle_require_restraints) + buckled.unbuckle_mob() + update_inv_handcuffed() /mob/living/carbon/human/can_break_cuffs() . = ..() || species.can_shred(src,1) @@ -140,7 +141,7 @@ if(unbuckle_time && buckled) var/stages = 2 for(var/i = 1 to stages) - if(!unbuckle_time || do_after(usr, unbuckle_time*0.5, do_flags = DO_DEFAULT | DO_USER_UNIQUE_ACT, incapacitation_flags = INCAPACITATION_DISABLED)) + if(!unbuckle_time || do_after(usr, unbuckle_time*(1/stages), do_flags = DO_DEFAULT | DO_USER_UNIQUE_ACT, incapacitation_flags = INCAPACITATION_DISABLED)) if(!buckled) return to_chat(src, SPAN_WARNING("You try to unbuckle yourself ([i*100/stages]% done).")) diff --git a/code/modules/spells/targeted/projectile/stuncuff.dm b/code/modules/spells/targeted/projectile/stuncuff.dm index 1959fa8282c21..4d5a5e0ba7674 100644 --- a/code/modules/spells/targeted/projectile/stuncuff.dm +++ b/code/modules/spells/targeted/projectile/stuncuff.dm @@ -37,8 +37,7 @@ /obj/item/handcuffs/wizard name = "beams of light" desc = "Undescribable and unpenetrable. Or so they say." - - breakouttime = 300 //30 seconds + breakout_time = 30 SECONDS /obj/item/handcuffs/wizard/dropped(mob/user) ..()