diff --git a/code/game/gamemodes/factions.dm b/code/game/gamemodes/factions.dm index 1aaa70e2a5..47c8586f6e 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 ccce7f9bff..d9f129a27e 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 3948f70f33..c7d592c1d0 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 fc1d2e2b8a..3ad4972caf 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 b5b8796b3c..4185215f28 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 db7f0ec78b..f750b7428e 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 36199c0305..9f42da94d9 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 b09a6ec548..b96a615170 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 b4b213972f..fa17429016 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 b4ae141cd7..a65a7bc4d1 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 d0cb2915dc..54c65fe019 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 d7aae8f8f7..dc9c77a294 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 bea28e9c37..a500af113f 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 0e5f0d68cd..98049fb8a5 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 f12420f7dc..6dd1cfbe9b 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 226e6467aa..dc2870892b 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 e96c7637e3..c23acfa129 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 a380974fbe..525d1ccb77 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 3c2a3dd8e2..b758192bee 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)