From 3980f2dd77ddccaac931b185ebeacdb08916049e Mon Sep 17 00:00:00 2001 From: Charlie <69320440+hal9000PR@users.noreply.github.com> Date: Wed, 6 Jul 2022 19:46:52 +0100 Subject: [PATCH] stun and telebaton rework (#18127) * stun and telebaton rework * batons now do stamina * makes it work * indicator * tweaks * farie review * moxian review * sod it --- code/__HELPERS/traits.dm | 1 + code/game/objects/items/weapons/batons.dm | 28 ++++---- code/game/objects/items/weapons/stunbaton.dm | 65 +++++++++++-------- code/game/objects/items/weapons/teleprod.dm | 1 - .../contractor/items/contractor_baton.dm | 9 ++- 5 files changed, 56 insertions(+), 48 deletions(-) diff --git a/code/__HELPERS/traits.dm b/code/__HELPERS/traits.dm index 83ba539baef..dd16f7ee66e 100644 --- a/code/__HELPERS/traits.dm +++ b/code/__HELPERS/traits.dm @@ -230,6 +230,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define STAT_TRAIT "stat_trait" #define TRANSFORMING_TRAIT "transforming" #define BUCKLING_TRAIT "buckled" +#define TRAIT_WAS_BATONNED "batonged" //quirk traits #define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance" diff --git a/code/game/objects/items/weapons/batons.dm b/code/game/objects/items/weapons/batons.dm index ada35397da3..33a3b306bf2 100644 --- a/code/game/objects/items/weapons/batons.dm +++ b/code/game/objects/items/weapons/batons.dm @@ -16,8 +16,12 @@ // Settings /// Whether the baton can stun silicon mobs var/affect_silicon = FALSE + /// The amount of stamina damage the baton does per swing + var/stamina_damage = 30 + /// How much melee armour is ignored by the stamina damage + var/stamina_armour_pen = 0 /// The stun time (in seconds) for non-silicons - var/stun_time = 6 SECONDS + var/knockdown_duration = 6 SECONDS /// The stun time (in seconds) for silicons var/stun_time_silicon = 10 SECONDS /// Cooldown in seconds between two knockdowns @@ -38,7 +42,7 @@ if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) user.visible_message("[user] accidentally clubs [user.p_them()]self with [src]!", \ "You accidentally club yourself with [src]!") - user.Weaken(stun_time) + user.KnockDown(knockdown_duration) if(ishuman(user)) var/mob/living/carbon/human/H = user H.apply_damage(force * 2, BRUTE, "head") @@ -53,7 +57,7 @@ if(issilicon(target) && !affect_silicon) return ..() else - stun(target, user) + baton_knockdown(target, user) /** * Called when a target is about to be hit non-lethally. @@ -62,7 +66,7 @@ * * target - The mob about to be hit * * user - The attacking user */ -/obj/item/melee/classic_baton/proc/stun(mob/living/target, mob/living/user) +/obj/item/melee/classic_baton/proc/baton_knockdown(mob/living/target, mob/living/user) if(issilicon(target)) user.visible_message("[user] pulses [target]'s sensors with [src]!",\ "You pulse [target]'s sensors with [src]!") @@ -81,12 +85,12 @@ // Visuals and sound user.do_attack_animation(target) playsound(target, stun_sound, 75, TRUE, -1) - add_attack_logs(user, target, "Stunned with [src]") + add_attack_logs(user, target, "Knocked down with [src]") // Hit 'em target.LAssailant = iscarbon(user) ? user : null - target.Weaken(stun_time) + target.KnockDown(knockdown_duration) on_cooldown = TRUE - addtimer(CALLBACK(src, .proc/cooldown_finished), cooldown) + addtimer(VARSET_CALLBACK(src, on_cooldown, FALSE), cooldown) return TRUE /** @@ -108,13 +112,9 @@ * * user - The attacking user */ /obj/item/melee/classic_baton/proc/on_non_silicon_stun(mob/living/target, mob/living/user) - return - -/** - * Called some time after a non-lethal attack - */ -/obj/item/melee/classic_baton/proc/cooldown_finished() - on_cooldown = FALSE + var/armour = target.run_armor_check("chest", armour_penetration = stamina_armour_pen) // returns a % of their chest melee armour + var/factor = (100 - armour) / 100 // converts the % into a decimal + target.adjustStaminaLoss(stamina_damage * factor) /** * # Fancy Cane diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index d3c39d48170..080b3b87f1a 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -11,15 +11,19 @@ origin_tech = "combat=2" attack_verb = list("beaten") armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 80, ACID = 80) - /// How many life ticks does the stun last for - var/stunforce = 14 SECONDS + /// How many seconds does the knockdown last for? + var/knockdown_duration = 10 SECONDS + /// how much stamina damage does this baton do? + var/stam_damage = 60 // 2 hits or 1 hit + 2 disabler shots /// Is the baton currently turned on var/turned_on = FALSE /// How much power does it cost to stun someone var/hitcost = 1000 - /// Chance for the baton to stun when thrown at someone - var/throw_hit_chance = 35 var/obj/item/stock_parts/cell/high/cell = null + /// the initial cooldown tracks the time between swings. tracks the world.time when the baton is usable again. + var/cooldown = 3.5 SECONDS + /// the time it takes before the target falls over + var/knockdown_delay = 2.5 SECONDS /obj/item/melee/baton/Initialize(mapload) . = ..() @@ -80,11 +84,6 @@ /obj/item/melee/baton/get_cell() return cell -/obj/item/melee/baton/throw_impact(atom/hit_atom) - ..() - if(prob(throw_hit_chance) && turned_on && isliving(hit_atom) && !issilicon(hit_atom)) - baton_stun(hit_atom) - /** * Removes the specified amount of charge from the batons power cell. * @@ -153,10 +152,9 @@ /obj/item/melee/baton/attack(mob/M, mob/living/user) if(turned_on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) - user.visible_message("[user] accidentally hits [user.p_them()]self with [src]!", + if(baton_stun(user, user, skip_cooldown = TRUE)) // for those super edge cases where you clumsy baton yourself in quick succession + user.visible_message("[user] accidentally hits [user.p_them()]self with [src]!", "You accidentally hit yourself with [src]!") - user.Weaken(stunforce * 3) - deductcharge(hitcost) return if(issilicon(M)) // Can't stunbaton borgs and AIs @@ -181,23 +179,34 @@ "[L == user ? "You prod yourself" : "[user] has prodded you"] with [src]. Luckily it was off.") return - baton_stun(L, user) - user.do_attack_animation(L) + if(baton_stun(L, user)) + user.do_attack_animation(L) -/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user) +/// returning false results in no baton attack animation, returning true results in an animation. +/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user, skip_cooldown = FALSE) + if(cooldown > world.time && !skip_cooldown) + return FALSE + + var/user_UID = user.UID() + if(HAS_TRAIT_FROM(L, TRAIT_WAS_BATONNED, user_UID)) // prevents double baton cheese. + return FALSE + + cooldown = world.time + initial(cooldown) // tracks the world.time when hitting will be next available. if(ishuman(L)) var/mob/living/carbon/human/H = L if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) //No message; check_shields() handles that playsound(L, 'sound/weapons/genhit.ogg', 50, TRUE) - return + return FALSE H.forcesay(GLOB.hit_appends) + H.Confused(10 SECONDS) + H.Jitter(10 SECONDS) + H.adjustStaminaLoss(stam_damage) + + ADD_TRAIT(L, TRAIT_WAS_BATONNED, user.UID()) // so one person cannot hit the same person with two separate batons + addtimer(CALLBACK(src, .proc/baton_knockdown, L, user_UID, knockdown_duration), knockdown_delay) SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK, 33) - L.Weaken(stunforce) - L.Stuttering(stunforce) - - if(user) L.lastattacker = user.real_name L.lastattackerckey = user.ckey @@ -206,7 +215,11 @@ add_attack_logs(user, L, "stunned") playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1) deductcharge(hitcost) + return TRUE +/obj/item/melee/baton/proc/baton_knockdown(mob/living/target, user_UID, knockdown_duration) + target.KnockDown(knockdown_duration) + REMOVE_TRAIT(target, TRAIT_WAS_BATONNED, user_UID) /obj/item/melee/baton/emp_act(severity) . = ..() @@ -216,13 +229,9 @@ /obj/item/melee/baton/wash(mob/living/user, atom/source) if(turned_on && cell?.charge) flick("baton_active", source) - user.Stun(stunforce) - user.Weaken(stunforce) - user.SetStuttering(stunforce) - deductcharge(hitcost) + baton_stun(user, user, skip_cooldown = TRUE) user.visible_message("[user] shocks [user.p_them()]self while attempting to wash the active [src]!", "You unwisely attempt to wash [src] while it's still on.") - playsound(src, "sparks", 50, TRUE) return TRUE ..() @@ -235,9 +244,9 @@ item_state = "prod" force = 3 throwforce = 5 - stunforce = 10 SECONDS + knockdown_duration = 6 SECONDS + stam_damage = 40 // three hits to crit hitcost = 2000 - throw_hit_chance = 10 slot_flags = SLOT_BACK var/obj/item/assembly/igniter/sparkler = null @@ -249,6 +258,6 @@ QDEL_NULL(sparkler) return ..() -/obj/item/melee/baton/cattleprod/baton_stun() +/obj/item/melee/baton/cattleprod/baton_stun(mob/living/L, mob/user, skip_cooldown = FALSE) if(sparkler.activate()) return ..() diff --git a/code/game/objects/items/weapons/teleprod.dm b/code/game/objects/items/weapons/teleprod.dm index b15d843c98c..e1bb74ff273 100644 --- a/code/game/objects/items/weapons/teleprod.dm +++ b/code/game/objects/items/weapons/teleprod.dm @@ -13,7 +13,6 @@ if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) user.visible_message("[user] accidentally hits [user.p_them()]self with [src]!", "You accidentally hit yourself with [src]!") - user.Weaken(stunforce * 3) deductcharge(hitcost) do_teleport(user, get_turf(user), 50)//honk honk else if(iscarbon(M) && !M.anchored) diff --git a/code/modules/antagonists/traitor/contractor/items/contractor_baton.dm b/code/modules/antagonists/traitor/contractor/items/contractor_baton.dm index 30fc73ac222..fc94e31373b 100644 --- a/code/modules/antagonists/traitor/contractor/items/contractor_baton.dm +++ b/code/modules/antagonists/traitor/contractor/items/contractor_baton.dm @@ -3,8 +3,10 @@ desc = "A compact, specialised baton issued to Syndicate contractors. Applies light electrical shocks to targets." // Overrides affect_silicon = TRUE - stun_time = 2 SECONDS + knockdown_duration = 4 SECONDS cooldown = 2.5 SECONDS + stamina_damage = 70 + stamina_armour_pen = 100 force_off = 5 force_on = 15 item_state_on = "contractor_baton" @@ -13,15 +15,12 @@ stun_sound = 'sound/weapons/contractorbatonhit.ogg' extend_sound = 'sound/weapons/contractorbatonextend.ogg' // Settings - /// Stamina damage to deal on stun. - var/stamina_damage = 70 /// Jitter to deal on stun. var/jitter_amount = 5 SECONDS /// Stutter to deal on stun. var/stutter_amount = 10 SECONDS -/obj/item/melee/classic_baton/telescopic/contractor/stun(mob/living/target, mob/living/user) +/obj/item/melee/classic_baton/telescopic/contractor/baton_knockdown(mob/living/target, mob/living/user) . = ..() - target.adjustStaminaLoss(stamina_damage) target.Jitter(jitter_amount) target.AdjustStuttering(stutter_amount)