Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Firearm Condition and Jamming #4322

Draft
wants to merge 22 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3403ebc
Guns can jam now. That was easy enough, time for the hard part.
SomeguyManperson Feb 5, 2025
ba94020
Initial design for jamming, guns now jam. sometimes.
SomeguyManperson Feb 9, 2025
cb0dfcc
desc work and better numbers
SomeguyManperson Feb 9, 2025
f0dbf71
initial generic values & repair kit framework
SomeguyManperson Feb 15, 2025
01ab5d0
Repair kit work. it works now. probably. no sprite, though.
SomeguyManperson Feb 19, 2025
985c2b7
forgor
SomeguyManperson Feb 19, 2025
c489c79
whoops
SomeguyManperson Feb 21, 2025
7c2d51b
Merge remote-tracking branch 'origin/master' into aspacerisawake
SomeguyManperson Mar 5, 2025
668866d
waugh
SomeguyManperson Mar 5, 2025
836c484
Numbers! They're probably fine. Mostly. Aiming for about 3-5 magazine…
SomeguyManperson Mar 6, 2025
5bba509
Player-accessible repair kits, accidents now occur from the gun inste…
SomeguyManperson Mar 6, 2025
ee40d7a
Flavortext runover, indev cleaning and a slight price reduction. We'l…
SomeguyManperson Mar 6, 2025
1e0b737
Testing fixes, probably feature complete enough
SomeguyManperson Mar 6, 2025
40f0a94
Underbarrels can't jam, otherwise something really emberassing could …
SomeguyManperson Mar 6, 2025
290273c
Surplus bullets lose their damage reduction in exchange for the doubl…
SomeguyManperson Mar 6, 2025
fd5d871
Switches shotgun wear to automatic shotguns only. Pump action shotgun…
SomeguyManperson Mar 6, 2025
3a55a8d
better sprite. Not like this one is being used right now.
SomeguyManperson Mar 6, 2025
a7fda0f
wear rate on marksman rifles for readability
SomeguyManperson Mar 6, 2025
1156cfa
pistol readability, also obliterates duplicate candor/penix definitions
SomeguyManperson Mar 6, 2025
b77ac7d
rattlesnake statted as an SMG
SomeguyManperson Mar 6, 2025
db02f6f
Name switch for readability repair kit > maint kit in code
SomeguyManperson Mar 6, 2025
e519b38
Maintenance ND now checks if there is a chambered round OR a magazine…
SomeguyManperson Mar 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
allowed_ammo_types = list(
/obj/item/ammo_box/magazine/internal/shot/underbarrel,
)
wear_rate = 0

/obj/item/attachment/gun/ballistic/shotgun
name = "underbarrel shotgun"
Expand Down Expand Up @@ -74,6 +75,7 @@
allowed_ammo_types = list(
/obj/item/ammo_box/magazine/m22lr_himehabu/hognose,
)
wear_rate = 0

/obj/item/ammo_box/magazine/m22lr_himehabu/hognose
name = "Hognose magazine (.22 LR)"
Expand Down
39 changes: 39 additions & 0 deletions code/game/objects/items/gun_maint_kit.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/obj/item/gun_maint_kit
name = "firearm maintenance kit"
desc = "A toolkit containing everything needed to scrub the frontier-gunk out of a gun and return it to a mostly-usable state. Chemicals included in the kit are expended in a cleaning cycle, preventing re-use more than a few times."
icon = 'icons/obj/improvised.dmi'
icon_state = "kitsuitcase"
w_class = WEIGHT_CLASS_BULKY //no carrying these around, sorry :(
custom_materials = list(/datum/material/iron = 500)
/// Amount of wear removed from a gun on use
var/wear_reduction = 60
/// Number of times this gun fixer can be used
var/uses = 5

/obj/item/gun_maint_kit/examine(mob/user)
. = ..()
. += "it can be used [uses] more times."

