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"