diff --git a/code/datums/repositories/ammomaterial.dm b/code/datums/repositories/ammomaterial.dm
new file mode 100644
index 00000000000..7186adbd002
--- /dev/null
+++ b/code/datums/repositories/ammomaterial.dm
@@ -0,0 +1,18 @@
+var/global/datum/repository/ammomaterial/ammo_repository = new()
+
+/datum/repository/ammomaterial
+ var/list/ammotypes
+
+/datum/repository/ammomaterial/New()
+ ammotypes = list()
+ ..()
+
+/datum/repository/ammomaterial/proc/get_materials_from_object(obj/item/ammo_casing/I)
+
+ if(!(I in ammotypes))
+ ammotypes += I
+ var/obj/item/ammo_casing/temp = new I
+ ammotypes[I] = temp.matter
+ qdel(temp)
+
+ return ammotypes[I]
\ No newline at end of file
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index ddd50a8f50a..4424a338f9c 100644
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -8,7 +8,7 @@ obj/machinery/recharger
idle_power_usage = 4
active_power_usage = 40000 //40 kW
var/obj/item/charging = null
- var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/device/laptop, /obj/item/weapon/cell, /obj/item/device/flashlight, /obj/item/device/electronic_assembly, /obj/item/weapon/weldingtool/electric)
+ var/list/allowed_devices = list(/obj/item/weapon/gun/energy, /obj/item/weapon/melee/baton, /obj/item/device/laptop, /obj/item/weapon/cell, /obj/item/device/flashlight, /obj/item/device/electronic_assembly, /obj/item/weapon/weldingtool/electric, /obj/item/ammo_magazine/smart)
var/icon_state_charged = "recharger2"
var/icon_state_charging = "recharger1"
var/icon_state_idle = "recharger0" //also when unpowered
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index a9307e10ac0..52e02bd7bac 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -86,6 +86,8 @@
var/ammo_type = /obj/item/ammo_casing //ammo type that is initially loaded
var/initial_ammo = null
+ var/can_remove_ammo = TRUE // Can this thing have bullets removed one-by-one? As of first implementation, only affects smart magazines
+
var/multiple_sprites = 0
//because BYOND doesn't support numbers as keys in associative lists
var/list/icon_keys = list() //keys
@@ -117,7 +119,7 @@
return
user.remove_from_mob(C)
C.loc = src
- stored_ammo.Insert(1, C) //add to the head of the list
+ stored_ammo.Add(C)
update_icon()
if(istype(W, /obj/item/ammo_magazine/clip))
var/obj/item/ammo_magazine/clip/L = W
@@ -138,16 +140,34 @@
playsound(user.loc, 'sound/weapons/flipblade.ogg', 50, 1)
update_icon()
+// This dumps all the bullets right on the floor
/obj/item/ammo_magazine/attack_self(mob/user)
- if(!stored_ammo.len)
- to_chat(user, "[src] is already empty!")
+ if(can_remove_ammo)
+ if(!stored_ammo.len)
+ to_chat(user, "[src] is already empty!")
+ return
+ to_chat(user, "You empty [src].")
+ for(var/obj/item/ammo_casing/C in stored_ammo)
+ C.loc = user.loc
+ C.set_dir(pick(cardinal))
+ stored_ammo.Cut()
+ update_icon()
+ else
+ to_chat(user, "\The [src] is not designed to be unloaded.")
return
- to_chat(user, "You empty [src].")
- for(var/obj/item/ammo_casing/C in stored_ammo)
- C.loc = user.loc
- C.set_dir(pick(cardinal))
- stored_ammo.Cut()
- update_icon()
+
+// This puts one bullet from the magazine into your hand
+/obj/item/ammo_magazine/attack_hand(mob/user)
+ if(can_remove_ammo) // For Smart Magazines
+ if(user.get_inactive_hand() == src)
+ if(stored_ammo.len)
+ var/obj/item/ammo_casing/C = stored_ammo[stored_ammo.len]
+ stored_ammo-=C
+ user.put_in_hands(C)
+ user.visible_message("\The [user] removes \a [C] from [src].", "You remove \a [C] from [src].")
+ update_icon()
+ return
+ ..()
/obj/item/ammo_magazine/update_icon()
if(multiple_sprites)
diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm
index 5ea1c0a2d69..6f88fed227a 100644
--- a/code/modules/projectiles/ammunition/magazines.dm
+++ b/code/modules/projectiles/ammunition/magazines.dm
@@ -51,7 +51,7 @@
/obj/item/ammo_magazine/s38/rubber
name = "speedloader (.38 rubber)"
icon_state = "T38"
- ammo_type = /obj/item/ammo_casing/a38r
+ ammo_type = /obj/item/ammo_casing/a38/rubber
/obj/item/ammo_magazine/s38/emp
name = "speedloader (.38 haywire)"
@@ -74,19 +74,19 @@
/obj/item/ammo_magazine/m45/rubber
name = "magazine (.45 rubber)"
- ammo_type = /obj/item/ammo_casing/a45r
+ ammo_type = /obj/item/ammo_casing/a45/rubber
/obj/item/ammo_magazine/m45/practice
name = "magazine (.45 practice)"
- ammo_type = /obj/item/ammo_casing/a45p
+ ammo_type = /obj/item/ammo_casing/a45/practice
/obj/item/ammo_magazine/m45/flash
name = "magazine (.45 flash)"
- ammo_type = /obj/item/ammo_casing/a45f
+ ammo_type = /obj/item/ammo_casing/a45/flash
/obj/item/ammo_magazine/m45/ap
name = "magazine (.45 AP)"
- ammo_type = /obj/item/ammo_casing/a45ap
+ ammo_type = /obj/item/ammo_casing/a45/ap
/obj/item/ammo_magazine/box/emp/b45
name = "ammunition box (.45 haywire)"
@@ -116,7 +116,7 @@
/obj/item/ammo_magazine/m45tommy/ap
name = "tommygun magazine (.45 AP)"
- ammo_type = /obj/item/ammo_casing/a45ap
+ ammo_type = /obj/item/ammo_casing/a45/ap
/obj/item/ammo_magazine/m45tommy/empty
initial_ammo = 0
@@ -133,7 +133,7 @@
/obj/item/ammo_magazine/m45tommydrum/ap
name = "tommygun drum magazine (.45 AP)"
- ammo_type = /obj/item/ammo_casing/a45ap
+ ammo_type = /obj/item/ammo_casing/a45/ap
/obj/item/ammo_magazine/m45tommydrum/empty
initial_ammo = 0
@@ -150,15 +150,15 @@
/obj/item/ammo_magazine/clip/c45/rubber
name = "ammo clip (.45 rubber)"
- ammo_type = /obj/item/ammo_casing/a45r
+ ammo_type = /obj/item/ammo_casing/a45/rubber
/obj/item/ammo_magazine/clip/c45/practice
name = "ammo clip (.45 practice)"
- ammo_type = /obj/item/ammo_casing/a45p
+ ammo_type = /obj/item/ammo_casing/a45/practice
/obj/item/ammo_magazine/clip/c45/flash
name = "ammo clip (.45 flash)"
- ammo_type = /obj/item/ammo_casing/a45f
+ ammo_type = /obj/item/ammo_casing/a45/flash
/obj/item/ammo_magazine/s45
name = "speedloader (.45)"
@@ -174,19 +174,19 @@
/obj/item/ammo_magazine/s45/rubber
name = "speedloader (.45 rubber)"
- ammo_type = /obj/item/ammo_casing/a45r
+ ammo_type = /obj/item/ammo_casing/a45/rubber
/obj/item/ammo_magazine/s45/practice
name = "speedloader (.45 practice)"
- ammo_type = /obj/item/ammo_casing/a45p
+ ammo_type = /obj/item/ammo_casing/a45/practice
/obj/item/ammo_magazine/s45/flash
name = "speedloader (.45 flash)"
- ammo_type = /obj/item/ammo_casing/a45f
+ ammo_type = /obj/item/ammo_casing/a45/flash
/obj/item/ammo_magazine/s45/ap
name = "speedloader (.45 AP)"
- ammo_type = /obj/item/ammo_casing/a45ap
+ ammo_type = /obj/item/ammo_casing/a45/ap
///////// 9mm /////////
@@ -215,15 +215,15 @@
/obj/item/ammo_magazine/m9mm/flash
name = "magazine (9mm flash)"
- ammo_type = /obj/item/ammo_casing/a9mmf
+ ammo_type = /obj/item/ammo_casing/a9mm/flash
/obj/item/ammo_magazine/m9mm/rubber
name = "magazine (9mm rubber)"
- ammo_type = /obj/item/ammo_casing/a9mmr
+ ammo_type = /obj/item/ammo_casing/a9mm/rubber
/obj/item/ammo_magazine/m9mm/practice
name = "magazine (9mm practice)"
- ammo_type = /obj/item/ammo_casing/a9mmp
+ ammo_type = /obj/item/ammo_casing/a9mm/practice
// Compact
/obj/item/ammo_magazine/m9mm/compact
@@ -242,15 +242,15 @@
/obj/item/ammo_magazine/m9mm/compact/flash
name = "compact magazine (9mm flash)"
- ammo_type = /obj/item/ammo_casing/a9mmf
+ ammo_type = /obj/item/ammo_casing/a9mm/flash
/obj/item/ammo_magazine/m9mm/compact/rubber
name = "compact magazine (9mm rubber)"
- ammo_type = /obj/item/ammo_casing/a9mmr
+ ammo_type = /obj/item/ammo_casing/a9mm/rubber
/obj/item/ammo_magazine/m9mm/compact/practice
name = "compact magazine (9mm practice)"
- ammo_type = /obj/item/ammo_casing/a9mmp
+ ammo_type = /obj/item/ammo_casing/a9mm/practice
// SMG
/obj/item/ammo_magazine/m9mmt
@@ -268,15 +268,15 @@
/obj/item/ammo_magazine/m9mmt/rubber
name = "top mounted magazine (9mm rubber)"
- ammo_type = /obj/item/ammo_casing/a9mmr
+ ammo_type = /obj/item/ammo_casing/a9mm/rubber
/obj/item/ammo_magazine/m9mmt/flash
name = "top mounted magazine (9mm flash)"
- ammo_type = /obj/item/ammo_casing/a9mmf
+ ammo_type = /obj/item/ammo_casing/a9mm/flash
/obj/item/ammo_magazine/m9mmt/practice
name = "top mounted magazine (9mm practice)"
- ammo_type = /obj/item/ammo_casing/a9mmp
+ ammo_type = /obj/item/ammo_casing/a9mm/practice
/obj/item/ammo_magazine/m9mmp90
name = "large capacity top mounted magazine (9mm armor-piercing)"
@@ -303,15 +303,15 @@
/obj/item/ammo_magazine/clip/c9mm/rubber
name = "ammo clip (.45 rubber)"
- ammo_type = /obj/item/ammo_casing/a9mmr
+ ammo_type = /obj/item/ammo_casing/a9mm/rubber
/obj/item/ammo_magazine/clip/c9mm/practice
name = "ammo clip (.45 practice)"
- ammo_type = /obj/item/ammo_casing/a9mmp
+ ammo_type = /obj/item/ammo_casing/a9mm/practice
/obj/item/ammo_magazine/clip/c9mm/flash
name = "ammo clip (.45 flash)"
- ammo_type = /obj/item/ammo_casing/a9mmf
+ ammo_type = /obj/item/ammo_casing/a9mm/flash
/obj/item/ammo_magazine/box/c9mm // Made by RnD for Prototype SMG and should probably be removed because why does it require DIAMONDS to make bullets?
name = "ammunition Box (9mm)"
@@ -406,7 +406,7 @@
/obj/item/ammo_magazine/m545/practice
name = "magazine (5.45mm practice)"
- ammo_type = /obj/item/ammo_casing/a545p
+ ammo_type = /obj/item/ammo_casing/a545/practice
/obj/item/ammo_magazine/m545/practice/ext
name = "extended magazine (5.45mm practice)"
@@ -439,7 +439,7 @@
/obj/item/ammo_magazine/m545/small/practice
name = "magazine (5.45mm practice)"
- ammo_type = /obj/item/ammo_casing/a545p
+ ammo_type = /obj/item/ammo_casing/a545/practice
/obj/item/ammo_magazine/m545/small/ap
name = "magazine (5.45mm armor-piercing)"
@@ -534,7 +534,7 @@
/obj/item/ammo_magazine/s44/rubber
name = "speedloader (.44 rubber)"
icon_state = "R44"
- ammo_type = /obj/item/ammo_casing/a44r
+ ammo_type = /obj/item/ammo_casing/a44/rubber
///////// 7.62mm /////////
@@ -604,7 +604,7 @@
/obj/item/ammo_magazine/clip/c762/practice
name = "rifle clip (7.62mm practice)"
- ammo_type = /obj/item/ammo_casing/a762p
+ ammo_type = /obj/item/ammo_casing/a762/practice
/obj/item/ammo_magazine/clip/c762/hunter
name = "rifle clip (7.62mm hunting)"
diff --git a/code/modules/projectiles/ammunition/rounds.dm b/code/modules/projectiles/ammunition/rounds.dm
index 028d1cac1e1..406dbcae88b 100644
--- a/code/modules/projectiles/ammunition/rounds.dm
+++ b/code/modules/projectiles/ammunition/rounds.dm
@@ -27,6 +27,7 @@
desc = "A .357 bullet casing."
caliber = ".357"
projectile_type = /obj/item/projectile/bullet/pistol/strong
+ matter = list(DEFAULT_WALL_MATERIAL = 210)
/*
* .38
@@ -36,10 +37,10 @@
desc = "A .38 bullet casing."
caliber = ".38"
projectile_type = /obj/item/projectile/bullet/pistol
+ matter = list(DEFAULT_WALL_MATERIAL = 60)
-/obj/item/ammo_casing/a38r
+/obj/item/ammo_casing/a38/rubber
desc = "A .38 rubber bullet casing."
- caliber = ".38"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/bullet/pistol/rubber
@@ -58,12 +59,13 @@
desc = "A .44 bullet casing."
caliber = ".44"
projectile_type = /obj/item/projectile/bullet/pistol/strong
+ matter = list(DEFAULT_WALL_MATERIAL = 210)
-/obj/item/ammo_casing/a44r
+/obj/item/ammo_casing/a44/rubber
icon_state = "r-casing"
desc = "A .44 rubber bullet casing."
- caliber = ".44"
projectile_type = /obj/item/projectile/bullet/pistol/rubber/strong
+ matter = list(DEFAULT_WALL_MATERIAL = 60)
/*
* .75 (aka Gyrojet Rockets, aka admin abuse)
@@ -73,6 +75,7 @@
desc = "A .75 gyrojet rocket sheathe."
caliber = ".75"
projectile_type = /obj/item/projectile/bullet/gyro
+ matter = list(DEFAULT_WALL_MATERIAL = 4000)
/*
* 9mm
@@ -82,26 +85,25 @@
desc = "A 9mm bullet casing."
caliber = "9mm"
projectile_type = /obj/item/projectile/bullet/pistol
+ matter = list(DEFAULT_WALL_MATERIAL = 60)
/obj/item/ammo_casing/a9mm/ap
desc = "A 9mm armor-piercing bullet casing."
projectile_type = /obj/item/projectile/bullet/pistol/ap
+ matter = list(DEFAULT_WALL_MATERIAL = 80)
-/obj/item/ammo_casing/a9mmf
+/obj/item/ammo_casing/a9mm/flash
desc = "A 9mm flash shell casing."
- caliber = "9mm"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/energy/flash
-/obj/item/ammo_casing/a9mmr
+/obj/item/ammo_casing/a9mm/rubber
desc = "A 9mm rubber bullet casing."
- caliber = "9mm"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/bullet/pistol/rubber
-/obj/item/ammo_casing/a9mmp
+/obj/item/ammo_casing/a9mm/practice
desc = "A 9mm practice bullet casing."
- caliber = "9mm"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/bullet/pistol/practice
@@ -113,30 +115,30 @@
desc = "A .45 bullet casing."
caliber = ".45"
projectile_type = /obj/item/projectile/bullet/pistol/medium
+ matter = list(DEFAULT_WALL_MATERIAL = 75)
-/obj/item/ammo_casing/a45ap
+/obj/item/ammo_casing/a45/ap
desc = "A .45 Armor-Piercing bullet casing."
- caliber = ".45"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/bullet/pistol/medium/ap
-/obj/item/ammo_casing/a45p
+/obj/item/ammo_casing/a45/practice
desc = "A .45 practice bullet casing."
- caliber = ".45"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/bullet/pistol/practice
+ matter = list(DEFAULT_WALL_MATERIAL = 60)
-/obj/item/ammo_casing/a45r
+/obj/item/ammo_casing/a45/rubber
desc = "A .45 rubber bullet casing."
- caliber = ".45"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/bullet/pistol/rubber
+ matter = list(DEFAULT_WALL_MATERIAL = 60)
-/obj/item/ammo_casing/a45f
+/obj/item/ammo_casing/a45/flash
desc = "A .45 flash shell casing."
- caliber = ".45"
icon_state = "r-casing"
projectile_type = /obj/item/projectile/energy/flash
+ matter = list(DEFAULT_WALL_MATERIAL = 60)
/obj/item/ammo_casing/a45/emp
name = ".45 haywire round"
@@ -149,7 +151,6 @@
desc = "A .45 hollow-point bullet casing."
projectile_type = /obj/item/projectile/bullet/pistol/medium/hollow
-
/*
* 10mm
*/
@@ -158,6 +159,7 @@
desc = "A 10mm bullet casing."
caliber = "10mm"
projectile_type = /obj/item/projectile/bullet/pistol/medium
+ matter = list(DEFAULT_WALL_MATERIAL = 75)
/obj/item/ammo_casing/a10mm/emp
name = "10mm haywire round"
@@ -183,7 +185,6 @@
desc = "A 12 gauge shell."
icon_state = "gshell"
projectile_type = /obj/item/projectile/bullet/pellet/shotgun
- matter = list(DEFAULT_WALL_MATERIAL = 360)
/obj/item/ammo_casing/a12g/blank
name = "shotgun shell"
@@ -197,7 +198,7 @@
desc = "A practice shell."
icon_state = "pshell"
projectile_type = /obj/item/projectile/bullet/shotgun/practice
- matter = list("metal" = 90)
+ matter = list(DEFAULT_WALL_MATERIAL = 90)
/obj/item/ammo_casing/a12g/beanbag
name = "beanbag shell"
@@ -244,16 +245,18 @@
caliber = "7.62mm"
icon_state = "rifle-casing"
projectile_type = /obj/item/projectile/bullet/rifle/a762
+ matter = list(DEFAULT_WALL_MATERIAL = 200)
/obj/item/ammo_casing/a762/ap
desc = "A 7.62mm armor-piercing bullet casing."
projectile_type = /obj/item/projectile/bullet/rifle/a762/ap
+ matter = list(DEFAULT_WALL_MATERIAL = 300)
-/obj/item/ammo_casing/a762p
+/obj/item/ammo_casing/a762/practice
desc = "A 7.62mm practice bullet casing."
- caliber = "7.62mm"
icon_state = "rifle-casing" // Need to make an icon for these
projectile_type = /obj/item/projectile/bullet/rifle/practice
+ matter = list(DEFAULT_WALL_MATERIAL = 90)
/obj/item/ammo_casing/a762/blank
desc = "A blank 7.62mm bullet casing."
@@ -288,16 +291,18 @@
caliber = "5.45mm"
icon_state = "rifle-casing"
projectile_type = /obj/item/projectile/bullet/rifle/a545
+ matter = list(DEFAULT_WALL_MATERIAL = 180)
/obj/item/ammo_casing/a545/ap
desc = "A 5.45mm armor-piercing bullet casing."
projectile_type = /obj/item/projectile/bullet/rifle/a545/ap
+ matter = list(DEFAULT_WALL_MATERIAL = 270)
-/obj/item/ammo_casing/a545p
+/obj/item/ammo_casing/a545/practice
desc = "A 5.45mm practice bullet casing."
- caliber = "5.45mm"
icon_state = "rifle-casing" // Need to make an icon for these
projectile_type = /obj/item/projectile/bullet/rifle/practice
+ matter = list(DEFAULT_WALL_MATERIAL = 90)
/obj/item/ammo_casing/a545/blank
desc = "A blank 5.45mm bullet casing."
@@ -322,6 +327,7 @@
icon_state = "rocketshell"
projectile_type = /obj/item/missile
caliber = "rocket"
+ matter = list(DEFAULT_WALL_MATERIAL = 10000)
/obj/item/ammo_casing/cap
name = "cap"
@@ -330,6 +336,7 @@
icon_state = "r-casing"
color = "#FF0000"
projectile_type = /obj/item/projectile/bullet/pistol/cap
+ matter = list(DEFAULT_WALL_MATERIAL = 85)
/obj/item/ammo_casing/spent // For simple hostile mobs only, so they don't cough up usable bullets when firing. This is for literally nothing else.
icon_state = "s-casing-spent"
diff --git a/code/modules/projectiles/ammunition/smartmag.dm b/code/modules/projectiles/ammunition/smartmag.dm
new file mode 100644
index 00000000000..4b42f18251b
--- /dev/null
+++ b/code/modules/projectiles/ammunition/smartmag.dm
@@ -0,0 +1,226 @@
+///////// Smart Mags /////////
+
+/obj/item/ammo_magazine/smart
+ name = "smart magazine"
+ icon_state = "smartmag-empty"
+ desc = "A Hephaistos Industries brand Smart Magazine. It uses advanced matter manipulation technology to create bullets from energy. Simply present your loaded gun or magazine to the Smart Magazine."
+ multiple_sprites = 1
+ max_ammo = 5
+ mag_type = MAGAZINE
+
+ caliber = null //Set later
+ ammo_type = null //Set later
+ initial_ammo = 0 //Ensure no problems with no ammo_type or caliber set
+
+ can_remove_ammo = FALSE // Interferes with batteries
+
+ var/production_time = 6 SECONDS // Delay in between bullets forming
+ var/last_production_time = 0 // Used in determining if we should make a new bullet
+ var/production_cost = null // Set when an ammo type is scanned in
+ var/production_modifier = 2 // Multiplier on the ammo_casing's matter cost
+ var/production_delay = 75 // If we're in a gun, how long since it last shot do we need to wait before making bullets?
+
+ var/obj/item/weapon/gun/holding_gun = null // What gun are we in, if any?
+
+ var/obj/item/weapon/cell/device/attached_cell = null // What cell are we using, if any?
+
+ var/emagged = 0 // If you emag the smart mag, you can get the bullets out by clicking it
+
+/obj/item/ammo_magazine/smart/New()
+ processing_objects |= src
+ ..()
+
+/obj/item/ammo_magazine/smart/Destroy()
+ processing_objects -= src
+ ..()
+
+/obj/item/ammo_magazine/smart/process()
+ if(!holding_gun) // Yes, this is awful, sorry. Don't know a better way to figure out if we've been moved into or out of a gun.
+ if(istype(src.loc, /obj/item/weapon/gun))
+ holding_gun = src.loc
+
+ if(caliber && ammo_type && attached_cell)
+ if(stored_ammo.len == max_ammo)
+ last_production_time = world.time // Otherwise the max_ammo var is basically always off by 1
+ return
+ if(holding_gun && world.time < holding_gun.last_shot + production_delay) // Same as recharging energy weapons.
+ return
+ if(world.time > last_production_time + production_time)
+ last_production_time = world.time
+ produce()
+
+/obj/item/ammo_magazine/smart/examine(mob/user)
+ ..()
+
+ if(attached_cell)
+ to_chat(user, "\The [src] is loaded with a [attached_cell.name]. It is [round(attached_cell.percent())]% charged.")
+ else
+ to_chat(user, "\The [src] does not appear to have a power source installed.")
+
+/obj/item/ammo_magazine/smart/update_icon()
+ if(attached_cell)
+ icon_state = "smartmag-filled"
+ else
+ icon_state = "smartmag-empty"
+
+// Emagging lets you remove bullets from your bullet-making magazine
+/obj/item/ammo_magazine/smart/emag_act(var/remaining_charges, var/mob/user)
+ if(!emagged)
+ to_chat(user, "You overload \the [src]'s security measures causing widespread destabilisation. It is likely you could empty \the [src] now.")
+ emagged = TRUE
+ can_remove_ammo = TRUE
+ return TRUE
+ return FALSE
+
+/obj/item/ammo_magazine/smart/attackby(var/obj/item/I as obj, mob/user)
+ if(istype(I, /obj/item/weapon/cell/device))
+ if(attached_cell)
+ to_chat(user, "\The [src] already has a [attached_cell.name] attached.")
+ return
+ else
+ to_chat(user, "You begin inserting \the [I] into \the [src].")
+ if(do_after(user, 25))
+ user.drop_item()
+ I.forceMove(src)
+ attached_cell = I
+ user.visible_message("[user] installs a cell in \the [src].", "You install \the [I] into \the [src].")
+ update_icon()
+ return
+
+ else if(I.is_screwdriver())
+ if(attached_cell)
+ to_chat(user, "You begin removing \the [attached_cell] from \the [src].")
+ if(do_after(user, 10)) // Faster than doing it by hand
+ attached_cell.update_icon()
+ attached_cell.forceMove(get_turf(src.loc))
+ attached_cell = null
+ user.visible_message("[user] removes a cell from \the [src].", "You remove \the [attached_cell] from \the [src].")
+ update_icon()
+ return
+
+ else if(istype(I, /obj/item/ammo_magazine) || istype(I, /obj/item/ammo_casing))
+ scan_ammo(I, user)
+
+ ..()
+
+/obj/item/ammo_magazine/smart/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
+ if(src.loc == user)
+ scan_ammo(target, user)
+ ..()
+
+// You can remove the power cell from the magazine by hand, but it's way slower than using a screwdriver
+/obj/item/ammo_magazine/smart/attack_hand(mob/user)
+ if(user.get_inactive_hand() == src)
+ if(attached_cell)
+ to_chat(user, "You struggle to remove \the [attached_cell] from \the [src].")
+ if(do_after(user, 40))
+ attached_cell.update_icon()
+ user.put_in_hands(attached_cell)
+ attached_cell = null
+ user.visible_message("[user] removes a cell from \the [src].", "You remove \the [attached_cell] from \the [src].")
+ update_icon()
+ return
+ ..()
+
+// Classic emp_act, just drains the battery
+/obj/item/ammo_magazine/smart/emp_act(severity)
+ ..()
+ if(attached_cell)
+ attached_cell.emp_act(severity)
+
+// Finds the cell for the magazine, used by rechargers
+/obj/item/ammo_magazine/smart/get_cell()
+ return attached_cell
+
+// Removes energy from the attached cell when creating new bullets
+/obj/item/ammo_magazine/smart/proc/chargereduction()
+ return attached_cell && attached_cell.checked_use(production_cost)
+
+// Sets how much energy is drained to make each bullet
+/obj/item/ammo_magazine/smart/proc/set_production_cost(var/obj/item/ammo_casing/A)
+ var/list/matters = ammo_repository.get_materials_from_object(A)
+ var/tempcost
+ for(var/key in matters)
+ var/value = matters[key]
+ tempcost += value * production_modifier
+ production_cost = tempcost
+
+// Scans a magazine or ammo casing and tells the smart mag to start making those, if it can
+/obj/item/ammo_magazine/smart/proc/scan_ammo(atom/target, mob/user)
+
+ var/new_caliber = caliber // Tracks what our new caliber will be
+ var/new_ammo_type = ammo_type // Tracks what our new ammo_type will be
+
+ if(istype(target, /obj/item/ammo_magazine))
+ var/obj/item/ammo_magazine/M = target
+ if(!new_caliber)
+ new_caliber = M.caliber // If caliber isn't set, set it now
+
+ if(new_caliber && new_caliber != M.caliber) // If we still don't have a caliber, or if our caliber doesn't match the thing we're scanning, give up
+ return
+ else
+ new_ammo_type = M.ammo_type
+
+ if(istype(target, /obj/item/ammo_casing))
+ var/obj/item/ammo_casing/C = target
+
+ if(!new_caliber)
+ new_caliber = C.caliber // If caliber isn't set, set it now
+
+ if(new_caliber && new_caliber != C.caliber) // If we still don't have a caliber, or if our caliber doesn't match the thing we're scanning, give up
+ return
+ else
+ new_ammo_type = C.type
+
+ var/change = FALSE // If we've changed caliber or ammo_type, display the built message.
+ var/msg = "You scan \the [target] with \the [src], copying \the [target]'s "
+ if(new_caliber != caliber) // This should never happen without the ammo_type switching too
+ change = TRUE
+ msg += "caliber and "
+ if(new_ammo_type != ammo_type)
+ change = TRUE
+ msg += "ammunition type."
+
+ if(change)
+ to_chat(user, "[msg]")
+ caliber = new_caliber
+ ammo_type = new_ammo_type
+ set_production_cost(ammo_type) // Update our cost
+
+ return
+
+// Actually makes the bullets
+/obj/item/ammo_magazine/smart/proc/produce()
+ if(chargereduction())
+ var/obj/item/ammo_casing/W = new ammo_type(src)
+ stored_ammo.Insert(1, W) //add to the head of the list
+ return 1
+ return 0
+
+
+// This verb clears out the smart mag's copied data, but only if it's empty
+/obj/item/ammo_magazine/smart/verb/clear_ammo_data()
+ set name = "Clear Ammo Data"
+ set category = "Object"
+ set src in usr
+
+ if(!istype(src.loc, /mob/living)) // Needs to be in your hands to reset
+ return
+
+ var/mob/living/carbon/human/H = usr
+ if(!istype(H))
+ return
+ if(H.stat)
+ return
+
+ if(LAZYLEN(stored_ammo))
+ to_chat(usr, "You can't reset \the [src] unless it's empty!")
+ return
+
+ to_chat(usr, "You clear \the [src]'s data buffers.")
+
+ caliber = null
+ ammo_type = null
+ production_cost = null
+
+ return
\ No newline at end of file
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index f8445008fe9..68ad8f0fd55 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -91,6 +91,7 @@
var/obj/item/dnalockingchip/attached_lock
var/last_shot = 0 //records the last shot fired
+
/obj/item/weapon/gun/New()
..()
for(var/i in 1 to firemodes.len)
@@ -376,9 +377,11 @@
last_shot = world.time
-/* // Commented out for quality control and testing.
+/*
+ // Commented out for quality control and testing.
shooting = 0
*/
+
// We do this down here, so we don't get the message if we fire an empty gun.
if(user.item_is_in_hands(src) && user.hands_are_full())
if(one_handed_penalty >= 20)
@@ -478,8 +481,6 @@
if(muzzle_flash)
set_light(0)
-
-
//obtains the next projectile to fire
/obj/item/weapon/gun/proc/consume_next_projectile()
return null
@@ -551,7 +552,6 @@
shake_camera(user, recoil+1, recoil)
update_icon()
-
/obj/item/weapon/gun/proc/process_point_blank(obj/projectile, mob/user, atom/target)
var/obj/item/projectile/P = projectile
if(!istype(P))
@@ -640,7 +640,6 @@
return launched
-
/obj/item/weapon/gun/proc/play_fire_sound(var/mob/user, var/obj/item/projectile/P)
var/shot_sound = (istype(P) && P.fire_sound)? P.fire_sound : fire_sound
if(silenced)
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index be37c824bb4..6539ba7c4a2 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -41,6 +41,7 @@
loaded += new ammo_type(src)
if(ispath(magazine_type) && (load_method & MAGAZINE))
ammo_magazine = new magazine_type(src)
+ allowed_magazines += /obj/item/ammo_magazine/smart
update_icon()
/obj/item/weapon/gun/projectile/consume_next_projectile()
@@ -50,7 +51,7 @@
if(handle_casings != HOLD_CASINGS)
loaded -= chambered
else if(ammo_magazine && ammo_magazine.stored_ammo.len)
- chambered = ammo_magazine.stored_ammo[1]
+ chambered = ammo_magazine.stored_ammo[ammo_magazine.stored_ammo.len]
if(handle_casings != HOLD_CASINGS)
ammo_magazine.stored_ammo -= chambered
diff --git a/code/modules/projectiles/guns/projectile/boltaction.dm b/code/modules/projectiles/guns/projectile/boltaction.dm
index 45e5f1ece57..5ebbb4e9514 100644
--- a/code/modules/projectiles/guns/projectile/boltaction.dm
+++ b/code/modules/projectiles/guns/projectile/boltaction.dm
@@ -15,7 +15,7 @@
/obj/item/weapon/gun/projectile/shotgun/pump/rifle/practice // For target practice
desc = "A bolt-action rifle with a lightweight synthetic wood stock, designed for competitive shooting. Comes shipped with practice rounds pre-loaded into the gun. Popular among professional marksmen. Uses 7.62mm rounds."
- ammo_type = /obj/item/ammo_casing/a762p
+ ammo_type = /obj/item/ammo_casing/a762/practice
/obj/item/weapon/gun/projectile/shotgun/pump/rifle/ceremonial
name = "ceremonial bolt-action rifle"
diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm
index a2329566841..47108364081 100644
--- a/code/modules/projectiles/guns/projectile/pistol.dm
+++ b/code/modules/projectiles/guns/projectile/pistol.dm
@@ -266,8 +266,8 @@
var/global/list/ammo_types = list(
/obj/item/ammo_casing/a357 = ".357",
- /obj/item/ammo_casing/a9mmf = "9mm",
- /obj/item/ammo_casing/a45f = ".45",
+ /obj/item/ammo_casing/a9mm = "9mm",
+ /obj/item/ammo_casing/a45 = ".45",
/obj/item/ammo_casing/a10mm = "10mm",
/obj/item/ammo_casing/a12g = "12g",
/obj/item/ammo_casing/a12g = "12g",
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index 481530856f1..2d25265ea55 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -74,7 +74,7 @@
caliber = ".45"
origin_tech = list(TECH_COMBAT = 2, TECH_MATERIAL = 2)
fire_sound = 'sound/weapons/gunshot_heavy.ogg'
- ammo_type = /obj/item/ammo_casing/a45r
+ ammo_type = /obj/item/ammo_casing/a45/rubber
max_shells = 7
diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi
index 56d3a651249..e225bf77770 100644
Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ
diff --git a/polaris.dme b/polaris.dme
index e0a4bc02f9c..cb53cdf3ff2 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -275,6 +275,7 @@
#include "code\datums\outfits\military\marines.dm"
#include "code\datums\outfits\military\military.dm"
#include "code\datums\outfits\military\sifguard.dm"
+#include "code\datums\repositories\ammomaterial.dm"
#include "code\datums\repositories\cameras.dm"
#include "code\datums\repositories\crew.dm"
#include "code\datums\repositories\decls.dm"
@@ -2126,6 +2127,7 @@
#include "code\modules\projectiles\ammunition\magazines.dm"
#include "code\modules\projectiles\ammunition\magnetic.dm"
#include "code\modules\projectiles\ammunition\rounds.dm"
+#include "code\modules\projectiles\ammunition\smartmag.dm"
#include "code\modules\projectiles\guns\energy.dm"
#include "code\modules\projectiles\guns\launcher.dm"
#include "code\modules\projectiles\guns\modular_guns.dm"