/obj/item/gun_maint_kit/afterattack(atom/target, mob/user, proximity)
if(!proximity)
return
if(!uses)
to_chat(user, span_warning("[src] is out of uses!"))
return
var/obj/item/gun/ballistic/fixable = target
if(!istype(fixable))
return
if(!fixable.gun_wear)
to_chat(user, span_notice("[fixable] is already in good condition!"))
return
fixable.add_overlay(GLOB.cleaning_bubbles)
playsound(src, 'sound/misc/slip.ogg', 15, TRUE, -8)
user.visible_message(span_notice("[user] starts to wipe down [fixable] with [src]!"), span_notice("You start to give [fixable] a deep clean with [src]..."))
if(!do_after(user, 20 SECONDS, target = target, extra_checks = CALLBACK(fixable, TYPE_PROC_REF(/obj/item/gun/ballistic, accidents_happen), user)))
fixable.cut_overlay(GLOB.cleaning_bubbles)
return
fixable.cut_overlay(GLOB.cleaning_bubbles)
fixable.wash(CLEAN_SCRUB)
fixable.gun_wear = clamp(fixable.gun_wear - wear_reduction, 0, 300)
user.visible_message(span_notice("[user] finishes cleaning [fixable]!"), span_notice("You finish cleaning [fixable], [fixable.gun_wear < wear_reduction ? "and it's in pretty good condition" : "though it would benefit from another cycle"]."))
uses--
7 changes: 7 additions & 0 deletions code/modules/cargo/packs/sec_supply.dm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@
cost = 150
crate_name = "sandbag crate"

/datum/supply_pack/sec_supply/maintenance_kit
name = "Firearm Maintenance Kit"
desc = "Contains a five-use firearm maintenance kit, useful for cleaning blood, sand, and mud out of guns."
contains = list(/obj/item/gun_maint_kit)
cost = 100 //Price check this later. It's probably fine but it might be okay if it's a little more expensive
crate_name = "maintenance kit crate"

/datum/supply_pack/sec_supply/flashbangs
name = "Flashbangs Crate"
desc = "Contains seven flashbangs for use in door breaching and riot control."
Expand Down
2 changes: 2 additions & 0 deletions code/modules/projectiles/ammunition/_ammo_casing.dm
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
var/click_cooldown_override = 0
///If true, overrides the bouncing sfx from the turf to this one
var/list/bounce_sfx_override
///Multiplier for weapon gun_wear
var/wear_modifier = 1

///What this casing can be stacked into.
var/obj/item/ammo_box/magazine/stack_type = /obj/item/ammo_box/magazine/ammo_stack
Expand Down
3 changes: 3 additions & 0 deletions code/modules/projectiles/ammunition/_firing.dm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
user.changeNext_move(click_cooldown_override)

user.newtonian_move(get_dir(target, user))
var/obj/item/gun/ballistic/foulmouth = fired_from
if(istype(foulmouth))
foulmouth.gun_wear = round(clamp(foulmouth.gun_wear + foulmouth.wear_rate * wear_modifier, 0, 300), 0.01)
update_appearance()
return TRUE

Expand Down
3 changes: 3 additions & 0 deletions code/modules/projectiles/ammunition/ballistic/pistol.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
desc = "A 10mm surplus bullet casing."
bullet_skin = "surplus"
projectile_type = /obj/projectile/bullet/c10mm/surplus
wear_modifier = 2

/obj/item/ammo_casing/c10mm/ap
name = "10mm armor-piercing bullet casing"
Expand Down Expand Up @@ -46,6 +47,7 @@
desc = "A 9mm surplus bullet casing."
bullet_skin = "surplus"
projectile_type = /obj/projectile/bullet/c9mm/surplus
wear_modifier = 2

/obj/item/ammo_casing/c9mm/ap
name = "9mm armor-piercing bullet casing"
Expand Down Expand Up @@ -80,6 +82,7 @@
desc = "A .45 surplus bullet casing."
bullet_skin = "surplus"
projectile_type = /obj/projectile/bullet/c45/surplus
wear_modifier = 2

/obj/item/ammo_casing/c45/ap
name = ".45 armor-piercing bullet casing"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
name = ".38 surplus bullet casing"
desc = "A .38 surplus bullet casing."
projectile_type = /obj/projectile/bullet/c38/surplus
wear_modifier = 2

/obj/item/ammo_casing/c38/trac
name = ".38 TRAC bullet casing"
Expand Down
2 changes: 2 additions & 0 deletions code/modules/projectiles/ammunition/ballistic/smg.dm
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
caliber = "4.6x30mm"
projectile_type = /obj/projectile/bullet/c46x30mm/recycled
stack_size = 15
wear_modifier = 2

/obj/item/ammo_casing/c46x30mm/ap
name = "4.6x30mm armor-piercing bullet casing"
Expand Down Expand Up @@ -83,6 +84,7 @@
name = "5.56mm HITP caseless surplus round"
desc = "A 5.56mm HITP caseless surplus round."
projectile_type = /obj/projectile/bullet/c556mm/surplus
wear_modifier = 2

/obj/item/ammo_casing/caseless/c556mm/ap
name = "5.56mm HITP caseless armor-piercing round"
Expand Down
63 changes: 61 additions & 2 deletions code/modules/projectiles/guns/ballistic.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
spawn_no_ammo = TRUE; \
}


#define JAM_CHANCE_MINOR 10
#define JAM_GRACE_MINOR 4
#define JAM_CHANCE_MAJOR 30

///Subtype for any kind of ballistic gun
///This has a shitload of vars on it, and I'm sorry for that, but it does make making new subtypes really easy
/obj/item/gun/ballistic
Expand All @@ -18,6 +23,16 @@
safety = TRUE
// when we load the gun, should it instantly chamber the next round?
var/always_chambers = FALSE
/// How utterly fucked the gun is. High gun_wear can cause failure to cycle rounds in some guns
var/gun_wear = 0
/// How much gun_wear is generated when we shoot. Increased when using surplus rounds
var/wear_rate = 1 // 60 to malfunction, 180 to critical
/// Number of times we have successfully fired since the last time the the gun has jammed. Low but not abysmal condition will only jam so often.
var/last_jam = 0
/// Gun will start to jam at this level of wear
var/wear_minor_threshold = 60
/// Gun will start to jam more at this level of wear. The grace period between jams is also removed for extra fun
var/wear_major_threshold = 180

min_recoil = 0.1

Expand Down Expand Up @@ -119,10 +134,23 @@
chambered = null
else if(empty_chamber)
chambered = null
if (chamber_next_round && (magazine?.max_ammo > 1))
if (chamber_next_round && (magazine?.max_ammo > 1) && !condition_check(from_firing))
chamber_round()
SEND_SIGNAL(src, COMSIG_GUN_CHAMBER_PROCESSED)

/// Handles weapon condition. Returning TRUE prevents process_chamber from automatically loading a new round
/obj/item/gun/ballistic/proc/condition_check(from_firing = TRUE)
if(bolt_type == BOLT_TYPE_NO_BOLT || !from_firing || !magazine.ammo_count(FALSE)) //The revolver is one of the most reliable firearms ever designed, as long as you don't need to fire any more than six bullets at something. Which, of course, you do not.
return FALSE
last_jam++
if(gun_wear < wear_minor_threshold)
return FALSE
if(gun_wear >= wear_major_threshold ? prob(JAM_CHANCE_MAJOR) : prob(JAM_CHANCE_MINOR) && last_jam >= JAM_GRACE_MINOR)
bolt_locked = TRUE
last_jam = 0 // sighs and erases number on whiteboard
playsound(src, 'sound/weapons/gun/general/dry_fire_old.ogg', 50, TRUE, -15) //click. uhoh.
return TRUE

///Used to chamber a new round and eject the old one
/obj/item/gun/ballistic/proc/chamber_round(keep_bullet = FALSE)
if (chambered || !magazine)
Expand Down Expand Up @@ -345,8 +373,20 @@
. += "It does not seem to have a round chambered."
if (bolt_locked)
. += "The [bolt_wording] is locked back and needs to be released before firing."
if(bolt_type != BOLT_TYPE_NO_BOLT)
if(bolt_type != BOLT_TYPE_NO_BOLT && wear_rate)
. += "You can [bolt_wording] [src] by pressing the <b>unique action</b> key. By default, this is <b>space</b>"
var/conditionstr = span_boldwarning("critical")
var/minorhalf = wear_minor_threshold / 2
var/majorhalf = wear_minor_threshold + (wear_major_threshold-wear_minor_threshold) / 2
if(gun_wear <= minorhalf)
conditionstr = span_green("good")
else if(gun_wear <= wear_minor_threshold)
conditionstr = span_nicegreen("decent") //nicegreen is less neon than green so it looks less :)))
else if(gun_wear <= majorhalf)
conditionstr = span_red("poor")
else if(gun_wear <= wear_major_threshold) //TTD: switch doesn't play nice with variables but this sucks
conditionstr = span_warning("terrible")
. += "it is in [conditionstr] condition[gun_wear >= wear_minor_threshold ? gun_wear >= wear_major_threshold ? " and will suffer constant malfunctions" : " and will suffer from regular malfunctions" :""]."

///Gets the number of bullets in the gun
/obj/item/gun/ballistic/proc/get_ammo(countchambered = TRUE)
Expand Down Expand Up @@ -379,3 +419,22 @@
. = ..()
process_chamber(empty_chamber,TRUE)

/// Remember: you can always trust a loaded gun to go off at least once.
/obj/item/gun/ballistic/proc/accidents_happen(mob/darwin)
. = TRUE
if(!magazine && !chambered)
return
if(internal_magazine && !magazine.ammo_count(TRUE))
return
if(prob(0.5)) //this gets called I think once per decisecond so we don't really want a high chance here
if(safety)
toggle_safety(darwin)
to_chat(darwin, span_warning("You bump the safety-"))
return
if(!chambered)
to_chat(darwin, span_warning("You accidentally rack the [bolt_wording] of [src]-"))
chamber_round()
return
to_chat(darwin, span_boldwarning("The trigger on [src] gets caught-"))
unsafe_shot(darwin)
return FALSE
2 changes: 2 additions & 0 deletions code/modules/projectiles/guns/ballistic/assault.dm
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
gunslinger_spread_bonus = 16

light_range = 2
wear_rate = 0.6 // 100 to malfunction, 300 to critical

/obj/item/gun/ballistic/automatic/assault/skm
name = "\improper SKM-24"
Expand Down Expand Up @@ -96,6 +97,7 @@
icon_state = "skm_pirate"
item_state = "skm_pirate"
manufacturer = MANUFACTURER_NONE
wear_rate = 1.2 // 50 to malfunction, 150 to critical

/obj/item/gun/ballistic/automatic/assault/skm/inteq
name = "\improper SKM-44"
Expand Down
1 change: 1 addition & 0 deletions code/modules/projectiles/guns/ballistic/automatic.dm
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@
actions_types = list()
show_magazine_on_sprite = TRUE
weapon_weight = WEAPON_LIGHT
wear_rate = 5 //it's a. piece of shit.
1 change: 1 addition & 0 deletions code/modules/projectiles/guns/ballistic/gauss.dm
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@
wield_slowdown = HEAVY_RIFLE_SLOWDOWN
wield_delay = 1 SECONDS
fire_select_icon_state_prefix = "pellet_"
wear_rate = 0 // magnetically accelerated, very little if any wear to the gun
1 change: 1 addition & 0 deletions code/modules/projectiles/guns/ballistic/hmg.dm
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
/obj/structure/railing,
/obj/structure/flippedtable
)
wear_rate = 0.2 //300 to malfunction, 900 to critical


