Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MIRROR] Adds ability to resist out of gift-wrapped mob #1450

Merged
merged 1 commit into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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