diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm
index d0bb6f6db9a..45d59812bb2 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm
@@ -85,7 +85,7 @@
/obj/effect/decal/cleanable/blood/gibs,
/obj/item/clothing/under/rank/security/officer,
/obj/item/clothing/suit/armor/vest,
-/obj/item/melee/baton/loaded,
+/obj/item/melee/baton/security/loaded,
/obj/item/clothing/head/helmet,
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/ruin/unpowered/xenonest)
diff --git a/_maps/RandomRuins/SpaceRuins/TheDerelict.dmm b/_maps/RandomRuins/SpaceRuins/TheDerelict.dmm
index f2c587a41f7..696453702a2 100644
--- a/_maps/RandomRuins/SpaceRuins/TheDerelict.dmm
+++ b/_maps/RandomRuins/SpaceRuins/TheDerelict.dmm
@@ -491,7 +491,7 @@
/area/ruin/space/derelict/bridge/access)
"cy" = (
/obj/structure/rack,
-/obj/item/melee/classic_baton,
+/obj/item/melee/baton,
/turf/open/floor/iron,
/area/ruin/space/derelict/bridge/access)
"cz" = (
diff --git a/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm b/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm
index e52c3efbb63..1b479fda27f 100644
--- a/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm
+++ b/_maps/RandomRuins/SpaceRuins/abandonedzoo.dmm
@@ -179,7 +179,7 @@
pixel_x = -25
},
/obj/structure/rack,
-/obj/item/melee/baton/cattleprod,
+/obj/item/melee/baton/security/cattleprod,
/obj/effect/spawner/lootdrop/maintenance,
/obj/structure/cable,
/turf/open/floor/iron/dark/side,
diff --git a/_maps/RandomRuins/SpaceRuins/gasthelizards.dmm b/_maps/RandomRuins/SpaceRuins/gasthelizards.dmm
index 0bb6c7036e6..a9582a09ed7 100644
--- a/_maps/RandomRuins/SpaceRuins/gasthelizards.dmm
+++ b/_maps/RandomRuins/SpaceRuins/gasthelizards.dmm
@@ -263,7 +263,7 @@
"J" = (
/obj/structure/rack,
/obj/item/storage/toolbox/drone,
-/obj/item/melee/baton/cattleprod,
+/obj/item/melee/baton/security/cattleprod,
/turf/open/floor/iron,
/area/ruin/space/has_grav/gasthelizard)
"K" = (
diff --git a/_maps/RandomRuins/SpaceRuins/mrow_thats_right.dmm b/_maps/RandomRuins/SpaceRuins/mrow_thats_right.dmm
index 7791bf72bb5..807c112eda8 100644
--- a/_maps/RandomRuins/SpaceRuins/mrow_thats_right.dmm
+++ b/_maps/RandomRuins/SpaceRuins/mrow_thats_right.dmm
@@ -469,8 +469,8 @@
/area/ruin/space/has_grav/powered/cat_man)
"bx" = (
/obj/structure/rack,
-/obj/item/melee/baton/cattleprod,
-/obj/item/melee/baton/cattleprod,
+/obj/item/melee/baton/security/cattleprod,
+/obj/item/melee/baton/security/cattleprod,
/obj/item/restraints/handcuffs,
/obj/item/restraints/handcuffs,
/turf/open/floor/carpet,
diff --git a/_maps/RandomZLevels/caves.dmm b/_maps/RandomZLevels/caves.dmm
index 6bbfabd94ce..2e976fbd99c 100644
--- a/_maps/RandomZLevels/caves.dmm
+++ b/_maps/RandomZLevels/caves.dmm
@@ -856,7 +856,7 @@
/area/awaymission/caves/research)
"cX" = (
/obj/structure/table,
-/obj/item/melee/baton,
+/obj/item/melee/baton/security,
/turf/open/floor/iron{
initial_gas_mix = "n2=23;o2=14;TEMP=2.7"
},
diff --git a/_maps/RandomZLevels/moonoutpost19.dmm b/_maps/RandomZLevels/moonoutpost19.dmm
index ea6a2fa738d..50f8436a74e 100644
--- a/_maps/RandomZLevels/moonoutpost19.dmm
+++ b/_maps/RandomZLevels/moonoutpost19.dmm
@@ -164,7 +164,7 @@
/obj/item/clothing/mask/facehugger/impregnated,
/obj/item/clothing/under/rank/security/officer,
/obj/item/clothing/suit/armor/vest,
-/obj/item/melee/baton/loaded,
+/obj/item/melee/baton/security/loaded,
/obj/item/clothing/head/helmet,
/turf/open/floor/plating/asteroid{
heat_capacity = 1e+006;
diff --git a/_maps/RandomZLevels/research.dmm b/_maps/RandomZLevels/research.dmm
index 18744ac612d..544673fc7a3 100644
--- a/_maps/RandomZLevels/research.dmm
+++ b/_maps/RandomZLevels/research.dmm
@@ -3016,7 +3016,7 @@
/turf/open/floor/iron/white,
/area/awaymission/research/interior/cryo)
"gR" = (
-/obj/item/melee/classic_baton/telescopic,
+/obj/item/melee/baton/telescopic,
/obj/effect/turf_decal/tile/purple{
dir = 1
},
diff --git a/_maps/RandomZLevels/snowdin.dmm b/_maps/RandomZLevels/snowdin.dmm
index efa24a9ba6f..d9740c16474 100644
--- a/_maps/RandomZLevels/snowdin.dmm
+++ b/_maps/RandomZLevels/snowdin.dmm
@@ -11334,7 +11334,7 @@
/obj/item/clothing/head/helmet{
pixel_y = 8
},
-/obj/item/melee/baton{
+/obj/item/melee/baton/security{
pixel_x = 4
},
/turf/open/floor/plating/asteroid/snow,
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index d780c0cc682..3e75df4262d 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -24056,7 +24056,7 @@
"gkw" = (
/obj/structure/safe,
/obj/item/storage/secure/briefcase{
- contents = newlist(/obj/item/clothing/suit/armor/vest,/obj/item/gun/ballistic/automatic/pistol,/obj/item/suppressor,/obj/item/melee/classic_baton/telescopic,/obj/item/clothing/mask/balaclava,/obj/item/bodybag,/obj/item/soap/nanotrasen)
+ contents = newlist(/obj/item/clothing/suit/armor/vest,/obj/item/gun/ballistic/automatic/pistol,/obj/item/suppressor,/obj/item/melee/baton/telescopic,/obj/item/clothing/mask/balaclava,/obj/item/bodybag,/obj/item/soap/nanotrasen)
},
/obj/item/storage/backpack/duffelbag/syndie/hitman,
/obj/item/card/id/advanced/silver/reaper,
diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm
index 2f7f7edc161..35ffe84198f 100644
--- a/_maps/map_files/generic/CentCom.dmm
+++ b/_maps/map_files/generic/CentCom.dmm
@@ -111,7 +111,7 @@
/obj/item/clothing/shoes/sneakers/brown,
/obj/item/clothing/suit/armor/tdome/red,
/obj/item/clothing/head/helmet/thunderdome,
-/obj/item/melee/baton/loaded,
+/obj/item/melee/baton/security/loaded,
/obj/item/melee/energy/sword/saber/red,
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -182,7 +182,7 @@
/obj/item/clothing/shoes/sneakers/brown,
/obj/item/clothing/suit/armor/tdome/green,
/obj/item/clothing/head/helmet/thunderdome,
-/obj/item/melee/baton/loaded,
+/obj/item/melee/baton/security/loaded,
/obj/item/melee/energy/sword/saber/green,
/obj/effect/turf_decal/stripes/line{
dir = 8
@@ -12151,7 +12151,7 @@
/obj/item/clothing/shoes/sneakers/brown,
/obj/item/clothing/suit/armor/tdome/red,
/obj/item/clothing/head/helmet/thunderdome,
-/obj/item/melee/baton/loaded,
+/obj/item/melee/baton/security/loaded,
/obj/item/melee/energy/sword/saber/red,
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -12275,7 +12275,7 @@
/obj/item/clothing/shoes/sneakers/brown,
/obj/item/clothing/suit/armor/tdome/green,
/obj/item/clothing/head/helmet/thunderdome,
-/obj/item/melee/baton/loaded,
+/obj/item/melee/baton/security/loaded,
/obj/item/melee/energy/sword/saber/green,
/obj/effect/turf_decal/stripes/line{
dir = 8
diff --git a/_maps/shuttles/emergency_pubby.dmm b/_maps/shuttles/emergency_pubby.dmm
index 7f3fa041b22..5a503d0e380 100644
--- a/_maps/shuttles/emergency_pubby.dmm
+++ b/_maps/shuttles/emergency_pubby.dmm
@@ -608,7 +608,7 @@
"bz" = (
/obj/structure/table/reinforced,
/obj/item/restraints/handcuffs,
-/obj/item/melee/baton,
+/obj/item/melee/baton/security,
/turf/open/floor/mineral/plastitanium/red/brig,
/area/shuttle/escape/brig)
"bA" = (
diff --git a/_maps/shuttles/ruin_pirate_cutter.dmm b/_maps/shuttles/ruin_pirate_cutter.dmm
index b9bd78ba0de..fadc30ff55b 100644
--- a/_maps/shuttles/ruin_pirate_cutter.dmm
+++ b/_maps/shuttles/ruin_pirate_cutter.dmm
@@ -991,7 +991,7 @@
"Xq" = (
/obj/structure/table/reinforced,
/obj/machinery/recharger,
-/obj/item/melee/classic_baton,
+/obj/item/melee/baton,
/obj/effect/turf_decal/tile/red,
/turf/open/floor/iron/dark,
/area/shuttle/caravan/pirate)
diff --git a/_maps/shuttles/whiteship_box.dmm b/_maps/shuttles/whiteship_box.dmm
index 4728d36e876..218f32bf7b4 100644
--- a/_maps/shuttles/whiteship_box.dmm
+++ b/_maps/shuttles/whiteship_box.dmm
@@ -1898,7 +1898,7 @@
/obj/structure/rack,
/obj/item/storage/box/zipties,
/obj/item/assembly/flash/handheld,
-/obj/item/melee/classic_baton/telescopic,
+/obj/item/melee/baton/telescopic,
/obj/machinery/light/small/built/directional/west,
/obj/machinery/airalarm/all_access{
dir = 4;
diff --git a/_maps/shuttles/whiteship_tram.dmm b/_maps/shuttles/whiteship_tram.dmm
index 127b179181a..0db5c869dfe 100644
--- a/_maps/shuttles/whiteship_tram.dmm
+++ b/_maps/shuttles/whiteship_tram.dmm
@@ -1295,7 +1295,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/item/storage/box/zipties,
/obj/item/assembly/flash/handheld,
-/obj/item/melee/classic_baton/telescopic,
+/obj/item/melee/baton/telescopic,
/turf/open/floor/mineral/titanium/tiled/blue,
/area/shuttle/abandoned/bridge)
"ds" = (
diff --git a/_maps/templates/holodeck_animeschool.dmm b/_maps/templates/holodeck_animeschool.dmm
index 117dab6e78e..6b5afca430c 100644
--- a/_maps/templates/holodeck_animeschool.dmm
+++ b/_maps/templates/holodeck_animeschool.dmm
@@ -63,7 +63,7 @@
"Y" = (
/obj/structure/table/wood,
/obj/item/folder,
-/obj/item/melee/classic_baton/telescopic,
+/obj/item/melee/baton/telescopic,
/turf/open/floor/holofloor,
/area/template_noop)
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 4e7480888b7..3d378b53d2a 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -309,3 +309,11 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
/// IF an object is weak against armor, this is the value that any present armor is multiplied by
#define ARMOR_WEAKENED_MULTIPLIER 2
+
+/// Return values used in item/melee/baton/baton_attack.
+/// Does a normal item attack.
+#define BATON_DO_NORMAL_ATTACK 1
+/// The attack has been stopped. Either because the user was clumsy or the attack was blocked.
+#define BATON_ATTACK_DONE 2
+/// The baton attack is still going. baton_effect() is called.
+#define BATON_ATTACKING 3
diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm
index e9dfa9ed70f..12627a95a9a 100644
--- a/code/__DEFINES/inventory.dm
+++ b/code/__DEFINES/inventory.dm
@@ -157,7 +157,6 @@ GLOBAL_LIST_INIT(advanced_hardsuit_allowed, typecacheof(list(
/obj/item/flashlight,
/obj/item/gun,
/obj/item/melee/baton,
- /obj/item/melee/classic_baton,
/obj/item/reagent_containers/spray/pepper,
/obj/item/restraints/handcuffs,
/obj/item/tank/internals,
@@ -170,7 +169,6 @@ GLOBAL_LIST_INIT(security_hardsuit_allowed, typecacheof(list(
/obj/item/gun/ballistic,
/obj/item/gun/energy,
/obj/item/melee/baton,
- /obj/item/melee/classic_baton,
/obj/item/reagent_containers/spray/pepper,
/obj/item/restraints/handcuffs,
/obj/item/tank/internals,
@@ -185,7 +183,6 @@ GLOBAL_LIST_INIT(detective_vest_allowed, typecacheof(list(
/obj/item/gun/energy,
/obj/item/lighter,
/obj/item/melee/baton,
- /obj/item/melee/classic_baton,
/obj/item/reagent_containers/spray/pepper,
/obj/item/restraints/handcuffs,
/obj/item/storage/fancy/cigarettes,
@@ -204,7 +201,6 @@ GLOBAL_LIST_INIT(security_vest_allowed, typecacheof(list(
/obj/item/gun/energy,
/obj/item/kitchen/knife/combat,
/obj/item/melee/baton,
- /obj/item/melee/classic_baton,
/obj/item/reagent_containers/spray/pepper,
/obj/item/restraints/handcuffs,
/obj/item/tank/internals/emergency_oxygen,
@@ -219,7 +215,6 @@ GLOBAL_LIST_INIT(security_wintercoat_allowed, typecacheof(list(
/obj/item/gun/ballistic,
/obj/item/gun/energy,
/obj/item/melee/baton,
- /obj/item/melee/classic_baton,
/obj/item/reagent_containers/spray/pepper,
/obj/item/restraints/handcuffs,
/obj/item/storage/belt/holster/detective,
diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm
index 45f22771f41..d86a9b79545 100644
--- a/code/_globalvars/lists/maintenance_loot.dm
+++ b/code/_globalvars/lists/maintenance_loot.dm
@@ -169,7 +169,7 @@ GLOBAL_LIST_INIT(uncommon_loot, list(//uncommon: useful items
/obj/item/restraints/handcuffs/cable = 1,
/obj/item/spear = 1,
/obj/item/grenade/iedcasing/spawned = 1,
- /obj/item/melee/baton/cattleprod = 1,
+ /obj/item/melee/baton/security/cattleprod = 1,
/obj/item/pen/fountain = 1,
) = 8,
@@ -271,7 +271,7 @@ GLOBAL_LIST_INIT(rarity_loot, list(//rare: really good items
/obj/item/kitchen/knife = 1,
/obj/item/restraints/handcuffs = 1,
/obj/item/shield/riot/buckler = 1,
- /obj/item/melee/baton/cattleprod/teleprod = 1,
+ /obj/item/melee/baton/security/cattleprod/teleprod = 1,
/obj/item/throwing_star = 1,
/obj/item/pen/survival = 1,
/obj/item/flashlight/flashdark = 1,
diff --git a/code/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm
index 088c90db696..c0da85d7275 100644
--- a/code/controllers/subsystem/traumas.dm
+++ b/code/controllers/subsystem/traumas.dm
@@ -79,7 +79,7 @@ SUBSYSTEM_DEF(traumas)
/obj/item/trash/cheesie,
)),
- "greytide" = typecacheof(list(/obj/item/clothing/under/color/grey, /obj/item/melee/baton/cattleprod,
+ "greytide" = typecacheof(list(/obj/item/clothing/under/color/grey, /obj/item/melee/baton/security/cattleprod,
/obj/item/spear, /obj/item/clothing/mask/gas,
)),
@@ -124,7 +124,7 @@ SUBSYSTEM_DEF(traumas)
/obj/item/clothing/under/rank/security/head_of_security, /obj/item/clothing/under/rank/rnd/research_director,
/obj/item/clothing/under/rank/medical/chief_medical_officer, /obj/item/clothing/under/rank/engineering/chief_engineer,
/obj/item/clothing/under/rank/centcom/officer, /obj/item/clothing/under/rank/centcom/commander,
- /obj/item/melee/classic_baton/telescopic, /obj/item/card/id/advanced/silver, /obj/item/card/id/advanced/gold,
+ /obj/item/melee/baton/telescopic, /obj/item/card/id/advanced/silver, /obj/item/card/id/advanced/gold,
/obj/item/card/id/advanced/centcom, /obj/machinery/door/airlock/command, /obj/item/card/id/advanced/black,
)),
diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm
index 90fdacc0a00..badf9801541 100644
--- a/code/datums/components/crafting/recipes.dm
+++ b/code/datums/components/crafting/recipes.dm
@@ -95,7 +95,7 @@
/datum/crafting_recipe/stunprod
name = "Stunprod"
- result = /obj/item/melee/baton/cattleprod
+ result = /obj/item/melee/baton/security/cattleprod
reqs = list(/obj/item/restraints/handcuffs/cable = 1,
/obj/item/stack/rods = 1,
/obj/item/assembly/igniter = 1)
@@ -105,7 +105,7 @@
/datum/crafting_recipe/teleprod
name = "Teleprod"
- result = /obj/item/melee/baton/cattleprod/teleprod
+ result = /obj/item/melee/baton/security/cattleprod/teleprod
reqs = list(/obj/item/restraints/handcuffs/cable = 1,
/obj/item/stack/rods = 1,
/obj/item/assembly/igniter = 1,
@@ -341,7 +341,7 @@
result = /mob/living/simple_animal/bot/secbot
reqs = list(/obj/item/assembly/signaler = 1,
/obj/item/clothing/head/helmet/sec = 1,
- /obj/item/melee/baton = 1,
+ /obj/item/melee/baton/security/ = 1,
/obj/item/assembly/prox_sensor = 1,
/obj/item/bodypart/r_arm/robot = 1)
tool_behaviors = list(TOOL_WELDER)
@@ -539,7 +539,7 @@
/obj/item/spear = 1,
/obj/item/storage/toolbox= 1)
tool_behaviors = list(TOOL_SCREWDRIVER)
- tool_paths = list(/obj/item/clothing/gloves/color/yellow, /obj/item/clothing/mask/gas, /obj/item/melee/baton/cattleprod)
+ tool_paths = list(/obj/item/clothing/gloves/color/yellow, /obj/item/clothing/mask/gas, /obj/item/melee/baton/security/cattleprod)
time = 300 //contemplate for a bit
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index 800af0d2c39..7c72604a9b3 100755
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -17,7 +17,7 @@
var/static/list/allowed_devices = typecacheof(list(
/obj/item/gun/energy,
- /obj/item/melee/baton,
+ /obj/item/melee/baton/security,
/obj/item/ammo_box/magazine/recharge,
/obj/item/modular_computer))
@@ -167,10 +167,10 @@
if(E.cell)
E.cell.emp_act(severity)
- else if(istype(charging, /obj/item/melee/baton))
- var/obj/item/melee/baton/B = charging
- if(B.cell)
- B.cell.charge = 0
+ else if(istype(charging, /obj/item/melee/baton/security))
+ var/obj/item/melee/baton/security/batong = charging
+ if(batong.cell)
+ batong.cell.charge = 0
/obj/machinery/recharger/update_appearance(updates)
. = ..()
diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm
new file mode 100644
index 00000000000..54b0ca0db81
--- /dev/null
+++ b/code/game/objects/items/melee/baton.dm
@@ -0,0 +1,656 @@
+/obj/item/melee/baton
+ name = "police baton"
+ desc = "A wooden truncheon for beating criminal scum. Left click to stun, right click to harm."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "classic_baton"
+ inhand_icon_state = "classic_baton"
+ worn_icon_state = "classic_baton"
+ lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
+ slot_flags = ITEM_SLOT_BELT
+ force = 12 //9 hit crit
+ w_class = WEIGHT_CLASS_NORMAL
+ wound_bonus = 15
+
+ /// Whether this baton is active or not
+ var/active = TRUE
+ /// Used interally, you don't want to modify
+ var/cooldown_check = 0
+ /// Default wait time until can stun again.
+ var/cooldown = (4 SECONDS)
+ /// The length of the knockdown applied to a struck living, non-cyborg mob.
+ var/knockdown_time = (1.5 SECONDS)
+ /// If affect_cyborg is TRUE, this is how long we stun cyborgs for on a hit.
+ var/stun_time_cyborg = (5 SECONDS)
+ /// The length of the knockdown applied to the user on clumsy_check()
+ var/clumsy_knockdown_time = 18 SECONDS
+ /// How much stamina damage we deal on a successful hit against a living, non-cyborg mob.
+ var/stamina_damage = 55
+ /// Can we stun cyborgs?
+ var/affect_cyborg = FALSE
+ /// The path of the default sound to play when we stun something.
+ var/on_stun_sound = 'sound/effects/woodhit.ogg'
+ /// The volume of the above.
+ var/on_stun_volume = 75
+ /// Do we animate the "hit" when stunning something?
+ var/stun_animation = TRUE
+ /// Whether the stun attack is logged. Only relevant for abductor batons, which have different modes.
+ var/log_stun_attack = TRUE
+
+/obj/item/melee/baton/Initialize()
+ . = ..()
+ // Adding an extra break for the sake of presentation
+ if(stamina_damage != 0)
+ offensive_notes = "\nVarious interviewed security forces report being able to beat criminals into exhaustion with only [span_warning("[CEILING(100 / stamina_damage, 1)] hit\s!")]"
+
+/**
+ * Ok, think of baton attacks like a melee attack chain:
+ *
+ * [/baton_attack()] comes first. It checks if the user is clumsy, if the target parried the attack and handles some messages and sounds.
+ * * Depending on its return value, it'll either do a normal attack, continue to the next step or stop the attack.
+ *
+ * [/finalize_baton_attack()] is then called. It handles logging stuff, sound effects and calls baton_effect().
+ * * The proc is also called in other situations such as stunbatons right clicking or throw impact. Basically when baton_attack()
+ * * checks are either redundant or unnecessary.
+ *
+ * [/baton_effect()] is third in the line. It knockdowns targets, along other effects called in additional_effects_cyborg() and
+ * * additional_effects_non_cyborg().
+ *
+ * Last but not least [/set_batoned()], which gives the target the IWASBATONED trait with REF(user) as source and then removes it
+ * * after a cooldown has passed. Basically, it stops users from cheesing the cooldowns by dual wielding batons.
+ *
+ * TL;DR: [/baton_attack()] -> [/finalize_baton_attack()] -> [/baton_effect()] -> [/set_batoned()]
+ */
+/obj/item/melee/baton/attack(mob/living/target, mob/living/user, params)
+ add_fingerprint(user)
+ var/list/modifiers = params2list(params)
+ switch(baton_attack(target, user, modifiers))
+ if(BATON_DO_NORMAL_ATTACK)
+ return ..()
+ if(BATON_ATTACKING)
+ finalize_baton_attack(target, user, modifiers)
+
+/obj/item/melee/baton/proc/baton_attack(mob/living/target, mob/living/user, modifiers)
+ . = BATON_ATTACKING
+
+ if(clumsy_check(user, target))
+ return BATON_ATTACK_DONE
+
+ if(!active || LAZYACCESS(modifiers, RIGHT_CLICK))
+ return BATON_DO_NORMAL_ATTACK
+
+ if(cooldown_check > world.time)
+ var/wait_desc = get_wait_description()
+ if (wait_desc)
+ to_chat(user, wait_desc)
+ return BATON_ATTACK_DONE
+
+ if(check_parried(target, user))
+ return BATON_ATTACK_DONE
+
+ if(HAS_TRAIT_FROM(target, TRAIT_IWASBATONED, REF(user))) //no doublebaton abuse anon!
+ to_chat(user, span_danger("You fumble and miss [target]!"))
+ return BATON_ATTACK_DONE
+
+ if(stun_animation)
+ user.do_attack_animation(target)
+
+ var/list/desc
+
+ if(iscyborg(target))
+ if(affect_cyborg)
+ desc = get_cyborg_stun_description(target, user)
+ else
+ desc = get_unga_dunga_cyborg_stun_description(target, user)
+ playsound(get_turf(src), 'sound/effects/bang.ogg', 10, TRUE) //bonk
+ . = BATON_ATTACK_DONE
+ else
+ desc = get_stun_description(target, user)
+
+ if(desc)
+ target.visible_message(desc["visible"], desc["local"])
+
+/obj/item/melee/baton/proc/check_parried(mob/living/carbon/human/human_target, mob/living/user)
+ if(!ishuman(human_target))
+ return
+ if (human_target.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
+ playsound(human_target, 'sound/weapons/genhit.ogg', 50, TRUE)
+ return TRUE
+ if(check_martial_counter(human_target, user))
+ return TRUE
+
+/obj/item/melee/baton/proc/finalize_baton_attack(mob/living/target, mob/living/user, modifiers, in_attack_chain = TRUE)
+ if(!in_attack_chain && HAS_TRAIT_FROM(target, TRAIT_IWASBATONED, REF(user)))
+ return BATON_ATTACK_DONE
+
+ cooldown_check = world.time + cooldown
+ if(on_stun_sound)
+ playsound(get_turf(src), on_stun_sound, on_stun_volume, TRUE, -1)
+ if(user)
+ target.lastattacker = user.real_name
+ target.lastattackerckey = user.ckey
+ target.LAssailant = WEAKREF(user)
+ if(log_stun_attack)
+ log_combat(user, target, "stun attacked", src)
+ if(baton_effect(target, user, modifiers) && user)
+ set_batoned(target, user, cooldown)
+
+/obj/item/melee/baton/proc/baton_effect(mob/living/target, mob/living/user, modifiers, stun_override)
+ var/trait_check = HAS_TRAIT(target, TRAIT_STUNRESISTANCE)
+ if(iscyborg(target))
+ if(!affect_cyborg)
+ return FALSE
+ target.flash_act(affect_silicon = TRUE)
+ target.Paralyze((isnull(stun_override) ? stun_time_cyborg : stun_override) * (trait_check ? 0.1 : 1))
+ additional_effects_cyborg(target, user)
+ else
+ target.apply_damage(stamina_damage, STAMINA, BODY_ZONE_CHEST)
+ target.Knockdown((isnull(stun_override) ? knockdown_time : stun_override) * (trait_check ? 0.1 : 1))
+ additional_effects_non_cyborg(target, user)
+ return TRUE
+
+/// Description for trying to stun when still on cooldown.
+/obj/item/melee/baton/proc/get_wait_description()
+ return
+
+/// Default message for stunning a living, non-cyborg mob.
+/obj/item/melee/baton/proc/get_stun_description(mob/living/target, mob/living/user)
+ . = list()
+
+ .["visible"] = "[user] knocks [target] down with [src]!"
+ .["local"] = "[user] knocks you down with [src]!"
+
+ return .
+
+/// Default message for stunning a cyborg.
+/obj/item/melee/baton/proc/get_cyborg_stun_description(mob/living/target, mob/living/user)
+ . = list()
+
+ .["visible"] = span_danger("[user] pulses [target]'s sensors with the baton!")
+ .["local"] = span_danger("You pulse [target]'s sensors with the baton!")
+
+ return .
+
+/// Default message for trying to stun a cyborg with a baton that can't stun cyborgs.
+/obj/item/melee/baton/proc/get_unga_dunga_cyborg_stun_description(mob/living/target, mob/living/user)
+ . = list()
+
+ .["visible"] = "[user] tries to knock down [target] with [src], and predictably fails!" //look at this duuuuuude
+ .["local"] = "[target] tries to... knock you down with [src]?" //look at the top of his head!
+
+ return .
+
+/// Contains any special effects that we apply to living, non-cyborg mobs we stun. Does not include applying a knockdown, dealing stamina damage, etc.
+/obj/item/melee/baton/proc/additional_effects_non_cyborg(mob/living/target, mob/living/user)
+ return
+
+/// Contains any special effects that we apply to cyborgs we stun. Does not include flashing the cyborg's screen, hardstunning them, etc.
+/obj/item/melee/baton/proc/additional_effects_cyborg(mob/living/target, mob/living/user)
+ return
+
+/obj/item/melee/baton/proc/set_batoned(mob/living/target, mob/living/user, cooldown)
+ if(!cooldown)
+ return
+ var/user_ref = REF(user) // avoids harddels.
+ ADD_TRAIT(target, TRAIT_IWASBATONED, user_ref)
+ addtimer(TRAIT_CALLBACK_REMOVE(target, TRAIT_IWASBATONED, user_ref), cooldown)
+
+/obj/item/melee/baton/proc/clumsy_check(mob/living/user, mob/living/intented_target)
+ if(!active || !HAS_TRAIT(user, TRAIT_CLUMSY) || prob(50))
+ return FALSE
+ user.visible_message(span_danger("[user] accidentally hits [user.p_them()]self over the head with [src]! What a doofus!"), span_userdanger("You accidentally hit yourself over the head with [src]!"))
+
+ if(iscyborg(user))
+ if(affect_cyborg)
+ user.flash_act(affect_silicon = TRUE)
+ user.Paralyze(clumsy_knockdown_time)
+ additional_effects_cyborg(user, user) // user is the target here
+ if(on_stun_sound)
+ playsound(get_turf(src), on_stun_sound, on_stun_volume, TRUE, -1)
+ else
+ playsound(get_turf(src), 'sound/effects/bang.ogg', 10, TRUE)
+ else
+ user.Knockdown(clumsy_knockdown_time)
+ user.apply_damage(stamina_damage, STAMINA, BODY_ZONE_HEAD)
+ additional_effects_non_cyborg(user, user) // user is the target here
+ if(on_stun_sound)
+ playsound(get_turf(src), on_stun_sound, on_stun_volume, TRUE, -1)
+
+ user.apply_damage(2*force, BRUTE, BODY_ZONE_HEAD)
+
+ log_combat(user, user, "accidentally stun attacked [user.p_them()]self due to their clumsiness", src)
+ if(stun_animation)
+ user.do_attack_animation(user)
+ return
+
+/obj/item/conversion_kit
+ name = "conversion kit"
+ desc = "A strange box containing wood working tools and an instruction paper to turn stun batons into something else."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "uk"
+ custom_price = PAYCHECK_HARD * 4.5
+
+/obj/item/melee/baton/telescopic
+ name = "telescopic baton"
+ desc = "A compact yet robust personal defense weapon. Can be concealed when folded."
+ icon_state = "telebaton"
+ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
+ inhand_icon_state = null
+ attack_verb_continuous = list("hits", "pokes")
+ attack_verb_simple = list("hit", "poke")
+ worn_icon_state = "tele_baton"
+ slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+ item_flags = NONE
+ force = 0
+ bare_wound_bonus = 5
+ clumsy_knockdown_time = 15 SECONDS
+ active = FALSE
+
+ /// The sound effecte played when our baton is extended.
+ var/on_sound = 'sound/weapons/batonextend.ogg'
+ /// The inhand iconstate used when our baton is extended.
+ var/on_inhand_icon_state = "nullrod"
+ /// The force on extension.
+ var/active_force = 10
+
+/obj/item/melee/baton/telescopic/Initialize()
+ . = ..()
+ AddComponent(/datum/component/transforming, \
+ force_on = active_force, \
+ hitsound_on = hitsound, \
+ w_class_on = WEIGHT_CLASS_NORMAL, \
+ clumsy_check = FALSE, \
+ attack_verb_continuous_on = list("smacks", "strikes", "cracks", "beats"), \
+ attack_verb_simple_on = list("smack", "strike", "crack", "beat"))
+ RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, .proc/on_transform)
+
+/obj/item/melee/baton/telescopic/suicide_act(mob/user)
+ var/mob/living/carbon/human/human_user = user
+ var/obj/item/organ/brain/our_brain = human_user.getorgan(/obj/item/organ/brain)
+
+ user.visible_message(span_suicide("[user] stuffs [src] up [user.p_their()] nose and presses the 'extend' button! It looks like [user.p_theyre()] trying to clear [user.p_their()] mind."))
+ if(active)
+ playsound(src, on_sound, 50, TRUE)
+ add_fingerprint(user)
+ else
+ attack_self(user)
+
+ sleep(3)
+ if (!QDELETED(human_user))
+ if(!QDELETED(our_brain))
+ human_user.internal_organs -= our_brain
+ qdel(our_brain)
+ new /obj/effect/gibspawner/generic(human_user.drop_location(), human_user)
+ return (BRUTELOSS)
+
+/*
+ * Signal proc for [COMSIG_TRANSFORMING_ON_TRANSFORM].
+ *
+ * Gives feedback to the user and makes it show up inhand.
+ */
+/obj/item/melee/baton/telescopic/proc/on_transform(obj/item/source, mob/user, active)
+ SIGNAL_HANDLER
+
+ src.active = active
+ inhand_icon_state = active ? on_inhand_icon_state : null // When inactive, there is no inhand icon_state.
+ balloon_alert(user, active ? "extended" : "collapsed")
+ playsound(user ? user : src, on_sound, 50, TRUE)
+ return COMPONENT_NO_DEFAULT_MESSAGE
+
+/obj/item/melee/baton/telescopic/contractor_baton
+ name = "contractor baton"
+ desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "contractor_baton"
+ worn_icon_state = "contractor_baton"
+ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
+ slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+ item_flags = NONE
+ force = 5
+ cooldown = 2.5 SECONDS
+ stamina_damage = 85
+ clumsy_knockdown_time = 24 SECONDS
+ affect_cyborg = TRUE
+ on_stun_sound = 'sound/effects/contractorbatonhit.ogg'
+
+ on_inhand_icon_state = "contractor_baton_on"
+ on_sound = 'sound/weapons/contractorbatonextend.ogg'
+ active_force = 16
+
+/obj/item/melee/baton/telescopic/contractor_baton/get_wait_description()
+ return span_danger("The baton is still charging!")
+
+/obj/item/melee/baton/telescopic/contractor_baton/additional_effects_non_cyborg(mob/living/target, mob/living/user)
+ target.Jitter(20)
+ target.stuttering += 20
+
+/obj/item/melee/baton/security
+ name = "stun baton"
+ desc = "A stun baton for incapacitating people with. Left click to stun, right click to harm."
+
+ icon_state = "stunbaton"
+ inhand_icon_state = "baton"
+ worn_icon_state = "baton"
+
+ force = 10
+ wound_bonus = 0
+ attack_verb_continuous = list("beats")
+ attack_verb_simple = list("beat")
+
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 80, ACID = 80)
+
+ throwforce = 7
+ stamina_damage = 60
+ knockdown_time = 5 SECONDS
+ clumsy_knockdown_time = 15 SECONDS
+ cooldown = 2.5 SECONDS
+ on_stun_sound = 'sound/weapons/egloves.ogg'
+ on_stun_volume = 50
+ active = FALSE
+
+ var/throw_stun_chance = 35
+ var/obj/item/stock_parts/cell/cell
+ var/preload_cell_type //if not empty the baton starts with this type of cell
+ var/cell_hit_cost = 1000
+ var/can_remove_cell = TRUE
+ var/convertible = TRUE //if it can be converted with a conversion kit
+
+/obj/item/melee/baton/security/Initialize()
+ . = ..()
+ if(preload_cell_type)
+ if(!ispath(preload_cell_type,/obj/item/stock_parts/cell))
+ log_mapping("[src] at [AREACOORD(src)] had an invalid preload_cell_type: [preload_cell_type].")
+ else
+ cell = new preload_cell_type(src)
+ RegisterSignal(src, COMSIG_PARENT_ATTACKBY, .proc/convert)
+ update_appearance()
+
+/obj/item/melee/baton/security/get_cell()
+ return cell
+
+/obj/item/melee/baton/security/suicide_act(mob/user)
+ if(cell?.charge && active)
+ user.visible_message(span_suicide("[user] is putting the live [name] in [user.p_their()] mouth! It looks like [user.p_theyre()] trying to commit suicide!"))
+ . = (FIRELOSS)
+ attack(user,user)
+ else
+ user.visible_message(span_suicide("[user] is shoving the [name] down their throat! It looks like [user.p_theyre()] trying to commit suicide!"))
+ . = (OXYLOSS)
+
+/obj/item/melee/baton/security/Destroy()
+ if(cell)
+ QDEL_NULL(cell)
+ UnregisterSignal(src, COMSIG_PARENT_ATTACKBY)
+ return ..()
+
+/obj/item/melee/baton/security/proc/convert(datum/source, obj/item/I, mob/user)
+ SIGNAL_HANDLER
+
+ if(istype(I,/obj/item/conversion_kit) && convertible)
+ var/turf/source_turf = get_turf(src)
+ var/obj/item/melee/baton/baton = new (source_turf)
+ baton.alpha = 20
+ playsound(source_turf, 'sound/items/drill_use.ogg', 80, TRUE, -1)
+ animate(src, alpha = 0, time = 10)
+ animate(baton, alpha = 255, time = 10)
+ qdel(I)
+ qdel(src)
+
+/obj/item/melee/baton/security/Exited(atom/movable/mov_content)
+ . = ..()
+ if(mov_content == cell)
+ cell.update_appearance()
+ cell = null
+ active = FALSE
+ update_appearance()
+
+/obj/item/melee/baton/security/update_icon_state()
+ if(active)
+ icon_state = "[initial(icon_state)]_active"
+ return ..()
+ if(!cell)
+ icon_state = "[initial(icon_state)]_nocell"
+ return ..()
+ icon_state = "[initial(icon_state)]"
+ return ..()
+
+/obj/item/melee/baton/security/examine(mob/user)
+ . = ..()
+ if(cell)
+ . += span_notice("\The [src] is [round(cell.percent())]% charged.")
+ else
+ . += span_warning("\The [src] does not have a power source installed.")
+
+/obj/item/melee/baton/security/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/stock_parts/cell))
+ var/obj/item/stock_parts/cell/C = W
+ if(cell)
+ to_chat(user, span_warning("[src] already has a cell!"))
+ else
+ if(C.maxcharge < cell_hit_cost)
+ to_chat(user, span_notice("[src] requires a higher capacity cell."))
+ return
+ if(!user.transferItemToLoc(W, src))
+ return
+ cell = W
+ to_chat(user, span_notice("You install a cell in [src]."))
+ update_appearance()
+
+ else if(W.tool_behaviour == TOOL_SCREWDRIVER)
+ tryremovecell(user)
+ else
+ return ..()
+
+/obj/item/melee/baton/security/proc/tryremovecell(mob/user)
+ if(cell && can_remove_cell)
+ cell.forceMove(drop_location())
+ to_chat(user, span_notice("You remove the cell from [src]."))
+
+/obj/item/melee/baton/security/attack_self(mob/user)
+ if(cell?.charge >= cell_hit_cost)
+ active = !active
+ balloon_alert(user, "turned [active ? "on" : "off"]")
+ playsound(src, "sparks", 75, TRUE, -1)
+ else
+ active = FALSE
+ if(!cell)
+ balloon_alert(user, "no power source!")
+ else
+ balloon_alert(user, "out of charge!")
+ update_appearance()
+ add_fingerprint(user)
+
+/obj/item/melee/baton/security/proc/deductcharge(deducted_charge)
+ if(!cell)
+ return
+ //Note this value returned is significant, as it will determine
+ //if a stun is applied or not
+ . = cell.use(deducted_charge)
+ if(active && cell.charge < cell_hit_cost)
+ //we're below minimum, turn off
+ active = FALSE
+ update_appearance()
+ playsound(src, "sparks", 75, TRUE, -1)
+
+/obj/item/melee/baton/security/clumsy_check(mob/living/carbon/human/user)
+ . = ..()
+ if(.)
+ SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK)
+ deductcharge(cell_hit_cost)
+
+/// Handles prodding targets with turned off stunbatons and right clicking stun'n'bash
+/obj/item/melee/baton/security/baton_attack(mob/living/target, mob/living/user, modifiers)
+ . = ..()
+ if(. != BATON_DO_NORMAL_ATTACK)
+ return
+ if(LAZYACCESS(modifiers, RIGHT_CLICK))
+ if(active && cooldown_check <= world.time && check_parried(target, user))
+ finalize_baton_attack(target, user, modifiers)
+ else if(!user.combat_mode)
+ target.visible_message(span_warning("[user] prods [target] with [src]. Luckily it was off."), \
+ span_warning("[user] prods you with [src]. Luckily it was off."))
+ return BATON_ATTACK_DONE
+
+/obj/item/melee/baton/security/baton_effect(mob/living/target, mob/living/user, modifiers, stun_override)
+ if(iscyborg(loc))
+ var/mob/living/silicon/robot/R = loc
+ if(!R || !R.cell || !R.cell.use(cell_hit_cost))
+ return FALSE
+ else if(!deductcharge(cell_hit_cost))
+ return FALSE
+ stun_override = 0 //Avoids knocking people down prematurely.
+ return ..()
+
+/*
+ * After a target is hit, we apply some status effects.
+ * After a period of time, we then check to see what stun duration we give.
+ */
+/obj/item/melee/baton/security/additional_effects_non_cyborg(mob/living/target, mob/living/user)
+ target.Jitter(20)
+ target.set_confusion(max(10, target.get_confusion()))
+ target.stuttering = max(8, target.stuttering)
+
+ SEND_SIGNAL(target, COMSIG_LIVING_MINOR_SHOCK)
+ addtimer(CALLBACK(src, .proc/apply_stun_effect_end, target), 2 SECONDS)
+
+/// After the initial stun period, we check to see if the target needs to have the stun applied.
+/obj/item/melee/baton/security/proc/apply_stun_effect_end(mob/living/target)
+ var/trait_check = HAS_TRAIT(target, TRAIT_STUNRESISTANCE) //var since we check it in out to_chat as well as determine stun duration
+ if(!target.IsKnockdown())
+ to_chat(target, span_warning("Your muscles seize, making you collapse [trait_check ? ", but your body quickly recovers..." : "!"]"))
+
+ target.Knockdown(knockdown_time * (trait_check ? 0.1 : 1))
+
+/obj/item/melee/baton/security/get_wait_description()
+ return span_danger("The baton is still charging!")
+
+/obj/item/melee/baton/security/get_stun_description(mob/living/target, mob/living/user)
+ . = list()
+
+ .["visible"] = span_danger("[user] stuns [target] with [src]!")
+ .["local"] = span_userdanger("[user] stuns you with [src]!")
+
+/obj/item/melee/baton/security/get_unga_dunga_cyborg_stun_description(mob/living/target, mob/living/user)
+ . = list()
+
+ .["visible"] = span_danger("[user] tries to stun [target] with [src], and predictably fails!")
+ .["local"] = span_userdanger("[target] tries to... stun you with [src]?")
+
+/obj/item/melee/baton/security/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ . = ..()
+ if(active && prob(throw_stun_chance) && isliving(hit_atom))
+ finalize_baton_attack(hit_atom, thrownby?.resolve(), in_attack_chain = FALSE)
+
+/obj/item/melee/baton/security/emp_act(severity)
+ . = ..()
+ if (!(. & EMP_PROTECT_SELF))
+ deductcharge(1000 / severity)
+
+/obj/item/melee/baton/security/loaded //this one starts with a cell pre-installed.
+ preload_cell_type = /obj/item/stock_parts/cell/high
+
+//Makeshift stun baton. Replacement for stun gloves.
+/obj/item/melee/baton/security/cattleprod
+ name = "stunprod"
+ desc = "An improvised stun baton. Left click to stun, right click to harm."
+ icon_state = "stunprod"
+ inhand_icon_state = "prod"
+ worn_icon_state = null
+ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
+ w_class = WEIGHT_CLASS_BULKY
+ force = 3
+ throwforce = 5
+ cell_hit_cost = 2000
+ throw_stun_chance = 10
+ slot_flags = ITEM_SLOT_BACK
+ convertible = FALSE
+ var/obj/item/assembly/igniter/sparkler
+
+/obj/item/melee/baton/security/cattleprod/Initialize()
+ . = ..()
+ sparkler = new (src)
+
+/obj/item/melee/baton/security/cattleprod/attackby(obj/item/item, mob/user, params)//handles sticking a crystal onto a stunprod to make a teleprod
+ if(istype(item, /obj/item/stack/ore/bluespace_crystal))
+ if(!cell)
+ var/obj/item/stack/ore/bluespace_crystal/crystal = item
+ var/obj/item/melee/baton/security/cattleprod/teleprod/prod = new
+ remove_item_from_storage(user)
+ qdel(src)
+ crystal.use(1)
+ user.put_in_hands(prod)
+ to_chat(user, span_notice("You place the bluespace crystal firmly into the igniter."))
+ else
+ user.visible_message(span_warning("You can't put the crystal onto the stunprod while it has a power cell installed!"))
+ else
+ return ..()
+
+/obj/item/melee/baton/security/cattleprod/baton_effect()
+ if(!sparkler.activate())
+ return BATON_ATTACK_DONE
+ return ..()
+
+/obj/item/melee/baton/security/cattleprod/Destroy()
+ if(sparkler)
+ QDEL_NULL(sparkler)
+ return ..()
+
+/obj/item/melee/baton/security/boomerang
+ name = "\improper OZtek Boomerang"
+ desc = "A device invented in 2486 for the great Space Emu War by the confederacy of Australicus, these high-tech boomerangs also work exceptionally well at stunning crewmembers. Just be careful to catch it when thrown!"
+ throw_speed = 1
+ icon_state = "boomerang"
+ inhand_icon_state = "boomerang"
+ force = 5
+ throwforce = 5
+ throw_range = 5
+ cell_hit_cost = 2000
+ throw_stun_chance = 99 //Have you prayed today?
+ convertible = FALSE
+ custom_materials = list(/datum/material/iron = 10000, /datum/material/glass = 4000, /datum/material/silver = 10000, /datum/material/gold = 2000)
+
+/obj/item/melee/baton/security/boomerang/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE, quickstart = TRUE)
+ if(active)
+ if(ishuman(thrower))
+ var/mob/living/carbon/human/H = thrower
+ H.throw_mode_off(THROW_MODE_TOGGLE) //so they can catch it on the return.
+ return ..()
+
+/obj/item/melee/baton/security/boomerang/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ if(active)
+ var/caught = hit_atom.hitby(src, FALSE, FALSE, throwingdatum=throwingdatum)
+ var/mob/thrown_by = thrownby?.resolve()
+ if(isliving(hit_atom) && !iscyborg(hit_atom) && !caught && prob(throw_stun_chance))//if they are a living creature and they didn't catch it
+ finalize_baton_attack(hit_atom, thrown_by, in_attack_chain = FALSE)
+ if(thrown_by && !caught)
+ addtimer(CALLBACK(src, /atom/movable.proc/throw_at, thrown_by, throw_range+2, throw_speed, null, TRUE), 1)
+ else
+ return ..()
+
+/obj/item/melee/baton/security/boomerang/loaded //Same as above, comes with a cell.
+ preload_cell_type = /obj/item/stock_parts/cell/high
+
+/obj/item/melee/baton/security/cattleprod/teleprod
+ name = "teleprod"
+ desc = "A prod with a bluespace crystal on the end. The crystal doesn't look too fun to touch."
+ w_class = WEIGHT_CLASS_NORMAL
+ icon_state = "teleprod"
+ inhand_icon_state = "teleprod"
+ slot_flags = null
+
+/obj/item/melee/baton/security/cattleprod/teleprod/clumsy_check(mob/living/carbon/human/user)
+ . = ..()
+ if(!.)
+ return
+ do_teleport(user, get_turf(user), 50, channel = TELEPORT_CHANNEL_BLUESPACE)
+
+/obj/item/melee/baton/security/cattleprod/teleprod/baton_effect(mob/living/target, mob/living/user, modifiers, stun_override)
+ . = ..()
+ if(!. || target.move_resist >= MOVE_FORCE_OVERPOWERING)
+ return
+ do_teleport(target, get_turf(target), 15, channel = TELEPORT_CHANNEL_BLUESPACE)
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 245db54e609..0996797e5a5 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -171,271 +171,6 @@
playsound(get_turf(src), hitsound, 75, TRUE, -1)
return TOXLOSS
-/obj/item/melee/classic_baton
- name = "police baton"
- desc = "A wooden truncheon for beating criminal scum. Left click to stun, right click to harm."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "classic_baton"
- inhand_icon_state = "classic_baton"
- worn_icon_state = "classic_baton"
- lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
- slot_flags = ITEM_SLOT_BELT
- force = 12 //9 hit crit
- w_class = WEIGHT_CLASS_NORMAL
- wound_bonus = 15
-
- /// Whether this baton is active or not
- var/extended = TRUE
- /// Used interally, you don't want to modify
- var/cooldown_check = 0
- /// Default wait time until can stun again.
- var/cooldown = (4 SECONDS)
- /// The length of the knockdown applied to a struck living, non-cyborg mob.
- var/knockdown_time = (1.5 SECONDS)
- /// If affect_cyborg is TRUE, this is how long we stun cyborgs for on a hit.
- var/stun_time_cyborg = (5 SECONDS)
- /// How much stamina damage we deal on a successful hit against a living, non-cyborg mob.
- var/stamina_damage = 55
- /// Can we stun cyborgs?
- var/affect_cyborg = FALSE
- /// The path of the default sound to play when we stun something.
- var/on_stun_sound = 'sound/effects/woodhit.ogg'
- /// Do we animate the "hit" when stunning something?
- var/stun_animation = TRUE
-
-
-/obj/item/melee/classic_baton/Initialize()
- . = ..()
- // Adding an extra break for the sake of presentation
- if(stamina_damage != 0)
- offensive_notes = "\nVarious interviewed security forces report being able to beat criminals into exhaustion with only [span_warning("[round(100 / stamina_damage, 0.1)] hit\s!")]"
-
-/// Description for trying to stun when still on cooldown.
-/obj/item/melee/classic_baton/proc/get_wait_description()
- return
-
-/// Default message for stunning a living, non-cyborg mob.
-/obj/item/melee/classic_baton/proc/get_stun_description(mob/living/target, mob/living/user)
- . = list()
-
- .["visible"] = "[user] knocks [target] down with [src]!"
- .["local"] = "[user] knocks you down with [src]!"
-
- return .
-
-/// Default message for stunning a cyborg.
-/obj/item/melee/classic_baton/proc/get_cyborg_stun_description(mob/living/target, mob/living/user)
- . = list()
-
- .["visible"] = span_danger("[user] pulses [target]'s sensors with the baton!")
- .["local"] = span_danger("You pulse [target]'s sensors with the baton!")
-
- return .
-
-/// Default message for trying to stun a cyborg with a baton that can't stun cyborgs.
-/obj/item/melee/classic_baton/proc/get_unga_dunga_cyborg_stun_description(mob/living/target, mob/living/user)
- . = list()
-
- .["visible"] = "[user] tries to knock down [target] with [src], and predictably fails!" //look at this duuuuuude
- .["local"] = "[target] tries to... knock you down with [src]?" //look at the top of his head!
-
- return .
-
-/// Contains any special effects that we apply to living, non-cyborg mobs we stun. Does not include applying a knockdown, dealing stamina damage, etc.
-/obj/item/melee/classic_baton/proc/additional_effects_non_cyborg(mob/living/target, mob/living/user)
- return
-
-/// Contains any special effects that we apply to cyborgs we stun. Does not include flashing the cyborg's screen, hardstunning them, etc.
-/obj/item/melee/classic_baton/proc/additional_effects_cyborg(mob/living/target, mob/living/user)
- return
-
-/obj/item/melee/classic_baton/attack(mob/living/target, mob/living/user, params)
- if(!extended)
- return ..()
-
- add_fingerprint(user)
- if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
- user.visible_message(span_danger("[user] accidentally hits [user.p_them()]self over the head with [src]! What a doofus!"), span_userdanger("You accidentally hit yourself over the head with [src]!"))
-
- if(iscyborg(user))
- if(affect_cyborg)
- user.flash_act(affect_silicon = TRUE)
- user.Paralyze(stun_time_cyborg * force)
- additional_effects_cyborg(user, user) // user is the target here
- playsound(get_turf(src), on_stun_sound, 100, TRUE, -1)
- else
- playsound(get_turf(src), 'sound/effects/bang.ogg', 10, TRUE)
- else
- user.Paralyze(knockdown_time * force)
- user.apply_damage(stamina_damage, STAMINA, BODY_ZONE_HEAD)
- additional_effects_non_cyborg(user, user) // user is the target here
- playsound(get_turf(src), on_stun_sound, 75, TRUE, -1)
-
- user.apply_damage(2*force, BRUTE, BODY_ZONE_HEAD)
-
- log_combat(user, target, "accidentally stun attacked [user.p_them()]self due to their clumsiness", src)
- if(stun_animation)
- user.do_attack_animation(user)
- return
- if(!isliving(target))
- return
- var/list/modifiers = params2list(params)
-
- if(LAZYACCESS(modifiers, RIGHT_CLICK))
- ..()
- return
- 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)
-
- if(iscyborg(target))
- if(affect_cyborg)
- desc = get_cyborg_stun_description(target, user)
-
- target.flash_act(affect_silicon = TRUE)
- target.Paralyze(stun_time_cyborg)
- additional_effects_cyborg(target, user)
-
- playsound(get_turf(src), on_stun_sound, 75, TRUE, -1)
- else
- desc = get_unga_dunga_cyborg_stun_description(target, user)
-
- playsound(get_turf(src), 'sound/effects/bang.ogg', 10, TRUE) //bonk
- else
- target.Knockdown(knockdown_time)
- target.apply_damage(stamina_damage, STAMINA, BODY_ZONE_CHEST)
- additional_effects_non_cyborg(target, user)
-
- playsound(get_turf(src), on_stun_sound, 75, TRUE, -1)
-
- target.visible_message(desc["visible"], desc["local"])
- log_combat(user, target, "stun attacked", src)
- if(stun_animation)
- user.do_attack_animation(target)
-
- if(!iscarbon(user))
- target.LAssailant = null
- else
- target.LAssailant = WEAKREF(user)
- cooldown_check = world.time + cooldown
- return
-
-
-/obj/item/conversion_kit
- name = "conversion kit"
- desc = "A strange box containing wood working tools and an instruction paper to turn stun batons into something else."
- icon = 'icons/obj/storage.dmi'
- icon_state = "uk"
- custom_price = PAYCHECK_HARD * 4.5
-
-/obj/item/melee/classic_baton/telescopic
- name = "telescopic baton"
- desc = "A compact yet robust personal defense weapon. Can be concealed when folded."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "telebaton"
- lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
- inhand_icon_state = null
- attack_verb_continuous = list("hits", "pokes")
- attack_verb_simple = list("hit", "poke")
- worn_icon_state = "tele_baton"
- slot_flags = ITEM_SLOT_BELT
- w_class = WEIGHT_CLASS_SMALL
- item_flags = NONE
- force = 0
- bare_wound_bonus = 5
- extended = FALSE
-
- /// The sound effecte played when our baton is extended.
- var/on_sound = 'sound/weapons/batonextend.ogg'
- /// The inhand iconstate used when our baton is extended.
- var/on_inhand_icon_state = "nullrod"
- /// The force on extension.
- var/active_force = 10
-
-/obj/item/melee/classic_baton/telescopic/Initialize()
- . = ..()
- AddComponent(/datum/component/transforming, \
- force_on = active_force, \
- hitsound_on = hitsound, \
- w_class_on = WEIGHT_CLASS_NORMAL, \
- clumsy_check = FALSE, \
- attack_verb_continuous_on = list("smacks", "strikes", "cracks", "beats"), \
- attack_verb_simple_on = list("smack", "strike", "crack", "beat"))
- RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, .proc/on_transform)
-
-/obj/item/melee/classic_baton/telescopic/suicide_act(mob/user)
- var/mob/living/carbon/human/human_user = user
- var/obj/item/organ/brain/our_brain = human_user.getorgan(/obj/item/organ/brain)
-
- user.visible_message(span_suicide("[user] stuffs [src] up [user.p_their()] nose and presses the 'extend' button! It looks like [user.p_theyre()] trying to clear [user.p_their()] mind."))
- if(extended)
- playsound(src, on_sound, 50, TRUE)
- add_fingerprint(user)
- else
- attack_self(user)
-
- sleep(3)
- if (!QDELETED(human_user))
- if(!QDELETED(our_brain))
- human_user.internal_organs -= our_brain
- qdel(our_brain)
- new /obj/effect/gibspawner/generic(human_user.drop_location(), human_user)
- return (BRUTELOSS)
-
-/*
- * Signal proc for [COMSIG_TRANSFORMING_ON_TRANSFORM].
- *
- * Gives feedback to the user and makes it show up inhand.
- */
-/obj/item/melee/classic_baton/telescopic/proc/on_transform(obj/item/source, mob/user, active)
- SIGNAL_HANDLER
-
- extended = active
- inhand_icon_state = active ? on_inhand_icon_state : null // When inactive, there is no inhand icon_state.
- balloon_alert(user, "[active ? "extended" : "collapsed"] [src]")
- playsound(user ? user : src, on_sound, 50, TRUE)
- return COMPONENT_NO_DEFAULT_MESSAGE
-
-/obj/item/melee/classic_baton/telescopic/contractor_baton
- name = "contractor baton"
- desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "contractor_baton"
- worn_icon_state = "contractor_baton"
- lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
- slot_flags = ITEM_SLOT_BELT
- w_class = WEIGHT_CLASS_SMALL
- item_flags = NONE
- force = 5
- cooldown = 25
- stamina_damage = 85
- affect_cyborg = TRUE
- on_stun_sound = 'sound/effects/contractorbatonhit.ogg'
-
- on_inhand_icon_state = "contractor_baton_on"
- on_sound = 'sound/weapons/contractorbatonextend.ogg'
- active_force = 16
-
-/obj/item/melee/classic_baton/telescopic/contractor_baton/get_wait_description()
- return span_danger("The baton is still charging!")
-
-/obj/item/melee/classic_baton/telescopic/contractor_baton/additional_effects_non_cyborg(mob/living/target, mob/living/user)
- target.Jitter(20)
- target.stuttering += 20
-
/obj/item/melee/supermatter_sword
name = "supermatter sword"
desc = "In a station full of bad ideas, this might just be the worst."
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 4a86fd7eda2..a305f3a51fd 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -235,7 +235,6 @@
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.set_holdable(list(
/obj/item/melee/baton,
- /obj/item/melee/classic_baton,
/obj/item/grenade,
/obj/item/reagent_containers/spray/pepper,
/obj/item/restraints/handcuffs,
@@ -246,7 +245,7 @@
/obj/item/food/donut,
/obj/item/kitchen/knife/combat,
/obj/item/flashlight/seclite,
- /obj/item/melee/classic_baton/telescopic,
+ /obj/item/melee/baton/telescopic,
/obj/item/radio,
/obj/item/clothing/gloves,
/obj/item/restraints/legcuffs/bola,
@@ -258,7 +257,7 @@
new /obj/item/restraints/handcuffs(src)
new /obj/item/grenade/flashbang(src)
new /obj/item/assembly/flash/handheld(src)
- new /obj/item/melee/baton/loaded(src)
+ new /obj/item/melee/baton/security/loaded(src)
update_appearance()
/obj/item/storage/belt/security/webbing
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index 0732670e635..91ae423fde8 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -322,7 +322,7 @@
/obj/item/storage/box/syndicate/contract_kit/PopulateContents()
new /obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink(src)
new /obj/item/storage/box/syndicate/contractor_loadout(src)
- new /obj/item/melee/classic_baton/telescopic/contractor_baton(src)
+ new /obj/item/melee/baton/telescopic/contractor_baton(src)
// All about 4 TC or less - some nukeops only items, but fit nicely to the theme.
var/list/item_list = list(
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
deleted file mode 100644
index ffa08daefcd..00000000000
--- a/code/game/objects/items/stunbaton.dm
+++ /dev/null
@@ -1,352 +0,0 @@
-/obj/item/melee/baton
- name = "stun baton"
- desc = "A stun baton for incapacitating people with. Left click to stun, right click to harm."
-
- icon_state = "stunbaton"
- inhand_icon_state = "baton"
- worn_icon_state = "baton"
- lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
-
- force = 10
- attack_verb_continuous = list("beats")
- attack_verb_simple = list("beat")
-
- w_class = WEIGHT_CLASS_NORMAL
- slot_flags = ITEM_SLOT_BELT
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 0, RAD = 0, FIRE = 80, ACID = 80)
-
- throwforce = 7
- var/throw_stun_chance = 35
-
- var/obj/item/stock_parts/cell/cell
- var/preload_cell_type //if not empty the baton starts with this type of cell
- var/cell_hit_cost = 1000
- var/can_remove_cell = TRUE
-
- var/turned_on = FALSE
- var/activate_sound = "sparks"
-
- var/attack_cooldown_check = 0 SECONDS
- var/attack_cooldown = 2.5 SECONDS
- var/stun_sound = 'sound/weapons/egloves.ogg'
-
- var/confusion_amt = 10
- var/stamina_loss_amt = 60
- var/apply_stun_delay = 2 SECONDS
- var/stun_time = 5 SECONDS
-
- var/convertible = TRUE //if it can be converted with a conversion kit
-
-/obj/item/melee/baton/get_cell()
- return cell
-
-/obj/item/melee/baton/suicide_act(mob/user)
- if(cell?.charge && turned_on)
- user.visible_message(span_suicide("[user] is putting the live [name] in [user.p_their()] mouth! It looks like [user.p_theyre()] trying to commit suicide!"))
- . = (FIRELOSS)
- attack(user,user)
- else
- user.visible_message(span_suicide("[user] is shoving the [name] down their throat! It looks like [user.p_theyre()] trying to commit suicide!"))
- . = (OXYLOSS)
-
-/obj/item/melee/baton/Initialize()
- . = ..()
- // Adding an extra break for the sake of presentation
- if(stamina_loss_amt != 0)
- offensive_notes = "\nVarious interviewed security forces report being able to beat criminals into exhaustion with only [span_warning("[round(100 / stamina_loss_amt, 0.1)] hit\s!")]"
- if(preload_cell_type)
- if(!ispath(preload_cell_type,/obj/item/stock_parts/cell))
- log_mapping("[src] at [AREACOORD(src)] had an invalid preload_cell_type: [preload_cell_type].")
- else
- cell = new preload_cell_type(src)
- update_appearance()
- RegisterSignal(src, COMSIG_PARENT_ATTACKBY, .proc/convert)
-
-
-/obj/item/melee/baton/Destroy()
- if(cell)
- QDEL_NULL(cell)
- UnregisterSignal(src, COMSIG_PARENT_ATTACKBY)
- return ..()
-
-/obj/item/melee/baton/proc/convert(datum/source, obj/item/I, mob/user)
- SIGNAL_HANDLER
-
- if(istype(I,/obj/item/conversion_kit) && convertible)
- var/turf/T = get_turf(src)
- var/obj/item/melee/classic_baton/B = new /obj/item/melee/classic_baton (T)
- B.alpha = 20
- playsound(T, 'sound/items/drill_use.ogg', 80, TRUE, -1)
- animate(src, alpha = 0, time = 10)
- animate(B, alpha = 255, time = 10)
- qdel(I)
- qdel(src)
-
-/obj/item/melee/baton/handle_atom_del(atom/A)
- if(A == cell)
- cell = null
- turned_on = FALSE
- update_appearance()
- return ..()
-
-/obj/item/melee/baton/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
- ..()
- //Only mob/living types have stun handling
- if(turned_on && prob(throw_stun_chance) && isliving(hit_atom) && !iscyborg(hit_atom))
- baton_effect(hit_atom)
-
-/obj/item/melee/baton/loaded //this one starts with a cell pre-installed.
- preload_cell_type = /obj/item/stock_parts/cell/high
-
-/obj/item/melee/baton/proc/deductcharge(chrgdeductamt)
- if(cell)
- //Note this value returned is significant, as it will determine
- //if a stun is applied or not
- . = cell.use(chrgdeductamt)
- if(turned_on && cell.charge < cell_hit_cost)
- //we're below minimum, turn off
- turned_on = FALSE
- update_appearance()
- playsound(src, activate_sound, 75, TRUE, -1)
-
-
-/obj/item/melee/baton/update_icon_state()
- if(turned_on)
- icon_state = "[initial(icon_state)]_active"
- return ..()
- if(!cell)
- icon_state = "[initial(icon_state)]_nocell"
- return ..()
- icon_state = "[initial(icon_state)]"
- return ..()
-
-/obj/item/melee/baton/examine(mob/user)
- . = ..()
- if(cell)
- . += span_notice("\The [src] is [round(cell.percent())]% charged.")
- else
- . += span_warning("\The [src] does not have a power source installed.")
-
-/obj/item/melee/baton/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/stock_parts/cell))
- var/obj/item/stock_parts/cell/C = W
- if(cell)
- to_chat(user, span_warning("[src] already has a cell!"))
- else
- if(C.maxcharge < cell_hit_cost)
- to_chat(user, span_notice("[src] requires a higher capacity cell."))
- return
- if(!user.transferItemToLoc(W, src))
- return
- cell = W
- to_chat(user, span_notice("You install a cell in [src]."))
- update_appearance()
-
- else if(W.tool_behaviour == TOOL_SCREWDRIVER)
- tryremovecell(user)
- else
- return ..()
-
-/obj/item/melee/baton/proc/tryremovecell(mob/user)
- if(cell && can_remove_cell)
- cell.update_appearance()
- cell.forceMove(get_turf(src))
- cell = null
- to_chat(user, span_notice("You remove the cell from [src]."))
- turned_on = FALSE
- update_appearance()
-
-/obj/item/melee/baton/attack_self(mob/user)
- toggle_on(user)
-
-/obj/item/melee/baton/proc/toggle_on(mob/user)
- if(cell && cell.charge >= cell_hit_cost)
- turned_on = !turned_on
- to_chat(user, span_notice("[src] is now [turned_on ? "on" : "off"]."))
- playsound(src, activate_sound, 75, TRUE, -1)
- else
- turned_on = FALSE
- if(!cell)
- to_chat(user, span_warning("[src] does not have a power source!"))
- else
- to_chat(user, span_warning("[src] is out of charge."))
- update_appearance()
- add_fingerprint(user)
-
-/obj/item/melee/baton/proc/clumsy_check(mob/living/carbon/human/user)
- if(turned_on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
- playsound(src, stun_sound, 75, TRUE, -1)
- user.visible_message(span_danger("[user] accidentally hits [user.p_them()]self with [src]!"), \
- span_userdanger("You accidentally hit yourself with [src]!"))
- user.Knockdown(stun_time*3) //should really be an equivalent to attack(user,user)
- deductcharge(cell_hit_cost)
- return TRUE
- return FALSE
-
-/obj/item/melee/baton/attack(mob/M, mob/living/carbon/human/user, params)
- if(clumsy_check(user))
- return FALSE
-
- if(iscyborg(M))
- ..()
- return
-
-
- if(ishuman(M))
- var/mob/living/carbon/human/L = M
- if(check_martial_counter(L, user))
- return
-
- var/list/modifiers = params2list(params)
- if(LAZYACCESS(modifiers, RIGHT_CLICK))
- if(turned_on)
- if(attack_cooldown_check <= world.time)
- baton_effect(M, user)
- ..()
- return
- else if(turned_on)
- if(attack_cooldown_check <= world.time)
- if(baton_effect(M, user))
- user.do_attack_animation(M)
- return
- else
- to_chat(user, span_danger("The baton is still charging!"))
- return
- else if(user.combat_mode && !turned_on)
- ..()
- return
- else
- M.visible_message(span_warning("[user] prods [M] with [src]. Luckily it was off."), \
- span_warning("[user] prods you with [src]. Luckily it was off."))
- return
-
-/obj/item/melee/baton/proc/baton_effect(mob/living/L, mob/user)
- if(shields_blocked(L, user))
- return FALSE
- if(HAS_TRAIT_FROM(L, TRAIT_IWASBATONED, user)) //no doublebaton abuse anon!
- to_chat(user, span_danger("[L] manages to avoid the attack!"))
- return FALSE
- if(iscyborg(loc))
- var/mob/living/silicon/robot/R = loc
- if(!R || !R.cell || !R.cell.use(cell_hit_cost))
- return FALSE
- else
- if(!deductcharge(cell_hit_cost))
- return FALSE
- /// After a target is hit, we do a chunk of stamina damage, along with other effects.
- /// After a period of time, we then check to see what stun duration we give.
- L.Jitter(20)
- L.set_confusion(max(confusion_amt, L.get_confusion()))
- L.stuttering = max(8, L.stuttering)
- L.apply_damage(stamina_loss_amt, STAMINA, BODY_ZONE_CHEST)
-
- SEND_SIGNAL(L, COMSIG_LIVING_MINOR_SHOCK)
- addtimer(CALLBACK(src, .proc/apply_stun_effect_end, L), apply_stun_delay)
-
- if(user)
- L.lastattacker = user.real_name
- L.lastattackerckey = user.ckey
- L.visible_message(span_danger("[user] stuns [L] with [src]!"), \
- span_userdanger("[user] stuns you with [src]!"))
- log_combat(user, L, "stunned")
-
- playsound(src, stun_sound, 50, TRUE, -1)
-
- attack_cooldown_check = world.time + attack_cooldown
-
- ADD_TRAIT(L, TRAIT_IWASBATONED, user)
- addtimer(TRAIT_CALLBACK_REMOVE(L, TRAIT_IWASBATONED, user), attack_cooldown)
-
- return 1
-
-/// After the initial stun period, we check to see if the target needs to have the stun applied.
-/obj/item/melee/baton/proc/apply_stun_effect_end(mob/living/target)
- var/trait_check = HAS_TRAIT(target, TRAIT_STUNRESISTANCE) //var since we check it in out to_chat as well as determine stun duration
- if(!target.IsKnockdown())
- to_chat(target, span_warning("Your muscles seize, making you collapse[trait_check ? ", but your body quickly recovers..." : "!"]"))
-
- if(trait_check)
- target.Knockdown(stun_time * 0.1)
- else
- target.Knockdown(stun_time)
-
-/obj/item/melee/baton/emp_act(severity)
- . = ..()
- if (!(. & EMP_PROTECT_SELF))
- deductcharge(1000 / severity)
-
-/obj/item/melee/baton/proc/shields_blocked(mob/living/L, mob/user)
- 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(H, 'sound/weapons/genhit.ogg', 50, TRUE)
- return TRUE
- return FALSE
-
-//Makeshift stun baton. Replacement for stun gloves.
-/obj/item/melee/baton/cattleprod
- name = "stunprod"
- desc = "An improvised stun baton. Left click to stun, right click to harm."
- icon_state = "stunprod"
- inhand_icon_state = "prod"
- worn_icon_state = null
- lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
- w_class = WEIGHT_CLASS_BULKY
- force = 3
- throwforce = 5
- stun_time = 5 SECONDS
- cell_hit_cost = 2000
- throw_stun_chance = 10
- slot_flags = ITEM_SLOT_BACK
- convertible = FALSE
- var/obj/item/assembly/igniter/sparkler = 0
-
-/obj/item/melee/baton/cattleprod/Initialize()
- . = ..()
- sparkler = new (src)
-
-/obj/item/melee/baton/cattleprod/baton_effect()
- if(sparkler.activate())
- ..()
-
-/obj/item/melee/baton/cattleprod/Destroy()
- if(sparkler)
- QDEL_NULL(sparkler)
- return ..()
-
-/obj/item/melee/baton/boomerang
- name = "\improper OZtek Boomerang"
- desc = "A device invented in 2486 for the great Space Emu War by the confederacy of Australicus, these high-tech boomerangs also work exceptionally well at stunning crewmembers. Just be careful to catch it when thrown!"
- throw_speed = 1
- icon_state = "boomerang"
- inhand_icon_state = "boomerang"
- force = 5
- throwforce = 5
- throw_range = 5
- cell_hit_cost = 2000
- throw_stun_chance = 99 //Have you prayed today?
- convertible = FALSE
- custom_materials = list(/datum/material/iron = 10000, /datum/material/glass = 4000, /datum/material/silver = 10000, /datum/material/gold = 2000)
-
-/obj/item/melee/baton/boomerang/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE, quickstart = TRUE)
- if(turned_on)
- if(ishuman(thrower))
- var/mob/living/carbon/human/H = thrower
- H.throw_mode_off(THROW_MODE_TOGGLE) //so they can catch it on the return.
- return ..()
-
-/obj/item/melee/baton/boomerang/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
- if(turned_on)
- var/caught = hit_atom.hitby(src, FALSE, FALSE, throwingdatum=throwingdatum)
- if(isliving(hit_atom) && !iscyborg(hit_atom) && !caught && prob(throw_stun_chance))//if they are a living creature and they didn't catch it
- baton_effect(hit_atom)
- var/mob/thrown_by = thrownby?.resolve()
- if(thrown_by && !caught)
- addtimer(CALLBACK(src, /atom/movable.proc/throw_at, thrown_by, throw_range+2, throw_speed, null, TRUE), 1)
- else
- return ..()
-
-/obj/item/melee/baton/boomerang/loaded //Same as above, comes with a cell.
- preload_cell_type = /obj/item/stock_parts/cell/high
diff --git a/code/game/objects/items/teleprod.dm b/code/game/objects/items/teleprod.dm
deleted file mode 100644
index 2e2eee5f678..00000000000
--- a/code/game/objects/items/teleprod.dm
+++ /dev/null
@@ -1,44 +0,0 @@
-/obj/item/melee/baton/cattleprod/teleprod
- name = "teleprod"
- desc = "A prod with a bluespace crystal on the end. The crystal doesn't look too fun to touch."
- w_class = WEIGHT_CLASS_NORMAL
- icon_state = "teleprod"
- inhand_icon_state = "teleprod"
- slot_flags = null
-
-/obj/item/melee/baton/cattleprod/teleprod/attack(mob/living/carbon/M, mob/living/carbon/user)//handles making things teleport when hit
- ..()
- if(turned_on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
- user.visible_message(span_danger("[user] accidentally hits [user.p_them()]self with [src]!"), \
- span_userdanger("You accidentally hit yourself with [src]!"))
- if(do_teleport(user, get_turf(user), 50, channel = TELEPORT_CHANNEL_BLUESPACE))//honk honk
- SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK)
- user.Paralyze(stun_time*3)
- deductcharge(cell_hit_cost)
- else
- SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK)
- user.Paralyze(stun_time*3)
- deductcharge(cell_hit_cost/4)
- return
- else
- if(turned_on)
- if(!istype(M) && M.anchored)
- return .
- else
- SEND_SIGNAL(M, COMSIG_LIVING_MINOR_SHOCK)
- do_teleport(M, get_turf(M), 15, channel = TELEPORT_CHANNEL_BLUESPACE)
-
-/obj/item/melee/baton/cattleprod/attackby(obj/item/I, mob/user, params)//handles sticking a crystal onto a stunprod to make a teleprod
- if(istype(I, /obj/item/stack/ore/bluespace_crystal))
- if(!cell)
- var/obj/item/stack/ore/bluespace_crystal/BSC = I
- var/obj/item/melee/baton/cattleprod/teleprod/S = new /obj/item/melee/baton/cattleprod/teleprod
- remove_item_from_storage(user)
- qdel(src)
- BSC.use(1)
- user.put_in_hands(S)
- to_chat(user, span_notice("You place the bluespace crystal firmly into the igniter."))
- else
- user.visible_message(span_warning("You can't put the crystal onto the stunprod while it has a power cell installed!"))
- else
- return ..()
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 1befd79fb64..9c91fbf245d 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -300,7 +300,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
to_chat(user, span_notice("You fasten the glass shard to the top of the rod with the cable."))
else if(istype(I, /obj/item/assembly/igniter) && !(HAS_TRAIT(I, TRAIT_NODROP)))
- var/obj/item/melee/baton/cattleprod/P = new /obj/item/melee/baton/cattleprod
+ var/obj/item/melee/baton/security/cattleprod/prod = new
remove_item_from_storage(user)
@@ -309,7 +309,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
qdel(I)
qdel(src)
- user.put_in_hands(P)
+ user.put_in_hands(prod)
else
return ..()
diff --git a/code/game/objects/structures/crates_lockers/closets/gimmick.dm b/code/game/objects/structures/crates_lockers/closets/gimmick.dm
index c61e340e45a..1587bff56e0 100644
--- a/code/game/objects/structures/crates_lockers/closets/gimmick.dm
+++ b/code/game/objects/structures/crates_lockers/closets/gimmick.dm
@@ -71,7 +71,7 @@
for(var/i in 1 to 3)
new /obj/item/gun/energy/laser(src)
for(var/i in 1 to 3)
- new /obj/item/melee/baton/loaded(src)
+ new /obj/item/melee/baton/security/loaded(src)
for(var/i in 1 to 3)
new /obj/item/storage/box/flashbangs(src)
for(var/i in 1 to 3)
@@ -90,7 +90,7 @@
for(var/i in 1 to 3)
new /obj/item/gun/energy/laser(src)
for(var/i in 1 to 3)
- new /obj/item/melee/baton/loaded(src)
+ new /obj/item/melee/baton/security/loaded(src)
for(var/i in 1 to 3)
new /obj/item/storage/box/flashbangs(src)
for(var/i in 1 to 3)
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index ecd281a2c8c..2712bb6e640 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -488,7 +488,7 @@
/datum/outfit/syndicate_empty/battlecruiser/assault/captain
name = "Syndicate Battlecruiser Captain"
l_pocket = /obj/item/melee/energy/sword/saber/red
- r_pocket = /obj/item/melee/classic_baton/telescopic
+ r_pocket = /obj/item/melee/baton/telescopic
suit = /obj/item/clothing/suit/armor/vest/capcarapace/syndicate
suit_store = /obj/item/gun/ballistic/revolver/mateba
back = /obj/item/storage/backpack/satchel/leather
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 7f09ebf2f93..56c7dc75b30 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -361,16 +361,16 @@
to_chat(user, span_notice("\The [RG] is full."))
return FALSE
- if(istype(O, /obj/item/melee/baton))
- var/obj/item/melee/baton/B = O
- if(B.cell && B.cell.charge && B.turned_on)
+ if(istype(O, /obj/item/melee/baton/security))
+ var/obj/item/melee/baton/security/baton = O
+ if(baton.cell?.charge && baton.active)
flick("baton_active", src)
- user.Paralyze(B.stun_time)
- user.stuttering = B.stun_time/20
- B.deductcharge(B.cell_hit_cost)
- user.visible_message(span_warning("[user] shocks [user.p_them()]self while attempting to wash the active [B.name]!"), \
- span_userdanger("You unwisely attempt to wash [B] while it's still on."))
- playsound(src, B.stun_sound, 50, TRUE)
+ user.Paralyze(baton.knockdown_time)
+ user.stuttering = baton.knockdown_time*0.5
+ baton.cell.use(baton.cell_hit_cost)
+ user.visible_message(span_warning("[user] shocks [user.p_them()]self while attempting to wash the active [baton.name]!"), \
+ span_userdanger("You unwisely attempt to wash [baton] while it's still on."))
+ playsound(src, baton.on_stun_sound, 50, TRUE)
return
if(istype(O, /obj/item/mop))
@@ -571,16 +571,16 @@
to_chat(user, span_notice("\The [container] is full."))
return FALSE
- if(istype(O, /obj/item/melee/baton))
- var/obj/item/melee/baton/baton = O
- if(baton.cell && baton.cell.charge && baton.turned_on)
+ if(istype(O, /obj/item/melee/baton/security))
+ var/obj/item/melee/baton/security/baton = O
+ if(baton.cell?.charge && baton.active)
flick("baton_active", src)
- user.Paralyze(baton.stun_time)
- user.stuttering = baton.stun_time * 0.05
- baton.deductcharge(baton.cell_hit_cost)
+ user.Paralyze(baton.knockdown_time)
+ user.stuttering = baton.knockdown_time*0.5
+ baton.cell.use(baton.cell_hit_cost)
user.visible_message(span_warning("[user] shocks [user.p_them()]self while attempting to wash the active [baton.name]!"), \
span_userdanger("You unwisely attempt to wash [baton] while it's still on."))
- playsound(src, baton.stun_sound, 50, TRUE)
+ playsound(src, baton.on_stun_sound, 50, TRUE)
return
if(istype(O, /obj/item/mop))
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index 399394c7e13..0b3599229eb 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -17,7 +17,6 @@
actions_types = list(/datum/action/item_action/hands_free/activate)
allowed = list(
/obj/item/abductor,
- /obj/item/melee/baton/abductor,
/obj/item/melee/baton,
/obj/item/gun/energy,
/obj/item/restraints/handcuffs
@@ -442,22 +441,15 @@ Congratulations! You are now trained for invasive xenobiology research!"}
inhand_icon_state = "wonderprod"
force = 7
-
- w_class = WEIGHT_CLASS_NORMAL
- slot_flags = ITEM_SLOT_BELT
+ wound_bonus = FALSE
actions_types = list(/datum/action/item_action/toggle_mode)
- convertible = FALSE
- attack_cooldown = 0 SECONDS
- confusion_amt = 0
- stamina_loss_amt = 0
- apply_stun_delay = 0 SECONDS
- stun_time = 14 SECONDS
-
- preload_cell_type = /obj/item/stock_parts/cell/infinite //Any sufficiently advanced technology is indistinguishable from magic
- activate_sound = null
- can_remove_cell = FALSE
+ cooldown = 0 SECONDS
+ stamina_damage = 0
+ knockdown_time = 14 SECONDS
+ on_stun_sound = 'sound/weapons/egloves.ogg'
+ affect_cyborg = TRUE
var/mode = BATON_STUN
@@ -483,8 +475,14 @@ Congratulations! You are now trained for invasive xenobiology research!"}
if(BATON_PROBE)
txt = "probing"
- if(!turned_on)
- toggle_on(user)
+ var/is_stun_mode = mode == BATON_STUN
+ var/is_stun_or_sleep = mode == BATON_STUN || mode == BATON_SLEEP
+
+ affect_cyborg = is_stun_mode
+ log_stun_attack = is_stun_mode // other modes have their own log entries.
+ stun_animation = is_stun_or_sleep
+ on_stun_sound = is_stun_or_sleep ? 'sound/weapons/egloves.ogg' : null
+
to_chat(usr, span_notice("You switch the baton to [txt] mode."))
update_appearance()
@@ -504,61 +502,40 @@ Congratulations! You are now trained for invasive xenobiology research!"}
icon_state = "wonderprodProbe"
inhand_icon_state = "wonderprodProbe"
-/obj/item/melee/baton/abductor/attack(mob/target, mob/living/user)
+/obj/item/melee/baton/abductor/baton_attack(mob/target, mob/living/user, modifiers)
if(!AbductorCheck(user))
- return FALSE
-
- if(!deductcharge(cell_hit_cost))
- to_chat(user, span_warning("[src] [cell ? "is out of charge" : "does not have a power source installed"]."))
- return FALSE
-
- if(!turned_on)
- toggle_on(user)
-
- if(iscyborg(target))
- if(mode == BATON_STUN)
- ..()
- return FALSE
-
- if(!isliving(target))
- return FALSE
-
- if(clumsy_check(user))
- return FALSE
-
- var/mob/living/L = target
-
- user.do_attack_animation(L)
-
- if(shields_blocked(L, user))
- return FALSE
+ return BATON_ATTACK_DONE
+ return ..()
+/obj/item/melee/baton/abductor/baton_effect(mob/living/target, mob/living/user, modifiers, stun_override)
switch (mode)
if(BATON_STUN)
- ..()
+ target.visible_message(span_danger("[user] stuns [target] with [src]!"),
+ span_userdanger("[user] stuns you with [src]!"))
+ target.Jitter(20)
+ target.set_confusion(max(10, target.get_confusion()))
+ target.stuttering = max(8, target.stuttering)
+ SEND_SIGNAL(target, COMSIG_LIVING_MINOR_SHOCK)
+ target.Paralyze(knockdown_time * (HAS_TRAIT(target, TRAIT_STUNRESISTANCE) ? 0.1 : 1))
if(BATON_SLEEP)
- SleepAttack(L,user)
+ SleepAttack(target,user)
if(BATON_CUFF)
- CuffAttack(L,user)
+ CuffAttack(target,user)
if(BATON_PROBE)
- ProbeAttack(L,user)
- return
+ ProbeAttack(target,user)
-/obj/item/melee/baton/abductor/apply_stun_effect_end(mob/living/target)
- StunAttack(target)
+/obj/item/melee/baton/abductor/get_stun_description(mob/living/target, mob/living/user)
+ return // chat messages are handled in their own procs.
-/obj/item/melee/baton/abductor/proc/StunAttack(mob/living/L)
- L.Paralyze(stun_time)
+/obj/item/melee/baton/abductor/get_cyborg_stun_description(mob/living/target, mob/living/user)
+ return // same as above.
/obj/item/melee/baton/abductor/attack_self(mob/living/user)
+ . = ..()
toggle(user)
-/obj/item/melee/baton/abductor/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
- turned_on = FALSE
- ..()
-
/obj/item/melee/baton/abductor/proc/SleepAttack(mob/living/L,mob/living/user)
- playsound(src, stun_sound, 50, TRUE, -1)
+ playsound(src, on_stun_sound, 50, TRUE, -1)
if(L.incapacitated(TRUE, TRUE))
if(L.anti_magic_check(FALSE, FALSE, TRUE))
to_chat(user, span_warning("The specimen's tinfoil protection is interfering with the sleep inducement!"))
diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm
index 02d0ee4dead..f4a7540cce6 100644
--- a/code/modules/awaymissions/mission_code/snowdin.dm
+++ b/code/modules/awaymissions/mission_code/snowdin.dm
@@ -443,8 +443,8 @@
/obj/effect/spawner/lootdrop/snowdin/dungeonlite
name = "dungeon lite"
- loot = list(/obj/item/melee/classic_baton = 11,
- /obj/item/melee/classic_baton/telescopic = 12,
+ loot = list(/obj/item/melee/baton = 11,
+ /obj/item/melee/baton/telescopic = 12,
/obj/item/book/granter/spell/smoke = 10,
/obj/item/book/granter/spell/blind = 10,
/obj/item/storage/firstaid/regular = 45,
diff --git a/code/modules/cargo/bounties/assistant.dm b/code/modules/cargo/bounties/assistant.dm
index af9c46f889a..b2ef5f5d360 100644
--- a/code/modules/cargo/bounties/assistant.dm
+++ b/code/modules/cargo/bounties/assistant.dm
@@ -21,7 +21,7 @@
name = "Stunprod"
description = "CentCom demands a stunprod to use against dissidents. Craft one, then ship it."
reward = CARGO_CRATE_VALUE * 2.6
- wanted_types = list(/obj/item/melee/baton/cattleprod)
+ wanted_types = list(/obj/item/melee/baton/security/cattleprod)
/datum/bounty/item/assistant/soap
name = "Soap"
diff --git a/code/modules/cargo/exports/weapons.dm b/code/modules/cargo/exports/weapons.dm
index 779b935c5f0..b62cd7126d0 100644
--- a/code/modules/cargo/exports/weapons.dm
+++ b/code/modules/cargo/exports/weapons.dm
@@ -6,8 +6,8 @@
/datum/export/weapon/baton
cost = CARGO_CRATE_VALUE * 0.5
unit_name = "stun baton"
- export_types = list(/obj/item/melee/baton)
- exclude_types = list(/obj/item/melee/baton/cattleprod)
+ export_types = list(/obj/item/melee/baton/security)
+ exclude_types = list(/obj/item/melee/baton/security/cattleprod)
include_subtypes = TRUE
/datum/export/weapon/knife
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index bbbdf9455b3..3e6de23a7d3 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -418,9 +418,9 @@
desc = "Arm the Civil Protection Forces with three stun batons. Batteries included. Requires Security access to open."
cost = CARGO_CRATE_VALUE * 2
access_view = ACCESS_SECURITY
- contains = list(/obj/item/melee/baton/loaded,
- /obj/item/melee/baton/loaded,
- /obj/item/melee/baton/loaded)
+ contains = list(/obj/item/melee/baton/security/loaded,
+ /obj/item/melee/baton/security/loaded,
+ /obj/item/melee/baton/security/loaded)
crate_name = "stun baton crate"
/datum/supply_pack/security/wall_flash
diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm
index 0be53013ce5..dfddcf4c017 100644
--- a/code/modules/clothing/outfits/ert.dm
+++ b/code/modules/clothing/outfits/ert.dm
@@ -38,7 +38,7 @@
suit_store = /obj/item/gun/energy/e_gun
back = /obj/item/storage/backpack/ert
backpack_contents = list(
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/storage/box/survival/engineer = 1,
)
belt = /obj/item/storage/belt/security/full
@@ -59,7 +59,7 @@
backpack_contents = list(
/obj/item/gun/energy/pulse/pistol/loyalpin = 1,
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/storage/box/survival/engineer = 1,
)
glasses = /obj/item/clothing/glasses/thermal/eyepatch
@@ -73,7 +73,7 @@
suit_store = /obj/item/gun/energy/e_gun/stun
back = /obj/item/storage/backpack/ert/security
backpack_contents = list(
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/storage/box/handcuffs = 1,
/obj/item/storage/box/survival/engineer = 1,
)
@@ -96,7 +96,7 @@
belt = /obj/item/gun/energy/pulse/carbine/loyalpin
backpack_contents = list(
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/storage/belt/security/full = 1,
/obj/item/storage/box/handcuffs = 1,
/obj/item/storage/box/survival/engineer = 1,
@@ -111,7 +111,7 @@
back = /obj/item/storage/backpack/ert/medical
backpack_contents = list(
/obj/item/gun/medbeam = 1,
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/reagent_containers/hypospray/combat = 1,
/obj/item/storage/box/hug/plushes = 1,
/obj/item/storage/box/survival/engineer = 1,
@@ -136,7 +136,7 @@
backpack_contents = list(
/obj/item/gun/energy/pulse/pistol/loyalpin = 1,
/obj/item/gun/medbeam = 1,
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/reagent_containers/hypospray/combat/nanites = 1,
/obj/item/storage/box/hug/plushes = 1,
/obj/item/storage/box/survival/engineer = 1,
@@ -152,7 +152,7 @@
back = /obj/item/storage/backpack/ert/engineer
backpack_contents = list(
/obj/item/construction/rcd/loaded/upgraded = 1,
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/pipe_dispenser = 1,
/obj/item/storage/box/survival/engineer = 1,
)
@@ -176,7 +176,7 @@
backpack_contents = list(
/obj/item/construction/rcd/combat = 1,
/obj/item/gun/energy/pulse/pistol/loyalpin = 1,
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/pipe_dispenser = 1,
/obj/item/storage/box/survival/engineer = 1,
)
@@ -232,7 +232,7 @@
suit_store = /obj/item/gun/energy/e_gun/stun
backpack_contents = list(
/obj/item/construction/rcd/loaded = 1,
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/storage/box/handcuffs = 1,
/obj/item/storage/box/survival/engineer = 1,
)
@@ -243,7 +243,7 @@
suit = /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor
backpack_contents = list(
/obj/item/gun/medbeam = 1,
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/storage/box/survival/engineer = 1,
/obj/item/reagent_containers/hypospray/combat = 1,
/obj/item/reagent_containers/hypospray/combat/heresypurge = 1,
@@ -289,7 +289,7 @@
back = /obj/item/storage/backpack/ert/janitor
backpack_contents = list(
/obj/item/grenade/clusterbuster/cleaner = 1,
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/mop/advanced = 1,
/obj/item/reagent_containers/glass/bucket = 1,
/obj/item/storage/box/lights/mixed = 1,
@@ -316,7 +316,7 @@
backpack_contents = list(
/obj/item/grenade/clusterbuster/cleaner = 3,
- /obj/item/melee/baton/loaded = 1,
+ /obj/item/melee/baton/security/loaded = 1,
/obj/item/storage/box/lights/mixed = 1,
/obj/item/storage/box/survival/engineer = 1,
)
@@ -363,7 +363,7 @@
backpack_contents = list(
/obj/item/storage/box/survival = 1,
)
- belt = /obj/item/melee/classic_baton
+ belt = /obj/item/melee/baton
ears = /obj/item/radio/headset/headset_cent
glasses = /obj/item/clothing/glasses/sunglasses
gloves = /obj/item/clothing/gloves/color/black
@@ -395,7 +395,7 @@
suit = /obj/item/clothing/suit/armor/vest
suit_store = /obj/item/gun/ballistic/rifle/boltaction/brand_new
- belt = /obj/item/melee/baton/loaded
+ belt = /obj/item/melee/baton/security/loaded
head = /obj/item/clothing/head/intern
l_hand = /obj/item/megaphone
@@ -436,7 +436,7 @@
/obj/item/storage/box/handcuffs = 1,
/obj/item/storage/box/survival/engineer = 1,
)
- belt = /obj/item/melee/classic_baton/telescopic
+ belt = /obj/item/melee/baton/telescopic
l_pocket = /obj/item/assembly/flash
r_pocket = /obj/item/storage/wallet
diff --git a/code/modules/clothing/suits/bio.dm b/code/modules/clothing/suits/bio.dm
index cb41cb438ac..1e0b6c0d963 100644
--- a/code/modules/clothing/suits/bio.dm
+++ b/code/modules/clothing/suits/bio.dm
@@ -84,7 +84,7 @@
/obj/item/clothing/suit/bio_suit/cmo/Initialize()
. = ..()
- allowed += list(/obj/item/melee/classic_baton/telescopic)
+ allowed += list(/obj/item/melee/baton/telescopic)
//Plague Dr mask can be found in clothing/masks/gasmask.dm
/obj/item/clothing/suit/bio_suit/plaguedoctorsuit
diff --git a/code/modules/clothing/suits/labcoat.dm b/code/modules/clothing/suits/labcoat.dm
index bb1c8ce248b..cd263ae5ef8 100644
--- a/code/modules/clothing/suits/labcoat.dm
+++ b/code/modules/clothing/suits/labcoat.dm
@@ -38,8 +38,8 @@
/obj/item/clothing/suit/toggle/labcoat/cmo/Initialize()
. = ..()
allowed += list(
- /obj/item/melee/classic_baton/telescopic,
- )
+ /obj/item/melee/baton/telescopic,
+ )
/obj/item/clothing/suit/toggle/labcoat/paramedic
name = "paramedic's jacket"
diff --git a/code/modules/clothing/suits/wintercoats.dm b/code/modules/clothing/suits/wintercoats.dm
index ce2649f196b..19c1a676b3c 100644
--- a/code/modules/clothing/suits/wintercoats.dm
+++ b/code/modules/clothing/suits/wintercoats.dm
@@ -82,7 +82,7 @@
inhand_icon_state = "coathop"
armor = list(MELEE = 10, BULLET = 15, LASER = 15, ENERGY = 25, BOMB = 10, BIO = 0, RAD = 0, FIRE = 0, ACID = 35)
allowed = list(
- /obj/item/melee/classic_baton/telescopic,
+ /obj/item/melee/baton/telescopic,
)
hoodtype = /obj/item/clothing/head/hooded/winterhood/hop
@@ -206,7 +206,7 @@
/obj/item/clothing/suit/hooded/wintercoat/medical/cmo/Initialize()
. = ..()
allowed += list(
- /obj/item/melee/classic_baton/telescopic,
+ /obj/item/melee/baton/telescopic,
)
/obj/item/clothing/head/hooded/winterhood/medical/cmo
@@ -289,7 +289,7 @@
/obj/item/clothing/suit/hooded/wintercoat/science/rd/Initialize()
. = ..()
allowed += list(
- /obj/item/melee/classic_baton/telescopic,
+ /obj/item/melee/baton/telescopic,
)
/obj/item/clothing/head/hooded/winterhood/science/rd
@@ -354,7 +354,7 @@
/obj/item/clothing/suit/hooded/wintercoat/engineering/ce/Initialize()
. = ..()
allowed += list(
- /obj/item/melee/classic_baton/telescopic,
+ /obj/item/melee/baton/telescopic,
)
/obj/item/clothing/head/hooded/winterhood/engineering/ce
diff --git a/code/modules/explorer_drone/loot.dm b/code/modules/explorer_drone/loot.dm
index 9a600d1d3ec..47f12b8cf28 100644
--- a/code/modules/explorer_drone/loot.dm
+++ b/code/modules/explorer_drone/loot.dm
@@ -84,7 +84,7 @@ GLOBAL_LIST_INIT(adventure_loot_generator_index,generate_generator_index())
/// Assorted weaponry
/datum/adventure_loot_generator/simple/weapons
id = "weapons"
- loot_list = list(/obj/item/gun/energy/laser,/obj/item/melee/baton/loaded)
+ loot_list = list(/obj/item/gun/energy/laser,/obj/item/melee/baton/security/loaded)
/// Pets and pet accesories in carriers
/datum/adventure_loot_generator/pet
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index 5a063c585da..6abda221483 100755
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -57,7 +57,7 @@
suit = /obj/item/clothing/suit/armor/vest/capcarapace
shoes = /obj/item/clothing/shoes/sneakers/brown
head = /obj/item/clothing/head/caphat
- backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/station_charter=1)
+ backpack_contents = list(/obj/item/melee/baton/telescopic=1, /obj/item/station_charter=1)
skillchips = list(/obj/item/skillchip/disk_verifier)
diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm
index ee3e5a7714f..e7ed1b42e36 100644
--- a/code/modules/jobs/job_types/chief_engineer.dm
+++ b/code/modules/jobs/job_types/chief_engineer.dm
@@ -62,7 +62,7 @@
shoes = /obj/item/clothing/shoes/sneakers/brown
head = /obj/item/clothing/head/hardhat/white
gloves = /obj/item/clothing/gloves/color/black
- backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced/command/engineering=1)
+ backpack_contents = list(/obj/item/melee/baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced/command/engineering=1)
backpack = /obj/item/storage/backpack/industrial
satchel = /obj/item/storage/backpack/satchel/eng
diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm
index a652828bffa..41e7ec3cbcf 100644
--- a/code/modules/jobs/job_types/chief_medical_officer.dm
+++ b/code/modules/jobs/job_types/chief_medical_officer.dm
@@ -60,7 +60,7 @@
suit = /obj/item/clothing/suit/toggle/labcoat/cmo
l_hand = /obj/item/storage/firstaid/medical
suit_store = /obj/item/flashlight/pen/paramedic
- backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced/command=1)
+ backpack_contents = list(/obj/item/melee/baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced/command=1)
skillchips = list(/obj/item/skillchip/entrails_reader)
diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm
index cf4a9090a3f..b2b05eb8024 100644
--- a/code/modules/jobs/job_types/detective.dm
+++ b/code/modules/jobs/job_types/detective.dm
@@ -58,7 +58,7 @@
r_pocket = /obj/item/lighter
backpack_contents = list(/obj/item/storage/box/evidence=1,\
/obj/item/detective_scanner=1,\
- /obj/item/melee/classic_baton=1)
+ /obj/item/melee/baton=1)
mask = /obj/item/clothing/mask/cigarette
implants = list(/obj/item/implant/mindshield)
diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm
index ff04f7e2649..f22c1431157 100644
--- a/code/modules/jobs/job_types/head_of_personnel.dm
+++ b/code/modules/jobs/job_types/head_of_personnel.dm
@@ -57,7 +57,7 @@
shoes = /obj/item/clothing/shoes/sneakers/brown
head = /obj/item/clothing/head/hopcap
backpack_contents = list(/obj/item/storage/box/ids=1,\
- /obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced/command = 1)
+ /obj/item/melee/baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced/command = 1)
chameleon_extras = list(/obj/item/gun/energy/e_gun, /obj/item/stamp/hop)
diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm
index 15d95d14ba0..92683212061 100644
--- a/code/modules/jobs/job_types/head_of_security.dm
+++ b/code/modules/jobs/job_types/head_of_security.dm
@@ -58,7 +58,7 @@
suit_store = /obj/item/gun/energy/e_gun
r_pocket = /obj/item/assembly/flash/handheld
l_pocket = /obj/item/restraints/handcuffs
- backpack_contents = list(/obj/item/melee/baton/loaded=1, /obj/item/modular_computer/tablet/preset/advanced/command=1)
+ backpack_contents = list(/obj/item/melee/baton/security/loaded=1, /obj/item/modular_computer/tablet/preset/advanced/command=1)
backpack = /obj/item/storage/backpack/security
satchel = /obj/item/storage/backpack/satchel/sec
@@ -77,4 +77,4 @@
mask = /obj/item/clothing/mask/gas/sechailer
suit = /obj/item/clothing/suit/space/hardsuit/security/hos
suit_store = /obj/item/tank/internals/oxygen
- backpack_contents = list(/obj/item/melee/baton/loaded=1)
+ backpack_contents = list(/obj/item/melee/baton/security/loaded=1)
diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm
index a79780cf9f4..84b460d3d4b 100644
--- a/code/modules/jobs/job_types/research_director.dm
+++ b/code/modules/jobs/job_types/research_director.dm
@@ -59,7 +59,7 @@
suit = /obj/item/clothing/suit/toggle/labcoat
l_hand = /obj/item/clipboard
l_pocket = /obj/item/laser_pointer
- backpack_contents = list(/obj/item/melee/classic_baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced/command=1)
+ backpack_contents = list(/obj/item/melee/baton/telescopic=1, /obj/item/modular_computer/tablet/preset/advanced/command=1)
backpack = /obj/item/storage/backpack/science
satchel = /obj/item/storage/backpack/satchel/science
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index 1e63771b97d..2b2fa5a4099 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -34,7 +34,7 @@
/obj/item/food/donut/matcha = 10,
/obj/item/food/donut/blumpkin = 5,
/obj/item/clothing/mask/whistle = 5,
- /obj/item/melee/baton/boomerang/loaded = 1
+ /obj/item/melee/baton/security/boomerang/loaded = 1
)
job_flags = JOB_ANNOUNCE_ARRIVAL | JOB_CREW_MANIFEST | JOB_EQUIP_RANK | JOB_CREW_MEMBER | JOB_NEW_PLAYER_JOINABLE | JOB_REOPEN_ON_ROUNDSTART_LOSS | JOB_ASSIGN_QUIRKS
@@ -204,7 +204,7 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
l_pocket = /obj/item/restraints/handcuffs
r_pocket = /obj/item/assembly/flash/handheld
suit_store = /obj/item/gun/energy/disabler
- backpack_contents = list(/obj/item/melee/baton/loaded=1)
+ backpack_contents = list(/obj/item/melee/baton/security/loaded=1)
backpack = /obj/item/storage/backpack/security
satchel = /obj/item/storage/backpack/satchel/sec
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
index a983e620773..610c73893b3 100644
--- a/code/modules/jobs/job_types/warden.dm
+++ b/code/modules/jobs/job_types/warden.dm
@@ -56,7 +56,7 @@
r_pocket = /obj/item/assembly/flash/handheld
l_pocket = /obj/item/restraints/handcuffs
suit_store = /obj/item/gun/energy/disabler
- backpack_contents = list(/obj/item/melee/baton/loaded=1)
+ backpack_contents = list(/obj/item/melee/baton/security/loaded=1)
backpack = /obj/item/storage/backpack/security
satchel = /obj/item/storage/backpack/satchel/sec
diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm
index becd950c48c..54ee5a6b1fa 100644
--- a/code/modules/mining/abandoned_crates.dm
+++ b/code/modules/mining/abandoned_crates.dm
@@ -150,7 +150,7 @@
if(46 to 50)
new /obj/item/storage/box/syndie_kit/chameleon/broken
if(51 to 52) // 2% chance
- new /obj/item/melee/classic_baton(src)
+ new /obj/item/melee/baton(src)
if(53 to 54)
new /obj/item/toy/balloon/corgi(src)
if(55 to 56)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 51ce2ba4e46..fb953ddaea7 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -101,10 +101,9 @@
F.times_used = 0
F.burnt_out = FALSE
F.update_appearance()
- else if(istype(I, /obj/item/melee/baton))
- var/obj/item/melee/baton/B = I
- if(B.cell)
- B.cell.charge = B.cell.maxcharge
+ else if(istype(I, /obj/item/melee/baton/security))
+ var/obj/item/melee/baton/security/baton = I
+ baton.cell?.charge = baton.cell.maxcharge
else if(istype(I, /obj/item/gun/energy))
var/obj/item/gun/energy/EG = I
if(!EG.chambered)
@@ -422,7 +421,7 @@
basic_modules = list(
/obj/item/assembly/flash/cyborg,
/obj/item/restraints/handcuffs/cable/zipties,
- /obj/item/melee/baton/loaded,
+ /obj/item/melee/baton/security/loaded,
/obj/item/gun/energy/disabler/cyborg,
/obj/item/clothing/mask/gas/sechailer/cyborg,
/obj/item/extinguisher/mini)
diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm
index 0613b78b417..9d682c311d4 100644
--- a/code/modules/mob/living/simple_animal/bot/construction.dm
+++ b/code/modules/mob/living/simple_animal/bot/construction.dm
@@ -366,7 +366,7 @@
build_step--
if(ASSEMBLY_FOURTH_STEP)
- if(istype(I, /obj/item/melee/baton))
+ if(istype(I, /obj/item/melee/baton/security))
if(!can_finish_build(I, user))
return
to_chat(user, span_notice("You complete the Securitron! Beep boop."))
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index 83600bd7b42..db2818cf12a 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -23,7 +23,7 @@
combat_mode = TRUE
- var/baton_type = /obj/item/melee/baton
+ var/baton_type = /obj/item/melee/baton/security
var/obj/item/weapon
var/mob/living/carbon/target
var/oldtarget_name
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index 28875da4779..68020ff781c 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -335,6 +335,6 @@
id = "stun_boomerang"
build_type = PROTOLATHE | AWAY_LATHE
materials = list(/datum/material/iron = 10000, /datum/material/glass = 4000, /datum/material/silver = 10000, /datum/material/gold = 2000)
- build_path = /obj/item/melee/baton/boomerang
+ build_path = /obj/item/melee/baton/security/boomerang
category = list("Weapons")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
diff --git a/code/modules/surgery/revival.dm b/code/modules/surgery/revival.dm
index b8d620a98db..d8cedff3426 100644
--- a/code/modules/surgery/revival.dm
+++ b/code/modules/surgery/revival.dm
@@ -30,7 +30,7 @@
name = "shock body"
implements = list(
/obj/item/shockpaddles = 100,
- /obj/item/melee/baton = 75,
+ /obj/item/melee/baton/security = 75,
/obj/item/gun/energy = 60)
repeatable = TRUE
time = 5 SECONDS
@@ -42,9 +42,9 @@
if((paddles.req_defib && !paddles.defib.powered) || !paddles.wielded || paddles.cooldown || paddles.busy)
to_chat(user, span_warning("You need to wield both paddles, and [paddles.defib] must be powered!"))
return FALSE
- if(istype(tool, /obj/item/melee/baton))
- var/obj/item/melee/baton/baton = tool
- if(!baton.turned_on)
+ if(istype(tool, /obj/item/melee/baton/security))
+ var/obj/item/melee/baton/security/baton = tool
+ if(!baton.active)
to_chat(user, span_warning("[baton] needs to be active!"))
return FALSE
if(istype(tool, /obj/item/gun/energy))
diff --git a/tgstation.dme b/tgstation.dme
index a23a3d1a841..19cc621090e 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1268,11 +1268,9 @@
#include "code\game\objects\items\singularityhammer.dm"
#include "code\game\objects\items\skub.dm"
#include "code\game\objects\items\spear.dm"
-#include "code\game\objects\items\stunbaton.dm"
#include "code\game\objects\items\tail_pin.dm"
#include "code\game\objects\items\taster.dm"
#include "code\game\objects\items\teleportation.dm"
-#include "code\game\objects\items\teleprod.dm"
#include "code\game\objects\items\theft_tools.dm"
#include "code\game\objects\items\toy_mechs.dm"
#include "code\game\objects\items\toys.dm"
@@ -1378,6 +1376,7 @@
#include "code\game\objects\items\implants\implanter.dm"
#include "code\game\objects\items\implants\implantpad.dm"
#include "code\game\objects\items\implants\implantuplink.dm"
+#include "code\game\objects\items\melee\baton.dm"
#include "code\game\objects\items\melee\energy.dm"
#include "code\game\objects\items\melee\misc.dm"
#include "code\game\objects\items\robot\ai_upgrades.dm"