/obj/item/gun/ballistic/automatic/hmg/Initialize()
Expand Down
1 change: 1 addition & 0 deletions code/modules/projectiles/guns/ballistic/marksman.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
min_recoil = 0.1

light_range = 2
wear_rate = 1
45 changes: 1 addition & 44 deletions code/modules/projectiles/guns/ballistic/pistol.dm
Original file line number Diff line number Diff line change
Expand Up @@ -24,56 +24,13 @@

muzzleflash_iconstate = "muzzle_flash_light"
light_range = 1
wear_rate = 1

refused_attachments = list(
/obj/item/attachment/gun,
/obj/item/attachment/sling
)


/obj/item/gun/ballistic/automatic/pistol/candor
name = "\improper Candor"
desc = "A classic semi-automatic handgun, widely popular throughout the Frontier. An engraving on the slide marks it as a product of Hunter's Pride. Chambered in .45."
icon_state = "candor"
item_state = "hp_generic"
icon = 'icons/obj/guns/manufacturer/hunterspride/48x32.dmi'
lefthand_file = 'icons/obj/guns/manufacturer/hunterspride/lefthand.dmi'
righthand_file = 'icons/obj/guns/manufacturer/hunterspride/righthand.dmi'
mob_overlay_icon = 'icons/obj/guns/manufacturer/hunterspride/onmob.dmi'

