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

Tonfa updates #11200

Merged
merged 7 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
5 changes: 5 additions & 0 deletions code/__DEFINES/inventory.dm
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ GLOBAL_LIST_INIT(advanced_hardsuit_allowed, typecacheof(list(
/obj/item/flashlight,
/obj/item/gun,
/obj/item/melee/baton,
/obj/item/melee/tonfa,
/obj/item/reagent_containers/peppercloud_deployer,
/obj/item/restraints/handcuffs,
/obj/item/tank/internals)))
Expand All @@ -160,6 +161,7 @@ GLOBAL_LIST_INIT(security_hardsuit_allowed, typecacheof(list(
/obj/item/gun/energy,
/obj/item/gun/grenadelauncher,
/obj/item/melee/baton,
/obj/item/melee/tonfa,
/obj/item/reagent_containers/peppercloud_deployer,
/obj/item/restraints/handcuffs,
/obj/item/tank/internals)))
Expand All @@ -175,6 +177,7 @@ GLOBAL_LIST_INIT(detective_vest_allowed, typecacheof(list(
/obj/item/gun/grenadelauncher,
/obj/item/lighter,
/obj/item/melee/baton,
/obj/item/melee/tonfa,
/obj/item/melee/classic_baton/police,
/obj/item/reagent_containers/peppercloud_deployer,
/obj/item/restraints/handcuffs,
Expand All @@ -191,6 +194,7 @@ GLOBAL_LIST_INIT(security_vest_allowed, typecacheof(list(
/obj/item/gun/grenadelauncher,
/obj/item/knife/combat,
/obj/item/melee/baton,
/obj/item/melee/tonfa,
/obj/item/melee/classic_baton/police/telescopic,
/obj/item/reagent_containers/peppercloud_deployer,
/obj/item/restraints/handcuffs,
Expand All @@ -207,6 +211,7 @@ GLOBAL_LIST_INIT(security_wintercoat_allowed, typecacheof(list(
/obj/item/gun/grenadelauncher,
/obj/item/lighter,
/obj/item/melee/baton,
/obj/item/melee/tonfa,
/obj/item/melee/classic_baton/police/telescopic,
/obj/item/reagent_containers/peppercloud_deployer,
/obj/item/restraints/handcuffs,
Expand Down
1 change: 1 addition & 0 deletions code/controllers/subsystem/traumas.dm
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ SUBSYSTEM_DEF(traumas)
/obj/item/clothing/under/rank/security/warden,
/obj/item/clothing/under/rank/security/head_of_security, /obj/item/clothing/under/rank/security/detective,
/obj/item/melee/baton, /obj/item/gun/energy/taser, /obj/item/restraints/handcuffs,
/obj/item/melee/tonfa,
/obj/machinery/door/airlock/security, /obj/effect/hallucination/simple/securitron)),

"clowns" = typecacheof(list(
Expand Down
274 changes: 97 additions & 177 deletions code/game/objects/items/melee/misc.dm
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
var/stamina_damage = 55 // Do we deal stamina damage.
var/affect_silicon = FALSE // Does it stun silicons.
var/on_sound // "On" sound, played when switching between able to stun or not.
var/on_stun_sound = "sound/effects/woodhit.ogg" // Default path to sound for when we stun.
var/on_stun_sound = 'sound/effects/woodhit.ogg' // Default path to sound for when we stun.
var/stun_animation = FALSE // Do we animate the "hit" when stunning.
var/on = TRUE // Are we on or off

Expand Down Expand Up @@ -294,6 +294,7 @@
if (H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
return
if(check_martial_counter(H, user))
log_combat(user, target, "attampted to attack", src, "(blocked by martial arts)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spelling

return

var/list/desc = get_stun_description(target, user)
Expand Down Expand Up @@ -339,182 +340,6 @@
stamina_damage = 20
stun_animation = TRUE

//Former Wooden Baton
/obj/item/melee/classic_baton/police/tonfa
name = "Police Tonfa"
desc = "Favored by hot headed Security Officers who don't want to get in trouble with CentCom but still want to get that nostalgic feeling of beating some criminal scum upside the head with a chunk of wood."
icon_state = "beater"
item_state = "beater"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
force = 8
throwforce = 7
cooldown = 0
stamina_damage = 30 // 4 hits to stamcrit < that was a lie
stun_animation = TRUE
/// Per-mob paralyze cooldowns.
/// [mob] = [world.time where the cooldown ends]
var/static/list/paralyze_cooldowns = list()
/// Per-mob trip cooldowns.
/// [mob] = [world.time where the cooldown ends]
var/static/list/trip_cooldowns = list()

/obj/item/melee/classic_baton/police/tonfa/attack(mob/living/target, mob/living/user)
var/def_check = target.getarmor(type = MELEE, penetration = armour_penetration)

add_fingerprint(user)
if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
to_chat(user, "<span class ='danger'>You hit yourself over the head.</span>")
user.adjustStaminaLoss(stamina_damage)

additional_effects_carbon(user) // user is the target here
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.apply_damage(2*force, BRUTE, BODY_ZONE_HEAD)
else
user.take_bodypart_damage(2*force)
return
if(!isliving(target))
return
if(iscyborg(target))
if (user.a_intent != INTENT_HARM)
playsound(get_turf(src), on_stun_sound, 75, 1, -1)
user.do_attack_animation(target) // The attacker cuddles the Cyborg, awww. No damage here.
return
return ..()
if (user.a_intent == INTENT_HARM)
if(!..())
target.apply_damage(force, STAMINA, blocked = def_check)
return
else if(cooldown_check > world.time)
var/wait_desc = get_wait_description()
if (wait_desc)
to_chat(user, wait_desc)
return
if(ishuman(target))
var/mob/living/carbon/human/H = target
if (H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
return
if(check_martial_counter(H, user))
return

var/list/desc = get_stun_description(target, user)
var/obj/item/bodypart/La = target.get_bodypart(BODY_ZONE_L_ARM)
var/obj/item/bodypart/Ra = target.get_bodypart(BODY_ZONE_R_ARM)
var/obj/item/bodypart/Ll = target.get_bodypart(BODY_ZONE_L_LEG)
var/obj/item/bodypart/Rl = target.get_bodypart(BODY_ZONE_R_LEG)
var/mob/living/carbon/human/T = target

user.do_attack_animation(target)
playsound(get_turf(src), on_stun_sound, 75, 1, -1)
additional_effects_carbon(target, user)
if(user.is_zone_selected(BODY_ZONE_CHEST) || user.is_zone_selected(BODY_ZONE_PRECISE_GROIN))
target.apply_damage(stamina_damage, STAMINA, BODY_ZONE_CHEST, def_check)
log_combat(user, target, "stunned", src)
target.visible_message(desc["visiblestun"], desc["localstun"])

else if(user.is_zone_selected(BODY_ZONE_HEAD) || user.is_zone_selected(BODY_ZONE_PRECISE_EYES) || user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH))
target.apply_damage(stamina_damage*0.8, STAMINA, BODY_ZONE_HEAD, def_check) // 90 : 5 = 18 , 5 hits to KnockOut

if(target.staminaloss > 89 && !target.has_status_effect(STATUS_EFFECT_PARALYZED) && (!paralyze_cooldowns[target] || COOLDOWN_FINISHED(src, paralyze_cooldowns[target])))
T.force_say(user)
target.balloon_alert_to_viewers("Knock-Down!")
if(!target.has_status_effect(STATUS_EFFECT_PARALYZED))
target.Paralyze(80)
target.setStaminaLoss(0)
playsound(usr.loc, "sound/machines/bellsound.ogg", 15, 1)
log_combat(user, target, "Knocked-Down", src)
if(CHECK_BITFIELD(target.mobility_flags, MOBILITY_STAND)) //this is here so the "falls" message doesn't appear if the target is already on the floor
target.visible_message("<span class='emote'><b>[T]</b> [pick(list("falls limp like a bag of bricks.","falls to the ground, unresponsive.","lays down on the ground.","got [T.p_their()] dome rung in."))]</span>")
else
target.visible_message("<span class='emote'><b>[T]</b> [pick(list("goes limp.","falls flat."))]</span>")
COOLDOWN_START(src, paralyze_cooldowns[target], 16 SECONDS)
else
log_combat(user, target, "stunned", src)
target.visible_message(desc["visiblestun"], desc["localstun"])

else if(user.is_zone_selected(BODY_ZONE_L_LEG))
log_combat(user, target, "stunned", src)
target.visible_message(desc["visibleleg"], desc["localleg"])
if (Rl.get_staminaloss() < 26 && Ra.get_staminaloss() < 26 && La.get_staminaloss() < 26)
target.apply_damage(stamina_damage, STAMINA, BODY_ZONE_L_LEG, def_check)
else
target.apply_damage(stamina_damage*0.5, STAMINA, BODY_ZONE_L_LEG, def_check)
if (Ll.get_staminaloss() == 50)
target.apply_damage(stamina_damage*0.5, STAMINA, BODY_ZONE_CHEST, def_check)
else
target.apply_damage(stamina_damage*0.2, STAMINA, BODY_ZONE_CHEST, def_check)

if(Ll.get_staminaloss() == 50 && CHECK_BITFIELD(target.mobility_flags, MOBILITY_STAND) && (!trip_cooldowns[target] || COOLDOWN_FINISHED(src, trip_cooldowns[target])))
target.visible_message("<span class='emote'><b>[T]</b> [pick(list("falls down.","falls face first into the floor.","gets viciously tripped.","got clumsy."))]</span>")
target.balloon_alert_to_viewers("Tripped!")
target.Knockdown(7)
log_combat(user, target, "tripped", src)
target.visible_message(desc["visibletrip"], desc["localtrip"])
playsound(usr.loc, "sound/misc/slip.ogg", 30, 1)
COOLDOWN_START(src, trip_cooldowns[target], 3 SECONDS)

else if(user.is_zone_selected(BODY_ZONE_R_LEG))
log_combat(user, target, "stunned", src)
target.visible_message(desc["visibleleg"], desc["localleg"])
if (Ll.get_staminaloss() < 26 && Ra.get_staminaloss() < 26 && La.get_staminaloss() < 26)
target.apply_damage(stamina_damage, STAMINA, BODY_ZONE_R_LEG, def_check)
else
target.apply_damage(stamina_damage*0.5, STAMINA, BODY_ZONE_R_LEG, def_check)
if (Rl.get_staminaloss() == 50)
target.apply_damage(stamina_damage*0.5, STAMINA, BODY_ZONE_CHEST, def_check)
else
target.apply_damage(stamina_damage*0.2, STAMINA, BODY_ZONE_CHEST, def_check)

if(Rl.get_staminaloss() == 50 && CHECK_BITFIELD(target.mobility_flags, MOBILITY_STAND) && (!trip_cooldowns[target] || COOLDOWN_FINISHED(src, trip_cooldowns[target])))
target.visible_message("<span class='emote'><b>[T]</b> [pick(list("falls down.","falls face first into the floor.","gets viciously tripped.","got clumsy."))]</span>")
target.balloon_alert_to_viewers("Tripped!")
target.Knockdown(7)
log_combat(user, target, "tripped", src)
playsound(usr.loc, "sound/misc/slip.ogg", 30, 1)
target.visible_message(desc["visibletrip"], desc["localtrip"])
COOLDOWN_START(src, trip_cooldowns[target], 3 SECONDS)

else if(user.is_zone_selected(BODY_ZONE_L_ARM))
if(!La.get_staminaloss() == 50)
log_combat(user, target, "stunned", src)
target.visible_message(desc["visiblearm"], desc["localarm"])
else
log_combat(user, target, "disarmed", src)
target.visible_message(desc["visibledisarm"], desc["localdisarm"])
if (Ra.get_staminaloss() < 26 && Ll.get_staminaloss() < 26 && Rl.get_staminaloss() < 26)
target.apply_damage(stamina_damage*0.8, STAMINA, BODY_ZONE_L_ARM, def_check)
else
target.apply_damage(stamina_damage*0.2, STAMINA, BODY_ZONE_L_ARM, def_check)
if (La.get_staminaloss() == 50)
target.apply_damage(stamina_damage*0.5, STAMINA, BODY_ZONE_CHEST, def_check)
else
target.apply_damage(stamina_damage*0.2, STAMINA, BODY_ZONE_CHEST, def_check)

else if(user.is_zone_selected(BODY_ZONE_R_ARM))
if(!Ra.get_staminaloss() == 50)
log_combat(user, target, "stunned", src)
target.visible_message(desc["visiblearm"], desc["localarm"])
else
log_combat(user, target, "disarmed", src)
target.visible_message(desc["visibledisarm"], desc["localdisarm"])
if (La.get_staminaloss() < 26 && Ll.get_staminaloss() < 26 && Rl.get_staminaloss() < 26)
target.apply_damage(stamina_damage*0.8, STAMINA, BODY_ZONE_R_ARM, def_check)
else
target.apply_damage(stamina_damage*0.2, STAMINA, BODY_ZONE_R_ARM, def_check)
if (Ra.get_staminaloss() == 50)
target.apply_damage(stamina_damage*0.5, STAMINA, BODY_ZONE_CHEST, def_check)
else
target.apply_damage(stamina_damage*0.2, STAMINA, BODY_ZONE_CHEST, def_check)

add_fingerprint(user)

if(!iscarbon(user))
target.LAssailant = null
else
target.LAssailant = WEAKREF(user)
COOLDOWN_START(src, cooldown_check, cooldown)

//Telescopic Baton
/obj/item/melee/classic_baton/police/telescopic
name = "telescopic baton"
Expand Down Expand Up @@ -710,6 +535,7 @@
if (H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
return
if(check_martial_counter(H, user))
log_combat(user, target, "attampted to attack", src, "(blocked by martial arts)")
Rukofamicom marked this conversation as resolved.
Show resolved Hide resolved
return

var/list/desc = get_stun_description(target, user)
Expand Down Expand Up @@ -1079,3 +905,97 @@
target.LAssailant = user

cooldown = world.time + 15

//Former Wooden Baton
/obj/item/melee/tonfa
name = "Police Tonfa"
desc = "A traditional police baton for gaining the submission of an uncooperative target without the use of lethal-force. \
As with all traditional weapons, the target will find themselves bruised, but alive. It has proven to be effective in preventing \
repeat offenses and has brought employment to lawyers for decades."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "beater"
item_state = "beater"
worn_icon_state = "classic_baton"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
force = 12
throwforce = 7
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_LARGE
hitsound = 'sound/effects/woodhit.ogg'
/// Damage dealt while on help intent
var/non_harm_force = 4
PowerfulBacon marked this conversation as resolved.
Show resolved Hide resolved
/// Stamina damage dealt
var/stamina_force = 25

// #11200 Review - TEMP: Hacky code to deal with force string for this item.
/obj/item/melee/tonfa/openTip(location, control, params, mob/user)
if (user != null && user.a_intent != INTENT_HARM)
force = non_harm_force
else
force = initial(force)
return ..()

/obj/item/melee/tonfa/attack(mob/living/target, mob/living/user)
var/target_zone = user.get_combat_bodyzone(target)
var/armour_level = target.getarmor(target_zone, STAMINA, penetration = armour_penetration - 15)
EvilDragonfiend marked this conversation as resolved.
Show resolved Hide resolved

add_fingerprint(user)
if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
to_chat(user, "<span class ='danger'>You hit yourself over the head.</span>")
user.adjustStaminaLoss(stamina_force)

// Deal full damage
force = initial(force)
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.apply_damage(2*force, BRUTE, BODY_ZONE_HEAD)
else
user.take_bodypart_damage(2*force)
PowerfulBacon marked this conversation as resolved.
Show resolved Hide resolved
return
if(!isliving(target))
return ..()
if(iscyborg(target))
if (user.a_intent != INTENT_HARM)
playsound(get_turf(src), hitsound, 75, 1, -1)
user.do_attack_animation(target) // The attacker cuddles the Cyborg, awww. No damage here.
return
if (user.a_intent != INTENT_HARM)
force = non_harm_force
else
force = initial(force)
PowerfulBacon marked this conversation as resolved.
Show resolved Hide resolved
if(ishuman(target))
var/mob/living/carbon/human/H = target
if (H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
return
if(check_martial_counter(H, user))
log_combat(user, target, "attampted to attack", src, "(blocked by martial arts)")
return

var/mob/living/carbon/human/T = target

target.visible_message("[user] strikes [target] in the [parse_zone(target_zone)].", "You strike [target] in the [parse_zone(target_zone)].")
log_combat(user, target, "attacked", src)

// If the target has a lot of stamina loss, knock them down
if ((user.is_zone_selected(BODY_ZONE_L_LEG) || user.is_zone_selected(BODY_ZONE_R_LEG)) && target.getStaminaLoss() > 22)
var/effectiveness = CLAMP01((target.getStaminaLoss() - 22) / 50)
EvilDragonfiend marked this conversation as resolved.
Show resolved Hide resolved
log_combat(user, target, "knocked-down", src, "(additional effect)")
// Move the target back upon knockdown, to give them some time to recover
var/shove_dir = get_dir(user.loc, target.loc)
var/turf/target_shove_turf = get_step(target.loc, shove_dir)
var/mob/living/carbon/human/target_collateral_human = locate(/mob/living/carbon) in target_shove_turf.contents
if (target_collateral_human && target_shove_turf != get_turf(user))
target.Knockdown(max(0.5 SECONDS, effectiveness * 4 SECONDS * (100-armour_level)/100))
target_collateral_human.Knockdown(0.5 SECONDS)
else
target.Knockdown(effectiveness * 4 SECONDS * (100-armour_level)/100)
target.Move(target_shove_turf, shove_dir)
if (user.is_zone_selected(BODY_ZONE_L_LEG) || user.is_zone_selected(BODY_ZONE_R_LEG) || user.is_zone_selected(BODY_ZONE_L_ARM) || user.is_zone_selected(BODY_ZONE_R_ARM))
EvilDragonfiend marked this conversation as resolved.
Show resolved Hide resolved
// 4-5 hits on an unarmoured target
target.apply_damage(stamina_force*0.6, STAMINA, target_zone, armour_level)
else
// 4-5 hits on an unarmoured target
target.apply_damage(stamina_force, STAMINA, target_zone, armour_level)

return ..()
2 changes: 1 addition & 1 deletion code/game/objects/items/shields.dm
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
transparent = TRUE

/obj/item/shield/riot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/melee/baton))
if(istype(W, /obj/item/melee/baton) || istype(W, /obj/item/melee/tonfa))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably include /obj/item/melee/classic_baton subtypes too, no?

It should clunk if I hit it with a tonfa, stunbaton, Billy club, or det baton

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll let it work for any melee weapon that isn't sharp

if(cooldown < world.time - 25)
user.visible_message("<span class='warning'>[user] bashes [src] with [W]!</span>")
playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1)
Expand Down
1 change: 1 addition & 0 deletions code/game/objects/items/storage/belt.dm
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
var/static/list/can_hold = typecacheof(list(
/obj/item/melee/baton,
/obj/item/melee/tonfa,
/obj/item/melee/classic_baton/police,
/obj/item/grenade,
/obj/item/reagent_containers/peppercloud_deployer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
/obj/item/abductor,
/obj/item/abductor/baton,
/obj/item/melee/baton,
/obj/item/melee/tonfa,
/obj/item/gun/energy,
/obj/item/restraints/handcuffs
)
Expand Down
1 change: 1 addition & 0 deletions code/modules/clothing/spacesuits/swat.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
/obj/item/ammo_box,
/obj/item/ammo_casing,
/obj/item/melee/baton,
/obj/item/melee/tonfa,
/obj/item/restraints/handcuffs,
/obj/item/tank/internals,
/obj/item/knife/combat
Expand Down
1 change: 1 addition & 0 deletions code/modules/jobs/job_mail.dm
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@
/obj/effect/spawner/mail/donut = 20,
/obj/effect/spawner/mail/rdonut = 15,
/obj/item/melee/baton = 1,
/obj/item/melee/tonfa,
)

//DETECTIVE
Expand Down
Loading
Loading