diff --git a/code/game/gamemodes/factions.dm b/code/game/gamemodes/factions.dm
index 1aaa70e2a54..47c8586f6e1 100644
--- a/code/game/gamemodes/factions.dm
+++ b/code/game/gamemodes/factions.dm
@@ -119,7 +119,7 @@
operative_notes = "We'd like to remind our operatives to keep it professional. You are not here to have a good time, you are here to accomplish your objectives. These vile communists must be stopped at all costs. You may collaborate with any friends of the Syndicate coalition, but keep an eye on any of those Tiger punks if they do show up. You are completely free to accomplish your objectives any way you see fit."
uplink_contents = {"Highly Visible and Dangerous Weapons;
-/obj/item/weapon/gun/projectile:6:Revolver;
+/obj/item/weapon/gun/projectile/revolver:6:Revolver;
/obj/item/ammo_magazine/a357:2:Ammo-357;
/obj/item/weapon/gun/energy/crossbow:5:Energy Crossbow;
/obj/item/weapon/melee/energy/sword:4:Energy Sword;
diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm
index ccce7f9bff6..d9f129a27e0 100644
--- a/code/game/gamemodes/wizard/rightandwrong.dm
+++ b/code/game/gamemodes/wizard/rightandwrong.dm
@@ -49,7 +49,7 @@
if("combatshotgun")
new /obj/item/weapon/gun/projectile/shotgun/pump/combat(get_turf(H))
if("mateba")
- new /obj/item/weapon/gun/projectile/mateba(get_turf(H))
+ new /obj/item/weapon/gun/projectile/revolver/mateba(get_turf(H))
if("smg")
new /obj/item/weapon/gun/projectile/automatic(get_turf(H))
if("uzi")
diff --git a/code/game/machinery/autolathe_datums.dm b/code/game/machinery/autolathe_datums.dm
index 3948f70f33c..c7d592c1d0d 100644
--- a/code/game/machinery/autolathe_datums.dm
+++ b/code/game/machinery/autolathe_datums.dm
@@ -217,13 +217,13 @@
category = "Arms and Ammunition"
/datum/autolathe/recipe/magazine_rubber
- name = "ammunition (rubber)"
- path = /obj/item/ammo_magazine/c45r
+ name = "ammunition (.45, rubber)"
+ path = /obj/item/ammo_magazine/c45m/rubber
category = "Arms and Ammunition"
/datum/autolathe/recipe/magazine_flash
- name = "ammunition (flash)"
- path = /obj/item/ammo_magazine/c45f
+ name = "ammunition (.45, flash)"
+ path = /obj/item/ammo_magazine/c45m/flash
category = "Arms and Ammunition"
/datum/autolathe/recipe/consolescreen
diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm
index fc1d2e2b8a4..3ad4972cafc 100644
--- a/code/game/objects/items/weapons/storage/uplink_kits.dm
+++ b/code/game/objects/items/weapons/storage/uplink_kits.dm
@@ -26,7 +26,7 @@
return
if("guns")
- new /obj/item/weapon/gun/projectile(src)
+ new /obj/item/weapon/gun/projectile/revolver(src)
new /obj/item/ammo_magazine/a357(src)
new /obj/item/weapon/card/emag(src)
new /obj/item/weapon/plastique(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index b5b8796b3c0..4185215f28b 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -258,8 +258,8 @@
new /obj/item/device/radio/headset/headset_sec(src)
new /obj/item/device/detective_scanner(src)
new /obj/item/clothing/suit/armor/det_suit(src)
- new /obj/item/ammo_magazine/c45r(src)
- new /obj/item/ammo_magazine/c45r(src)
+ new /obj/item/ammo_magazine/c45m/rubber(src)
+ new /obj/item/ammo_magazine/c45m/rubber(src)
new /obj/item/taperoll/police(src)
new /obj/item/weapon/gun/projectile/detective/semiauto(src)
new /obj/item/clothing/tie/holster/armpit(src)
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index db7f0ec78bf..f750b7428e2 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -710,7 +710,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
for(var/i=3, i>0, i--)
sec_briefcase.contents += new /obj/item/weapon/spacecash/c1000
sec_briefcase.contents += new /obj/item/weapon/gun/energy/crossbow
- sec_briefcase.contents += new /obj/item/weapon/gun/projectile/mateba
+ sec_briefcase.contents += new /obj/item/weapon/gun/projectile/revolver/mateba
sec_briefcase.contents += new /obj/item/ammo_magazine/a357
sec_briefcase.contents += new /obj/item/weapon/plastique
M.equip_to_slot_or_del(sec_briefcase, slot_l_hand)
@@ -892,7 +892,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/eyepatch(M), slot_glasses)
M.equip_to_slot_or_del(new /obj/item/clothing/suit/hgpirate(M), slot_wear_suit)
M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(M), slot_back)
- M.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/mateba(M), slot_belt)
+ M.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver/mateba(M), slot_belt)
M.equip_to_slot_or_del(new /obj/item/clothing/under/soviet(M), slot_w_uniform)
var/obj/item/weapon/card/id/W = new(M)
W.name = "[M.real_name]'s ID Card"
diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm
index 36199c0305d..9f42da94d9f 100644
--- a/code/modules/admin/verbs/striketeam.dm
+++ b/code/modules/admin/verbs/striketeam.dm
@@ -153,7 +153,7 @@ var/global/sent_strike_team = 0
equip_to_slot_or_del(new /obj/item/weapon/melee/energy/sword(src), slot_l_store)
equip_to_slot_or_del(new /obj/item/weapon/grenade/flashbang(src), slot_r_store)
equip_to_slot_or_del(new /obj/item/weapon/tank/emergency_oxygen(src), slot_s_store)
- equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/mateba(src), slot_belt)
+ equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver/mateba(src), slot_belt)
equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle(src), slot_r_hand)
diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm
index b09a6ec548c..b96a615170c 100644
--- a/code/modules/mob/living/simple_animal/hostile/russian.dm
+++ b/code/modules/mob/living/simple_animal/hostile/russian.dm
@@ -38,7 +38,7 @@
icon_state = "russianranged"
icon_living = "russianranged"
corpse = /obj/effect/landmark/mobcorpse/russian/ranged
- weapon1 = /obj/item/weapon/gun/projectile/mateba
+ weapon1 = /obj/item/weapon/gun/projectile/revolver/mateba
ranged = 1
projectiletype = /obj/item/projectile/bullet
projectilesound = 'sound/weapons/Gunshot.ogg'
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index b4b213972f5..fa17429016a 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -6,73 +6,125 @@
flags = CONDUCT
slot_flags = SLOT_BELT
throwforce = 1
- w_class = 1.0
+ w_class = 1
var/caliber = "" //Which kind of guns it can be loaded into
var/projectile_type //The bullet type to create when New() is called
- var/obj/item/projectile/BB = null //The loaded bullet
-
-
- New()
- ..()
- if(ispath(projectile_type))
- BB = new projectile_type(src)
- pixel_x = rand(-10.0, 10)
- pixel_y = rand(-10.0, 10)
- set_dir(pick(cardinal))
+ var/obj/item/projectile/BB = null //The loaded bullet - make it so that the projectiles are created only when needed?
+/obj/item/ammo_casing/New()
+ ..()
+ if(ispath(projectile_type))
+ BB = new projectile_type(src)
+ pixel_x = rand(-10, 10)
+ pixel_y = rand(-10, 10)
+ set_dir(pick(cardinal))
/obj/item/ammo_casing/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/screwdriver))
- if(BB)
- if(initial(BB.name) == "bullet")
- var/tmp_label = ""
- var/label_text = sanitize(copytext(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), 1, MAX_NAME_LEN))
- if(length(label_text) > 20)
- user << "\red The inscription can be at most 20 characters long."
- else
- if(label_text == "")
- user << "\blue You scratch the inscription off of [initial(BB)]."
- BB.name = initial(BB.name)
- else
- user << "\blue You inscribe \"[label_text]\" into \the [initial(BB.name)]."
- BB.name = "[initial(BB.name)] \"[label_text]\""
- else
- user << "\blue You can only inscribe a metal bullet." //because inscribing beanbags is silly
- else
+ if(!BB)
user << "\blue There is no bullet in the casing to inscribe anything into."
+ return
+
+ var/tmp_label = ""
+ var/label_text = sanitize(copytext(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), 1, MAX_NAME_LEN))
+ if(length(label_text) > 20)
+ user << "\red The inscription can be at most 20 characters long."
+ else if(!label_text)
+ user << "\blue You scratch the inscription off of [initial(BB)]."
+ BB.name = initial(BB.name)
+ else
+ user << "\blue You inscribe \"[label_text]\" into \the [initial(BB.name)]."
+ BB.name = "[initial(BB.name)] (\"[label_text]\")"
/obj/item/ammo_casing/examine(mob/user)
..()
if (!BB)
user << "This one is spent."
-//Boxes of ammo
+//Gun loading types
+#define SINGLE_CASING 1 //The gun only accepts ammo_casings. ammo_magazines should never have this as their mag_type.
+#define SPEEDLOADER 2 //Transfers casings from the mag to the gun when used.
+#define MAGAZINE 4 //The magazine item itself goes inside the gun
+
+//An item that holds casings and can be used to put them inside guns
/obj/item/ammo_magazine
- name = "ammo box (.357)"
- desc = "A box of ammo"
+ name = "magazine"
+ desc = "A magazine for some kind of gun."
icon_state = "357"
icon = 'icons/obj/ammo.dmi'
flags = CONDUCT
slot_flags = SLOT_BELT
item_state = "syringe_kit"
- matter = list("metal" = 50000)
- throwforce = 2
- w_class = 2.0
+ matter = list("metal" = 500)
+ throwforce = 5
+ w_class = 2
throw_speed = 4
throw_range = 10
+
var/list/stored_ammo = list()
- var/ammo_type = "/obj/item/ammo_casing"
+ var/mag_type = SPEEDLOADER //ammo_magazines can only be used with compatible guns
+ var/caliber = "357"
var/max_ammo = 7
+
+ var/ammo_type = /obj/item/ammo_casing //ammo type that is initially loaded
+ var/initial_ammo = null
+
var/multiple_sprites = 0
+ var/list/icon_map = list()
+/obj/item/ammo_magazine/New()
+ if(multiple_sprites)
+ //should probably be cached or something.
+ icon_map = list(max_ammo = icon_state)
+ var/list/states = icon_states(icon)
+ for(var/i = 0, i <= max_ammo, i++)
+ var/ammo_state = "[icon_state]-[i]"
+ if(ammo_state in states)
+ //icon_map += i //so stupid BYOND understands that it's an association
+ icon_map[i] = ammo_state
- New()
- for(var/i = 1, i <= max_ammo, i++)
+ if(isnull(initial_ammo))
+ initial_ammo = max_ammo
+
+ if(initial_ammo)
+ for(var/i in 1 to initial_ammo)
stored_ammo += new ammo_type(src)
+ update_icon()
+
+/obj/item/ammo_magazine/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/ammo_casing))
+ var/obj/item/ammo_casing/C = W
+ if(C.caliber != caliber)
+ user << "[C] does not fit into [src]."
+ return
+ if(stored_ammo.len >= max_ammo)
+ user << "[src] is full!"
+ return
+ user.remove_from_mob(C)
+ C.loc = src
+ stored_ammo.Insert(1, C) //add to the head of the list
update_icon()
-
+/obj/item/ammo_magazine/attack_self(mob/user)
+ if(!stored_ammo.len)
+ user << "[src] is already empty!"
+ return
+ user << "You empty [src]."
+ for(var/obj/item/ammo_casing/C in stored_ammo)
+ C.loc = user.loc
+ stored_ammo.Cut()
update_icon()
- if(multiple_sprites)
- icon_state = "[initial(icon_state)]-[stored_ammo.len]"
- desc = "There are [stored_ammo.len] shell\s left!"
+
+/obj/item/ammo_magazine/update_icon()
+ if(multiple_sprites)
+ //find the lowest key greater than or equal to stored_ammo.len
+ var/new_state = null
+ for(var/i in icon_map)
+ if (i >= stored_ammo.len)
+ new_state = icon_map[i]
+ break
+ icon_state = (new_state)? new_state : initial(icon_state)
+
+/obj/item/ammo_magazine/examine(mob/user)
+ ..()
+ user << "There [(stored_ammo.len > 1)? "are" : "is"] [stored_ammo.len] round\s left!"
\ No newline at end of file
diff --git a/code/modules/projectiles/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm
index b4ae141cd74..a65a7bc4d13 100644
--- a/code/modules/projectiles/ammunition/boxes.dm
+++ b/code/modules/projectiles/ammunition/boxes.dm
@@ -2,44 +2,147 @@
name = "ammo box (.357)"
desc = "A box of .357 ammo"
icon_state = "357"
- ammo_type = "/obj/item/ammo_casing/a357"
+ caliber = "357"
+ ammo_type = /obj/item/ammo_casing/a357
max_ammo = 7
multiple_sprites = 1
/obj/item/ammo_magazine/c38
name = "speed loader (.38)"
icon_state = "38"
- ammo_type = "/obj/item/ammo_casing/c38"
+ caliber = "38"
+ ammo_type = /obj/item/ammo_casing/c38
max_ammo = 6
multiple_sprites = 1
+/obj/item/ammo_magazine/c38/rubber
+ name = "speed loader (.38 rubber)"
+ ammo_type = /obj/item/ammo_casing/c38r
/obj/item/ammo_magazine/c45m
name = "magazine (.45)"
icon_state = "45"
- ammo_type = "/obj/item/ammo_casing/c45"
+ mag_type = MAGAZINE
+ ammo_type = /obj/item/ammo_casing/c45
+ caliber = ".45"
max_ammo = 7
multiple_sprites = 1
-/obj/item/ammo_magazine/c45/empty
- max_ammo = 0
+/obj/item/ammo_magazine/c45m/empty
+ initial_ammo = 0
-/obj/item/ammo_magazine/c45r
+/obj/item/ammo_magazine/c45m/rubber
name = "magazine (.45 rubber)"
- icon_state = "45"
- ammo_type = "/obj/item/ammo_casing/c45r"
- max_ammo = 7
- multiple_sprites = 1
+ ammo_type = /obj/item/ammo_casing/c45r
-/obj/item/ammo_magazine/c45f
+/obj/item/ammo_magazine/c45m/flash
name = "magazine (.45 flash)"
- icon_state = "45"
ammo_type = "/obj/item/ammo_casing/c45f"
+
+/obj/item/ammo_magazine/mc9mm
+ name = "magazine (9mm)"
+ icon_state = "9x19p"
+ origin_tech = "combat=2"
+ mag_type = MAGAZINE
+ caliber = "9mm"
+ ammo_type = /obj/item/ammo_casing/c9mm
+ max_ammo = 10
+ multiple_sprites = 1
+
+/obj/item/ammo_magazine/mc9mm/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/mc9mm/flash
+ ammo_type = /obj/item/ammo_casing/c9mmf
+
+/obj/item/ammo_magazine/c9mm
+ name = "ammunition Box (9mm)"
+ icon_state = "9mm"
+ origin_tech = "combat=2"
+ caliber = "9mm"
+ ammo_type = /obj/item/ammo_casing/c9mm
+ max_ammo = 30
+
+/obj/item/ammo_magazine/c9mm/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/c45
+ name = "ammunition Box (.45)"
+ icon_state = "9mm"
+ origin_tech = "combat=2"
+ caliber = ".45"
+ ammo_type = /obj/item/ammo_casing/c45
+ max_ammo = 30
+
+/obj/item/ammo_magazine/c9mm/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/a12mm
+ name = "magazine (12mm)"
+ icon_state = "12mm"
+ origin_tech = "combat=2"
+ mag_type = MAGAZINE
+ caliber = "12mm"
+ ammo_type = "/obj/item/ammo_casing/a12mm"
+ max_ammo = 20
+ multiple_sprites = 1
+
+/obj/item/ammo_magazine/a12mm/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/a50
+ name = "magazine (.50)"
+ icon_state = "50ae"
+ origin_tech = "combat=2"
+ mag_type = MAGAZINE
+ caliber = ".50"
+ ammo_type = /obj/item/ammo_casing/a50
max_ammo = 7
multiple_sprites = 1
-/obj/item/ammo_magazine/c45r/empty
- max_ammo = 0
+/obj/item/ammo_magazine/a50/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/a75
+ name = "ammo magazine (20mm)"
+ icon_state = "75"
+ mag_type = MAGAZINE
+ caliber = "75"
+ ammo_type = /obj/item/ammo_casing/a75
+ multiple_sprites = 1
+ max_ammo = 4
+
+/obj/item/ammo_magazine/a75/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/a762
+ name = "magazine box (7.62mm)"
+ icon_state = "a762"
+ origin_tech = "combat=2"
+ mag_type = MAGAZINE
+ caliber = "a762"
+ ammo_type = /obj/item/ammo_casing/a762
+ max_ammo = 50
+ multiple_sprites = 1
+
+/obj/item/ammo_magazine/a762/empty
+ initial_ammo = 0
+
+/obj/item/ammo_magazine/chameleon
+ name = "magazine (.45)"
+ icon_state = "45"
+ mag_type = MAGAZINE
+ caliber = ".45"
+ ammo_type = /obj/item/ammo_casing/chameleon
+ max_ammo = 7
+ multiple_sprites = 1
+ matter = list()
+
+/obj/item/ammo_magazine/chameleon/empty
+ initial_ammo = 0
+
+/*
+//unused garbage
/obj/item/ammo_magazine/a418
name = "ammo box (.418)"
@@ -48,114 +151,10 @@
max_ammo = 7
multiple_sprites = 1
-
-
/obj/item/ammo_magazine/a666
name = "ammo box (.666)"
icon_state = "666"
ammo_type = "/obj/item/ammo_casing/a666"
max_ammo = 4
multiple_sprites = 1
-
-
-/obj/item/ammo_magazine/mc9mm
- name = "magazine (9mm)"
- icon_state = "9x19p"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/c9mm"
- max_ammo = 10
- multiple_sprites = 1
-
-/obj/item/ammo_magazine/mc9mm/empty
- max_ammo = 0
-
-/obj/item/ammo_magazine/c9mm
- name = "Ammunition Box (9mm)"
- icon_state = "9mm"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/c9mm"
- max_ammo = 30
-
-
-
-/obj/item/ammo_magazine/c45
- name = "Ammunition Box (.45)"
- icon_state = "9mm"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/c45"
- max_ammo = 30
-
-
-
-/obj/item/ammo_magazine/a12mm
- name = "magazine (12mm)"
- icon_state = "12mm"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/a12mm"
- max_ammo = 20
- multiple_sprites = 1
-
-
-/obj/item/ammo_magazine/a12mm/empty
- name = "magazine (12mm)"
- icon_state = "12mm"
- ammo_type = "/obj/item/ammo_casing/12mm"
- max_ammo = 0
-
-/obj/item/ammo_magazine/a50
- name = "magazine (.50)"
- icon_state = "50ae"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/a50"
- max_ammo = 7
- multiple_sprites = 1
-
-/obj/item/ammo_magazine/a50/empty
- name = "magazine (.50)"
- icon_state = "50ae"
- ammo_type = "/obj/item/ammo_casing/a50"
- max_ammo = 0
-
-/obj/item/ammo_magazine/a75
- name = "ammo magazine (.75)"
- icon_state = "75"
- ammo_type = "/obj/item/ammo_casing/a75"
- multiple_sprites = 1
- max_ammo = 8
-
-/obj/item/ammo_magazine/a75/empty
- name = "ammo magazine (.75)"
- icon_state = "75"
- ammo_type = "/obj/item/ammo_casing/a75"
- max_ammo = 0
-
-/obj/item/ammo_magazine/a762
- name = "magazine (a762)"
- icon_state = "a762"
- origin_tech = "combat=2"
- ammo_type = "/obj/item/ammo_casing/a762"
- max_ammo = 50
- multiple_sprites = 1
-
-/obj/item/ammo_magazine/a762/empty
- name = "magazine (a762)"
- icon_state = "a762"
- ammo_type = "/obj/item/ammo_casing/a762"
- max_ammo = 0
- multiple_sprites = 1
-
-/obj/item/ammo_magazine/chameleon
- name = "magazine (.45)"
- icon_state = "45"
- ammo_type = "/obj/item/ammo_casing/chameleon"
- max_ammo = 7
- multiple_sprites = 1
- matter = list()
-
-/obj/item/ammo_magazine/chameleon/empty
- name = "magazine (.45)"
- icon_state = "45"
- ammo_type = "/obj/item/ammo_casing/chameleon"
- max_ammo = 0
- multiple_sprites = 1
- matter = list()
+*/
\ No newline at end of file
diff --git a/code/modules/projectiles/ammunition/bullets.dm b/code/modules/projectiles/ammunition/bullets.dm
index d0cb2915dc6..54c65fe019f 100644
--- a/code/modules/projectiles/ammunition/bullets.dm
+++ b/code/modules/projectiles/ammunition/bullets.dm
@@ -16,6 +16,11 @@
/obj/item/ammo_casing/c38
desc = "A .38 bullet casing."
caliber = "38"
+ projectile_type = /obj/item/projectile/bullet/pistol
+
+/obj/item/ammo_casing/c38r
+ desc = "A .38 rubber bullet casing."
+ caliber = "38"
projectile_type = /obj/item/projectile/bullet/pistol/rubber
/obj/item/ammo_casing/c9mm
@@ -23,6 +28,12 @@
caliber = "9mm"
projectile_type = /obj/item/projectile/bullet/pistol
+/obj/item/ammo_casing/c9mmf
+ desc = "A 9mm flash shell casing."
+ caliber = "9mm"
+ projectile_type = /obj/item/projectile/energy/flash
+
+
/obj/item/ammo_casing/c45
desc = "A .45 bullet casing."
caliber = ".45"
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index d7aae8f8f7d..dc9c77a294f 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -78,7 +78,7 @@
/obj/item/weapon/gun/proc/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)//TODO: go over this
//Exclude lasertag guns from the CLUMSY check.
if(!user) return
-
+
if(clumsy_check)
if(istype(user, /mob/living))
var/mob/living/M = user
@@ -122,7 +122,7 @@
"You hear a [istype(in_chamber, /obj/item/projectile/beam) ? "laser blast" : "gunshot"]!")
user.next_move = world.time + 4
-
+
var/x_offset = 0
var/y_offset = 0
if(istype(user, /mob/living/carbon))
@@ -135,21 +135,20 @@
x_offset = rand(-1,1)
if(in_chamber)
- if(params) in_chamber.set_clickpoint(params)
-
+ if(params)
+ in_chamber.set_clickpoint(params)
+
var/fail = in_chamber.launch(
- target = target,
- user = user,
- launcher = src,
- target_zone = user.zone_sel.selecting,
- x_offset = x_offset,
- y_offset = y_offset,
- px = p_x,
- py = p_y
+ target = target,
+ user = user,
+ launcher = src,
+ target_zone = user.zone_sel.selecting,
+ x_offset = x_offset,
+ y_offset = y_offset
)
-
+
if(fail) return
-
+
if(recoil)
spawn()
shake_camera(user, recoil + 1, recoil)
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index bea28e9c37c..a500af113f0 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -1,111 +1,160 @@
-#define SPEEDLOADER 0
-#define FROM_BOX 1
-#define MAGAZINE 2
-
/obj/item/weapon/gun/projectile
- name = "revolver"
- desc = "A classic revolver. Uses .357 ammo"
+ name = "gun"
+ desc = "A gun that fires bullets."
icon_state = "revolver"
caliber = "357"
origin_tech = "combat=2;materials=2"
- w_class = 3.0
+ w_class = 3
matter = list("metal" = 1000)
recoil = 1
- var/ammo_type = "/obj/item/ammo_casing/a357"
+
+ var/load_method = SINGLE_CASING|SPEEDLOADER //1 = Single shells, 2 = box or quick loader, 3 = magazine
+
+ //For SINGLE_CASING or SPEEDLOADER guns
+ var/max_shells = 0
+ var/ammo_type = null
var/list/loaded = list()
- var/max_shells = 7
- var/load_method = SPEEDLOADER //0 = Single shells or quick loader, 1 = box, 2 = magazine
- var/obj/item/ammo_magazine/empty_mag = null
- var/mag_type = null
+
+ //For MAGAZINE guns
+ var/magazine_type = null
+ var/obj/item/ammo_magazine/ammo_magazine = null
+ var/auto_eject = 0 //if the magazine should automatically eject itself when empty.
/obj/item/weapon/gun/projectile/New()
..()
- for(var/i = 1, i <= max_shells, i++)
- loaded += new ammo_type(src)
- if(load_method == MAGAZINE)
- empty_mag = new mag_type(src)
+
+ if(load_method & (SINGLE_CASING|SPEEDLOADER))
+ for(var/i in 1 to max_shells)
+ loaded += new ammo_type(src)
+ if(load_method & MAGAZINE)
+ ammo_magazine = new magazine_type(src)
+
update_icon()
- return
-
+//This proc is badly named. There is no "chamber." Would be better to call this get_next_projectile() or something.
/obj/item/weapon/gun/projectile/load_into_chamber()
if(in_chamber)
return 1 //{R}
- if(!loaded.len)
- return 0
- var/obj/item/ammo_casing/AC = loaded[1] //load next casing.
- loaded -= AC //Remove casing from loaded list.
- if(isnull(AC) || !istype(AC))
- return 0
- AC.loc = get_turf(src) //Eject casing onto ground.
- if(AC.BB)
- in_chamber = AC.BB //Load projectile into chamber.
- AC.BB.loc = src //Set projectile loc to gun.
- return 1
+ var/obj/item/ammo_casing/C = null
+ if(loaded.len)
+ C = loaded[1] //load next casing.
+ loaded -= C
+ else if(ammo_magazine && ammo_magazine.stored_ammo.len)
+ C = ammo_magazine.stored_ammo[1]
+ ammo_magazine.stored_ammo -= C
+
+ if(istype(C))
+ C.loc = get_turf(src) //Eject casing onto ground.
+ if(C.BB)
+ in_chamber = C.BB
+ C.BB.loc = src //Set projectile loc to gun.
+ return 1
+
return 0
+//Attempts to load A into src, depending on the type of thing being loaded and the load_method
+/obj/item/weapon/gun/projectile/proc/load_ammo(var/obj/item/A, mob/user)
+ if(istype(A, /obj/item/ammo_magazine))
+ var/obj/item/ammo_magazine/AM = A
+ if(!(load_method & AM.mag_type) || caliber != AM.caliber)
+ return //incompatible
+
+ switch(AM.mag_type)
+ if(MAGAZINE)
+ if(ammo_magazine)
+ return //already a magazine here
+ user.remove_from_mob(AM)
+ AM.loc = src
+ ammo_magazine = AM
+ user.visible_message("[user] inserts [AM] into [src].", "You insert [AM] into [src]!")
+ if(SPEEDLOADER)
+ var/count = 0
+ for(var/obj/item/ammo_casing/C in AM.stored_ammo)
+ if(loaded.len >= max_shells)
+ break
+ if(C.caliber == caliber)
+ C.loc = src
+ loaded += C
+ AM.stored_ammo -= C //should probably go inside an ammo_magazine proc, but I guess less proc calls this way...
+ count++
+ if(count)
+ user.visible_message("[user] reloads [src].", "You load [count] round\s into [src]!")
+ AM.update_icon()
+ update_icon()
+ return
+
+ else if(istype(A, /obj/item/ammo_casing))
+ var/obj/item/ammo_casing/C = A
+ if(!(load_method & SINGLE_CASING) || caliber != C.caliber || loaded.len >= max_shells)
+ return //incompatible or full
+
+ user.remove_from_mob(C)
+ C.loc = src
+ loaded += C
+ user.visible_message("[user] inserts \a [C] into [src].", "You insert \a [C] into [src]!")
+ update_icon()
+ return
+
+//attempts to unload src
+/obj/item/weapon/gun/projectile/proc/unload_ammo(mob/user)
+ if(ammo_magazine)
+ user.put_in_hands(ammo_magazine)
+ user.visible_message("[user] removes [ammo_magazine] from [src].", "You remove [ammo_magazine] from [src]!")
+ ammo_magazine.update_icon()
+ ammo_magazine = null
+ update_icon()
+
+ else if(loaded.len)
+ //presumably, if it can be speed-loaded, it can be speed-unloaded.
+ if(load_method & SPEEDLOADER)
+ var/count = 0
+ var/turf/T = get_turf(user)
+ if(T)
+ for(var/obj/item/ammo_casing/C in loaded)
+ C.loc = T
+ count++
+ loaded.Cut()
+ if(count)
+ user.visible_message("[user] unloads [src].", "You unload [count] round\s from [src]!")
+ else
+ var/obj/item/ammo_casing/C = loaded[loaded.len]
+ loaded.len--
+ user.put_in_hands(C)
+ user.visible_message("[user] removes \a [C] from [src].", "You remove \a [C] from [src]!")
+ update_icon()
+
+ else
+ user << "There's nothing loaded in [src]!"
/obj/item/weapon/gun/projectile/attackby(var/obj/item/A as obj, mob/user as mob)
-
- var/num_loaded = 0
- if(istype(A, /obj/item/ammo_magazine))
- if((load_method == MAGAZINE) && loaded.len) return
- var/obj/item/ammo_magazine/AM = A
- if(AM.stored_ammo.len <= 0)
- user << "The magazine is empty!"
- return
- for(var/obj/item/ammo_casing/AC in AM.stored_ammo)
- if(loaded.len >= max_shells)
- break
- if(AC.caliber == caliber && loaded.len < max_shells)
- AC.loc = src
- AM.stored_ammo -= AC
- loaded += AC
- num_loaded++
- if(load_method == MAGAZINE)
- user.remove_from_mob(AM)
- empty_mag = AM
- empty_mag.loc = src
- if(istype(A, /obj/item/ammo_casing) && load_method == SPEEDLOADER)
- var/obj/item/ammo_casing/AC = A
- if(AC.caliber == caliber && loaded.len < max_shells)
- user.drop_item()
- AC.loc = src
- loaded += AC
- num_loaded++
- if(num_loaded)
- user << "\blue You load [num_loaded] shell\s into the gun!"
- A.update_icon()
- update_icon()
- return
+ load_ammo(A, user)
/obj/item/weapon/gun/projectile/attack_self(mob/user as mob)
- if (target)
+ if (target) //TODO replace untargeting with a hotkey
return ..()
- if (loaded.len)
- if (load_method == SPEEDLOADER)
- var/obj/item/ammo_casing/AC = loaded[1]
- loaded -= AC
- AC.loc = get_turf(src) //Eject casing onto ground.
- user << "\blue You unload shell from \the [src]!"
- if (load_method == MAGAZINE)
- var/obj/item/ammo_magazine/AM = empty_mag
- for (var/obj/item/ammo_casing/AC in loaded)
- AM.stored_ammo += AC
- loaded -= AC
- AM.loc = get_turf(src)
- empty_mag = null
- update_icon()
- AM.update_icon()
- user << "\blue You unload magazine from \the [src]!"
- else
- user << "\red Nothing loaded in \the [src]!"
+ unload_ammo(user)
+/obj/item/weapon/gun/projectile/afterattack(atom/A, mob/living/user)
+ ..()
+ if(auto_eject && !ammo_magazine.stored_ammo.len)
+ eject_magazine(user)
+//called when the magazine auto-ejects
+/obj/item/weapon/gun/projectile/proc/eject_magazine(mob/user)
+ if(ammo_magazine)
+ ammo_magazine.loc = get_turf(src.loc)
+ user.visible_message(
+ "[ammo_magazine] falls out and clatters on the floor!",
+ "[ammo_magazine] falls out and clatters on the floor!"
+ )
+ ammo_magazine = null
+ update_icon()
/obj/item/weapon/gun/projectile/examine(mob/user)
..(user)
+ if(ammo_magazine)
+ user << "It has \a [ammo_magazine] loaded."
user << "Has [getAmmo()] round\s remaining."
// if(in_chamber && !loaded.len)
// user << "However, it has a chambered round."
@@ -115,7 +164,8 @@
/obj/item/weapon/gun/projectile/proc/getAmmo()
var/bullets = 0
- for(var/obj/item/ammo_casing/AC in loaded)
- if(istype(AC))
- bullets += 1
+ if(loaded)
+ bullets += loaded.len
+ if(ammo_magazine.stored_ammo)
+ bullets += ammo_magazine.stored_ammo.len
return bullets
diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm
index 0e5f0d68cd3..98049fb8a59 100644
--- a/code/modules/projectiles/guns/projectile/automatic.dm
+++ b/code/modules/projectiles/guns/projectile/automatic.dm
@@ -2,11 +2,12 @@
name = "submachine gun"
desc = "A lightweight, fast firing gun. Uses 9mm rounds."
icon_state = "saber" //ugly
- w_class = 3.0
+ w_class = 3
+ load_method = SPEEDLOADER //yup. until someone sprites a magazine for it.
max_shells = 22
caliber = "9mm"
origin_tech = "combat=4;materials=2"
- ammo_type = "/obj/item/ammo_casing/c9mm"
+ ammo_type = /obj/item/ammo_casing/c9mm
automatic = 1
fire_delay = 0
@@ -14,19 +15,16 @@
isHandgun()
return 0
-/obj/item/weapon/gun/projectile/automatic/test
- name = "test gun"
- ammo_type = "/obj/item/ammo_casing/a145"
-
/obj/item/weapon/gun/projectile/automatic/mini_uzi
name = "\improper Uzi"
desc = "A lightweight, fast firing gun, for when you want someone dead. Uses .45 rounds."
icon_state = "mini-uzi"
- w_class = 3.0
- max_shells = 16
+ w_class = 3
+ load_method = SPEEDLOADER //yup. until someone sprites a magazine for it.
+ max_shells = 15
caliber = ".45"
origin_tech = "combat=5;materials=2;syndicate=8"
- ammo_type = "/obj/item/ammo_casing/c45"
+ ammo_type = /obj/item/ammo_casing/c45
isHandgun()
return 1
@@ -37,32 +35,26 @@
desc = "A lightweight, fast firing gun, for when you REALLY need someone dead. Uses 12mm rounds. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp"
icon_state = "c20r"
item_state = "c20r"
- w_class = 3.0
- max_shells = 20
+ w_class = 3
caliber = "12mm"
origin_tech = "combat=5;materials=2;syndicate=8"
- ammo_type = "/obj/item/ammo_casing/a12mm"
fire_sound = 'sound/weapons/Gunshot_smg.ogg'
load_method = MAGAZINE
- mag_type = /obj/item/ammo_magazine/a12mm/empty
+ magazine_type = /obj/item/ammo_magazine/a12mm
+ auto_eject = 1
- afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
- ..()
- if(!loaded.len && empty_mag)
- empty_mag.loc = get_turf(src.loc)
- empty_mag = null
- playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
- update_icon()
- return
+/obj/item/weapon/gun/projectile/automatic/c20r/eject_magazine(mob/user)
+ ..()
+ playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
+/obj/item/weapon/gun/projectile/automatic/c20r/update_icon()
+ ..()
+ if(ammo_magazine)
+ icon_state = "c20r-[round(loaded.len,4)]"
+ else
+ icon_state = "c20r"
+ return
- update_icon()
- ..()
- if(empty_mag)
- icon_state = "c20r-[round(loaded.len,4)]"
- else
- icon_state = "c20r"
- return
/obj/item/weapon/gun/projectile/automatic/l6_saw
name = "\improper L6 SAW"
@@ -77,19 +69,16 @@
ammo_type = "/obj/item/ammo_casing/a762"
fire_sound = 'sound/weapons/Gunshot_smg.ogg'
load_method = MAGAZINE
+ magazine_type = /obj/item/ammo_magazine/a762
var/cover_open = 0
- var/mag_inserted = 1
-
/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_self(mob/user as mob)
cover_open = !cover_open
user << "You [cover_open ? "open" : "close"] [src]'s cover."
update_icon()
-
/obj/item/weapon/gun/projectile/automatic/l6_saw/update_icon()
- icon_state = "l6[cover_open ? "open" : "closed"][mag_inserted ? round(loaded.len, 25) : "-empty"]"
-
+ icon_state = "l6[cover_open ? "open" : "closed"][ammo_magazine ? round(loaded.len, 25) : "-empty"]"
/obj/item/weapon/gun/projectile/automatic/l6_saw/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params) //what I tried to do here is just add a check to see if the cover is open or not and add an icon_state change because I can't figure out how c-20rs do it with overlays
if(cover_open)
@@ -98,46 +87,14 @@
..()
update_icon()
-
/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_hand(mob/user as mob)
if(loc != user)
- ..()
- return //let them pick it up
- if(!cover_open || (cover_open && !mag_inserted))
- ..()
- else if(cover_open && mag_inserted)
- //drop the mag
- empty_mag = new /obj/item/ammo_magazine/a762(src)
- empty_mag.stored_ammo = loaded
- empty_mag.icon_state = "a762-[round(loaded.len, 10)]"
- empty_mag.desc = "There are [loaded.len] shells left!"
- empty_mag.loc = get_turf(src.loc)
- user.put_in_hands(empty_mag)
- empty_mag = null
- mag_inserted = 0
- loaded = list()
- update_icon()
- user << "You remove the magazine from [src]."
-
+ ..() //let them pick it up
+ else if(cover_open)
+ unload_ammo(user)
/obj/item/weapon/gun/projectile/automatic/l6_saw/attackby(var/obj/item/A as obj, mob/user as mob)
- if(!cover_open)
+ if(istype(A,/obj/item/ammo_magazine) && !cover_open)
user << "[src]'s cover is closed! You can't insert a new mag!"
return
- else if(cover_open && mag_inserted)
- user << "[src] already has a magazine inserted!"
- return
- else if(cover_open && !mag_inserted)
- mag_inserted = 1
- user << "You insert the magazine!"
- update_icon()
- ..()
-
-
-/* The thing I found with guns in ss13 is that they don't seem to simulate the rounds in the magazine in the gun.
- Afaik, since projectile.dm features a revolver, this would make sense since the magazine is part of the gun.
- However, it looks like subsequent guns that use removable magazines don't take that into account and just get
- around simulating a removable magazine by adding the casings into the loaded list and spawning an empty magazine
- when the gun is out of rounds. Which means you can't eject magazines with rounds in them. The below is a very
- rough and poor attempt at making that happen. -Ausops */
-
\ No newline at end of file
+ ..()
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm
index f12420f7dce..6dd1cfbe9b2 100644
--- a/code/modules/projectiles/guns/projectile/pistol.dm
+++ b/code/modules/projectiles/guns/projectile/pistol.dm
@@ -2,42 +2,32 @@
name = "silenced pistol"
desc = "A small, quiet, easily concealable gun. Uses .45 rounds."
icon_state = "silenced_pistol"
- w_class = 3.0
- max_shells = 12
+ w_class = 3
caliber = ".45"
silenced = 1
origin_tech = "combat=2;materials=2;syndicate=8"
- ammo_type = "/obj/item/ammo_casing/c45"
-
-
+ load_method = MAGAZINE
+ magazine_type = /obj/item/ammo_magazine/c45m
/obj/item/weapon/gun/projectile/deagle
name = "desert eagle"
desc = "A robust handgun that uses .50 AE ammo"
icon_state = "deagle"
force = 14.0
- max_shells = 7
caliber = ".50"
- ammo_type ="/obj/item/ammo_casing/a50"
load_method = MAGAZINE
- mag_type = /obj/item/ammo_magazine/a50/empty
+ magazine_type = /obj/item/ammo_magazine/a50
+ auto_eject = 1
- afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
- ..()
- if(!loaded.len && empty_mag)
- empty_mag.loc = get_turf(src.loc)
- empty_mag = null
- playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
- update_icon()
- return
+/obj/item/weapon/gun/projectile/deagle/eject_magazine(mob/user)
+ ..()
+ playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
/obj/item/weapon/gun/projectile/deagle/gold
desc = "A gold plated gun folded over a million times by superior martian gunsmiths. Uses .50 AE ammo."
icon_state = "deagleg"
item_state = "deagleg"
-
-
/obj/item/weapon/gun/projectile/deagle/camo
desc = "A Deagle brand Deagle for operators operating operationally. Uses .50 AE ammo."
icon_state = "deaglecamo"
@@ -55,44 +45,34 @@
origin_tech = "combat=3"
ammo_type = "/obj/item/ammo_casing/a75"
load_method = MAGAZINE
- mag_type = /obj/item/ammo_magazine/a75/empty
+ magazine_type = /obj/item/ammo_magazine/a75
+ auto_eject = 1
- afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
- ..()
- if(!loaded.len && empty_mag)
- empty_mag.loc = get_turf(src.loc)
- empty_mag = null
- playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
- update_icon()
- return
+/obj/item/weapon/gun/projectile/gyropistol/eject_magazine(mob/user)
+ ..()
+ playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
- update_icon()
- ..()
- if(empty_mag)
- icon_state = "gyropistolloaded"
- else
- icon_state = "gyropistol"
- return
+/obj/item/weapon/gun/projectile/gyropistol/update_icon()
+ ..()
+ if(ammo_magazine)
+ icon_state = "gyropistolloaded"
+ else
+ icon_state = "gyropistol"
/obj/item/weapon/gun/projectile/pistol
name = "\improper Stechtkin pistol"
desc = "A small, easily concealable gun. Uses 9mm rounds."
icon_state = "pistol"
w_class = 2
- max_shells = 10
caliber = "9mm"
silenced = 0
origin_tech = "combat=2;materials=2;syndicate=2"
- ammo_type = "/obj/item/ammo_casing/c9mm"
load_method = MAGAZINE
- mag_type = /obj/item/ammo_magazine/mc9mm/empty
+ magazine_type = /obj/item/ammo_magazine/mc9mm
-/obj/item/weapon/gun/projectile/pistol/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
- ..()
- if(!loaded.len && empty_mag)
- empty_mag.loc = get_turf(src.loc)
- empty_mag = null
- return
+/obj/item/weapon/gun/projectile/pistol/flash
+ desc = "A small, easily concealable gun. Uses 9mm illumination rounds."
+ magazine_type = /obj/item/ammo_magazine/mc9mm/flash
/obj/item/weapon/gun/projectile/pistol/attack_hand(mob/user as mob)
if(loc == user)
@@ -108,7 +88,6 @@
return
..()
-
/obj/item/weapon/gun/projectile/pistol/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/weapon/silencer))
if(user.l_hand != src && user.r_hand != src) //if we're not in his hands
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index 226e6467aae..dc2870892b6 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -1,3 +1,13 @@
+/obj/item/weapon/gun/projectile/revolver
+ name = "revolver"
+ desc = "A classic revolver. Uses .357 ammo"
+ icon_state = "revolver"
+ caliber = "357"
+ origin_tech = "combat=2;materials=2"
+
+ max_shells = 7
+ ammo_type = /obj/item/ammo_casing/a357
+
/obj/item/weapon/gun/projectile/detective
name = "revolver"
desc = "A cheap Martian knock-off of a Smith & Wesson Model 10. Uses .38-Special rounds."
@@ -5,7 +15,7 @@
max_shells = 6
caliber = "38"
origin_tech = "combat=2;materials=2"
- ammo_type = "/obj/item/ammo_casing/c38"
+ ammo_type = /obj/item/ammo_casing/c38
special_check(var/mob/living/carbon/human/M)
if(caliber == initial(caliber))
@@ -73,37 +83,27 @@
name = "\improper Colt M1911"
desc = "A cheap Martian knock-off of a Colt M1911. Uses less-than-lethal .45 rounds."
icon_state = "colt"
- max_shells = 7
caliber = ".45"
- ammo_type = "/obj/item/ammo_casing/c45r"
load_method = MAGAZINE
- mag_type = /obj/item/ammo_magazine/c45r/empty
+ magazine_type = /obj/item/ammo_magazine/c45m/rubber
/obj/item/weapon/gun/projectile/detective/semiauto/flash
- ammo_type = "/obj/item/ammo_casing/c45f"
+ magazine_type = /obj/item/ammo_magazine/c45m/flash
/obj/item/weapon/gun/projectile/detective/semiauto/colt
desc = "A cheap Martian knock-off of a Colt M1911."
- ammo_type = "/obj/item/ammo_casing/c45"
+ magazine_type = /obj/item/ammo_magazine/c45m
-/obj/item/weapon/gun/projectile/detective/semiauto/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
- ..()
- if(!loaded.len && empty_mag)
- empty_mag.loc = get_turf(src.loc)
- empty_mag = null
- user << "The Magazine falls out and clatters on the floor!"
- return
-
-
-/obj/item/weapon/gun/projectile/mateba
+/obj/item/weapon/gun/projectile/revolver/mateba
name = "mateba"
desc = "When you absolutely, positively need a 10mm hole in the other guy. Uses .357 ammo." //>10mm hole >.357
icon_state = "mateba"
origin_tech = "combat=2;materials=2"
+
// A gun to play Russian Roulette!
// You can spin the chamber to randomize the position of the bullet.
-
+/*
/obj/item/weapon/gun/projectile/russian
name = "\improper Russian revolver"
desc = "A Russian made revolver. Uses .357 ammo. It has a single slot in it's chamber for a bullet."
@@ -184,3 +184,4 @@
user.apply_damage(300, BRUTE, affecting, sharp=1) // You are dead, dead, dead.
return
..()
+*/
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm
index e96c7637e3c..c23acfa1291 100644
--- a/code/modules/projectiles/guns/projectile/shotgun.dm
+++ b/code/modules/projectiles/guns/projectile/shotgun.dm
@@ -10,127 +10,89 @@
slot_flags = SLOT_BACK
caliber = "shotgun"
origin_tech = "combat=4;materials=2"
- ammo_type = "/obj/item/ammo_casing/shotgun/pellet"
+ load_method = SINGLE_CASING
+ ammo_type = /obj/item/ammo_casing/shotgun/pellet
var/recentpump = 0 // to prevent spammage
var/pumped = 0
var/obj/item/ammo_casing/current_shell = null
- isHandgun()
- return 0
+/obj/item/weapon/gun/projectile/shotgun/pump/isHandgun()
+ return 0
- load_into_chamber()
- if(in_chamber)
- return 1
- return 0
-
-
- attack_self(mob/living/user as mob)
- if(recentpump) return
- pump(user)
- recentpump = 1
- spawn(10)
- recentpump = 0
- return
-
-
- proc/pump(mob/M as mob)
- playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1)
- pumped = 0
- if(current_shell)//We have a shell in the chamber
- current_shell.loc = get_turf(src)//Eject casing
- current_shell = null
- if(in_chamber)
- in_chamber = null
- if(!loaded.len) return 0
- var/obj/item/ammo_casing/AC = loaded[1] //load next casing.
- loaded -= AC //Remove casing from loaded list.
- current_shell = AC
- if(AC.BB)
- in_chamber = AC.BB //Load projectile into chamber.
- update_icon() //I.E. fix the desc
+/obj/item/weapon/gun/projectile/shotgun/pump/load_into_chamber()
+ if(in_chamber)
return 1
+ return 0
+
+/obj/item/weapon/gun/projectile/shotgun/pump/attack_self(mob/living/user as mob)
+ if(world.time >= recentpump + 10)
+ pump(user)
+ recentpump = world.time
+
+/obj/item/weapon/gun/projectile/shotgun/pump/getAmmo()
+ . = ..()
+ if(current_shell) .++
+
+/obj/item/weapon/gun/projectile/shotgun/pump/proc/pump(mob/M as mob)
+ playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1)
+ pumped = 0
+ if(current_shell)//We have a shell in the chamber
+ current_shell.loc = get_turf(src)//Eject casing
+ current_shell = null
+ if(in_chamber)
+ in_chamber = null
+ if(!loaded.len) return 0
+ var/obj/item/ammo_casing/AC = loaded[1] //load next casing.
+ loaded -= AC //Remove casing from loaded list.
+ current_shell = AC
+ if(AC.BB)
+ in_chamber = AC.BB //Load projectile into chamber.
+ update_icon() //I.E. fix the desc
+ return 1
/obj/item/weapon/gun/projectile/shotgun/pump/combat
name = "combat shotgun"
icon_state = "cshotgun"
- max_shells = 8
origin_tech = "combat=5;materials=2"
- ammo_type = "/obj/item/ammo_casing/shotgun"
+ max_shells = 8
+ ammo_type = /obj/item/ammo_casing/shotgun
+
-//this is largely hacky and bad :( -Pete
/obj/item/weapon/gun/projectile/shotgun/doublebarrel
name = "double-barreled shotgun"
desc = "A true classic."
icon_state = "dshotgun"
item_state = "shotgun"
+ //SPEEDLOADER because rapid unloading.
+ //In principle someone could make a speedloader for it, so it makes sense.
+ load_method = SINGLE_CASING|SPEEDLOADER
max_shells = 2
- w_class = 4.0
+ w_class = 4
force = 10
flags = CONDUCT
slot_flags = SLOT_BACK
caliber = "shotgun"
origin_tech = "combat=3;materials=1"
- ammo_type = "/obj/item/ammo_casing/shotgun/beanbag"
+ ammo_type = /obj/item/ammo_casing/shotgun/beanbag
- New()
- for(var/i = 1, i <= max_shells, i++)
- loaded += new ammo_type(src)
-
- update_icon()
- return
-
- load_into_chamber()
-// if(in_chamber)
-// return 1 {R}
- if(!loaded.len)
- return 0
-
- var/obj/item/ammo_casing/AC = loaded[1] //load next casing.
- loaded -= AC //Remove casing from loaded list.
- AC.desc += " This one is spent."
-
- if(AC.BB)
- in_chamber = AC.BB //Load projectile into chamber.
- return 1
- return 0
-
- attack_self(mob/living/user as mob)
- if(!(locate(/obj/item/ammo_casing/shotgun) in src) && !loaded.len)
- user << "\The [src] is empty."
- return
-
- for(var/obj/item/ammo_casing/shotgun/shell in src) //This feels like a hack. //don't code at 3:30am kids!!
- if(shell in loaded)
- loaded -= shell
- shell.loc = get_turf(src.loc)
-
- user << "You break \the [src]."
- update_icon()
-
- attackby(var/obj/item/A as obj, mob/user as mob)
- if(istype(A, /obj/item/ammo_casing) && !load_method)
- var/obj/item/ammo_casing/AC = A
- if(AC.caliber == caliber && (loaded.len < max_shells) && (contents.len < max_shells)) //forgive me father, for i have sinned
- user.drop_item()
- AC.loc = src
- loaded += AC
- user << "You load a shell into \the [src]!"
- A.update_icon()
- update_icon()
- if(istype(A, /obj/item/weapon/circular_saw) || istype(A, /obj/item/weapon/melee/energy) || istype(A, /obj/item/weapon/pickaxe/plasmacutter))
- user << "You begin to shorten the barrel of \the [src]."
- if(loaded.len)
- afterattack(user, user) //will this work?
- afterattack(user, user) //it will. we call it twice, for twice the FUN
+//this is largely hacky and bad :( -Pete
+/obj/item/weapon/gun/projectile/shotgun/doublebarrel/attackby(var/obj/item/A as obj, mob/user as mob)
+ if(istype(A, /obj/item/weapon/circular_saw) || istype(A, /obj/item/weapon/melee/energy) || istype(A, /obj/item/weapon/pickaxe/plasmacutter))
+ user << "You begin to shorten the barrel of \the [src]."
+ if(loaded.len)
+ for(var/i in 1 to max_shells)
+ afterattack(user, user) //will this work? //it will. we call it twice, for twice the FUN
playsound(user, fire_sound, 50, 1)
- user.visible_message("The shotgun goes off!", "The shotgun goes off in your face!")
- return
- if(do_after(user, 30)) //SHIT IS STEALTHY EYYYYY
- icon_state = "sawnshotgun"
- w_class = 3.0
- item_state = "gun"
- slot_flags &= ~SLOT_BACK //you can't sling it on your back
- slot_flags |= SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally)
- name = "sawn-off shotgun"
- desc = "Omar's coming!"
- user << "You shorten the barrel of \the [src]!"
+ user.visible_message("The shotgun goes off!", "The shotgun goes off in your face!")
+ return
+ if(do_after(user, 30)) //SHIT IS STEALTHY EYYYYY
+ icon_state = "sawnshotgun"
+ w_class = 3
+ item_state = "gun"
+ slot_flags &= ~SLOT_BACK //you can't sling it on your back
+ slot_flags |= SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally)
+ name = "sawn-off shotgun"
+ desc = "Omar's coming!"
+ user << "You shorten the barrel of \the [src]!"
+ else
+ ..()
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index a380974fbed..525d1ccb774 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -103,8 +103,8 @@
user.bullet_act(src, target_zone)
del(src)
return 0
- if(targloc == curloc) //Shooting the ground
- targloc.bullet_act(src, target_zone)
+ if(targloc == curloc) //Shooting something in the same turf
+ target.bullet_act(src, target_zone)
del(src)
return 0
@@ -236,14 +236,20 @@
/obj/item/projectile/process()
if(kill_count < 1)
del(src)
- return
- step_towards(src, current)
- sleep(1)
- if(!bumped && !isturf(original))
- if(loc == get_turf(original))
- if(!(original in permutated))
- Bump(original)
- sleep(1)
+ kill_count--
+ spawn while(src)
+ if((!( current ) || loc == current))
+ current = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z)
+ if((x == 1 || x == world.maxx || y == 1 || y == world.maxy))
+ del(src)
+ return
+ step_towards(src, current)
+ sleep(1)
+ if(!bumped && !isturf(original))
+ if(loc == get_turf(original))
+ if(!(original in permutated))
+ Bump(original)
+ sleep(1)
//"Tracing" projectile
/obj/item/projectile/test //Used to see if you can hit them.
diff --git a/code/modules/research/xenoarchaeology/finds/finds.dm b/code/modules/research/xenoarchaeology/finds/finds.dm
index 3c2a3dd8e24..b758192bee0 100644
--- a/code/modules/research/xenoarchaeology/finds/finds.dm
+++ b/code/modules/research/xenoarchaeology/finds/finds.dm
@@ -367,7 +367,7 @@
item_type = "gun"
if(27)
//revolver
- var/obj/item/weapon/gun/projectile/new_gun = new /obj/item/weapon/gun/projectile(src.loc)
+ var/obj/item/weapon/gun/projectile/new_gun = new /obj/item/weapon/gun/projectile/revolver(src.loc)
new_item = new_gun
new_item.icon_state = "gun[rand(1,4)]"
new_item.icon = 'icons/obj/xenoarchaeology.dmi'
@@ -383,7 +383,7 @@
if(num_bullets < new_gun.loaded.len)
new_gun.loaded.Cut()
for(var/i = 1, i <= num_bullets, i++)
- var/A = text2path(new_gun.ammo_type)
+ var/A = new_gun.ammo_type
new_gun.loaded += new A(new_gun)
else
for(var/obj/item/I in new_gun)