default_ammo_type = /obj/item/ammo_box/magazine/m45
allowed_ammo_types = list(
/obj/item/ammo_box/magazine/m45,
)
fire_sound = 'sound/weapons/gun/pistol/candor.ogg'
rack_sound = 'sound/weapons/gun/pistol/candor_cocked.ogg'
lock_back_sound = 'sound/weapons/gun/pistol/slide_lock.ogg'
bolt_drop_sound = 'sound/weapons/gun/pistol/candor_cocked.ogg'
manufacturer = MANUFACTURER_HUNTERSPRIDE
load_sound = 'sound/weapons/gun/pistol/candor_reload.ogg'
load_empty_sound = 'sound/weapons/gun/pistol/candor_reload.ogg'
eject_sound = 'sound/weapons/gun/pistol/candor_unload.ogg'
eject_empty_sound = 'sound/weapons/gun/pistol/candor_unload.ogg'
show_magazine_on_sprite = TRUE

NO_MAG_GUN_HELPER(automatic/pistol/candor)

/obj/item/gun/ballistic/automatic/pistol/candor/factory //also give this to the srm, their candors should probably look factory fresh from how well taken care of they are
desc = "A classic semi-automatic handgun, widely popular throughout the Frontier. An engraving on the slide marks it as a product of 'Hunter's Pride Arms and Ammunition'. This example has been kept in especially good shape, and may as well be fresh out of the workshop. Chambered in .45."
item_state = "hp_generic_fresh"

