Skip to content

Commit

Permalink
[MIRROR] Adds ability to resist out of gift-wrapped mob
Browse files Browse the repository at this point in the history
  • Loading branch information
emmanuelbassil authored and SuhEugene committed Nov 12, 2023
1 parent d9bc588 commit a9cb995
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 68 deletions.
1 change: 1 addition & 0 deletions code/game/objects/buckling.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
60 changes: 47 additions & 13 deletions code/game/objects/items/weapons/gifts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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].")
29 changes: 19 additions & 10 deletions code/game/objects/items/weapons/handcuffs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion code/game/objects/items/weapons/wrapping_paper.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions code/game/objects/structures.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
47 changes: 29 additions & 18 deletions code/game/objects/structures/crates_lockers/closets/__closet.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions code/modules/hydroponics/spreading/spreading_response.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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]!",
Expand Down
45 changes: 23 additions & 22 deletions code/modules/mob/living/carbon/resist.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)."))
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)."))
Expand Down
3 changes: 1 addition & 2 deletions code/modules/spells/targeted/projectile/stuncuff.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
..()
Expand Down

0 comments on commit a9cb995

Please sign in to comment.