Hos updates + kaza ruz prevents shove knockdown (#5719)

## About The Pull Request

This PR is focused around the HoS and their gear. Most of it hasn't
changed in ages, and is quite frankly, VERY underwhelming for what is
widely considered the hardest job on station.

What this PR does:
Adds a case to the hoses locker instead of the x-01. It acts as a
voucher more or less. When it's opened you can select one of the 4
available service weapons.

One, is the classic x-01
One, is the compact peacekeeper shotgun
Two, are new guns:
The smart pistol is a prototype murphy. It does 10% less damage then
normal murphys, HOWEVER, it shoots past anyone with a mindsheild
implant. Great for HoSes who want to act more as supporters then direct
combatents.

The second, is the law. It's just a .38 revolver that does 10% more
damage, with a cool new sprite by Niim

The compact shotgun has been taken away from the warden, and in return:
Their martial arts gloves now give the wearer the inability to be
staggered or knocked down via shoving! They can still be knocked down
via plenty of other means, but it's like riot armor.
This is good for the warden, as they work in VERY close quarters. This
makes it so their gear is more directed at that then just a good gun.
The objective to steal the wardens compact has been changed to stealing
said gloves.

The x-01 traitor objective is of course accounted for. It now starts as
an objective to steal the case itself, but when the cases gun is
selected, it updates the objective to that specific gun and informs the
traitor.

Additionally, I resprited the compact shotgun slightly, and gave it some
additional basic animation. I also added a bayonet lug to it with a
custom placement/sprite for it.
## Why It's Good For The Game

Hos has felt incredibly lame gear wise for quite some time. When the
x-01 was initially added way back, it was cool and unique, but these
days the game has changed so much that it's just...meh. Additionally,
the warden having a compact shotgun felt...off. They're intended to
mostly be in the brig, so a portable compact shotgun didn't entirely
make sense for them.
## Proof Of Testing
Videos were too big for direct upload on github, so here they are.

Gun demo: https://files.catbox.moe/dzhihr.mp4

<details>
<summary>Screenshots/Videos</summary>
<img width="907" height="601" alt="image"
src="https://github.com/user-attachments/assets/3c3e4983-a745-4a04-b4c2-520951589047"
/>


</details>

## Changelog
🆑 UvvU
add: Added a HoS service weapon case, allowing them to select their
weapon. Revolver sprite by Niim
del: Removed the wardens compact shotgun from their locker
balance: made the wardens martial arts gloves make them unable to be
shoved down or staggered
/🆑

---------

Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com>
This commit is contained in:
CatoChristopherMrow
2026-07-03 15:03:00 -04:00
committed by GitHub
parent b8fec990e1
commit 4b5fc14909
10 changed files with 316 additions and 1 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -0,0 +1,26 @@
/datum/antagonist/traitor/forge_single_generic_objective()
if(prob(KILL_PROB))
var/datum/objective/gimmick/gimmick_objective = new()
gimmick_objective.owner = owner
return gimmick_objective
var/datum/objective/steal/steal_objective = new()
steal_objective.owner = owner
steal_objective.find_target()
return steal_objective
/datum/objective_item/steal/hoslaser
name = "the head of security's service weapon"
targetitem = /obj/item/gun/energy/e_gun/hos
altitems = list(/obj/item/hos_primary_case)
steal_hint = "A gun case found in the Head of Security's locker."
/datum/objective_item/steal/compactshotty
name = "the warden's kaza ruk gloves"
targetitem = /obj/item/gun/ballistic/shotgun/automatic/combat/compact
altitems = list(/obj/item/clothing/gloves/kaza_ruk/sec/warden)
steal_hint = "A reinforced set of kaza ruk gloves found in the Warden's locker."
/datum/objective_item/steal/compactshotty/check_special_completion(obj/item/thing)
return istype(thing, /obj/item/clothing/gloves/kaza_ruk/sec/warden)
@@ -38,6 +38,9 @@
/obj/item/storage/bag/garment/warden/PopulateContents()
. = ..()
for(var/obj/item/clothing/gloves/kaza_ruk/sec/original_gloves in src)
if(original_gloves.type == /obj/item/clothing/gloves/kaza_ruk/sec)
qdel(original_gloves)
new /obj/item/clothing/under/rank/security/viro/warden/skirt/(src)
new /obj/item/clothing/under/rank/security/viro/warden/(src)
new /obj/item/clothing/under/rank/security/viro/warden/formal/(src)
@@ -55,4 +58,3 @@
@@ -1,6 +1,39 @@
/obj/item/clothing/gloves/kaza_ruk/sec/warden
name = "warden's kaza ruk gloves"
desc = "These gloves seem to guide you through a non-lizardperson friendly variant of the Tiziran martial art, Kaza Ruk. \
Reinforced bracing helps keep the wearer planted during close-quarters scuffles."
clothing_traits = list(TRAIT_FAST_CUFFING, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH)
/obj/item/gun/energy/laser/scatter/shotty/warden
name = "warden's disabler shotgun"
desc = "A combat shotgun gutted and refitted with an internal disabler system. The power supply unit seems to have suffered during The Great Burgerstation Riots of '69"
ammo_type = list(/obj/item/ammo_casing/energy/laser/scatter/disabler)
pin = /obj/item/firing_pin
projectile_damage_multiplier = 0.75
/obj/item/clothing/gloves/kaza_ruk/sec/warden/add_stealing_item_objective()
return add_item_to_steal(src, /obj/item/gun/ballistic/shotgun/automatic/combat/compact)
/obj/structure/closet/secure_closet/hos/populate_contents_immediate()
. = ..()
var/obj/item/gun/energy/e_gun/hos/original_primary = locate(/obj/item/gun/energy/e_gun/hos) in src
if(original_primary)
qdel(original_primary)
new /obj/item/hos_primary_case(src)
/obj/structure/closet/secure_closet/warden/PopulateContents()
. = ..()
new /obj/item/stamp/warden(src)
if(!locate(/obj/item/clothing/gloves/kaza_ruk/sec/warden) in src)
new /obj/item/clothing/gloves/kaza_ruk/sec/warden(src)
if(!locate(/obj/item/gun/energy/laser/scatter/shotty) in src)
new /obj/item/gun/energy/laser/scatter/shotty/warden(src)
/obj/structure/closet/secure_closet/warden/populate_contents_immediate()
. = ..()
for(var/obj/item/gun/ballistic/shotgun/automatic/combat/compact/warden_primary in src)
if(warden_primary.type == /obj/item/gun/ballistic/shotgun/automatic/combat/compact)
qdel(warden_primary)
/obj/structure/closet/secure_closet/hop/populate_contents_immediate()
. = ..()
@@ -1,3 +1,49 @@
/datum/component/bayonet_attachable/no_overlay/on_update_overlays(obj/item/source, list/overlays)
return
/datum/component/seclite_attachable/compact_shotgun/on_update_overlays(obj/item/source, list/overlays)
if(!light_overlay || !light_overlay_icon || !light)
return
overlays += mutable_appearance(light_overlay_icon, "[light_overlay]_[light.light_on ? "on" : "off"]")
/obj/item/gun/ballistic/shotgun/automatic/combat/compact/add_seclight_point()
AddComponent(/datum/component/seclite_attachable/compact_shotgun, \
light_overlay_icon = 'modular_skyrat/modules/modular_weapons/icons/obj/company_and_or_faction_based/carwo_defense_systems/guns48x.dmi', \
light_overlay = "cshotgunc_light")
/obj/item/gun/ballistic/shotgun/automatic/combat/compact/add_bayonet_point()
AddComponent(/datum/component/bayonet_attachable/no_overlay)
/obj/item/gun/ballistic/shotgun/automatic/combat/compact
var/compact_bolt_animating = FALSE
/obj/item/gun/ballistic/shotgun/automatic/combat/compact/update_overlays()
. = ..()
var/datum/component/bayonet_attachable/bayonet_component = GetComponent(/datum/component/bayonet_attachable)
var/has_bayonet = bayonet_component?.bayonet ? TRUE : FALSE
if(has_bayonet)
. += "cshotgunc_bayonet"
. += has_bayonet ? "cshotgunc_laser_bayonet" : "cshotgunc_laser"
/obj/item/gun/ballistic/shotgun/automatic/combat/compact/shoot_live_shot(mob/living/user)
. = ..()
animate_compact_bolt()
/obj/item/gun/ballistic/shotgun/automatic/combat/compact/proc/animate_compact_bolt()
compact_bolt_animating = TRUE
update_appearance(UPDATE_OVERLAYS)
var/icon/bolt_icon = icon(src.icon, "cshotgunc_bolt_animated", SOUTH, 1)
var/atom/movable/flick_visual/bolt = flick_overlay_view(mutable_appearance(bolt_icon, "", layer + 0.1), 1)
if(bolt)
animate(bolt, icon = icon(src.icon, "cshotgunc_bolt_animated", SOUTH, 2), time = 0.2)
for(var/frame in 3 to 6)
animate(icon = icon(src.icon, "cshotgunc_bolt_animated", SOUTH, frame), time = 0.2)
addtimer(CALLBACK(src, PROC_REF(reset_compact_bolt_animation)), 1)
/obj/item/gun/ballistic/shotgun/automatic/combat/compact/proc/reset_compact_bolt_animation()
compact_bolt_animating = FALSE
update_appearance(UPDATE_OVERLAYS)
/obj/item/gun/ballistic/shotgun/bulldog/beanbag
name = "\improper Beandog Shotgun"
desc = "A 2-round burst fire, mag-fed shotgun for target suppression in narrow corridors, \
@@ -19,6 +19,211 @@
name = "security utility voucher"
icon_state = "security_voucher_utility"
#define HOS_PRIMARY_MARKINGS " This one's markings indicate that it was issued to the Head of Security."
/proc/retarget_hos_primary_objectives(obj/item/weapon_path, objective_name)
for(var/datum/objective/objective as anything in GLOB.objectives)
if(!istype(objective, /datum/objective/steal))
continue
var/datum/objective/steal/steal_objective = objective
if(!istype(steal_objective.targetinfo, /datum/objective_item/steal/hoslaser))
continue
steal_objective.steal_target = weapon_path
steal_objective.explanation_text = "Steal [objective_name], the head of security's service weapon."
for(var/datum/mind/owner as anything in steal_objective.get_owners())
if(!owner.current)
continue
to_chat(owner.current, span_notice("Your objective has been updated: [steal_objective.explanation_text]"))
for(var/datum/antagonist/antag as anything in owner.antag_datums)
antag.update_static_data(owner.current)
/obj/item/gun/energy/e_gun/hos/hos_primary
desc = parent_type::desc + HOS_PRIMARY_MARKINGS
/obj/item/gun/ballistic/shotgun/automatic/combat/compact/hos_primary
desc = parent_type::desc + HOS_PRIMARY_MARKINGS
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/obj/projectile/bullet/security/smart
name = "smart 9x19mm Murphy bullet"
/obj/projectile/bullet/security/smart/prehit_pierce(atom/target)
if(isliving(target) && HAS_TRAIT(target, TRAIT_MINDSHIELD))
return PROJECTILE_PIERCE_PHASE
return ..()
/obj/item/ammo_casing/security/ready_proj(atom/target, mob/living/user, quiet, zone_override = "", atom/fired_from)
if(istype(fired_from, /obj/item/gun/ballistic/automatic/pistol/sec_glock/smart))
QDEL_NULL(loaded_projectile)
loaded_projectile = new /obj/projectile/bullet/security/smart(src)
return ..()
/obj/item/gun/ballistic/automatic/pistol/sec_glock/smart
name = "\improper Smart Pistol"
desc = parent_type::desc + " This model is a new prototype that uses a compact IFF package to guide rounds past mindshield-implanted targets." + HOS_PRIMARY_MARKINGS
icon = 'modular_skyrat/modules/modular_weapons/icons/obj/company_and_or_faction_based/nanotrasen_system_inc/pistol.dmi'
icon_state = "firefly"
base_icon_state = "firefly"
projectile_damage_multiplier = 0.9
show_bolt_icon = FALSE
mag_display = FALSE
var/firefly_slide_animating = FALSE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/obj/item/gun/ballistic/automatic/pistol/sec_glock/smart/add_seclight_point()
AddComponent(/datum/component/seclite_attachable, \
starting_light = new /obj/item/flashlight/seclite(src), \
is_light_removable = FALSE)
/obj/item/gun/ballistic/automatic/pistol/sec_glock/smart/update_overlays()
. = ..()
if(magazine && !internal_magazine)
. += "firefly_mag"
var/datum/component/seclite_attachable/seclite = GetComponent(/datum/component/seclite_attachable)
if(seclite?.light)
var/light_state = seclite.light.light_on ? "on" : "off"
. += "firefly-light_[light_state]"
if(!firefly_slide_animating)
. += bolt_locked ? "firefly_bolt_locked" : "firefly_bolt"
/obj/item/gun/ballistic/automatic/pistol/sec_glock/smart/shoot_live_shot(mob/living/user, pointblank = FALSE, atom/pbtarget = null, message = TRUE)
. = ..()
recoil_firefly_slide()
/obj/item/gun/ballistic/automatic/pistol/sec_glock/smart/proc/recoil_firefly_slide()
firefly_slide_animating = TRUE
update_appearance(UPDATE_OVERLAYS)
var/atom/movable/flick_visual/slide = flick_overlay_view(mutable_appearance(icon, "firefly_bolt", layer + 0.1), 0.75)
if(slide)
animate(slide, pixel_w = -3, time = 0.375)
animate(pixel_w = 0, time = 0.375)
addtimer(CALLBACK(src, PROC_REF(reset_firefly_slide_recoil)), 0.75)
/obj/item/gun/ballistic/automatic/pistol/sec_glock/smart/proc/reset_firefly_slide_recoil()
firefly_slide_animating = FALSE
update_appearance(UPDATE_OVERLAYS)
/obj/item/gun/ballistic/revolver/c38/the_law
name = "\improper The Law"
desc = "A custom modified .38 Special revolver, it seems far heavier than standard models." + HOS_PRIMARY_MARKINGS
icon = 'modular_zubbers/icons/obj/weapons/hos_revolver.dmi'
icon_state = "the_law"
base_icon_state = "the_law"
projectile_damage_multiplier = 1.1
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/obj/item/storage/belt/holster/detective/full/ert/the_law
desc = parent_type::desc + HOS_PRIMARY_MARKINGS
/obj/item/storage/belt/holster/detective/full/ert/the_law/PopulateContents()
generate_items_inside(list(
/obj/item/ammo_box/speedloader/c38 = 3,
/obj/item/gun/ballistic/revolver/c38/the_law = 1,
), src)
/obj/item/hos_primary_case
name = "head of security's service weapon case"
desc = "A secure gun case containing one of the Head of Security's service weapons."
icon = 'modular_skyrat/modules/modular_weapons/icons/obj/gunsets.dmi'
icon_state = "guncase"
worn_icon = 'modular_skyrat/modules/modular_weapons/icons/mob/worn/cases.dmi'
worn_icon_state = "darkcase"
material_flags = NONE
w_class = WEIGHT_CLASS_NORMAL
/// Prevents double redemption if two interactions race each other.
var/redeemed = FALSE
/obj/item/hos_primary_case/click_alt(mob/user)
try_redeem(user)
return CLICK_ACTION_SUCCESS
/obj/item/hos_primary_case/attack_self(mob/user)
try_redeem(user)
/obj/item/hos_primary_case/add_stealing_item_objective()
return add_item_to_steal(src, /obj/item/gun/energy/e_gun/hos)
/obj/item/hos_primary_case/proc/try_redeem(mob/user)
if(redeemed || QDELETED(src))
return
if(!isliving(user))
return
var/mob/living/redeemer = user
if(redeemer.incapacitated)
return
var/static/list/primary_options
if(!primary_options)
var/datum/radial_menu_choice/x01_option = new
x01_option.image = image(icon = 'icons/obj/weapons/guns/energy.dmi', icon_state = "hoslaser")
x01_option.info = span_boldnotice("The Head of Security's unique three-mode energy gun.")
var/datum/radial_menu_choice/shotgun_option = new
shotgun_option.image = image(icon = 'icons/obj/weapons/guns/ballistic.dmi', icon_state = "cshotgunc")
shotgun_option.info = span_boldnotice("A miniaturized combat shotgun.")
var/datum/radial_menu_choice/smart_pistol_option = new
smart_pistol_option.image = image(icon = 'modular_skyrat/modules/modular_weapons/icons/obj/company_and_or_faction_based/nanotrasen_system_inc/pistol.dmi', icon_state = "firefly")
smart_pistol_option.info = span_boldnotice("A Murphy-pattern pistol that fires past mindshield-implanted targets.")
var/datum/radial_menu_choice/the_law_option = new
the_law_option.image = image(icon = 'modular_zubbers/icons/obj/weapons/hos_revolver.dmi', icon_state = "the_law")
the_law_option.info = span_boldnotice("The Law, an modified Detective Special that hits harder than standard models.")
primary_options = list(
"X-01 MultiPhase Energy Gun" = x01_option,
"Compact Shotgun" = shotgun_option,
"Smart Pistol" = smart_pistol_option,
"The Law" = the_law_option,
)
var/selection = show_radial_menu(redeemer, src, primary_options, custom_check = CALLBACK(src, PROC_REF(check_redeem_menu), redeemer), radius = 38, require_near = TRUE, tooltips = TRUE)
if(!selection || redeemed || QDELETED(src))
return
var/spawn_path
var/objective_path
var/objective_name
switch(selection)
if("X-01 MultiPhase Energy Gun")
spawn_path = /obj/item/gun/energy/e_gun/hos/hos_primary
objective_name = "the X-01 MultiPhase Energy Gun"
if("Compact Shotgun")
spawn_path = /obj/item/gun/ballistic/shotgun/automatic/combat/compact/hos_primary
objective_name = "the compact shotgun"
if("Smart Pistol")
spawn_path = /obj/item/gun/ballistic/automatic/pistol/sec_glock/smart
objective_name = "the Smart Pistol"
if("The Law")
spawn_path = /obj/item/storage/belt/holster/detective/full/ert/the_law
objective_path = /obj/item/gun/ballistic/revolver/c38/the_law
objective_name = "\"The Law\""
else
return
objective_path ||= spawn_path
redeemed = TRUE
var/obj/item/chosen_item = new spawn_path(drop_location())
redeemer.put_in_hands(chosen_item)
retarget_hos_primary_objectives(objective_path, objective_name)
balloon_alert(redeemer, "selected [LOWER_TEXT(selection)]")
qdel(src)
/obj/item/hos_primary_case/proc/check_redeem_menu(mob/living/redeemer)
if(!istype(redeemer))
return FALSE
if(redeemer.incapacitated)
return FALSE
if(QDELETED(src) || redeemed)
return FALSE
if(!redeemer.Adjacent(src))
return FALSE
return TRUE
#undef HOS_PRIMARY_MARKINGS
/obj/machinery/vending/security/Initialize(mapload)
. = ..()
AddElement(/datum/element/voucher_redeemer, /obj/item/security_voucher/primary, /datum/voucher_set/security/primary)
@@ -4,4 +4,6 @@
/obj/structure/closet/secure_closet/warden/PopulateContents()
. = ..()
if(!locate(/obj/item/clothing/gloves/kaza_ruk/sec/warden) in src)
new /obj/item/clothing/gloves/kaza_ruk/sec/warden(src)
new /obj/item/storage/toolbox/guncase/skyrat/pistol/hos_glock(src)
Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

+1
View File
@@ -9281,6 +9281,7 @@
#include "modular_zubbers\code\game\gamemodes\fleshmind\tyrant\tyrant.dm"
#include "modular_zubbers\code\game\gamemodes\fleshmind\tyrant\tyrant_ai.dm"
#include "modular_zubbers\code\game\gamemodes\objectives\gimmick.dm"
#include "modular_zubbers\code\game\gamemodes\objectives\overrides.dm"
#include "modular_zubbers\code\game\Items\big_bertha_shield.dm"
#include "modular_zubbers\code\game\Items\coins.dm"
#include "modular_zubbers\code\game\Items\lipstick.dm"