NO_MAG_GUN_HELPER(automatic/pistol/candor/factory)

/obj/item/gun/ballistic/automatic/pistol/candor/factory/update_overlays()
. = ..()
. += "[initial(icon_state)]_factory"

/obj/item/gun/ballistic/automatic/pistol/candor/phenex
name = "\improper HP Phenex"
desc = "A uniquely modified version of the Candor, famously created by Hunter's Pride. Named after the daemonic Phoenix of legend that the Ashen Huntsman had once slain, this hell-kissed weapon is more visually intimidating than its original counterpart, but mechanically acts the same. Chambered in .45."
icon_state = "phenex"
item_state = "hp_phenex"

/obj/item/gun/ballistic/automatic/pistol/commissar
name = "\improper Commissar"
desc = "A Nanotrasen-issue handgun, modified with a voice box to further enhance its effectiveness in troop discipline."
Expand Down
2 changes: 2 additions & 0 deletions code/modules/projectiles/guns/ballistic/shotgun.dm
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
gunslinger_recoil_bonus = -1

min_recoil = 0.1
wear_rate = 0

/obj/item/gun/ballistic/shotgun/blow_up(mob/user)
if(chambered && chambered.BB)
Expand All @@ -67,6 +68,7 @@
semi_auto = TRUE

gunslinger_recoil_bonus = 1
wear_rate = 2 //30 to malfunction, 90 to critical

//Dual Feed Shotgun

Expand Down
4 changes: 4 additions & 0 deletions code/modules/projectiles/guns/ballistic/smg.dm
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

gunslinger_recoil_bonus = 2
gunslinger_spread_bonus = 16
wear_rate = 0.5 // 120 to malfunction, 360 to critical

/obj/item/gun/ballistic/automatic/smg/wt550
name = "\improper WT-550 Automatic Rifle"
Expand Down Expand Up @@ -101,6 +102,9 @@

wield_delay = 0.6 SECONDS
wield_slowdown = SMG_SLOWDOWN

wear_rate = 0.8 //75 to malfunction, 225 to critical

unique_attachments = list(
/obj/item/attachment/foldable_stock
)
Expand Down
2 changes: 2 additions & 0 deletions code/modules/projectiles/guns/ballistic/toy.dm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
manufacturer = MANUFACTURER_NANOTRASEN
recoil = -10 //its a toy...
recoil_unwielded = -10
wear_rate = 0


/obj/item/gun/ballistic/automatic/toy/pistol
Expand Down Expand Up @@ -74,6 +75,7 @@
pb_knockback = 0
recoil = -10 //its a toy...
recoil_unwielded = -10
wear_rate = 0

/obj/item/gun/ballistic/shotgun/toy/process_chamber(empty_chamber = 0, from_firing = TRUE, chamber_next_round = TRUE, atom/shooter)
. = ..()
Expand Down
Loading
Loading