diff --git a/_maps/shuttles/hunter/hunter_russian.dmm b/_maps/shuttles/hunter/hunter_russian.dmm
index 9a57e48a871b1..14f712621e1d9 100644
--- a/_maps/shuttles/hunter/hunter_russian.dmm
+++ b/_maps/shuttles/hunter/hunter_russian.dmm
@@ -329,6 +329,7 @@
},
/obj/item/gun/ballistic/shotgun/doublebarrel/improvised/sawn{
name = "\improper TOZ-1";
+ reinforced = 1;
pixel_y = -7
},
/obj/effect/decal/cleanable/robot_debris{
@@ -624,8 +625,13 @@
},
/obj/item/gun/ballistic/shotgun/doublebarrel/improvised/sawn{
name = "\improper TOZ-1";
+ reinforced = 1;
pixel_y = -4
},
+/obj/item/hacksaw{
+ pixel_x = -2;
+ pixel_y = 8
+ },
/turf/open/floor/plasteel/dark,
/area/shuttle/hunter)
"Ec" = (
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index d82eac619e6ca..dabb8ba8f6337 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -213,6 +213,7 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
#define BOLT_TYPE_NO_BOLT 3
#define BOLT_TYPE_LOCKING 4
#define BOLT_TYPE_PUMP 5 //Requires 2 hands to pump, but standard
+#define BOLT_TYPE_TWO_STEP 6 //Pump, but each interaction toggles bolt between locked and unlocked
// Sawn off nerfs
#define SAWN_OFF_ACC_PENALTY 25
#define SAWN_OFF_RECOIL 1
diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm
index 88d6d11e24018..f64bb5f29b02c 100644
--- a/code/datums/components/crafting/recipes.dm
+++ b/code/datums/components/crafting/recipes.dm
@@ -371,6 +371,19 @@
subcategory = CAT_AMMO
dangerous_craft = TRUE
+/datum/crafting_recipe/improvisedglassslug
+ name = "Glasspack Shotgun Shell"
+ result = /obj/item/ammo_casing/shotgun/improvised/glasspack
+ reqs = list(/obj/item/grenade/chem_grenade = 1,
+ /obj/item/stack/sheet/glass = 1,
+ /obj/item/stack/cable_coil = 1,
+ /datum/reagent/fuel = 10)
+ tools = list(TOOL_SCREWDRIVER)
+ time = 5
+ category = CAT_WEAPONRY
+ subcategory = CAT_AMMO
+ dangerous_craft = TRUE
+
/datum/crafting_recipe/laserslug
name = "Scatter Laser Shell"
result = /obj/item/ammo_casing/shotgun/laserslug
@@ -383,6 +396,99 @@
subcategory = CAT_AMMO
dangerous_craft = TRUE
+/datum/crafting_recipe/a762improv
+ name = "Improvised 7.62 Cartridge"
+ result = /obj/item/ammo_casing/a762/improv
+ reqs = list(/obj/item/grenade/chem_grenade = 1,
+ /obj/item/stack/sheet/iron = 1,
+ /obj/item/stack/cable_coil = 1,
+ /datum/reagent/fuel = 10)
+ tools = list(TOOL_SCREWDRIVER)
+ time = 5
+ category = CAT_WEAPONRY
+ subcategory = CAT_AMMO
+ dangerous_craft = TRUE
+
+/datum/crafting_recipe/a762hotload
+ name = "Hot-Loaded 7.62 Cartridge"
+ result = /obj/item/ammo_casing/a762/improv/hotload
+ reqs = list(/obj/item/grenade/chem_grenade = 1,
+ /obj/item/stack/sheet/iron = 1,
+ /obj/item/stack/cable_coil = 1,
+ /datum/reagent/blackpowder = 10)
+ tools = list(TOOL_SCREWDRIVER)
+ time = 5
+ category = CAT_WEAPONRY
+ subcategory = CAT_AMMO
+ dangerous_craft = TRUE
+
+/datum/crafting_recipe/improv9mm_pack
+ name = "Improvised 9mm Ammo Pack"
+ result = /obj/item/ammo_box/pouch/c9mm/improv
+ reqs = list(/obj/item/grenade/chem_grenade = 2,
+ /obj/item/stack/rods = 3,
+ /obj/item/stack/cable_coil = 3,
+ /datum/reagent/fuel = 20,
+ /obj/item/paper = 1)
+ tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
+ time = 15
+ category = CAT_WEAPONRY
+ subcategory = CAT_AMMO
+ dangerous_craft = TRUE
+
+/datum/crafting_recipe/improv10mm_pack
+ name = "Improvised 10mm Ammo Pack"
+ result = /obj/item/ammo_box/pouch/c10mm/improv
+ reqs = list(/obj/item/grenade/chem_grenade = 2,
+ /obj/item/stack/sheet/iron = 2,
+ /obj/item/stack/cable_coil = 2,
+ /datum/reagent/fuel = 20,
+ /obj/item/paper = 1)
+ tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
+ time = 15
+ category = CAT_WEAPONRY
+ subcategory = CAT_AMMO
+ dangerous_craft = TRUE
+
+/datum/crafting_recipe/improv38_pack
+ name = "Improvised .38 Ammo Pack"
+ result = /obj/item/ammo_box/pouch/c38/improv
+ reqs = list(/obj/item/grenade/chem_grenade = 2,
+ /obj/item/stack/rods = 2,
+ /obj/item/stack/cable_coil = 2,
+ /datum/reagent/fuel = 20,
+ /obj/item/paper = 1)
+ tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
+ time = 15
+ category = CAT_WEAPONRY
+ subcategory = CAT_AMMO
+ dangerous_craft = TRUE
+
+/datum/crafting_recipe/improv357
+ name = "Improvised .357 Cartridge"
+ result = /obj/item/ammo_casing/a357/improv
+ reqs = list(/obj/item/grenade/chem_grenade = 1,
+ /obj/item/stack/sheet/iron = 1,
+ /obj/item/stack/cable_coil = 2,
+ /datum/reagent/blackpowder = 10)
+ tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
+ time = 5
+ category = CAT_WEAPONRY
+ subcategory = CAT_AMMO
+ dangerous_craft = TRUE
+
+/datum/crafting_recipe/pipesmg_mag
+ name = "Pipe Repeater Magazine"
+ result = /obj/item/ammo_box/magazine/pipem9mm
+ reqs = list(/obj/item/grenade/chem_grenade = 1,
+ /obj/item/stock_parts/matter_bin = 1,
+ /obj/item/stack/cable_coil = 3,
+ /obj/item/stack/package_wrap = 3)
+ tools = list(TOOL_WELDER, TOOL_WIRECUTTER)
+ time = 50
+ category = CAT_WEAPONRY
+ subcategory = CAT_AMMO
+
/datum/crafting_recipe/arrow
name = "Arrow"
result = /obj/item/ammo_casing/caseless/arrow/wood
@@ -428,8 +534,38 @@
reqs = list(/obj/item/weaponcrafting/receiver = 1,
/obj/item/pipe = 1,
/obj/item/weaponcrafting/stock = 1,
+ /obj/item/assembly/igniter = 1,
/obj/item/stack/package_wrap = 5)
- tools = list(TOOL_SCREWDRIVER)
+ tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
+ time = 100
+ category = CAT_WEAPONRY
+ subcategory = CAT_WEAPON
+ dangerous_craft = TRUE
+
+/datum/crafting_recipe/piperifle
+ name = "Singleshot Pipe Rifle"
+ result = /obj/item/gun/ballistic/rifle/pipe
+ reqs = list(/obj/item/weaponcrafting/receiver = 1,
+ /obj/item/pipe = 1,
+ /obj/item/weaponcrafting/stock = 1,
+ /obj/item/assembly/igniter = 1,
+ /obj/item/stack/package_wrap = 5)
+ tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
+ time = 100
+ category = CAT_WEAPONRY
+ subcategory = CAT_WEAPON
+ dangerous_craft = TRUE
+
+/datum/crafting_recipe/pipesmg
+ name = "Mag-Fed Pipe Repeater"
+ result = /obj/item/gun/ballistic/automatic/pipe_smg
+ reqs = list(/obj/item/weaponcrafting/receiver = 1,
+ /obj/item/pipe = 2,
+ /obj/item/stack/rods = 2,
+ /obj/item/stack/sheet/wood = 2,
+ /obj/item/assembly/igniter = 1,
+ /obj/item/stack/package_wrap = 5)
+ tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
time = 100
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
diff --git a/code/game/objects/items/shrapnel.dm b/code/game/objects/items/shrapnel.dm
index c068177d18a84..5ef59060bd9a1 100644
--- a/code/game/objects/items/shrapnel.dm
+++ b/code/game/objects/items/shrapnel.dm
@@ -18,6 +18,14 @@
icon = 'icons/obj/ammo.dmi'
icon_state = "s-casing"
item_flags = NONE
+ //Percent chance for bullets that embed to have the DROPDEL flag set on Initialize. There's an insane ammount of clutter otherwise.
+ var/vanish_chance = 45 //Lower = More likely to remain after falling out/failing to embed
+
+/obj/item/shrapnel/bullet/Initialize(mapload)
+ . = ..()
+
+ if(prob(vanish_chance)) //See if a bullet will remain after falling out/failing to embed
+ item_flags = DROPDEL
/obj/item/shrapnel/bullet/c38 // .38 round
name = "\improper .38 bullet"
@@ -25,6 +33,12 @@
/obj/item/shrapnel/bullet/c38/dumdum // .38 DumDum round
name = "\improper .38 DumDum bullet"
embedding = list(embed_chance=70, fall_chance=7, jostle_chance=7, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10)
+ vanish_chance = 60
+
+/obj/item/shrapnel/bullet/shotgun/glass // Improvised glasspack shell
+ name = "glass shard"
+ embedding = list(embed_chance=60, fall_chance=2, jostle_chance=10, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.3, pain_mult=2, jostle_pain_mult=3, rip_time=8)
+ vanish_chance = 75
/obj/projectile/bullet/shrapnel
name = "flying shrapnel shard"
diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm
index 2cb4295ef9c29..5b32766fc59ca 100644
--- a/code/modules/projectiles/ammunition/_ammunition.dm
+++ b/code/modules/projectiles/ammunition/_ammunition.dm
@@ -63,7 +63,8 @@
BB = new projectile_type(src, src)
/obj/item/ammo_casing/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/ammo_box))
+ //Regular boxes of ammo can sweep shells up from the floor, magazines that get insert into guns do not though
+ if(istype(I, /obj/item/ammo_box) && !istype(I, /obj/item/ammo_box/magazine))
var/obj/item/ammo_box/box = I
if(isturf(loc))
var/boolets = 0
diff --git a/code/modules/projectiles/ammunition/ballistic/pistol.dm b/code/modules/projectiles/ammunition/ballistic/pistol.dm
index d3f345b02f0ca..463f2e9258b65 100644
--- a/code/modules/projectiles/ammunition/ballistic/pistol.dm
+++ b/code/modules/projectiles/ammunition/ballistic/pistol.dm
@@ -6,6 +6,14 @@
caliber = "10mm"
projectile_type = /obj/projectile/bullet/c10mm
+/obj/item/ammo_casing/c10mm/improv
+ name = "improvised 10mm bullet casing"
+ desc = "A handmade 10mm bullet casing."
+ caliber = "10mm"
+ projectile_type = /obj/projectile/bullet/c10mm/improv
+ randomspread = TRUE
+ variance = 10 //Shit ammo is inaccurate.
+
/obj/item/ammo_casing/c10mm/ap
name = "10mm armor-piercing bullet casing"
desc = "A 10mm armor-piercing bullet casing."
@@ -29,6 +37,12 @@
caliber = "9mm"
projectile_type = /obj/projectile/bullet/c9mm
+/obj/item/ammo_casing/c9mm/improv
+ name = "improvised 9mm bullet casing"
+ desc = "A handmade 9mm bullet casing."
+ randomspread = TRUE
+ variance = 10 //Shit ammo is inaccurate.
+
/obj/item/ammo_casing/c9mm/ap
name = "9mm armor-piercing bullet casing"
desc = "A 9mm armor-piercing bullet casing."
diff --git a/code/modules/projectiles/ammunition/ballistic/revolver.dm b/code/modules/projectiles/ammunition/ballistic/revolver.dm
index bdae3c8334edf..09fc551674b9c 100644
--- a/code/modules/projectiles/ammunition/ballistic/revolver.dm
+++ b/code/modules/projectiles/ammunition/ballistic/revolver.dm
@@ -12,6 +12,12 @@
caliber = "357"
projectile_type = /obj/projectile/bullet/a357/match
+/obj/item/ammo_casing/a357/improv
+ name = "improv .357 bullet casing"
+ desc = "An improvised .357 bullet casing."
+ projectile_type = /obj/projectile/bullet/a357/improv
+ variance = 15
+
// 7.62x38mmR (Nagant Revolver)
/obj/item/ammo_casing/n762
@@ -77,6 +83,13 @@
icon_state = "sS-casing"
projectile_type = /obj/projectile/bullet/c38/emp
+/obj/item/ammo_casing/c38/improv
+ name = "improv .38 bullet casing"
+ desc = "An improvised .38 bullet casing."
+ caliber = "38"
+ projectile_type = /obj/projectile/bullet/c38/improv
+ variance = 10
+
/obj/item/ammo_casing/caseless/mime
name = "invisible .38 bullet casing"
icon_state = null
diff --git a/code/modules/projectiles/ammunition/ballistic/rifle.dm b/code/modules/projectiles/ammunition/ballistic/rifle.dm
index c06a06ceab05c..729bb9b2678d4 100644
--- a/code/modules/projectiles/ammunition/ballistic/rifle.dm
+++ b/code/modules/projectiles/ammunition/ballistic/rifle.dm
@@ -1,4 +1,4 @@
-// 7.62 (Nagant Rifle)
+// 7.62 (Nagant Rifle / Pipe Rifle)
/obj/item/ammo_casing/a762
name = "7.62 bullet casing"
@@ -7,6 +7,17 @@
caliber = "a762"
projectile_type = /obj/projectile/bullet/a762
+/obj/item/ammo_casing/a762/improv
+ name = "a762 improvised cartridge"
+ desc = "A handmade 7.62 cartidge, made from metal and some other scraps. It reeks of welding fuel."
+ icon_state = "762improv"
+ projectile_type = /obj/projectile/bullet/a762/improv
+
+/obj/item/ammo_casing/a762/improv/hotload
+ name = "7.62 hotload cartridge"
+ desc = "A higher quality handmade 7.62 cartridge. It smells like charcoal."
+ projectile_type = /obj/projectile/bullet/a762/improv/hotload
+
/obj/item/ammo_casing/a762/enchanted
projectile_type = /obj/projectile/bullet/a762_enchanted
diff --git a/code/modules/projectiles/ammunition/ballistic/shotgun.dm b/code/modules/projectiles/ammunition/ballistic/shotgun.dm
index c8c113ce4a47b..08303ee48a03e 100644
--- a/code/modules/projectiles/ammunition/ballistic/shotgun.dm
+++ b/code/modules/projectiles/ammunition/ballistic/shotgun.dm
@@ -5,6 +5,7 @@
desc = "A 12 gauge lead slug."
icon_state = "blshell"
caliber = "shotgun"
+ var/high_power = TRUE
custom_materials = list(/datum/material/iron=4000)
projectile_type = /obj/projectile/bullet/shotgun_slug
@@ -12,6 +13,7 @@
name = "beanbag slug"
desc = "A weak beanbag slug for riot control."
icon_state = "bshell"
+ high_power = FALSE
custom_materials = list(/datum/material/iron=250)
projectile_type = /obj/projectile/bullet/shotgun_beanbag
@@ -19,12 +21,14 @@
name = "incendiary slug"
desc = "An incendiary-coated shotgun slug."
icon_state = "ishell"
+ high_power = FALSE
projectile_type = /obj/projectile/bullet/incendiary/shotgun
/obj/item/ammo_casing/shotgun/dragonsbreath
name = "dragonsbreath shell"
desc = "A shotgun shell which fires a spread of incendiary pellets."
icon_state = "ishell2"
+ high_power = FALSE
projectile_type = /obj/projectile/bullet/incendiary/shotgun/dragonsbreath
pellets = 4
variance = 35
@@ -68,6 +72,7 @@
name = "rubber shot"
desc = "A shotgun casing filled with densely-packed rubber balls, used to incapacitate crowds from a distance."
icon_state = "bshell"
+ high_power = FALSE
projectile_type = /obj/projectile/bullet/pellet/shotgun_rubbershot
pellets = 6
variance = 20
@@ -77,6 +82,7 @@
name = "custom incapacitating shot"
desc = "A shotgun casing filled with... something. used to incapacitate targets."
icon_state = "bountyshell"
+ high_power = FALSE
projectile_type = /obj/projectile/bullet/pellet/shotgun_incapacitate
pellets = 12//double the pellets, but half the stun power of each, which makes this best for just dumping right in someone's face.
variance = 20
@@ -86,11 +92,20 @@
name = "improvised shell"
desc = "A shotgun shell improvised from small metal shards. It won't travel as far as a regular shotgun shell, but it will still pack a punch against unarmoured opponents at close ranges."
icon_state = "improvshell"
+ high_power = FALSE
projectile_type = /obj/projectile/bullet/pellet/shotgun_improvised
custom_materials = list(/datum/material/iron=250)
pellets = 9
variance = 15
+/obj/item/ammo_casing/shotgun/improvised/glasspack
+ name = "improvised glass-packed shell"
+ desc = "An extremely weak shotgun shell that's been filled with shards of glass instead of metal pellets."
+ projectile_type = /obj/projectile/bullet/pellet/shotgun_glass
+ custom_materials = list(/datum/material/iron=100, /datum/material/glass=100)
+ pellets = 5
+ variance = 15
+
/obj/item/ammo_casing/shotgun/ion
name = "ion shell"
desc = "An advanced shotgun shell which uses a subspace ansible crystal to produce an effect similar to a standard ion rifle. \
@@ -118,6 +133,7 @@
name = "shotgun dart"
desc = "A dart for use in shotguns. Can be injected with up to 30 units of any chemical."
icon_state = "cshell"
+ high_power = FALSE
projectile_type = /obj/projectile/bullet/dart
var/reagent_amount = 30
@@ -131,6 +147,7 @@
/obj/item/ammo_casing/shotgun/dart/noreact
name = "cryostasis shotgun dart"
desc = "A dart for use in shotguns, using similar technology as cryostatis beakers to keep internal reagents from reacting. Can be injected with up to 10 units of any chemical."
+ high_power = FALSE
icon_state = "cnrshell"
reagent_amount = 10
@@ -140,6 +157,7 @@
/obj/item/ammo_casing/shotgun/dart/bioterror
desc = "A shotgun dart filled with deadly toxins."
+ high_power = FALSE
/obj/item/ammo_casing/shotgun/dart/bioterror/Initialize(mapload)
. = ..()
@@ -153,5 +171,6 @@
name = "breaching slug"
desc = "A 12 gauge anti-material slug. Great for breaching airlocks and windows with minimal shots."
icon_state = "breacher"
+ high_power = FALSE
projectile_type = /obj/projectile/bullet/shotgun_breaching
custom_materials = list(/datum/material/iron=4000)
diff --git a/code/modules/projectiles/boxes_magazines/_box_magazine.dm b/code/modules/projectiles/boxes_magazines/_box_magazine.dm
index 750d8af362dca..c42820f9a48c4 100644
--- a/code/modules/projectiles/boxes_magazines/_box_magazine.dm
+++ b/code/modules/projectiles/boxes_magazines/_box_magazine.dm
@@ -10,7 +10,7 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
custom_materials = list(/datum/material/iron = 30000)
throwforce = 2
- w_class = WEIGHT_CLASS_TINY
+ w_class = WEIGHT_CLASS_SMALL
throw_speed = 3
throw_range = 7
var/list/stored_ammo = list()
@@ -18,7 +18,7 @@
var/max_ammo = 7
var/multiple_sprites = 0
var/caliber
- var/multiload = TRUE
+ var/multiload = FALSE //Only specific magazines have multi-load enabled. This includes all internal mags/cylinders
var/start_empty = FALSE
var/list/bullet_cost
var/list/base_cost// override this one as well if you override bullet_cost
@@ -48,7 +48,7 @@
stored_ammo.Insert(1,b)
return b
-/obj/item/ammo_box/proc/give_round(obj/item/ammo_casing/R, replace_spent = 0)
+/obj/item/ammo_box/proc/give_round(obj/item/ammo_casing/R)
// Boxes don't have a caliber type, magazines do. Not sure if it's intended or not, but if we fail to find a caliber, then we fall back to ammo_type.
if(!R || (caliber && R.caliber != caliber) || (!caliber && R.type != ammo_type))
return FALSE
@@ -57,45 +57,43 @@
stored_ammo += R
R.forceMove(src)
return TRUE
-
- //for accessibles magazines (e.g internal ones) when full, start replacing spent ammo
- else if(replace_spent)
- for(var/obj/item/ammo_casing/AC in stored_ammo)
- if(!AC.BB)//found a spent ammo
- stored_ammo -= AC
- AC.forceMove(get_turf(src.loc))
-
- stored_ammo += R
- R.forceMove(src)
- return TRUE
return FALSE
/obj/item/ammo_box/proc/can_load(mob/user)
return TRUE
-/obj/item/ammo_box/attackby(obj/item/A, mob/user, params, silent = FALSE, replace_spent = 0)
+/obj/item/ammo_box/attackby(obj/item/A, mob/user, params, silent = FALSE)
var/num_loaded = 0
if(!can_load(user))
return
if(istype(A, /obj/item/ammo_box))
var/obj/item/ammo_box/AM = A
for(var/obj/item/ammo_casing/AC in AM.stored_ammo)
- var/did_load = give_round(AC, replace_spent)
+ //If the box you're loading from is empty, break.
+ if(!AM.stored_ammo)
+ break
+ if(!multiload)
+ if(!do_after(user, 4, src, IGNORE_USER_LOC_CHANGE))
+ break
+ var/did_load = give_round(AC)
if(did_load)
AM.stored_ammo -= AC
num_loaded++
- if(!did_load || !multiload)
+ if(!silent && !multiload)
+ playsound(src, 'sound/weapons/bulletinsert.ogg', 60, TRUE)
+ if(!did_load)
break
if(istype(A, /obj/item/ammo_casing))
var/obj/item/ammo_casing/AC = A
- if(give_round(AC, replace_spent))
+ if(give_round(AC))
user.transferItemToLoc(AC, src, TRUE)
num_loaded++
if(num_loaded)
if(!silent)
- to_chat(user, "You load [num_loaded] shell\s into \the [src]!")
- playsound(src, 'sound/weapons/bulletinsert.ogg', 60, TRUE)
+ to_chat(user, "You loaded [num_loaded] shell\s into \the [src]!")
+ if(istype(A, /obj/item/ammo_casing))
+ playsound(src, 'sound/weapons/bulletinsert.ogg', 60, TRUE)
A.update_icon()
update_icon()
return num_loaded
@@ -149,3 +147,21 @@
/obj/item/ammo_box/magazine/handle_atom_del(atom/A)
stored_ammo -= A
update_icon()
+
+//Behavior for ammo pouches (disposable paper ammo box)
+/obj/item/ammo_box/pouch
+ icon_state = "bagobullets"
+ bullet_cost = null
+ base_cost = null
+
+/obj/item/ammo_box/pouch/attack_self(mob/user)
+ //If it's out of ammo, use it in hand to return the sheet of paper and 'destroy' the ammo box
+ if(!stored_ammo.len)
+ to_chat(user, "You flatten the empty [src]!")
+ var/obj/item/paper/unfolded = new /obj/item/paper
+ unfolded.forceMove(loc)
+ qdel(src)
+ user.put_in_hands(unfolded)
+ return
+
+ ..()
diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
index 780d44f02491e..7625da1c8d760 100644
--- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
+++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
@@ -67,18 +67,45 @@
item_flags = DROPDEL
ammo_type = /obj/item/ammo_casing/caseless/mime/lethal
+/obj/item/ammo_box/pouch/c38
+ name = "ammo pouch (.38)"
+ ammo_type = /obj/item/ammo_casing/c38
+ max_ammo = 4
+
+/obj/item/ammo_box/pouch/c38/improv
+ name = "ammo pouch (improv .38)"
+ ammo_type = /obj/item/ammo_casing/c38/improv
+
/obj/item/ammo_box/c9mm
name = "ammo box (9mm)"
icon_state = "9mmbox"
ammo_type = /obj/item/ammo_casing/c9mm
max_ammo = 30
+/obj/item/ammo_box/pouch/c9mm
+ name = "ammo pouch (9mm)"
+ ammo_type = /obj/item/ammo_casing/c9mm
+ max_ammo = 6
+
+/obj/item/ammo_box/pouch/c9mm/improv
+ name = "ammo pouch (improv 9mm)"
+ ammo_type = /obj/item/ammo_casing/c9mm/improv
+
/obj/item/ammo_box/c10mm
name = "ammo box (10mm)"
icon_state = "10mmbox"
ammo_type = /obj/item/ammo_casing/c10mm
max_ammo = 20
+/obj/item/ammo_box/pouch/c10mm
+ name = "ammo pouch (10mm)"
+ ammo_type = /obj/item/ammo_casing/c10mm
+ max_ammo = 4
+
+/obj/item/ammo_box/pouch/c10mm/improv
+ name = "ammo pouch (improv 10mm)"
+ ammo_type = /obj/item/ammo_casing/c10mm/improv
+
/obj/item/ammo_box/c45
name = "ammo box (.45)"
icon_state = "45box"
diff --git a/code/modules/projectiles/boxes_magazines/external/shotgun.dm b/code/modules/projectiles/boxes_magazines/external/shotgun.dm
index b1aebdee69d9d..09472837b0210 100644
--- a/code/modules/projectiles/boxes_magazines/external/shotgun.dm
+++ b/code/modules/projectiles/boxes_magazines/external/shotgun.dm
@@ -2,14 +2,11 @@
name = "shotgun magazine (12g buckshot slugs)"
desc = "A drum magazine."
icon_state = "m12gb"
+ multiple_sprites = 2
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
caliber = "shotgun"
max_ammo = 8
-/obj/item/ammo_box/magazine/m12g/update_icon()
- ..()
- icon_state = "[initial(icon_state)]-[CEILING(ammo_count(FALSE)/8, 1)*8]"
-
/obj/item/ammo_box/magazine/m12g/stun
name = "shotgun magazine (12g taser slugs)"
icon_state = "m12gs"
diff --git a/code/modules/projectiles/boxes_magazines/external/smg.dm b/code/modules/projectiles/boxes_magazines/external/smg.dm
index 23250e7bb52db..4a8c8407e30ab 100644
--- a/code/modules/projectiles/boxes_magazines/external/smg.dm
+++ b/code/modules/projectiles/boxes_magazines/external/smg.dm
@@ -82,3 +82,50 @@
ammo_type = /obj/item/ammo_casing/c45
caliber = ".45"
max_ammo = 50
+
+/obj/item/ammo_box/magazine/pipem9mm
+ name = "pipe repeater magazine (9mm)"
+ icon_state = "pipemag1"
+ start_empty = TRUE
+ ammo_type = /obj/item/ammo_casing/c9mm/improv
+ caliber = "9mm"
+ max_ammo = 6
+ var/obj/item/stock_parts/matter_bin/installed_bin
+
+/obj/item/ammo_box/magazine/pipem9mm/proc/update_capacity()
+ max_ammo = initial(max_ammo) + (installed_bin.rating * 3)
+ var/I = installed_bin.rating
+ if(I > 4)
+ I = 5
+ icon_state = "pipemag[I]"
+ update_icon()
+
+/obj/item/ammo_box/magazine/pipem9mm/Initialize(mapload)
+ . = ..()
+ //Initialize with a basic/T1 matter bin installed
+ installed_bin = new /obj/item/stock_parts/matter_bin(src)
+ update_capacity()
+
+/obj/item/ammo_box/magazine/pipem9mm/examine(mob/user)
+ . = ..()
+ . += "This one has a tier [installed_bin.rating] matter bin, and can hold [max_ammo] shells."
+ if(installed_bin.rating < 4)
+ . += "You could increase the capacity with a better matter bin..."
+
+/obj/item/ammo_box/magazine/pipem9mm/attackby(obj/item/A, mob/user, params, silent = FALSE)
+ if(istype(A, /obj/item/stock_parts/matter_bin))
+ var/obj/item/stock_parts/B = A
+ if(B.rating <= installed_bin.rating)
+ to_chat(user, "\The [B] isn't better than the matter bin that's already installed!")
+ return
+ to_chat(user, "You begin to rebuild \the [src] with the [B]")
+ if(do_after(user, 50, target = src))
+ installed_bin.forceMove(drop_location())
+ user.transferItemToLoc(B, src)
+ installed_bin = B
+ update_capacity()
+ to_chat(user, "\The [src] can now hold [max_ammo] bullets!")
+ if(B.rating > 4)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), user, "Where'd you find that matter bin anyway..?"), 50)
+ return
+ ..()
diff --git a/code/modules/projectiles/boxes_magazines/internal/_cylinder.dm b/code/modules/projectiles/boxes_magazines/internal/_cylinder.dm
index cc14f753e4f64..011e9dab90ba6 100644
--- a/code/modules/projectiles/boxes_magazines/internal/_cylinder.dm
+++ b/code/modules/projectiles/boxes_magazines/internal/_cylinder.dm
@@ -38,12 +38,9 @@
for(var/i in 1 to stored_ammo.len)
var/obj/item/ammo_casing/bullet = stored_ammo[i]
- if(!bullet || !bullet.BB) // found a spent ammo
+ if(!bullet) //Found an empty chamber in the cylinder
stored_ammo[i] = R
R.forceMove(src)
-
- if(bullet)
- bullet.forceMove(drop_location())
return TRUE
return FALSE
diff --git a/code/modules/projectiles/boxes_magazines/internal/_internal.dm b/code/modules/projectiles/boxes_magazines/internal/_internal.dm
index c14e66af82cf3..eda5b1ac3ed19 100644
--- a/code/modules/projectiles/boxes_magazines/internal/_internal.dm
+++ b/code/modules/projectiles/boxes_magazines/internal/_internal.dm
@@ -2,6 +2,7 @@
desc = "Oh god, this shouldn't be here"
flags_1 = CONDUCT_1
item_flags = ABSTRACT
+ multiload = TRUE
//internals magazines are accessible, so replace spent ammo if full when trying to put a live one in
/obj/item/ammo_box/magazine/internal/give_round(obj/item/ammo_casing/R)
diff --git a/code/modules/projectiles/boxes_magazines/internal/rifle.dm b/code/modules/projectiles/boxes_magazines/internal/rifle.dm
index a7469284a5c70..939955a3eb720 100644
--- a/code/modules/projectiles/boxes_magazines/internal/rifle.dm
+++ b/code/modules/projectiles/boxes_magazines/internal/rifle.dm
@@ -13,3 +13,18 @@
/obj/item/ammo_box/magazine/internal/boltaction/enchanted/arcane_barrage
ammo_type = /obj/item/ammo_casing/magic/arcane_barrage
+/obj/item/ammo_box/magazine/internal/leveraction
+ name = "lever action rifle internal magazine"
+ desc = "Why the fuck can you see this, this is meant to be IN the gun!"
+ ammo_type = /obj/item/ammo_casing/c38
+ caliber = "38"
+ max_ammo = 8
+ multiload = FALSE
+
+/obj/item/ammo_box/magazine/internal/piperifle
+ name = "pipegun internal magazine"
+ desc = "Me when I accidentally see items that shouldn't exist."
+ ammo_type = /obj/item/ammo_casing/a762/improv
+ caliber = "a762"
+ max_ammo = 1
+ start_empty = TRUE
diff --git a/code/modules/projectiles/boxes_magazines/internal/shotgun.dm b/code/modules/projectiles/boxes_magazines/internal/shotgun.dm
index 8edc86b5cbb46..6ee0aad92b22b 100644
--- a/code/modules/projectiles/boxes_magazines/internal/shotgun.dm
+++ b/code/modules/projectiles/boxes_magazines/internal/shotgun.dm
@@ -3,7 +3,7 @@
ammo_type = /obj/item/ammo_casing/shotgun/beanbag
caliber = "shotgun"
max_ammo = 4
- multiload = 0
+ multiload = FALSE
/obj/item/ammo_box/magazine/internal/shot/tube
name = "dual feed shotgun internal tube"
@@ -31,6 +31,7 @@
name = "improvised shotgun internal magazine"
ammo_type = /obj/item/ammo_casing/shotgun/improvised
max_ammo = 1
+ start_empty = TRUE
/obj/item/ammo_box/magazine/internal/shot/riot
name = "riot shotgun internal magazine"
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index e9c9aad01cf86..bda91dd594623 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -10,6 +10,7 @@
var/load_sound_volume = 40
var/load_sound_vary = TRUE
var/rack_sound = "gun_slide_lock"
+ var/half_rack_sound = "gun_slide_lock" //Only needs to be used on BOLT_TYPE_PUMP guns, for Ctrl-Click functionality
var/rack_sound_volume = 60
var/rack_sound_vary = TRUE
var/lock_back_sound = "sound/weapons/pistollock.ogg"
@@ -25,23 +26,32 @@
var/empty_alarm_volume = 70
var/empty_alarm_vary = TRUE
+ //Info below has to deal with guns with internal magazines or actual removable magazines.
var/spawnwithmagazine = TRUE
- var/mag_type = /obj/item/ammo_box/magazine/m10mm //Removes the need for max_ammo and caliber info
+ var/mag_type = /obj/item/ammo_box/magazine/m10mm //Removes the need for max_ammo and caliber info //Shame I had to add caliber back anyway :^)
var/mag_display = FALSE //Whether the sprite has a visible magazine or not
var/mag_display_ammo = FALSE //Whether the sprite has a visible ammo display or not
var/empty_indicator = FALSE //Whether the sprite has an indicator for being empty or not.
var/empty_alarm = FALSE //Whether the gun alarms when empty or not.
var/special_mags = FALSE //Whether the gun supports multiple special mag types
var/alarmed = FALSE
- //Four bolt types:
+ //Additional info related to the actual chambering, and to allow loading bullets directly into battery / into var/chambered
+ //Copies the caliber of the magazine in the gun during Initialize() | Must be explicitly set on the gun if it spawns without a magazine ;)
+ var/caliber = null
+ var/direct_loading = FALSE //A gun with this allows the internal magazine to be loaded without removing, ontop of directly chambering rounds
+ //Six bolt types:
//BOLT_TYPE_STANDARD: Gun has a bolt, it stays closed while not cycling. The gun must be racked to have a bullet chambered when a mag is inserted.
- //Example: c20, shotguns, m90
+ //Example: c20, m90
//BOLT_TYPE_OPEN: Gun has a bolt, it is open when ready to fire. The gun can never have a chambered bullet with no magazine, but the bolt stays ready when a mag is removed.
//Example: Some SMGs, the L6
//BOLT_TYPE_NO_BOLT: Gun has no moving bolt mechanism, it cannot be racked. Also dumps the entire contents when emptied instead of a magazine.
- //Example: Break action shotguns, revolvers
+ //Example: Rocket launchers, Break-action shotguns, revolvers, derringer
//BOLT_TYPE_LOCKING: Gun has a bolt, it locks back when empty. It can be released to chamber a round if a magazine is in.
//Example: Pistols with a slide lock, some SMGs
+ //BOLT_TYPE_PUMP: Functions identically to BOLT_TYPE_STANDARD, but requires two hands to rack the bolt.
+ //Examples: Pump-action shotguns
+ //BOLT_TYPE_TWO_STEP: Functions identically to BOLT_TYPE_PUMP (and thus, STANDARD), but each interaction with the bolt toggles between locked (open) & unlocked (closed).
+ //Examples: Mosin nagant, pipe guns
var/bolt_type = BOLT_TYPE_STANDARD
var/bolt_locked = FALSE //Used for locking bolt and open bolt guns. Set a bit differently for the two but prevents firing when true for both.
var/bolt_wording = "bolt" //bolt, slide, etc.
@@ -63,7 +73,10 @@
return
if (!magazine)
magazine = new mag_type(src)
- chamber_round()
+ if (!caliber)
+ caliber = magazine.caliber
+ if (bolt_type == BOLT_TYPE_NO_BOLT)
+ chamber_round()
update_icon()
/obj/item/gun/ballistic/fire_sounds()
@@ -95,8 +108,9 @@
else
icon_state = "[initial(icon_state)][sawn_off ? "_sawn" : ""]"
cut_overlays()
- if (bolt_type == BOLT_TYPE_LOCKING)
- add_overlay("[icon_state]_bolt[bolt_locked ? "_locked" : ""]")
+ switch(bolt_type)
+ if(BOLT_TYPE_LOCKING, BOLT_TYPE_PUMP, BOLT_TYPE_TWO_STEP)
+ add_overlay("[icon_state]_bolt[bolt_locked ? "_locked" : ""]")
if (bolt_type == BOLT_TYPE_OPEN && bolt_locked)
add_overlay("[icon_state]_bolt")
if (suppressed)
@@ -105,7 +119,10 @@
add_overlay("[icon_state]_empty")
if (magazine)
if (special_mags)
- add_overlay("[icon_state]_mag_[initial(magazine.icon_state)]")
+ if(magazine.multiple_sprites)
+ add_overlay("[icon_state]_mag_[initial(magazine.icon_state)]")
+ else
+ add_overlay("[icon_state]_mag_[magazine.icon_state]")
if (!magazine.ammo_count())
add_overlay("[icon_state]_mag_empty")
else
@@ -161,10 +178,33 @@
to_chat(user, "\The [src]'s [bolt_wording] is already cocked!")
return
bolt_locked = FALSE
+ if(BOLT_TYPE_TWO_STEP)
+ if(!is_wielded && !HAS_TRAIT(user, TRAIT_NICE_SHOT))
+ to_chat(user, "You require your other hand to be free to rack the [bolt_wording] of \the [src]!")
+ return
+ //If it's locked (open), drop the bolt to close and unlock it
+ if(bolt_locked == TRUE)
+ drop_bolt(user)
+ return
+ //Otherwise, we open the bolt and eject the current casing
+ if(!is_wielded && prob(20))
+ user.visible_message("[user] racks \the [src]'s [bolt_wording] with a single hand!")
+ to_chat(user, "You open the [bolt_wording] of \the [src].")
+ playsound(src, rack_sound, rack_sound_volume, rack_sound_vary)
+ process_chamber(!chambered, FALSE, FALSE)
+ bolt_locked = TRUE
+ update_icon()
+ return
if(BOLT_TYPE_PUMP)
- if(!is_wielded)
+ if(!is_wielded && !HAS_TRAIT(user, TRAIT_NICE_SHOT))
to_chat(user, "You require your other hand to be free to rack the [bolt_wording] of \the [src]!")
return
+ if(!is_wielded && prob(20))
+ user.visible_message("[user] racks \the [src]'s [bolt_wording] with a single hand!")
+ if(bolt_locked == TRUE) //If it's locked (open), drop the bolt to close and unlock it
+ drop_bolt(user)
+ return
+ //Otherwise, we open the bolt and eject the current casing
if(user)
to_chat(user, "You rack the [bolt_wording] of \the [src].")
process_chamber(!chambered, FALSE)
@@ -193,7 +233,7 @@
to_chat(user, "You load a new [magazine_wording] into \the [src].")
playsound(src, load_empty_sound, load_sound_volume, load_sound_vary)
if (bolt_type == BOLT_TYPE_OPEN && !bolt_locked)
- chamber_round(TRUE)
+ chamber_round()
update_icon()
return TRUE
else
@@ -202,6 +242,9 @@
/obj/item/gun/ballistic/proc/eject_magazine(mob/user, display_message = TRUE, obj/item/ammo_box/magazine/tac_load = null)
if(bolt_type == BOLT_TYPE_OPEN)
+ //Put the chambered bullet back into the magazine, because it was never really taken out in the first place.
+ if(chambered)
+ magazine.attackby(chambered, user, null, TRUE, FALSE)
chambered = null
if (magazine.ammo_count())
playsound(src, load_sound, load_sound_volume, load_sound_vary)
@@ -224,6 +267,9 @@
update_icon()
/obj/item/gun/ballistic/can_shoot()
+ //If it's locked open (TWO_STEP and PUMP), it can't fire.
+ if((bolt_type == BOLT_TYPE_TWO_STEP || bolt_type == BOLT_TYPE_PUMP) && bolt_locked)
+ return FALSE
return chambered
/obj/item/gun/ballistic/attackby(obj/item/A, mob/user, params)
@@ -241,19 +287,44 @@
to_chat(user, "There's already a [magazine_wording] in \the [src].")
return
if (istype(A, /obj/item/ammo_casing) || istype(A, /obj/item/ammo_box))
- if (bolt_type == BOLT_TYPE_NO_BOLT || internal_magazine)
- if (chambered && !chambered.BB)
- chambered.forceMove(drop_location())
- chambered = null
- var/num_loaded = magazine.attackby(A, user, params, TRUE)
- if (num_loaded)
- to_chat(user, "You load [num_loaded] [cartridge_wording]\s into \the [src].")
- playsound(src, load_sound, load_sound_volume, load_sound_vary)
- if (chambered == null && bolt_type == BOLT_TYPE_NO_BOLT)
- chamber_round()
- A.update_icon()
- update_icon()
+ //If it has a removable magazine, and does not support direct loading, return.
+ if(!internal_magazine && !direct_loading)
+ if(magazine)
+ to_chat(user, "Remove \the [src]'s magazine to load it!")
+ return
+ //Most guns with internal magazines (or the ability to load a removable one) are loaded through the bolt that gets locked open. PUMP are the exception here.
+ if(!bolt_locked && (bolt_type == BOLT_TYPE_LOCKING || bolt_type == BOLT_TYPE_OPEN || bolt_type == BOLT_TYPE_TWO_STEP))
+ to_chat(user, "The [bolt_wording] is closed!")
+ return
+ //For chambering cartridges directly, only possible with a single cartridge in hand on guns with either internal magazines or direct_loading set to true
+ //The additional check for bolt_locked only applies to PUMP bolt types, as they're the only ones that can load on a closed bolt.
+ if(!chambered && istype(A, /obj/item/ammo_casing) && bolt_locked && bolt_type != BOLT_TYPE_OPEN)
+ var/obj/item/ammo_casing/AC = A
+ //If the gun isn't chambered in the same caliber as the cartridge, don't load it.
+ if(src.caliber != AC.caliber)
+ to_chat(user, "\The [src] isn't chambered in this caliber!")
+ return
+ chambered = AC
+ chambered.forceMove(src)
+ to_chat(user, "You chamber a [cartridge_wording] directly into \the [src].")
+ playsound(src, load_sound, load_sound_volume, load_sound_vary)
+ return
+ //If we don't have a magazine at all, and didn't load into battery, abort loading
+ if(!magazine)
+ to_chat(user, "There's nowhere to load a [cartridge_wording] into!")
return
+ //Otherwise, try loading into the internal magazine next.
+ var/num_loaded = magazine.attackby(A, user, params, TRUE)
+ if (num_loaded)
+ to_chat(user, "You load [num_loaded] [cartridge_wording]\s into \the [src].")
+ playsound(src, load_sound, load_sound_volume, load_sound_vary)
+ if (chambered == null && bolt_type == BOLT_TYPE_NO_BOLT)
+ chamber_round()
+ A.update_icon()
+ update_icon()
+ else
+ to_chat(user, "\The [src] doesn't have room for another [cartridge_wording]!")
+ return
if(istype(A, /obj/item/suppressor))
var/obj/item/suppressor/S = A
if(!can_suppress)
@@ -300,6 +371,16 @@
update_icon()
return
+/obj/item/gun/ballistic/CtrlClick(mob/user)
+ if(bolt_type == BOLT_TYPE_PUMP && is_wielded && loc == user && !bolt_locked)
+ to_chat(user, "You lock open the [bolt_wording] of \the [src].")
+ playsound(src, half_rack_sound, rack_sound_volume, rack_sound_vary)
+ process_chamber(!chambered, FALSE, FALSE)
+ bolt_locked = TRUE
+ update_icon()
+ return
+ ..()
+
/obj/item/gun/ballistic/proc/prefire_empty_checks()
if (!chambered && !get_ammo())
if (bolt_type == BOLT_TYPE_OPEN && !bolt_locked)
@@ -335,6 +416,7 @@
if(!magazine.ammo_count())
eject_magazine(user)
return
+
if(bolt_type == BOLT_TYPE_NO_BOLT)
chambered = null
var/num_unloaded = 0
@@ -346,9 +428,8 @@
to_chat(user, "You unload [num_unloaded] [cartridge_wording]\s from [src].")
playsound(user, eject_sound, eject_sound_volume, eject_sound_vary)
update_icon()
- else
- to_chat(user, "[src] is empty!")
- return
+ return
+
if(bolt_type == BOLT_TYPE_LOCKING && bolt_locked)
drop_bolt(user)
return
@@ -358,10 +439,9 @@
rack(user)
return
-
/obj/item/gun/ballistic/examine(mob/user)
. = ..()
- var/count_chambered = !(bolt_type == BOLT_TYPE_NO_BOLT || bolt_type == BOLT_TYPE_OPEN)
+ var/count_chambered = !(bolt_type == BOLT_TYPE_NO_BOLT)
. += "It has [get_ammo(count_chambered)] round\s remaining."
if (!chambered)
. += "It does not seem to have a round chambered."
@@ -369,6 +449,8 @@
. += "The [bolt_wording] is locked back and needs to be released before firing."
if (suppressed)
. += "It has a suppressor attached that can be removed with alt+click."
+ if (bolt_type == BOLT_TYPE_PUMP)
+ . += "You can ctrl+click to half-pump \the [src] to directly chamber a [cartridge_wording]."
/obj/item/gun/ballistic/proc/get_ammo(countchambered = TRUE)
var/boolets = 0 //mature var names for mature people
@@ -454,7 +536,7 @@
item_state = "gun"
slot_flags &= ~ITEM_SLOT_BACK //you can't sling it on your back
slot_flags |= ITEM_SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally)
- recoil = SAWN_OFF_RECOIL
+ recoil += SAWN_OFF_RECOIL //Add the additional 1 recoil, instead of setting recoil to one (looking at you improv shotgun)
can_bayonet = FALSE //you got rid of the mounting lug with the rest of the barrel, dumbass
can_suppress = FALSE //ditto for the threaded barrel
sawn_off = TRUE
@@ -465,11 +547,11 @@
// Sawing guns related proc
/obj/item/gun/ballistic/proc/blow_up(mob/user)
. = FALSE
- for(var/obj/item/ammo_casing/AC in magazine.stored_ammo)
- if(AC.BB)
- process_fire(user, user, FALSE)
- . = TRUE
-
+ if(!chambered)
+ return
+ if(chambered.BB)
+ process_fire(user, user, FALSE)
+ . = TRUE
/obj/item/suppressor
name = "suppressor"
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index c02da26621c3d..4fa3926dc26b7 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -307,6 +307,26 @@
automatic = 0
fire_rate = 1.5
+// Improv Pipe Sub-Machinegun //
+
+/obj/item/gun/ballistic/automatic/pipe_smg
+ name = "pipe carbine"
+ desc = "A much more sophisticated improvised firearm, loaded from a removable magazine and automatically cycling cartridges. It's a shame it only takes 9mm ammo."
+ icon_state = "pipesmg"
+ item_state = "arg"
+ mag_type = /obj/item/ammo_box/magazine/pipem9mm
+ special_mags = TRUE
+ caliber = "9mm"
+ tac_reloads = FALSE
+ bolt_type = BOLT_TYPE_OPEN
+ no_pin_required = TRUE
+ spawnwithmagazine = FALSE
+ w_class = WEIGHT_CLASS_BULKY
+ slot_flags = ITEM_SLOT_BELT
+ actions_types = null
+ fire_rate = 2
+ spread = 10
+
// Laser rifle (rechargeable magazine) //
/obj/item/gun/ballistic/automatic/laser
diff --git a/code/modules/projectiles/guns/ballistic/pistol.dm b/code/modules/projectiles/guns/ballistic/pistol.dm
index ea19e1bea8634..ae12c1b291cbc 100644
--- a/code/modules/projectiles/guns/ballistic/pistol.dm
+++ b/code/modules/projectiles/guns/ballistic/pistol.dm
@@ -20,6 +20,7 @@
/obj/item/gun/ballistic/automatic/pistol/no_mag
spawnwithmagazine = FALSE
+ caliber = "10mm"
/obj/item/gun/ballistic/automatic/pistol/locker
desc = "A small, easily concealable 10mm handgun. Has a threaded barrel for suppressors. This one is rusted from being inside of a locker for so long."
@@ -46,7 +47,7 @@
tac_reloads = FALSE
fire_sound_volume = 60
spread = 18 //Innate spread of 18 degrees, unwielded spread of 48; Stechkin is unwielded 40
- spread_unwielded = 30 //Manually set unwielded spread to 30; Equivelant weight to 0.5 (Stechkin has weight 1)
+ weapon_weight = WEAPON_LIGHT * 0.5 //Equivelant weight to 0.5 (Stechkin has weight 1)
wild_spread = TRUE
wild_factor = 0.70 //Minimum spread is 70% of spread value
equip_time = 0
@@ -66,6 +67,7 @@
/obj/item/gun/ballistic/automatic/pistol/m1911/no_mag
spawnwithmagazine = FALSE
+ caliber = ".45"
/obj/item/gun/ballistic/automatic/pistol/deagle
name = "\improper Desert Eagle"
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index 5c7a0cdc89815..733c719417d35 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -148,6 +148,7 @@
to_chat(user, "You can't modify it!")
return TRUE
magazine.caliber = "357"
+ src.caliber = magazine.caliber
fire_rate = 1 //worse than a nromal .357
fire_sound = 'sound/weapons/revolver357shot.ogg'
desc = "The barrel and chamber assembly seems to have been modified."
@@ -163,7 +164,8 @@
to_chat(user, "You can't modify it!")
return
magazine.caliber = "38"
- fire_rate = null
+ src.caliber = magazine.caliber
+ fire_rate = initial(fire_rate)
fire_sound = 'sound/weapons/revolver38shot.ogg'
desc = initial(desc)
to_chat(user, "You remove the modifications on [src]. Now it will fire .38 rounds.")
diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm
index f03259356974e..bf6e4af030f1e 100644
--- a/code/modules/projectiles/guns/ballistic/rifle.dm
+++ b/code/modules/projectiles/guns/ballistic/rifle.dm
@@ -5,7 +5,7 @@
icon_state = "moistnugget"
mag_type = /obj/item/ammo_box/magazine/internal/boltaction
bolt_wording = "bolt"
- bolt_type = BOLT_TYPE_STANDARD
+ bolt_type = BOLT_TYPE_TWO_STEP
semi_auto = FALSE
internal_magazine = TRUE
fire_sound = "sound/weapons/rifleshot.ogg"
@@ -19,40 +19,12 @@
..()
add_overlay("[icon_state]_bolt[bolt_locked ? "_locked" : ""]")
-/obj/item/gun/ballistic/rifle/rack(mob/user = null)
- if(!is_wielded)
- to_chat(user, "You require your other hand to be free to rack the [bolt_wording] of \the [src]!")
- return
- if(bolt_locked == FALSE)
- to_chat(user, "You open the bolt of \the [src].")
- playsound(src, rack_sound, rack_sound_volume, rack_sound_vary)
- process_chamber(FALSE, FALSE, FALSE)
- bolt_locked = TRUE
- update_icon()
- return
- drop_bolt(user)
-
-/obj/item/gun/ballistic/rifle/can_shoot()
- if (bolt_locked)
- return FALSE
- return ..()
-
-/obj/item/gun/ballistic/rifle/attackby(obj/item/A, mob/user, params)
- if ((istype(A, /obj/item/ammo_casing/a762) || istype(A, /obj/item/ammo_box/a762)) && !bolt_locked)
- to_chat(user, "The bolt is closed!")
- return
- return ..()
-
-/obj/item/gun/ballistic/rifle/examine(mob/user)
- . = ..()
- . += "The bolt is [bolt_locked ? "open" : "closed"]."
-
/obj/item/gun/ballistic/rifle/shoot_live_shot(mob/living/user, pointblank, atom/pbtarget, message)
if(sawn_off == TRUE)
if(!is_wielded)
recoil = 5
else
- recoil = SAWN_OFF_RECOIL
+ recoil = initial(recoil) + SAWN_OFF_RECOIL
. = ..()
///////////////////////
@@ -73,6 +45,7 @@
can_bayonet = TRUE
knife_x_offset = 27
knife_y_offset = 13
+ recoil = 0.5
w_class = WEIGHT_CLASS_BULKY
weapon_weight = WEAPON_HEAVY
@@ -133,3 +106,86 @@
user.put_in_hands(gun)
else
user.dropItemToGround(src, TRUE)
+
+///////////////////////
+// .38 CAL RIFLE //
+///////////////////////
+
+/obj/item/gun/ballistic/rifle/leveraction
+ name = "lever action rifle"
+ desc = "Straight from the Wild West, this belongs in a museum but has found its way into your hands."
+ icon_state = "leverrifle"
+ lefthand_file = 'icons/mob/inhands/weapons/64x_guns_left.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/64x_guns_right.dmi'
+ item_state = "leveraction"
+ inhand_x_dimension = 64
+ inhand_y_dimension = 64
+ slot_flags = ITEM_SLOT_BACK
+ rack_sound = "sound/weapons/leveractionrack.ogg"
+ half_rack_sound = "sound/weapons/leveractionrack_open.ogg"
+ bolt_drop_sound = "sound/weapons/leveractionrack_close.ogg"
+ fire_sound = "sound/weapons/leveractionshot.ogg"
+ mag_type = /obj/item/ammo_box/magazine/internal/leveraction
+ w_class = WEIGHT_CLASS_BULKY
+ no_pin_required = TRUE //Nothing stops frontier justice
+ bolt_wording = "lever"
+ cartridge_wording = "cartridge"
+ recoil = 0.5
+ bolt_type = BOLT_TYPE_PUMP
+ fire_sound_volume = 70
+
+///////////////////////
+// 7.62 PIPE RIFLE //
+///////////////////////
+
+/obj/item/gun/ballistic/rifle/pipe
+ name = "pipe rifle"
+ desc = "It's amazing what you can do with some scrap wood and spare pipes."
+ can_sawoff = TRUE
+ sawn_name = "pipe pistol"
+ sawn_desc = "Why have more gun, when less gun can do!"
+ icon_state = "piperifle"
+ lefthand_file = 'icons/mob/inhands/weapons/64x_guns_left.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/64x_guns_right.dmi'
+ item_state = "shotgun_improv"
+ sawn_item_state = "shotgun_improv_shorty"
+ inhand_x_dimension = 64
+ inhand_y_dimension = 64
+ bolt_type = BOLT_TYPE_NO_BOLT
+ cartridge_wording = "cartridge"
+ slot_flags = null
+ mag_type = /obj/item/ammo_box/magazine/internal/piperifle
+ no_pin_required = TRUE
+ w_class = WEIGHT_CLASS_BULKY
+ force = 8
+ recoil = 0.8
+ var/slung = FALSE
+
+/obj/item/gun/ballistic/rifle/pipe/examine(mob/user)
+ . = ..()
+ if (slung)
+ . += "It has a shoulder sling fashioned from spare cable attached."
+ else
+ . += "You could improvise a shoulder sling from some cabling..."
+
+/obj/item/gun/ballistic/rifle/pipe/attackby(obj/item/A, mob/user, params)
+ ..()
+ if(istype(A, /obj/item/stack/cable_coil) && !sawn_off)
+ if(slung)
+ to_chat(user, "There is already a sling on [src]!")
+ return
+ var/obj/item/stack/cable_coil/C = A
+ if(C.use(10))
+ slot_flags = ITEM_SLOT_BACK
+ to_chat(user, "You tie the lengths of cable to the [src], making a sling.")
+ slung = TRUE
+ update_icon()
+ else
+ to_chat(user, "You need at least ten lengths of cable if you want to make a sling!")
+
+/obj/item/gun/ballistic/rifle/pipe/sawoff(mob/user)
+ . = ..()
+ if(. && slung) //sawing off the gun removes the sling
+ new /obj/item/stack/cable_coil(get_turf(src), 10)
+ slung = FALSE
+ update_icon()
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index fefca0bf033f1..7f254b98d3ce7 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -11,6 +11,8 @@
vary_fire_sound = FALSE
fire_sound_volume = 90
rack_sound = "sound/weapons/shotgunpump.ogg"
+ half_rack_sound = "sound/weapons/shotgunpump_open.ogg"
+ bolt_drop_sound = "sound/weapons/shotgunpump_close.ogg"
load_sound = "sound/weapons/shotguninsert.ogg"
w_class = WEIGHT_CLASS_BULKY
force = 10
@@ -29,12 +31,6 @@
recoil = 1
pb_knockback = 2
-/obj/item/gun/ballistic/shotgun/blow_up(mob/user)
- . = 0
- if(chambered?.BB)
- process_fire(user, user, FALSE)
- . = 1
-
/obj/item/gun/ballistic/shotgun/lethal
mag_type = /obj/item/ammo_box/magazine/internal/shot/lethal
@@ -234,15 +230,51 @@
name = "improvised shotgun"
desc = "Essentially a tube that aims shotgun shells."
icon_state = "ishotgun"
- item_state = "shotgun"
+ item_state = "shotgun_improv"
+ sawn_item_state = "shotgun_improv_shorty"
w_class = WEIGHT_CLASS_BULKY
force = 10
slot_flags = null
mag_type = /obj/item/ammo_box/magazine/internal/shot/improvised
sawn_desc = "I'm just here for the gasoline."
+ no_pin_required = TRUE
unique_reskin_icon = null
- recoil = 2
+ recoil = 1.5
var/slung = FALSE
+ var/reinforced = FALSE
+ var/barrel_stress = 0
+
+/obj/item/gun/ballistic/shotgun/doublebarrel/improvised/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+ if(chambered.BB && !reinforced)
+ var/obj/item/ammo_casing/shotgun/S = chambered
+ if(prob(10 + barrel_stress) && S.high_power) //Base 10% chance of misfiring. Goes up with each shot of high_power ammo
+ backfire(user)
+ return 0
+
+ else if (S.high_power)
+ barrel_stress += 5
+ if (barrel_stress == 10)
+ to_chat(user, "[src]'s barrel is left warped from the force of the shot!")
+ else if (barrel_stress == 25)
+ to_chat(user, "[src]'s barrel cracks from the repeated strain!")
+
+ else if (prob(5) && barrel_stress >= 30) // If the barrel is damaged enough to be cracked, flat 5% chance to detonate on low-power ammo as well.
+ backfire(user)
+ return 0
+ ..()
+
+/obj/item/gun/ballistic/shotgun/doublebarrel/improvised/proc/backfire(mob/living/user)
+ playsound(user, fire_sound, fire_sound_volume, vary_fire_sound)
+ to_chat(user, "[src] blows up in your face!")
+
+ user.take_bodypart_damage(0,15) //The explosion already does enough damage.
+ explosion(src, 0, 0, 1, 1)
+
+ barrel_stress += 10 //Big damage to barrel, two explosions/misfires will destroy the gun entirely
+ qdel(chambered.BB)
+ chambered.BB = null //Spend the bullet when you misfire and it explodes. What's blowing up otherwise?
+
+ user.dropItemToGround(src)
/obj/item/gun/ballistic/shotgun/doublebarrel/improvised/attackby(obj/item/A, mob/user, params)
..()
@@ -274,13 +306,24 @@
/obj/item/gun/ballistic/shotgun/doublebarrel/improvised/examine(mob/user)
. = ..()
if (slung)
- . += "It has a shoulder sling fashioned from spare wiring attached."
+ . += "It has a shoulder sling fashioned from spare cable attached."
+ else
+ . += "You could improvise a shoulder sling from some cabling..."
+
+ if (reinforced)
+ . += "The barrel has been reinforced for use with high-power ammunition."
+ else if (barrel_stress < 10)
+ . += "The barrel is in pristine condition."
+ else if (barrel_stress < 20)
+ . += "The barrel seems to be warped mildly..."
+ else
+ . += "The barrel is warped and cracked!"
/obj/item/gun/ballistic/shotgun/doublebarrel/improvised/sawn
name = "sawn-off improvised shotgun"
desc = "A single-shot shotgun. Better not miss."
icon_state = "ishotgun"
- item_state = "gun"
+ item_state = "shotgun_improv_shorty"
w_class = WEIGHT_CLASS_LARGE
sawn_off = TRUE
slot_flags = ITEM_SLOT_BELT
@@ -291,7 +334,6 @@
desc = "Range isn't an issue when you can bring your victim to you."
icon_state = "hookshotgun"
item_state = "shotgun"
- load_sound = "sound/weapons/shotguninsert.ogg"
mag_type = /obj/item/ammo_box/magazine/internal/shot/bounty
w_class = WEIGHT_CLASS_BULKY
weapon_weight = WEAPON_MEDIUM
diff --git a/code/modules/projectiles/guns/ballistic/sniper.dm b/code/modules/projectiles/guns/ballistic/sniper.dm
index 239f2e859b5d8..beb4695f4d75e 100644
--- a/code/modules/projectiles/guns/ballistic/sniper.dm
+++ b/code/modules/projectiles/guns/ballistic/sniper.dm
@@ -8,14 +8,15 @@
fire_sound = "sound/weapons/sniper_shot.ogg"
fire_sound_volume = 90
load_sound = "sound/weapons/sniper_mag_insert.ogg"
- rack_sound = "sound/weapons/sniper_rack.ogg"
- recoil = 2
+ rack_sound = "sound/weapons/sniper_rack_open.ogg"
+ bolt_drop_sound = 'sound/weapons/sniper_rack_close.ogg'
+ recoil = 1.5
weapon_weight = WEAPON_HEAVY
+ bolt_type = BOLT_TYPE_TWO_STEP
mag_type = /obj/item/ammo_box/magazine/sniper_rounds
- automatic = 0
+ direct_loading = TRUE
semi_auto = FALSE
- fire_rate = 1.5
- burst_size = 1
+ rack_delay = 4
w_class = WEIGHT_CLASS_LARGE
zoomable = TRUE
zoom_amt = 10 //Long range, enough to see in front of you, but no tiles behind you.
diff --git a/code/modules/projectiles/projectile/bullets/pistol.dm b/code/modules/projectiles/projectile/bullets/pistol.dm
index 0e4b3f4576ca2..df05999163478 100644
--- a/code/modules/projectiles/projectile/bullets/pistol.dm
+++ b/code/modules/projectiles/projectile/bullets/pistol.dm
@@ -20,6 +20,10 @@
name = "10mm bullet"
damage = 30
+/obj/projectile/bullet/c10mm/improv
+ name = "10mm bullet"
+ damage = 27
+
/obj/projectile/bullet/c10mm_ap
name = "10mm armor-piercing bullet"
damage = 27
diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm
index 9ff042723fa56..f2701dee9d531 100644
--- a/code/modules/projectiles/projectile/bullets/revolver.dm
+++ b/code/modules/projectiles/projectile/bullets/revolver.dm
@@ -98,6 +98,12 @@
. = ..()
empulse(target, 0, 2)
+/obj/projectile/bullet/c38/improv
+ damage = 25
+ ricochets_max = 1
+ ricochet_chance = 80
+ ricochet_auto_aim_range = 0
+
/obj/projectile/bullet/c38/mime
name = "invisible .38 bullet"
icon_state = null
@@ -132,6 +138,10 @@
name = ".357 bullet"
damage = 60
+/obj/projectile/bullet/a357/improv
+ damage = 50
+ armour_penetration = -10
+
// admin only really, for ocelot memes
/obj/projectile/bullet/a357/match
name = ".357 match bullet"
diff --git a/code/modules/projectiles/projectile/bullets/rifle.dm b/code/modules/projectiles/projectile/bullets/rifle.dm
index 92f0ef7f65ac7..ad418f033fab3 100644
--- a/code/modules/projectiles/projectile/bullets/rifle.dm
+++ b/code/modules/projectiles/projectile/bullets/rifle.dm
@@ -4,7 +4,7 @@
name = "5.56mm bullet"
damage = 35
-// 7.62 (Nagant Rifle)
+// 7.62 (Nagant Rifle / Pipe Rifle)
/obj/projectile/bullet/a762
name = "7.62 bullet"
@@ -15,3 +15,19 @@
name = "enchanted 7.62 bullet"
damage = 20
stamina = 80
+
+/obj/projectile/bullet/a762/improv
+ //Possible damage range between 27 and 30
+ damage = 30
+ armour_penetration = 0
+
+/obj/projectile/bullet/a762/improv/Initialize(mapload)
+ . = ..()
+ //Actual damage of projectile is reduced by 0 to 3 damage
+ damage -= (round(rand(0, 3), 1))
+
+/obj/projectile/bullet/a762/improv/hotload
+ //Possible damage between 32 and 35
+ damage = 35
+ speed = 0.7
+ armour_penetration = 15
diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm
index 6874ff76a3c37..2e23953e80cef 100644
--- a/code/modules/projectiles/projectile/bullets/shotgun.dm
+++ b/code/modules/projectiles/projectile/bullets/shotgun.dm
@@ -93,12 +93,25 @@
/obj/projectile/bullet/pellet/shotgun_improvised/Initialize(mapload)
. = ..()
- range = rand(1, 8)
+ range = rand(3, 8)
/obj/projectile/bullet/pellet/shotgun_improvised/on_range()
do_sparks(1, TRUE, src)
..()
+/obj/projectile/bullet/pellet/shotgun_glass
+ tile_dropoff = 0.5
+ damage = 6
+ range = 8
+ ricochets_max = 0
+ shrapnel_type = /obj/item/shrapnel/bullet/shotgun/glass
+
+/obj/projectile/bullet/pellet/shotgun_glass/Initialize(mapload)
+ . = ..()
+
+ if(prob(20)) //Each 'pellet' has a 20 percent chance to not shrapnel/attempt embedding
+ shrapnel_type = null
+
// Mech Scattershot
/obj/projectile/bullet/scattershot
diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm
index 1717192706724..303dda09e28f8 100644
--- a/code/modules/research/designs/autolathe_designs.dm
+++ b/code/modules/research/designs/autolathe_designs.dm
@@ -561,6 +561,14 @@
category = list("initial", "Medical", "Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+/datum/design/hacksaw
+ name = "Hacksaw"
+ id = "hacksaw"
+ build_type = AUTOLATHE
+ materials = list(/datum/material/iron=12000)
+ build_path = /obj/item/hacksaw
+ category = list("hacked", "Medical")
+
/datum/design/beanbag_slug
name = "Beanbag Slug"
id = "beanbag_slug"
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index 13a70301ddbe8..f9377f41bf5dd 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -221,6 +221,29 @@
attack_verb = list("attacked", "slashed", "sawed", "cut")
sharpness = IS_SHARP
+/obj/item/hacksaw
+ name = "hacksaw"
+ desc = "A hacksaw with a metal-cutting blade attached. You could use it as a regular saw in a pinch."
+ icon = 'icons/obj/tools.dmi'
+ icon_state = "hacksaw"
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ throwhitsound = 'sound/weapons/pierce.ogg'
+ lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
+ item_state = "wrench"
+ flags_1 = CONDUCT_1
+ force = 7
+ w_class = WEIGHT_CLASS_NORMAL
+ custom_materials = list(/datum/material/iron=12000)
+ attack_verb = list("attacked", "slashed", "sawed", "cut")
+ sharpness = IS_SHARP
+ tool_behaviour = TOOL_SAW
+ toolspeed = 2
+
+/obj/item/hacksaw/Initialize(mapload)
+ . = ..() //Much worse than a circular saw for butchering. Slower, less efficient, better chance for bonus items however.
+ AddComponent(/datum/component/butchering, 40 * toolspeed, 80, 10, 'sound/items/hacksaw.ogg')
+
/obj/item/surgical_drapes
name = "surgical drapes"
desc = "Nanotrasen brand surgical drapes provide optimal safety and infection control."
diff --git a/icons/mob/inhands/weapons/64x_guns_left.dmi b/icons/mob/inhands/weapons/64x_guns_left.dmi
index da7234d29dbf8..0a8c735b5a10e 100644
Binary files a/icons/mob/inhands/weapons/64x_guns_left.dmi and b/icons/mob/inhands/weapons/64x_guns_left.dmi differ
diff --git a/icons/mob/inhands/weapons/64x_guns_right.dmi b/icons/mob/inhands/weapons/64x_guns_right.dmi
index c3fb95125c03b..55f7ac9df0530 100644
Binary files a/icons/mob/inhands/weapons/64x_guns_right.dmi and b/icons/mob/inhands/weapons/64x_guns_right.dmi differ
diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi
index 6b4d11314ca6e..432f0c748ec0d 100644
Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ
diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi
index b69972dd60e2d..24a8768603550 100644
Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ
diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi
index bc19ae4b74d9e..0611c2226bbc2 100644
Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ
diff --git a/sound/items/hacksaw.ogg b/sound/items/hacksaw.ogg
new file mode 100644
index 0000000000000..43e2dab691d1b
Binary files /dev/null and b/sound/items/hacksaw.ogg differ
diff --git a/sound/weapons/leveractionrack_close.ogg b/sound/weapons/leveractionrack_close.ogg
new file mode 100644
index 0000000000000..4909d0b2ed34b
Binary files /dev/null and b/sound/weapons/leveractionrack_close.ogg differ
diff --git a/sound/weapons/leveractionrack_open.ogg b/sound/weapons/leveractionrack_open.ogg
new file mode 100644
index 0000000000000..99dd2cb15396b
Binary files /dev/null and b/sound/weapons/leveractionrack_open.ogg differ
diff --git a/sound/weapons/shotgunpump_close.ogg b/sound/weapons/shotgunpump_close.ogg
new file mode 100644
index 0000000000000..1b35fba728771
Binary files /dev/null and b/sound/weapons/shotgunpump_close.ogg differ
diff --git a/sound/weapons/shotgunpump_open.ogg b/sound/weapons/shotgunpump_open.ogg
new file mode 100644
index 0000000000000..69e817e1376b4
Binary files /dev/null and b/sound/weapons/shotgunpump_open.ogg differ
diff --git a/sound/weapons/sniper_rack_close.ogg b/sound/weapons/sniper_rack_close.ogg
new file mode 100644
index 0000000000000..550cb5da7eaee
Binary files /dev/null and b/sound/weapons/sniper_rack_close.ogg differ
diff --git a/sound/weapons/sniper_rack_open.ogg b/sound/weapons/sniper_rack_open.ogg
new file mode 100644
index 0000000000000..e58aa989eab18
Binary files /dev/null and b/sound/weapons/sniper_rack_open.ogg differ