From 295ef51ac6cf072216fb6db860ab9b356a6824b1 Mon Sep 17 00:00:00 2001 From: Zonespace <41448081+Zonespace27@users.noreply.github.com> Date: Wed, 23 Aug 2023 11:31:16 -0700 Subject: [PATCH] Brings automatic weaponry to the marine and surv arsenal (#4003) # About the pull request Gives full auto to the following guns: m41a (and mk1) m39 HPR (when bipodded) m46c in IFF off type71 mar40 nsg every civvie SMG except the nailgun laser uzi All newly automatic guns fire 20% slower in automatic mode, to balance for the fact that it is much easier to re-aim than burst. This creates a dynamic between the three firemodes: Semi: - Best accuracy - Lowest DPS Burst: - Okay accuracy - Highest DPS Auto: - Okay (it depends) accuracy, but you are able to adjust for a moving target unlike burst. - Slightly lower DPS # Explain why it's good for the game Guns not having autofire feels... pretty rough. This PR will bring CM to a more modern time, while reducing the number of players diagnosed with carpal tunnel yearly. # Testing Photographs and Procedure I went through and tested pretty much every base gun, but I cannot guarantee that they all handle well. Lemme know if something's off. # Changelog :cl: balance: The M41A, M41Amk1, m39, m46c (iff off), mar-30/40/60, type 71, laser uzi, and every SMG now has automatic fire. To compensate for the ability to re-aim (unlike burst), the guns fire 20% slower while automatic. This does not apply to already-existing automatic weaponry. balance: The HPR can now fire in full auto when bipodded. fix: Adding/removing attachments now keeps the current firemode, if possible. fix: The dualtube and spec sniper now can switch tubes/toggle laser again fix: Fixed a long-standing exploit with bipods and scopes. fix: Fixed guns jamming when shooting UI elements. fix: Fixed a bunch of guns unintentionally having burst. balance: You can transfer ammo between HPR ammo boxes by hitting one with another. /:cl: --------- Co-authored-by: John Doe Co-authored-by: Benedict --- code/__DEFINES/conflict.dm | 4 ++- .../dcs/signals/atom/signals_item.dm | 6 ++++ code/_globalvars/bitfields.dm | 1 + code/datums/components/autofire/autofire.dm | 9 ++++-- code/datums/supply_packs/ammo.dm | 10 ------- code/datums/supply_packs/black_market.dm | 7 ++--- code/modules/clothing/shoes/miscellaneous.dm | 4 +-- code/modules/projectiles/ammunition.dm | 11 ++++--- code/modules/projectiles/gun.dm | 23 +++++++++----- code/modules/projectiles/gun_attachables.dm | 30 +++++++++++++++++-- code/modules/projectiles/gun_helpers.dm | 9 ++++++ code/modules/projectiles/guns/energy.dm | 2 ++ .../modules/projectiles/guns/flamer/flamer.dm | 2 +- code/modules/projectiles/guns/rifles.dm | 12 ++++++-- code/modules/projectiles/guns/shotguns.dm | 13 +++++--- code/modules/projectiles/guns/smgs.dm | 8 +++-- code/modules/projectiles/guns/souto.dm | 2 ++ code/modules/projectiles/guns/specialist.dm | 14 +++++---- code/modules/projectiles/magazines/rifles.dm | 2 +- code/modules/projectiles/projectile.dm | 11 +++++-- 20 files changed, 130 insertions(+), 50 deletions(-) diff --git a/code/__DEFINES/conflict.dm b/code/__DEFINES/conflict.dm index 7a1b322a19ee..30b2627bb1b0 100644 --- a/code/__DEFINES/conflict.dm +++ b/code/__DEFINES/conflict.dm @@ -68,7 +68,7 @@ #define GUN_ANTIQUE (1<<13) /// Whether the gun has been fired by its current user (reset upon `dropped()`) #define GUN_RECOIL_BUILDUP (1<<14) -/// support weapon, bipod will grant IFF +/// support weapon, bipod will grant autofire #define GUN_SUPPORT_PLATFORM (1<<15) /// No gun description, only base desc #define GUN_NO_DESCRIPTION (1<<16) @@ -99,6 +99,8 @@ #define AMMUNITION_HANDFUL_BOX (1<<2) #define AMMUNITION_HIDE_AMMO (1<<3) #define AMMUNITION_CANNOT_REMOVE_BULLETS (1<<4) +/// If this magazine can transfer to other magazines of the same type by slapping one with the other +#define AMMUNITION_SLAP_TRANSFER (1<<5) //Slowdown from various armors. /// How much shoes slow you down by default. Negative values speed you up diff --git a/code/__DEFINES/dcs/signals/atom/signals_item.dm b/code/__DEFINES/dcs/signals/atom/signals_item.dm index 138e88d21746..b7bbca9f64a3 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_item.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_item.dm @@ -54,3 +54,9 @@ #define COMSIG_GUN_AUTOFIREDELAY_MODIFIED "gun_autofiredelay_modified" #define COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED "gun_burst_shots_to_fire_modified" #define COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED "gun_burst_shot_delay_modified" + +/// from /obj/item/weapon/gun/proc/recalculate_attachment_bonuses() : () +#define COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES "gun_recalculate_attachment_bonuses" + +/// from /obj/item/weapon/gun/proc/load_into_chamber() : () +#define COMSIG_GUN_INTERRUPT_FIRE "gun_interrupt_fire" diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 4936609d892e..d71125c318f6 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -128,6 +128,7 @@ DEFINE_BITFIELD(flags_magazine, list( "AMMUNITION_HANDFUL_BOX" = AMMUNITION_HANDFUL_BOX, "AMMUNITION_HIDE_AMMO" = AMMUNITION_HIDE_AMMO, "AMMUNITION_CANNOT_REMOVE_BULLETS" = AMMUNITION_CANNOT_REMOVE_BULLETS, + "AMMUNITION_SLAP_TRANSFER" = AMMUNITION_SLAP_TRANSFER, )) DEFINE_BITFIELD(flags_atom, list( diff --git a/code/datums/components/autofire/autofire.dm b/code/datums/components/autofire/autofire.dm index 31ca255f1b88..2b9401e8d346 100644 --- a/code/datums/components/autofire/autofire.dm +++ b/code/datums/components/autofire/autofire.dm @@ -15,6 +15,8 @@ var/have_to_reset_at_burst_end = FALSE ///If we are in a burst var/bursting = FALSE + /// The multiplier for how much slower the parent should fire in automatic mode. 1 is normal, 1.2 is 20% slower, 2 is 100% slower, etc. + var/automatic_delay_mult = 1 ///Callback to set bursting mode on the parent var/datum/callback/callback_bursting ///Callback to ask the parent to reset its firing vars @@ -26,7 +28,7 @@ ///Callback to set parent's fa_firing var/datum/callback/callback_set_firing -/datum/component/automatedfire/autofire/Initialize(auto_fire_shot_delay = 0.3 SECONDS, burstfire_shot_delay, burst_shots_to_fire = 3, fire_mode = GUN_FIREMODE_SEMIAUTO, datum/callback/callback_bursting, datum/callback/callback_reset_fire, datum/callback/callback_fire, datum/callback/callback_display_ammo, datum/callback/callback_set_firing) +/datum/component/automatedfire/autofire/Initialize(auto_fire_shot_delay = 0.3 SECONDS, burstfire_shot_delay, burst_shots_to_fire = 3, fire_mode = GUN_FIREMODE_SEMIAUTO, automatic_delay_mult = 1, datum/callback/callback_bursting, datum/callback/callback_reset_fire, datum/callback/callback_fire, datum/callback/callback_display_ammo, datum/callback/callback_set_firing) . = ..() RegisterSignal(parent, COMSIG_GUN_FIRE_MODE_TOGGLE, PROC_REF(modify_fire_mode)) @@ -35,11 +37,13 @@ RegisterSignal(parent, COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED, PROC_REF(modify_burstfire_shot_delay)) RegisterSignal(parent, COMSIG_GUN_FIRE, PROC_REF(initiate_shot)) RegisterSignal(parent, COMSIG_GUN_STOP_FIRE, PROC_REF(stop_firing)) + RegisterSignal(parent, COMSIG_GUN_INTERRUPT_FIRE, PROC_REF(hard_reset)) src.auto_fire_shot_delay = auto_fire_shot_delay src.burstfire_shot_delay = burstfire_shot_delay src.burst_shots_to_fire = burst_shots_to_fire src.fire_mode = fire_mode + src.automatic_delay_mult = automatic_delay_mult src.callback_bursting = callback_bursting src.callback_reset_fire = callback_reset_fire src.callback_fire = callback_fire @@ -96,6 +100,7 @@ ///Hard reset the autofire, happens when the shooter fall/is thrown, at the end of a burst or when it runs out of ammunition /datum/component/automatedfire/autofire/proc/hard_reset() + SIGNAL_HANDLER callback_reset_fire.Invoke() //resets the gun shots_fired = 0 have_to_reset_at_burst_end = FALSE @@ -131,7 +136,7 @@ next_fire = world.time + burstfire_shot_delay if(GUN_FIREMODE_AUTOMATIC) callback_set_firing.Invoke(TRUE) - next_fire = world.time + auto_fire_shot_delay + next_fire = world.time + (auto_fire_shot_delay * automatic_delay_mult) if(GUN_FIREMODE_SEMIAUTO) return schedule_shot() diff --git a/code/datums/supply_packs/ammo.dm b/code/datums/supply_packs/ammo.dm index e598a11be5e0..164511c25cc0 100644 --- a/code/datums/supply_packs/ammo.dm +++ b/code/datums/supply_packs/ammo.dm @@ -122,16 +122,6 @@ containername = "\improper M39 AP magazines crate" group = "Ammo" -/datum/supply_packs/ammo_smg_mag_box_ext - name = "Magazine box (M39, 10x extended mags)" - contains = list( - /obj/item/ammo_box/magazine/m39/ext, - ) - cost = 30 - containertype = /obj/structure/closet/crate/ammo - containername = "\improper M39 extended magazines crate" - group = "Ammo" - //------------------------For M4RA---------------- /datum/supply_packs/ammo_m4ra_mag_box diff --git a/code/datums/supply_packs/black_market.dm b/code/datums/supply_packs/black_market.dm index 65b15997d1b4..3f4453d03f32 100644 --- a/code/datums/supply_packs/black_market.dm +++ b/code/datums/supply_packs/black_market.dm @@ -184,10 +184,9 @@ Non-USCM items, from CLF, UPP, colonies, etc. Mostly combat-related. new /obj/item/ammo_magazine/rifle/mar40/extended(src) new /obj/item/ammo_magazine/rifle/mar40(src) else - new /obj/item/weapon/gun/rifle/m41aMK1/tactical(src) - new /obj/item/ammo_magazine/rifle/m41aMK1/ap(src) - new /obj/item/ammo_magazine/rifle/m41aMK1(src) - new /obj/item/ammo_magazine/rifle/m41aMK1(src) + new /obj/item/weapon/gun/rifle/mar40/lmg(src) + new /obj/item/ammo_magazine/rifle/mar40/lmg(src) + new /obj/item/ammo_magazine/rifle/mar40/lmg(src) /* Misc. Individual Guns */ diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index 9d53ac1103c0..e3b07a76a2ff 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -159,8 +159,8 @@ max_heat_protection_temperature = SHOE_MAX_HEAT_PROT /obj/item/clothing/shoes/souto - name = "\improper Souto Man's boots. Harder than the kick of Souto Red." - desc = "Souto Man boots" + name = "Souto Man boots" + desc = "\improper Souto Man's boots. Harder than the kick of Souto Red" icon_state = "souto_man" item_state = "souto_man" flags_inventory = CANTSTRIP|NOSLIPPING diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index 1947f87c574a..d747525f3feb 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -116,14 +116,17 @@ They're all essentially identical when it comes to getting the job done. /obj/item/ammo_magazine/attackby(obj/item/I, mob/living/user, bypass_hold_check = 0) if(istype(I, /obj/item/ammo_magazine)) var/obj/item/ammo_magazine/MG = I - if(MG.flags_magazine & AMMUNITION_HANDFUL) //got a handful of bullets + if((MG.flags_magazine & AMMUNITION_HANDFUL) || (MG.flags_magazine & AMMUNITION_SLAP_TRANSFER)) //got a handful of bullets if(flags_magazine & AMMUNITION_REFILLABLE) //and a refillable magazine var/obj/item/ammo_magazine/handful/transfer_from = I if(src == user.get_inactive_hand() || bypass_hold_check) //It has to be held. if(default_ammo == transfer_from.default_ammo) - transfer_ammo(transfer_from,user,transfer_from.current_rounds) // This takes care of the rest. - else to_chat(user, "Those aren't the same rounds. Better not mix them up.") - else to_chat(user, "Try holding [src] before you attempt to restock it.") + if(transfer_ammo(transfer_from,user,transfer_from.current_rounds)) // This takes care of the rest. + to_chat(user, SPAN_NOTICE("You transfer rounds to [src] from [transfer_from].")) + else + to_chat(user, SPAN_NOTICE("Those aren't the same rounds. Better not mix them up.")) + else + to_chat(user, SPAN_NOTICE("Try holding [src] before you attempt to restock it.")) //Generic proc to transfer ammo between ammo mags. Can work for anything, mags, handfuls, etc. /obj/item/ammo_magazine/proc/transfer_ammo(obj/item/ammo_magazine/source, mob/user, transfer_amount = 1) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 832f243a9602..257edd9a7720 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -127,7 +127,7 @@ ///How many full-auto shots to get to max scatter? var/fa_scatter_peak = 4 ///How bad does the scatter get on full auto? - var/fa_max_scatter = 8.5 + var/fa_max_scatter = 6.5 ///Click parameters to use when firing full-auto var/fa_params = null @@ -228,6 +228,8 @@ VAR_PROTECTED/start_semiauto = TRUE /// If this gun should spawn with automatic fire. Protected due to it never needing to be edited. VAR_PROTECTED/start_automatic = FALSE + /// The multiplier for how much slower this should fire in automatic mode. 1 is normal, 1.2 is 20% slower, 2 is 100% slower, etc. Protected due to it never needing to be edited. + VAR_PROTECTED/autofire_slow_mult = 1 /** @@ -274,7 +276,7 @@ AddElement(/datum/element/drop_retrieval/gun, auto_retrieval_slot) update_icon() //for things like magazine overlays gun_firemode = gun_firemode_list[1] || GUN_FIREMODE_SEMIAUTO - AddComponent(/datum/component/automatedfire/autofire, fire_delay, burst_delay, burst_amount, gun_firemode, CALLBACK(src, PROC_REF(set_bursting)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(fire_wrapper)), CALLBACK(src, PROC_REF(display_ammo)), CALLBACK(src, PROC_REF(set_auto_firing))) //This should go after handle_starting_attachment() and setup_firemodes() to get the proper values set. + AddComponent(/datum/component/automatedfire/autofire, fire_delay, burst_delay, burst_amount, gun_firemode, autofire_slow_mult, CALLBACK(src, PROC_REF(set_bursting)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(fire_wrapper)), CALLBACK(src, PROC_REF(display_ammo)), CALLBACK(src, PROC_REF(set_auto_firing))) //This should go after handle_starting_attachment() and setup_firemodes() to get the proper values set. /obj/item/weapon/gun/proc/set_gun_attachment_offsets() attachable_offset = null @@ -425,6 +427,10 @@ else if(M.r_hand == src) M.update_inv_r_hand() + setup_firemodes() + + SEND_SIGNAL(src, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES) + /obj/item/weapon/gun/proc/handle_random_attachments() var/attachmentchoice @@ -939,6 +945,10 @@ and you're good to go. //Let's check on the active attachable. It loads ammo on the go, so it never chambers anything if(active_attachable) + if(shots_fired >= 1) // This is what you'll want to remove if you want automatic underbarrel guns in the future + SEND_SIGNAL(src, COMSIG_GUN_INTERRUPT_FIRE) + return + if(active_attachable.current_rounds > 0) //If it's still got ammo and stuff. active_attachable.current_rounds-- var/obj/item/projectile/bullet = create_bullet(active_attachable.ammo, initial(name)) @@ -1073,10 +1083,10 @@ and you're good to go. This is where the grenade launcher and flame thrower function as attachments. This is also a general check to see if the attachment can fire in the first place. */ - var/check_for_attachment_fire = 0 + var/check_for_attachment_fire = FALSE if(active_attachable?.flags_attach_features & ATTACH_WEAPON) //Attachment activated and is a weapon. - check_for_attachment_fire = 1 + check_for_attachment_fire = TRUE if(!(active_attachable.flags_attach_features & ATTACH_PROJECTILE)) //If it's unique projectile, this is where we fire it. if((active_attachable.current_rounds <= 0) && !(active_attachable.flags_attach_features & ATTACH_IGNORE_EMPTY)) click_empty(user) //If it's empty, let them know. @@ -1202,8 +1212,7 @@ and you're good to go. shots_fired++ - else // This happens in very rare circumstances when you're moving a lot while burst firing, so I'm going to toss it up to guns jamming. - clear_jam(projectile_to_fire,user) + else return TRUE //>>POST PROCESSING AND CLEANUP BEGIN HERE.<< @@ -1892,7 +1901,7 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed if(!target) target = src.target if(!user) - user = src.gun_user + user = gun_user return Fire(target, user, params, reflex, dual_wield) /// Setter proc for fa_firing diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm index 7d2dbf5288be..eb0e53986f9d 100644 --- a/code/modules/projectiles/gun_attachables.dm +++ b/code/modules/projectiles/gun_attachables.dm @@ -852,6 +852,28 @@ Defined in conflicts.dm of the #defines folder. delay_scoped_nerf = FIRE_DELAY_TIER_11 //to compensate initial debuff. We want "high_fire_delay" damage_falloff_scoped_buff = -0.4 //has to be negative +/obj/item/attachable/scope/Attach(obj/item/weapon/gun/gun) + . = ..() + RegisterSignal(gun, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES, PROC_REF(handle_attachment_recalc)) + +/obj/item/attachable/scope/Detach(mob/user, obj/item/weapon/gun/detaching_gub) + . = ..() + UnregisterSignal(detaching_gub, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES) + + +/// Due to the bipod's interesting way of handling stat modifications, this is necessary to prevent exploits. +/obj/item/attachable/scope/proc/handle_attachment_recalc(obj/item/weapon/gun/source) + SIGNAL_HANDLER + + if(!source.zoom) + return + + if(using_scope) + source.accuracy_mult += accuracy_scoped_buff + source.modify_fire_delay(delay_scoped_nerf) + source.damage_falloff_mult += damage_falloff_scoped_buff + + /obj/item/attachable/scope/proc/apply_scoped_buff(obj/item/weapon/gun/G, mob/living/carbon/user) if(G.zoom) G.accuracy_mult += accuracy_scoped_buff @@ -1976,6 +1998,8 @@ Defined in conflicts.dm of the #defines folder. G.damage_mult = 1 icon_state += "-on" + SEND_SIGNAL(G, COMSIG_GUN_INTERRUPT_FIRE) + for(var/X in G.actions) var/datum/action/A = X A.update_button_icon() @@ -2646,13 +2670,14 @@ Defined in conflicts.dm of the #defines folder. burst_scatter_mod = 0 delay_mod = FIRE_DELAY_TIER_12 G.recalculate_attachment_bonuses() + G.stop_fire() var/mob/living/user if(isliving(G.loc)) user = G.loc UnregisterSignal(user, COMSIG_MOB_MOVE_OR_LOOK) if(G.flags_gun_features & GUN_SUPPORT_PLATFORM) - G.remove_bullet_trait("iff") + G.remove_firemode(GUN_FIREMODE_AUTOMATIC) if(!QDELETED(G)) playsound(user,'sound/items/m56dauto_rotate.ogg', 55, 1) @@ -2683,12 +2708,13 @@ Defined in conflicts.dm of the #defines folder. else delay_mod = -FIRE_DELAY_TIER_12 G.recalculate_attachment_bonuses() + G.stop_fire() initial_mob_dir = user.dir RegisterSignal(user, COMSIG_MOB_MOVE_OR_LOOK, PROC_REF(handle_mob_move_or_look)) if(G.flags_gun_features & GUN_SUPPORT_PLATFORM) - G.add_bullet_trait(BULLET_TRAIT_ENTRY_ID("iff", /datum/element/bullet_trait_iff)) + G.add_firemode(GUN_FIREMODE_AUTOMATIC) else to_chat(user, SPAN_NOTICE("You retract [src].")) diff --git a/code/modules/projectiles/gun_helpers.dm b/code/modules/projectiles/gun_helpers.dm index a60773c88be7..e86801c9d8c1 100644 --- a/code/modules/projectiles/gun_helpers.dm +++ b/code/modules/projectiles/gun_helpers.dm @@ -700,6 +700,9 @@ DEFINES in setup.dm, referenced here. CRASH("add_firemode called with a resulting gun_firemode_list length of [length(gun_firemode_list)].") /obj/item/weapon/gun/proc/remove_firemode(removed_firemode, mob/user) + if(!(removed_firemode in gun_firemode_list)) + return + if(!length(gun_firemode_list) || (length(gun_firemode_list) == 1)) CRASH("remove_firemode called with gun_firemode_list length [length(gun_firemode_list)].") @@ -710,7 +713,9 @@ DEFINES in setup.dm, referenced here. do_toggle_firemode(user, gun_firemode) /obj/item/weapon/gun/proc/setup_firemodes() + var/old_firemode = gun_firemode gun_firemode_list.len = 0 + if(start_semiauto) gun_firemode_list |= GUN_FIREMODE_SEMIAUTO @@ -722,6 +727,10 @@ DEFINES in setup.dm, referenced here. if(!length(gun_firemode_list)) CRASH("[src] called setup_firemodes() with an empty gun_firemode_list") + + else if(old_firemode in gun_firemode_list) + gun_firemode = old_firemode + else gun_firemode = gun_firemode_list[1] diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 61ea0442a427..5733b01195ff 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -181,6 +181,7 @@ fire_sound = 'sound/weapons/Laser4.ogg' has_charge_meter = FALSE charge_icon = "+laz_uzi_empty" + start_automatic = TRUE /obj/item/weapon/gun/energy/laz_uzi/set_gun_config_values() ..() @@ -194,6 +195,7 @@ scatter_unwielded = SCATTER_AMOUNT_TIER_6 damage_mult = BASE_BULLET_DAMAGE_MULT recoil_unwielded = RECOIL_AMOUNT_TIER_5 + fa_scatter_peak = SCATTER_AMOUNT_TIER_8 //############################ Taser ################## // Lots of bits for it so splitting off an area diff --git a/code/modules/projectiles/guns/flamer/flamer.dm b/code/modules/projectiles/guns/flamer/flamer.dm index a108b3a9948f..ee08fee0f845 100644 --- a/code/modules/projectiles/guns/flamer/flamer.dm +++ b/code/modules/projectiles/guns/flamer/flamer.dm @@ -370,7 +370,7 @@ /obj/item/weapon/gun/flamer/M240T/auto/set_gun_config_values() . = ..() - set_fire_delay(FIRE_DELAY_TIER_3) + set_fire_delay(FIRE_DELAY_TIER_7) GLOBAL_LIST_EMPTY(flamer_particles) /particles/flamer_fire diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm index 18ffb082217c..38649ff73ca1 100644 --- a/code/modules/projectiles/guns/rifles.dm +++ b/code/modules/projectiles/guns/rifles.dm @@ -75,6 +75,7 @@ flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER starting_attachment_types = list(/obj/item/attachable/attached_gun/grenade, /obj/item/attachable/stock/rifle/collapsible) map_specific_decoration = TRUE + start_automatic = TRUE /obj/item/weapon/gun/rifle/m41a/set_gun_attachment_offsets() attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 18,"rail_x" = 12, "rail_y" = 23, "under_x" = 24, "under_y" = 13, "stock_x" = 24, "stock_y" = 13) @@ -88,7 +89,6 @@ accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 + 2*HIT_ACCURACY_MULT_TIER_1 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_8 - //fa_scatter_peak = FULL_AUTO_SCATTER_PEAK_TIER_8 //Zonenote burst_scatter_mult = SCATTER_AMOUNT_TIER_10 scatter_unwielded = SCATTER_AMOUNT_TIER_2 damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_2 @@ -150,6 +150,7 @@ /obj/item/attachable/attached_gun/flamer/advanced, ) start_semiauto = FALSE + start_automatic = TRUE /obj/item/weapon/gun/rifle/nsg23/Initialize(mapload, spawn_empty) . = ..() @@ -171,6 +172,7 @@ damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_8 recoil_unwielded = RECOIL_AMOUNT_TIER_2 damage_falloff_mult = 0 + fa_max_scatter = SCATTER_AMOUNT_TIER_5 /obj/item/weapon/gun/rifle/nsg23/handle_starting_attachment() ..() @@ -383,6 +385,7 @@ flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER starting_attachment_types = list(/obj/item/attachable/attached_gun/grenade/mk1, /obj/item/attachable/stock/rifle/collapsible) + start_automatic = TRUE /obj/item/weapon/gun/rifle/m41aMK1/set_gun_attachment_offsets() attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 18,"rail_x" = 12, "rail_y" = 23, "under_x" = 23, "under_y" = 13, "stock_x" = 24, "stock_y" = 14) @@ -528,6 +531,7 @@ scatter_unwielded = SCATTER_AMOUNT_TIER_2 damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_3 recoil_unwielded = RECOIL_AMOUNT_TIER_2 + fa_max_scatter = SCATTER_AMOUNT_TIER_7 /obj/item/weapon/gun/rifle/m46c/able_to_fire(mob/user) . = ..() @@ -633,9 +637,11 @@ if(iff_enabled) modify_fire_delay(FIRE_DELAY_TIER_12) remove_firemode(GUN_FIREMODE_BURSTFIRE) + remove_firemode(GUN_FIREMODE_AUTOMATIC) else add_firemode(GUN_FIREMODE_BURSTFIRE) + add_firemode(GUN_FIREMODE_AUTOMATIC) /obj/item/weapon/gun/rifle/m46c/proc/name_after_co(mob/living/carbon/human/H) @@ -719,6 +725,7 @@ ) flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK + start_automatic = TRUE @@ -1232,7 +1239,7 @@ /obj/item/attachable/magnetic_harness, ) - flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY + flags_gun_features = GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WIELDED_FIRING_ONLY|GUN_SUPPORT_PLATFORM gun_category = GUN_CATEGORY_HEAVY /obj/item/weapon/gun/rifle/lmg/set_gun_attachment_offsets() @@ -1297,6 +1304,7 @@ flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER flags_equip_slot = SLOT_BACK + start_automatic = TRUE /obj/item/weapon/gun/rifle/type71/set_gun_attachment_offsets() attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 18,"rail_x" = 18, "rail_y" = 23, "under_x" = 20, "under_y" = 13, "stock_x" = 24, "stock_y" = 13) diff --git a/code/modules/projectiles/guns/shotguns.dm b/code/modules/projectiles/guns/shotguns.dm index a154062c9d10..3c366df40b57 100644 --- a/code/modules/projectiles/guns/shotguns.dm +++ b/code/modules/projectiles/guns/shotguns.dm @@ -1186,7 +1186,7 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/pump/dual_tube name = "generic dual-tube pump shotgun" - desc = "A twenty-round pump action shotgun with dual internal tube magazines. You can switch the active internal magazine by toggling burst fire mode." + desc = "A twenty-round pump action shotgun with dual internal tube magazines. You can switch the active internal magazine by toggling the shotgun tube." current_mag = /obj/item/ammo_magazine/internal/shotgun var/obj/item/ammo_magazine/internal/shotgun/primary_tube var/obj/item/ammo_magazine/internal/shotgun/secondary_tube @@ -1220,7 +1220,12 @@ can cause issues with ammo types getting mixed up during the burst. playsound(src, 'sound/machines/switch.ogg', 15, TRUE) return TRUE -/obj/item/weapon/gun/shotgun/pump/dual_tube/set_bursting() +/obj/item/weapon/gun/shotgun/pump/dual_tube/verb/toggle_tube() + set category = "Weapons" + set name = "Toggle Shotgun Tube" + set desc = "Toggles which shotgun tube your gun loads from." + set src = usr.contents + var/obj/item/weapon/gun/shotgun/pump/dual_tube/shotgun = get_active_firearm(usr) if(shotgun == src) swap_tube(usr) @@ -1229,7 +1234,7 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/pump/dual_tube/cmb name = "\improper HG 37-12 pump shotgun" - desc = "A eight-round pump action shotgun with four-round capacity dual internal tube magazines allowing for quick reloading and highly accurate fire. Used exclusively by Colonial Marshals. You can switch the active internal magazine by toggling burst fire mode." + desc = "A eight-round pump action shotgun with four-round capacity dual internal tube magazines allowing for quick reloading and highly accurate fire. Used exclusively by Colonial Marshals. You can switch the active internal magazine by toggling the shotgun tube." icon = 'icons/obj/items/weapons/guns/guns_by_faction/colony.dmi' icon_state = "hg3712" item_state = "hg3712" @@ -1269,7 +1274,7 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/pump/dual_tube/cmb/m3717 name = "\improper M37-17 pump shotgun" - desc = "A military version of the iconic HG 37-12, this design can fit one extra shell in each of its dual-tube internal magazines, and fires shells with increased velocity, resulting in more damage. Issued to select USCM vessels out on the rim. You can switch the active internal magazine by toggling burst fire mode." + desc = "A military version of the iconic HG 37-12, this design can fit one extra shell in each of its dual-tube internal magazines, and fires shells with increased velocity, resulting in more damage. Issued to select USCM vessels out on the rim. You can switch the active internal magazine by toggling the shotgun tube." icon = 'icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi' icon_state = "m3717" item_state = "m3717" diff --git a/code/modules/projectiles/guns/smgs.dm b/code/modules/projectiles/guns/smgs.dm index 70b0acb3f2c8..b9c2b9c3514d 100644 --- a/code/modules/projectiles/guns/smgs.dm +++ b/code/modules/projectiles/guns/smgs.dm @@ -20,6 +20,7 @@ flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK gun_category = GUN_CATEGORY_SMG + start_automatic = TRUE /obj/item/weapon/gun/smg/Initialize(mapload, spawn_empty) . = ..() @@ -32,6 +33,7 @@ /obj/item/weapon/gun/smg/set_gun_config_values() ..() movement_onehanded_acc_penalty_mult = 4 + fa_max_scatter = SCATTER_AMOUNT_TIER_5 //------------------------------------------------------- //M39 SMG @@ -85,6 +87,7 @@ scatter_unwielded = SCATTER_AMOUNT_TIER_4 damage_mult = BASE_BULLET_DAMAGE_MULT recoil_unwielded = RECOIL_AMOUNT_TIER_5 + fa_max_scatter = SCATTER_AMOUNT_TIER_10 + 0.5 /obj/item/weapon/gun/smg/m39/training @@ -270,6 +273,8 @@ scatter_unwielded = SCATTER_AMOUNT_TIER_4 damage_mult = BASE_BULLET_DAMAGE_MULT recoil_unwielded = RECOIL_AMOUNT_TIER_5 + fa_max_scatter = SCATTER_AMOUNT_TIER_9 + fa_scatter_peak = 1 // Seems a bit funny, but it works pretty well in the end /obj/item/weapon/gun/smg/ppsh/with_drum_mag current_mag = /obj/item/ammo_magazine/smg/ppsh/extended @@ -361,7 +366,6 @@ ) wield_delay = WIELD_DELAY_NONE aim_slowdown = SLOWDOWN_ADS_NONE - start_automatic = TRUE /obj/item/weapon/gun/smg/mac15/set_gun_attachment_offsets() attachable_offset = list("muzzle_x" = 32, "muzzle_y" = 20,"rail_x" = 16, "rail_y" = 22, "under_x" = 22, "under_y" = 16, "stock_x" = 22, "stock_y" = 16) @@ -410,7 +414,6 @@ ) wield_delay = WIELD_DELAY_MIN aim_slowdown = SLOWDOWN_ADS_QUICK - start_automatic = TRUE var/jammed = FALSE /obj/item/weapon/gun/smg/uzi/set_gun_attachment_offsets() @@ -567,6 +570,7 @@ flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK gun_category = GUN_CATEGORY_SMG civilian_usable_override = TRUE + start_automatic = FALSE var/nailing_speed = 2 SECONDS //Time to apply a sheet for patching. Also haha name. Try to keep sync with soundbyte duration var/repair_sound = 'sound/weapons/nailgun_repair_long.ogg' diff --git a/code/modules/projectiles/guns/souto.dm b/code/modules/projectiles/guns/souto.dm index 8d7a1b2550a4..6f45f57e1d61 100644 --- a/code/modules/projectiles/guns/souto.dm +++ b/code/modules/projectiles/guns/souto.dm @@ -14,6 +14,8 @@ var/obj/item/storage/backpack/souto/soutopack current_mag = null auto_retrieval_slot = WEAR_IN_BACK + start_automatic = TRUE + autofire_slow_mult = 0.8 //Fires FASTER when in Full Auto, that is the power of Souta /obj/item/weapon/gun/souto/set_gun_config_values() . = ..() diff --git a/code/modules/projectiles/guns/specialist.dm b/code/modules/projectiles/guns/specialist.dm index 7152106869a9..a73335971ffa 100644 --- a/code/modules/projectiles/guns/specialist.dm +++ b/code/modules/projectiles/guns/specialist.dm @@ -267,11 +267,15 @@ if(toggling_action) toggling_action.update_button_icon() -/obj/item/weapon/gun/rifle/sniper/set_bursting(mob/user) - if(has_aimed_shot) - toggle_laser(user) - else - ..() +/obj/item/weapon/gun/rifle/sniper/verb/toggle_gun_laser() + set category = "Weapons" + set name = "Toggle Laser" + set desc = "Toggles your laser on or off." + set src = usr.contents + + var/obj/item/weapon/gun/rifle/sniper/sniper = get_active_firearm(usr) + if((sniper == src) && has_aimed_shot) + toggle_laser(usr) //Pow! Headshot. /obj/item/weapon/gun/rifle/sniper/M42A diff --git a/code/modules/projectiles/magazines/rifles.dm b/code/modules/projectiles/magazines/rifles.dm index ca008c2d1376..57bcd7f0a563 100644 --- a/code/modules/projectiles/magazines/rifles.dm +++ b/code/modules/projectiles/magazines/rifles.dm @@ -263,7 +263,7 @@ icon_state = "m41ae2" max_rounds = 300 gun_type = /obj/item/weapon/gun/rifle/lmg - flags_magazine = AMMUNITION_CANNOT_REMOVE_BULLETS|AMMUNITION_REFILLABLE + flags_magazine = AMMUNITION_CANNOT_REMOVE_BULLETS|AMMUNITION_REFILLABLE|AMMUNITION_SLAP_TRANSFER ammo_band_icon = "+m41ae2_band" ammo_band_icon_empty = "+m41ae2_band_e" diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index e4251f5f6b31..eccba14a442a 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -110,7 +110,7 @@ /obj/item/projectile/Crossed(atom/movable/AM) /* Fun fact: Crossed is called for any contents involving operations. * This notably means, inserting a magazing in a gun Crossed() it with the bullets in the gun. */ - if(!loc.z) + if(!loc?.z) return // Not on the map. Don't scan a turf. Don't shoot the poor guy reloading his gun. if(AM && !(AM in permutated)) if(scan_a_turf(get_turf(AM))) @@ -1143,11 +1143,16 @@ // Need to do this in order to prevent the ping from being deleted addtimer(CALLBACK(I, TYPE_PROC_REF(/image, flick_overlay), src, 3), 1) +/// People getting shot by a large amount of bullets in a very short period of time can lag them out, with chat messages being one cause, so a 1s cooldown per hit message is introduced to assuage that +/mob/var/shot_cooldown = 0 + /mob/proc/bullet_message(obj/item/projectile/P) if(!P) return - visible_message(SPAN_DANGER("[src] is hit by the [P.name] in the [parse_zone(P.def_zone)]!"), \ - SPAN_HIGHDANGER("You are hit by the [P.name] in the [parse_zone(P.def_zone)]!"), null, 4, CHAT_TYPE_TAKING_HIT) + if(COOLDOWN_FINISHED(src, shot_cooldown)) + visible_message(SPAN_DANGER("[src] is hit by the [P.name] in the [parse_zone(P.def_zone)]!"), \ + SPAN_HIGHDANGER("You are hit by the [P.name] in the [parse_zone(P.def_zone)]!"), null, 4, CHAT_TYPE_TAKING_HIT) + COOLDOWN_START(src, shot_cooldown, 1 SECONDS) last_damage_data = P.weapon_cause_data if(P.firer && ismob(P.firer))