diff --git a/code/__DEFINES/autofire.dm b/code/__DEFINES/autofire.dm new file mode 100644 index 000000000000..934cdcd7dc79 --- /dev/null +++ b/code/__DEFINES/autofire.dm @@ -0,0 +1,4 @@ +// Controls how many buckets should be kept, each representing a tick. Max is ten seconds, to have better perf. +#define AUTOFIRE_BUCKET_LEN (world.fps * 10) +/// Helper for getting the correct bucket +#define AUTOFIRE_BUCKET_POS(next_fire) (((round((next_fire - SSautomatedfire.head_offset) / world.tick_lag) + 1) % AUTOFIRE_BUCKET_LEN) || AUTOFIRE_BUCKET_LEN) diff --git a/code/__DEFINES/conflict.dm b/code/__DEFINES/conflict.dm index fc8ca4e03a9f..7a1b322a19ee 100644 --- a/code/__DEFINES/conflict.dm +++ b/code/__DEFINES/conflict.dm @@ -54,30 +54,24 @@ #define GUN_TRIGGER_SAFETY (1<<1) #define GUN_UNUSUAL_DESIGN (1<<2) #define GUN_SILENCED (1<<3) -#define GUN_AUTOMATIC (1<<4) ///If checking for ammo with current.mag you have to check it against numerical values, as booleans will not trigger. -#define GUN_INTERNAL_MAG (1<<5) -#define GUN_AUTO_EJECTOR (1<<6) -#define GUN_AMMO_COUNTER (1<<7) -#define GUN_BURST_ON (1<<8) -#define GUN_BURST_FIRING (1<<9) -#define GUN_FLASHLIGHT_ON (1<<10) -#define GUN_WY_RESTRICTED (1<<11) -#define GUN_SPECIALIST (1<<12) -#define GUN_WIELDED_FIRING_ONLY (1<<13) -#define GUN_HAS_FULL_AUTO (1<<14) -#define GUN_FULL_AUTO_ON (1<<15) +#define GUN_INTERNAL_MAG (1<<4) +#define GUN_AUTO_EJECTOR (1<<5) +#define GUN_AMMO_COUNTER (1<<6) +#define GUN_BURST_FIRING (1<<7) +#define GUN_FLASHLIGHT_ON (1<<8) +#define GUN_WY_RESTRICTED (1<<9) +#define GUN_SPECIALIST (1<<10) +#define GUN_WIELDED_FIRING_ONLY (1<<11) /// removes unwielded accuracy and scatter penalties (not recoil) -#define GUN_ONE_HAND_WIELDED (1<<16) -#define GUN_ANTIQUE (1<<17) +#define GUN_ONE_HAND_WIELDED (1<<12) +#define GUN_ANTIQUE (1<<13) /// Whether the gun has been fired by its current user (reset upon `dropped()`) -#define GUN_RECOIL_BUILDUP (1<<18) +#define GUN_RECOIL_BUILDUP (1<<14) /// support weapon, bipod will grant IFF -#define GUN_SUPPORT_PLATFORM (1<<19) -#define GUN_BURST_ONLY (1<<20) -#define GUN_FULL_AUTO_ONLY (1<<21) +#define GUN_SUPPORT_PLATFORM (1<<15) /// No gun description, only base desc -#define GUN_NO_DESCRIPTION (1<<22) +#define GUN_NO_DESCRIPTION (1<<16) // NOTE: Don't add flags past 1<<23, it'll break things due to BYOND limitations. You can usually use a Component instead. #define USES_STREAKS (1<<0) @@ -85,15 +79,17 @@ #define MOVES_WHEN_LEVERING (1<<2) //Gun attachable related flags. -#define ATTACH_REMOVABLE 1 -#define ATTACH_ACTIVATION 2 +#define ATTACH_REMOVABLE (1<<0) +#define ATTACH_ACTIVATION (1<<1) /// for attachments that fire bullets -#define ATTACH_PROJECTILE 4 -#define ATTACH_RELOADABLE 8 +#define ATTACH_PROJECTILE (1<<2) +#define ATTACH_RELOADABLE (1<<3) /// is a weapon that fires stuff -#define ATTACH_WEAPON 16 +#define ATTACH_WEAPON (1<<4) +/// This attachment should override ignore if it is empty +#define ATTACH_IGNORE_EMPTY (1<<5) /// This attachment should activate if you attack() with it attached. -#define ATTACH_MELEE 32 +#define ATTACH_MELEE (1<<6) //Ammo magazine defines, for flags_magazine diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm index 347623798b74..323e0ee6966c 100644 --- a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm +++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm @@ -110,3 +110,9 @@ #define COMSIG_MOB_STAT_SET_DEAD "mob_stat_set_dead" #define COMSIG_GHOST_MOVED "ghost_moved" + +#define COMSIG_MOB_MOUSEDOWN "mob_mousedown" //from /client/MouseDown(): (atom/object, turf/location, control, params) +#define COMSIG_MOB_MOUSEUP "mob_mouseup" //from /client/MouseUp(): (atom/object, turf/location, control, params) +#define COMSIG_MOB_MOUSEDRAG "mob_mousedrag" //from /client/MouseDrag(): (atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params) + #define COMSIG_MOB_CLICK_CANCELED (1<<0) + #define COMSIG_MOB_CLICK_HANDLED (1<<1) diff --git a/code/__DEFINES/dcs/signals/atom/signals_item.dm b/code/__DEFINES/dcs/signals/atom/signals_item.dm index 9c2f3b92ba05..138e88d21746 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_item.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_item.dm @@ -38,3 +38,19 @@ #define COMSIG_ITEM_ZOOM "item_zoom" /// from /obj/item/proc/unzoom() : (mob/user) #define COMSIG_ITEM_UNZOOM "item_unzoom" + +//Signals for automatic fire at component +#define COMSIG_AUTOMATIC_SHOOTER_START_SHOOTING_AT "start_shooting_at" +#define COMSIG_AUTOMATIC_SHOOTER_STOP_SHOOTING_AT "stop_shooting_at" +#define COMSIG_AUTOMATIC_SHOOTER_SHOOT "shoot" + +//Signals for gun auto fire component +#define COMSIG_GET_BURST_FIRE "get_burst_fire" + #define BURST_FIRING (1<<0) + +#define COMSIG_GUN_FIRE "gun_fire" +#define COMSIG_GUN_STOP_FIRE "gun_stop_fire" +#define COMSIG_GUN_FIRE_MODE_TOGGLE "gun_fire_mode_toggle" +#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" diff --git a/code/__DEFINES/guns.dm b/code/__DEFINES/guns.dm index a89d98805e73..b29f7c7439f2 100644 --- a/code/__DEFINES/guns.dm +++ b/code/__DEFINES/guns.dm @@ -37,3 +37,11 @@ #define REVOLVER_TIP_COLOR_INCENDIARY AMMO_BAND_COLOR_INCENDIARY #define REVOLVER_TIP_COLOR_PENETRATING AMMO_BAND_COLOR_PENETRATING #define REVOLVER_TIP_COLOR_TOXIN AMMO_BAND_COLOR_TOXIN + +#define GUN_FIREMODE_SEMIAUTO "semi-auto fire mode" +#define GUN_FIREMODE_BURSTFIRE "burst-fire mode" +#define GUN_FIREMODE_AUTOMATIC "automatic fire mode" + +//autofire component fire callback return flags +#define AUTOFIRE_CONTINUE (1<<0) +#define AUTOFIRE_SUCCESS (1<<1) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 662bcb458c55..3a25d865fb60 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -173,6 +173,7 @@ #define SS_PRIORITY_INPUT 1000 #define SS_PRIORITY_TIMER 700 +#define SS_PRIORITY_AUTOFIRE 450 #define SS_PRIORITY_SOUND 250 #define SS_PRIORITY_TICKER 200 #define SS_PRIORITY_NIGHTMARE 180 diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 09b55accf16d..ef539b8459c7 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -108,24 +108,18 @@ DEFINE_BITFIELD(flags_gun_features, list( "GUN_TRIGGER_SAFETY" = GUN_TRIGGER_SAFETY, "GUN_UNUSUAL_DESIGN" = GUN_UNUSUAL_DESIGN, "GUN_SILENCED" = GUN_SILENCED, - "GUN_AUTOMATIC" = GUN_AUTOMATIC, "GUN_INTERNAL_MAG" = GUN_INTERNAL_MAG, "GUN_AUTO_EJECTOR" = GUN_AUTO_EJECTOR, "GUN_AMMO_COUNTER" = GUN_AMMO_COUNTER, - "GUN_BURST_ON" = GUN_BURST_ON, "GUN_BURST_FIRING" = GUN_BURST_FIRING, "GUN_FLASHLIGHT_ON" = GUN_FLASHLIGHT_ON, "GUN_WY_RESTRICTED" = GUN_WY_RESTRICTED, "GUN_SPECIALIST" = GUN_SPECIALIST, "GUN_WIELDED_FIRING_ONLY" = GUN_WIELDED_FIRING_ONLY, - "GUN_HAS_FULL_AUTO" = GUN_HAS_FULL_AUTO, - "GUN_FULL_AUTO_ON" = GUN_FULL_AUTO_ON, "GUN_ONE_HAND_WIELDED" = GUN_ONE_HAND_WIELDED, "GUN_ANTIQUE" = GUN_ANTIQUE, "GUN_RECOIL_BUILDUP" = GUN_RECOIL_BUILDUP, "GUN_SUPPORT_PLATFORM" = GUN_SUPPORT_PLATFORM, - "GUN_BURST_ONLY" = GUN_BURST_ONLY, - "GUN_FULL_AUTO_ONLY" = GUN_FULL_AUTO_ONLY, )) DEFINE_BITFIELD(flags_magazine, list( diff --git a/code/_onclick/click_hold.dm b/code/_onclick/click_hold.dm index c68beb52fc9e..f65dd33c2eea 100644 --- a/code/_onclick/click_hold.dm +++ b/code/_onclick/click_hold.dm @@ -30,6 +30,9 @@ mouse_trace_history = null LAZYADD(mouse_trace_history, A) + if(SEND_SIGNAL(mob, COMSIG_MOB_MOUSEDOWN, A, T, skin_ctl, params) & COMSIG_MOB_CLICK_CANCELED) + return + var/list/mods = params2list(params) if(mods["left"]) SEND_SIGNAL(src, COMSIG_CLIENT_LMB_DOWN, A, mods) @@ -62,6 +65,9 @@ params += ";click_catcher=1" holding_click = FALSE + if(SEND_SIGNAL(mob, COMSIG_MOB_MOUSEUP, A, T, skin_ctl, params) & COMSIG_MOB_CLICK_CANCELED) + return + var/list/mods = params2list(params) if(mods["left"]) SEND_SIGNAL(src, COMSIG_CLIENT_LMB_UP, A, params) @@ -75,6 +81,9 @@ if(click_catcher_click) params += ";click_catcher=1" + if(SEND_SIGNAL(mob, COMSIG_MOB_MOUSEDRAG, src_obj, over_obj, src_loc, over_loc, src_ctl, over_ctl, params) & COMSIG_MOB_CLICK_CANCELED) + return + var/list/mods = params2list(params) if(mods["left"]) SEND_SIGNAL(src, COMSIG_CLIENT_LMB_DRAG, src_obj, over_obj, params) diff --git a/code/controllers/subsystem/autofire.dm b/code/controllers/subsystem/autofire.dm new file mode 100644 index 000000000000..3d3abbd2669f --- /dev/null +++ b/code/controllers/subsystem/autofire.dm @@ -0,0 +1,85 @@ +/** + * # Autofire Subsystem + * + * Maintains a timer-like system to handle autofiring. Much of this code is modeled + * after or adapted from TGMC's runechat subsytem. + * + * Note that this has the same structure for storing and queueing shooter component as the timer subsystem does + * for handling timers: the bucket_list is a list of autofire component, each of which are the head + * of a linked list. Any given index in bucket_list could be null, representing an empty bucket. + * + * Doesn't support any event scheduled for more than 100 ticks in the future, as it has no secondary queue by design + */ +SUBSYSTEM_DEF(automatedfire) + name = "Automated fire" + flags = SS_TICKER | SS_NO_INIT + wait = 1 + priority = SS_PRIORITY_AUTOFIRE + + /// world.time of the first entry in the bucket list, effectively the 'start time' of the current buckets + var/head_offset = 0 + /// Index of the first non-empty bucket + var/practical_offset = 1 + ///How many buckets for every frame of world.fps + var/bucket_resolution = 0 + /// How many shooter are in the buckets + var/shooter_count = 0 + /// List of buckets, each bucket holds every shooter that has to shoot this byond tick + var/list/bucket_list = list() + /// Reference to the next shooter before we clean shooter.next + var/datum/component/automatedfire/next_shooter + +/datum/controller/subsystem/automatedfire/PreInit() + bucket_list.len = AUTOFIRE_BUCKET_LEN + head_offset = world.time + bucket_resolution = world.tick_lag + +/datum/controller/subsystem/automatedfire/stat_entry(msg = "ActShooters: [shooter_count]") + return ..() + +/datum/controller/subsystem/automatedfire/fire(resumed = FALSE) + // Check for when we need to loop the buckets, this occurs when + // the head_offset is approaching AUTOFIRE_BUCKET_LEN ticks in the past + if (practical_offset > AUTOFIRE_BUCKET_LEN) + head_offset += TICKS2DS(AUTOFIRE_BUCKET_LEN) + practical_offset = 1 + resumed = FALSE + + // Check for when we have to reset buckets, typically from auto-reset + if ((length(bucket_list) != AUTOFIRE_BUCKET_LEN) || (world.tick_lag != bucket_resolution)) + reset_buckets() + bucket_list = src.bucket_list + resumed = FALSE + + // Store a reference to the 'working' shooter so that we can resume if the MC + // has us stop mid-way through processing + var/static/datum/component/automatedfire/shooter + if (!resumed) + shooter = null + + // Iterate through each bucket starting from the practical offset + while (practical_offset <= AUTOFIRE_BUCKET_LEN && head_offset + ((practical_offset - 1) * world.tick_lag) <= world.time) + if(!shooter) + shooter = bucket_list[practical_offset] + bucket_list[practical_offset] = null + + while (shooter) + next_shooter = shooter.next + INVOKE_ASYNC(shooter, TYPE_PROC_REF(/datum/component/automatedfire, process_shot)) + + SSautomatedfire.shooter_count-- + shooter = next_shooter + if (MC_TICK_CHECK) + return + + // Move to the next bucket + practical_offset++ + +/datum/controller/subsystem/automatedfire/Recover() + bucket_list |= SSautomatedfire.bucket_list + +///In the event of a change of world.tick_lag, we refresh the size of the bucket and the bucket resolution +/datum/controller/subsystem/automatedfire/proc/reset_buckets() + bucket_list.len = AUTOFIRE_BUCKET_LEN + head_offset = world.time + bucket_resolution = world.tick_lag diff --git a/code/datums/agents/tools/tranq_gun.dm b/code/datums/agents/tools/tranq_gun.dm index e812aa57037e..e95f853cef82 100644 --- a/code/datums/agents/tools/tranq_gun.dm +++ b/code/datums/agents/tools/tranq_gun.dm @@ -6,11 +6,10 @@ item_state = "pk9r" current_mag = /obj/item/ammo_magazine/pistol/tranq - burst_amount = 1 /obj/item/weapon/gun/pistol/tranquilizer/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6 + set_fire_delay(FIRE_DELAY_TIER_6) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_7 accuracy_mult_unwielded = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_10 diff --git a/code/datums/components/autofire/_automated_fire.dm b/code/datums/components/autofire/_automated_fire.dm new file mode 100644 index 000000000000..9abd6a152199 --- /dev/null +++ b/code/datums/components/autofire/_automated_fire.dm @@ -0,0 +1,49 @@ +/datum/component/automatedfire + ///The owner of this component + var/atom/shooter + /// Contains the scheduled fire time, used for scheduling EOL + var/next_fire + /// Contains the reference to the next component in the bucket, used by autofire subsystem + var/datum/component/automatedfire/next + /// Contains the reference to the previous component in the bucket, used by autofire subsystem + var/datum/component/automatedfire/prev + + +/// schedule the shooter into the system, inserting it into the next fire queue +/datum/component/automatedfire/proc/schedule_shot() + //We move to another bucket, so we clean the reference from the former linked list + next = null + prev = null + var/list/bucket_list = SSautomatedfire.bucket_list + + // Ensure the next_fire time is properly bound to avoid missing a scheduled event + next_fire = max(CEILING(next_fire, world.tick_lag), world.time + world.tick_lag) + + // Get bucket position and a local reference to the datum var, it's faster to access this way + var/bucket_pos = AUTOFIRE_BUCKET_POS(next_fire) + + // Get the bucket head for that bucket, increment the bucket count + var/datum/component/automatedfire/bucket_head = bucket_list[bucket_pos] + SSautomatedfire.shooter_count++ + + // If there is no existing head of this bucket, we can set this shooter to be that head + if (!bucket_head) + bucket_list[bucket_pos] = src + return + + // Otherwise it's a simple insertion into the double-linked list + if (bucket_head.next) + next = bucket_head.next + next.prev = src + + bucket_head.next = src + prev = bucket_head + + //Something went wrong, probably a lag spike or something. To prevent infinite loops, we reschedule it to a another next fire + if(prev == src) + next_fire += 1 + schedule_shot() + +///Handle the firing of the autofire component +/datum/component/automatedfire/proc/process_shot() + return diff --git a/code/datums/components/autofire/autofire.dm b/code/datums/components/autofire/autofire.dm new file mode 100644 index 000000000000..31ca255f1b88 --- /dev/null +++ b/code/datums/components/autofire/autofire.dm @@ -0,0 +1,137 @@ +/datum/component/automatedfire/autofire + ///The current fire mode of the shooter + var/fire_mode + ///Delay between two shots when in full auto + var/auto_fire_shot_delay + ///Delay between two burst shots + var/burstfire_shot_delay + ///How many bullets are fired in burst mode + var/burst_shots_to_fire + ///Count the shots fired when bursting + var/shots_fired = 0 + ///If the shooter is currently shooting + var/shooting = FALSE + ///If TRUE, the shooter will reset its references at the end of the burst + var/have_to_reset_at_burst_end = FALSE + ///If we are in a burst + var/bursting = FALSE + ///Callback to set bursting mode on the parent + var/datum/callback/callback_bursting + ///Callback to ask the parent to reset its firing vars + var/datum/callback/callback_reset_fire + ///Callback to ask the parent to fire + var/datum/callback/callback_fire + ///Callback to ask the parent to display ammo + var/datum/callback/callback_display_ammo + ///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) + . = ..() + + RegisterSignal(parent, COMSIG_GUN_FIRE_MODE_TOGGLE, PROC_REF(modify_fire_mode)) + RegisterSignal(parent, COMSIG_GUN_AUTOFIREDELAY_MODIFIED, PROC_REF(modify_fire_shot_delay)) + RegisterSignal(parent, COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED, PROC_REF(modify_burst_shots_to_fire)) + 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)) + + 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.callback_bursting = callback_bursting + src.callback_reset_fire = callback_reset_fire + src.callback_fire = callback_fire + src.callback_display_ammo = callback_display_ammo + src.callback_set_firing = callback_set_firing + +/datum/component/automatedfire/autofire/Destroy(force, silent) + QDEL_NULL(callback_fire) + QDEL_NULL(callback_reset_fire) + QDEL_NULL(callback_bursting) + QDEL_NULL(callback_display_ammo) + QDEL_NULL(callback_set_firing) + return ..() + +///Setter for fire mode +/datum/component/automatedfire/autofire/proc/modify_fire_mode(datum/source, fire_mode) + SIGNAL_HANDLER + src.fire_mode = fire_mode + +///Setter for auto fire shot delay +/datum/component/automatedfire/autofire/proc/modify_fire_shot_delay(datum/source, auto_fire_shot_delay) + SIGNAL_HANDLER + src.auto_fire_shot_delay = auto_fire_shot_delay + +///Setter for the number of shots in a burst +/datum/component/automatedfire/autofire/proc/modify_burst_shots_to_fire(datum/source, burst_shots_to_fire) + SIGNAL_HANDLER + src.burst_shots_to_fire = burst_shots_to_fire + +///Setter for burst shot delay +/datum/component/automatedfire/autofire/proc/modify_burstfire_shot_delay(datum/source, burstfire_shot_delay) + SIGNAL_HANDLER + src.burstfire_shot_delay = burstfire_shot_delay + +///Insert the component in the bucket system if it was not in already +/datum/component/automatedfire/autofire/proc/initiate_shot() + SIGNAL_HANDLER + if(shooting)//if we are already shooting, it means the shooter is still on cooldown + return + shooting = TRUE + process_shot() + +///Remove the component from the bucket system if it was in +/datum/component/automatedfire/autofire/proc/stop_firing() + SIGNAL_HANDLER + if(!shooting) + return + ///We are burst firing, we can't clean the state now. We will do it when the burst is over + if(bursting) + have_to_reset_at_burst_end = TRUE + return + shooting = FALSE + shots_fired = 0 + +///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() + callback_reset_fire.Invoke() //resets the gun + shots_fired = 0 + have_to_reset_at_burst_end = FALSE + if(bursting) + bursting = FALSE + callback_bursting.Invoke(FALSE) + shooting = FALSE + + +///Ask the shooter to fire and schedule the next shot if need +/datum/component/automatedfire/autofire/process_shot() + if(!shooting) + return + if(next_fire > world.time)//This mean duplication somewhere, we abort now + return + if(!(callback_fire.Invoke() & AUTOFIRE_CONTINUE))//reset fire if we want to stop + hard_reset() + return + switch(fire_mode) + if(GUN_FIREMODE_BURSTFIRE) + shots_fired++ + if(shots_fired == burst_shots_to_fire) + callback_bursting.Invoke(FALSE) + callback_display_ammo.Invoke() + bursting = FALSE + stop_firing() + if(have_to_reset_at_burst_end)//We failed to reset because we were bursting, we do it now + callback_reset_fire.Invoke() + have_to_reset_at_burst_end = FALSE + return + callback_bursting.Invoke(TRUE) + bursting = TRUE + next_fire = world.time + burstfire_shot_delay + if(GUN_FIREMODE_AUTOMATIC) + callback_set_firing.Invoke(TRUE) + next_fire = world.time + auto_fire_shot_delay + if(GUN_FIREMODE_SEMIAUTO) + return + schedule_shot() diff --git a/code/modules/cm_preds/yaut_weapons.dm b/code/modules/cm_preds/yaut_weapons.dm index 986b30c27ddf..fbbe6c183aaa 100644 --- a/code/modules/cm_preds/yaut_weapons.dm +++ b/code/modules/cm_preds/yaut_weapons.dm @@ -757,7 +757,7 @@ /obj/item/weapon/gun/launcher/spike/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6 + set_fire_delay(FIRE_DELAY_TIER_6) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_5 accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_8 @@ -859,7 +859,7 @@ /obj/item/weapon/gun/energy/yautja/plasmarifle/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6*2 + set_fire_delay(FIRE_DELAY_TIER_6*2) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_10 accuracy_mult_unwielded = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_6 @@ -961,7 +961,7 @@ /obj/item/weapon/gun/energy/yautja/plasmapistol/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_7 + set_fire_delay(FIRE_DELAY_TIER_7) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_10 accuracy_mult_unwielded = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_8 @@ -1084,7 +1084,7 @@ /obj/item/weapon/gun/energy/yautja/plasma_caster/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6 + set_fire_delay(FIRE_DELAY_TIER_6) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT + FIRE_DELAY_TIER_6 scatter = SCATTER_AMOUNT_TIER_6 @@ -1100,21 +1100,21 @@ if("low power stun bolts") strength = "high power stun bolts" charge_cost = 100 - fire_delay = FIRE_DELAY_TIER_6 * 3 + set_fire_delay(FIRE_DELAY_TIER_6 * 3) fire_sound = 'sound/weapons/pred_lasercannon.ogg' to_chat(user, SPAN_NOTICE("[src] will now fire [strength].")) ammo = GLOB.ammo_list[/datum/ammo/energy/yautja/caster/bolt/stun] if("high power stun bolts") strength = "plasma immobilizers" charge_cost = 300 - fire_delay = FIRE_DELAY_TIER_6 * 20 + set_fire_delay(FIRE_DELAY_TIER_6 * 20) fire_sound = 'sound/weapons/pulse.ogg' to_chat(user, SPAN_NOTICE("[src] will now fire [strength].")) ammo = GLOB.ammo_list[/datum/ammo/energy/yautja/caster/sphere/stun] if("plasma immobilizers") strength = "low power stun bolts" charge_cost = 30 - fire_delay = FIRE_DELAY_TIER_6 + set_fire_delay(FIRE_DELAY_TIER_6) fire_sound = 'sound/weapons/pred_plasmacaster_fire.ogg' to_chat(user, SPAN_NOTICE("[src] will now fire [strength].")) ammo = GLOB.ammo_list[/datum/ammo/energy/yautja/caster/stun] @@ -1123,14 +1123,14 @@ if("plasma bolts") strength = "plasma spheres" charge_cost = 1200 - fire_delay = FIRE_DELAY_TIER_6 * 20 + set_fire_delay(FIRE_DELAY_TIER_6 * 20) fire_sound = 'sound/weapons/pulse.ogg' to_chat(user, SPAN_NOTICE("[src] will now fire [strength].")) ammo = GLOB.ammo_list[/datum/ammo/energy/yautja/caster/sphere] if("plasma spheres") strength = "plasma bolts" charge_cost = 100 - fire_delay = FIRE_DELAY_TIER_6 * 3 + set_fire_delay(FIRE_DELAY_TIER_6 * 3) fire_sound = 'sound/weapons/pred_lasercannon.ogg' to_chat(user, SPAN_NOTICE("[src] will now fire [strength].")) ammo = GLOB.ammo_list[/datum/ammo/energy/yautja/caster/bolt] @@ -1142,7 +1142,7 @@ to_chat(usr, SPAN_YAUTJABOLD("[src.source] beeps: [src] is now set to [mode] mode")) strength = "plasma bolts" charge_cost = 100 - fire_delay = FIRE_DELAY_TIER_6 * 3 + set_fire_delay(FIRE_DELAY_TIER_6 * 3) fire_sound = 'sound/weapons/pred_lasercannon.ogg' to_chat(usr, SPAN_NOTICE("[src] will now fire [strength].")) ammo = GLOB.ammo_list[/datum/ammo/energy/yautja/caster/bolt] @@ -1152,7 +1152,7 @@ to_chat(usr, SPAN_YAUTJABOLD("[src.source] beeps: [src] is now set to [mode] mode")) strength = "low power stun bolts" charge_cost = 30 - fire_delay = FIRE_DELAY_TIER_6 + set_fire_delay(FIRE_DELAY_TIER_6) fire_sound = 'sound/weapons/pred_plasmacaster_fire.ogg' to_chat(usr, SPAN_NOTICE("[src] will now fire [strength].")) ammo = GLOB.ammo_list[/datum/ammo/energy/yautja/caster/stun] diff --git a/code/modules/cm_tech/implements/adv_weapon.dm b/code/modules/cm_tech/implements/adv_weapon.dm index 58773f551306..3cc8f1ceb4d6 100644 --- a/code/modules/cm_tech/implements/adv_weapon.dm +++ b/code/modules/cm_tech/implements/adv_weapon.dm @@ -101,8 +101,8 @@ /obj/item/weapon/gun/rifle/techweb_railgun/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6*5 - burst_amount = BURST_AMOUNT_TIER_1 + set_fire_delay(FIRE_DELAY_TIER_6*5) + set_burst_amount(BURST_AMOUNT_TIER_1) accuracy_mult = BASE_ACCURACY_MULT * 3 //you HAVE to be able to hit scatter = SCATTER_AMOUNT_TIER_8 damage_mult = BASE_BULLET_DAMAGE_MULT diff --git a/code/modules/cm_tech/implements/medical_czsp.dm b/code/modules/cm_tech/implements/medical_czsp.dm index ccfd59ce7cbc..e0b00ebf5afd 100644 --- a/code/modules/cm_tech/implements/medical_czsp.dm +++ b/code/modules/cm_tech/implements/medical_czsp.dm @@ -186,21 +186,21 @@ /obj/item/weapon/gun/pill/Fire(atom/target, mob/living/user, params, reflex, dual_wield) if(!able_to_fire(user)) - return + return NONE if(!current_mag.current_rounds) click_empty(user) - return + return NONE if(!istype(current_mag, /obj/item/ammo_magazine/internal/pillgun)) - return + return NONE var/obj/item/ammo_magazine/internal/pillgun/internal_mag = current_mag var/obj/item/reagent_container/pill/pill_to_use = LAZYACCESS(internal_mag.pills, 1) if(QDELETED(pill_to_use)) click_empty(user) - return + return NONE var/obj/item/projectile/pill/P = new /obj/item/projectile/pill(src, user, src) P.generate_bullet(GLOB.ammo_list[/datum/ammo/pill], 0, 0) @@ -211,6 +211,7 @@ playsound(user.loc, 'sound/items/syringeproj.ogg', 50, 1) P.fire_at(target, user, src) + return AUTOFIRE_CONTINUE /datum/ammo/pill name = "syringe" diff --git a/code/modules/gear_presets/fun.dm b/code/modules/gear_presets/fun.dm index 3930f6fb9999..20a7f18077dd 100644 --- a/code/modules/gear_presets/fun.dm +++ b/code/modules/gear_presets/fun.dm @@ -141,7 +141,7 @@ launcher.cylinder.storage_slots = launcher.internal_slots //need to adjust the internal storage as well. for(var/i = 1 to launcher.internal_slots) new /obj/item/explosive/grenade/high_explosive/frag(launcher.cylinder) - launcher.fire_delay = FIRE_DELAY_TIER_4 //More HEFA per second, per second. Strictly speaking this is probably a nerf. + launcher.set_fire_delay(FIRE_DELAY_TIER_4) //More HEFA per second, per second. Strictly speaking this is probably a nerf. // Satchel if(satchel_success) diff --git a/code/modules/projectiles/full_auto.dm b/code/modules/projectiles/full_auto.dm deleted file mode 100644 index ad3e037b68e6..000000000000 --- a/code/modules/projectiles/full_auto.dm +++ /dev/null @@ -1,129 +0,0 @@ -/obj/item/weapon/gun/proc/full_auto_start(client/source, atom/A, params) - SIGNAL_HANDLER - if(!ismob(loc) || !A) - return - var/mob/user = loc - - // No FA with mods - if(params["shift"] || params["ctrl"] || params["alt"]) - return - - // No shooting the 4th wall - if(istype(A, /atom/movable/screen)) - return - - // No FA on attachables - if(active_attachable) - return - - if(user.get_active_hand() != src) - return - - if(user.throw_mode) - return - - // Don't open fire on adjacent targets. Let normal attack code handle this - if(A.Adjacent(user) && user.a_intent != INTENT_HARM) - return - - if(user.client?.prefs?.toggle_prefs & TOGGLE_HELP_INTENT_SAFETY && (user.a_intent == INTENT_HELP)) - if(world.time % 3) // Limits how often this message pops up, saw this somewhere else and thought it was clever - to_chat(user, SPAN_NOTICE("You consider shooting at [A], but do not follow through.")) - return - - fa_firing = TRUE - fa_shots = 0 - fa_target = A - fa_params = params - - // Ward off spamclickin fellas - if(world.time < last_fired + fa_delay) - if(world.time % 3) // Limits how often this message pops up, saw this somewhere else and it's fucking stupid - to_chat(user, SPAN_WARNING("[src] is not ready to fire again!")) - return - - // Kick off the full-auto - INVOKE_ASYNC(src, PROC_REF(repeat_fire), user) - -/obj/item/weapon/gun/proc/full_auto_stop(client/source, atom/A, params) - SIGNAL_HANDLER - fa_target = null - fa_params = null - -/obj/item/weapon/gun/proc/full_auto_new_target(client/source, atom/start, atom/hovered, params) - SIGNAL_HANDLER - if(!ismob(loc)) - return - var/mob/user = loc - - if(istype(hovered, /atom/movable/screen)) - return - - if(get_turf(hovered) == get_turf(user)) - return - - fa_target = hovered - fa_params = params2list(params) - -/obj/item/weapon/gun/proc/repeat_fire(mob/user) - if(!fa_target) - return - - // fun is ended - if(active_attachable) - return - - // fun's over - if(!in_chamber && !current_mag) - click_empty(user) - return - - // fun's also over - if(!user.canmove || user.stat || user.is_mob_restrained() || !user.loc || !isturf(user.loc)) - return - - // you abandoned the f u n - if(user.get_active_hand() != src || loc != user) - return - - if(user.throw_mode) - return - - user.face_atom(fa_target) - Fire(fa_target, user, fa_params) - - addtimer(CALLBACK(src, PROC_REF(repeat_fire), user), fa_delay) - -// Make sure we're not trying to start full auto when the gun isn't even held by anyone -/obj/item/weapon/gun/dropped(mob/user) - ..() - - if(!user.client) - return - - UnregisterSignal(user.client, list( - COMSIG_CLIENT_LMB_DOWN, - COMSIG_CLIENT_LMB_UP, - COMSIG_CLIENT_LMB_DRAG, - )) - -// Also make sure it's registered when held in any hand and full-auto is on -/obj/item/weapon/gun/equipped(mob/user, slot) - ..() - - if(!user.client) - return - - // If it was equipped to anything but the hands, make sure we're not registered - if(slot != WEAR_R_HAND && slot != WEAR_L_HAND) - UnregisterSignal(user.client, list( - COMSIG_CLIENT_LMB_DOWN, - COMSIG_CLIENT_LMB_UP, - COMSIG_CLIENT_LMB_DRAG, - )) - return - - if(flags_gun_features & GUN_FULL_AUTO_ON) - RegisterSignal(user.client, COMSIG_CLIENT_LMB_DOWN, PROC_REF(full_auto_start)) - RegisterSignal(user.client, COMSIG_CLIENT_LMB_UP, PROC_REF(full_auto_stop)) - RegisterSignal(user.client, COMSIG_CLIENT_LMB_DRAG, PROC_REF(full_auto_new_target)) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 263f5b07cca4..54e066e05544 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -92,8 +92,8 @@ ///Multiplier. Increased and decreased through attachments. Multiplies the accuracy/scatter penalty of the projectile when firing onehanded while moving. var/movement_onehanded_acc_penalty_mult = 5 //Multiplier. Increased and decreased through attachments. Multiplies the accuracy/scatter penalty of the projectile when firing onehanded while moving. - ///For regular shots, how long to wait before firing again. - var/fire_delay = 0 + ///For regular shots, how long to wait before firing again. Use modify_fire_delay and set_fire_delay instead of modifying this on the fly + VAR_PROTECTED/fire_delay = 0 ///When it was last fired, related to world.time. var/last_fired = 0 @@ -112,10 +112,10 @@ var/delay_style = WEAPON_DELAY_SCATTER_AND_ACCURACY //Burst fire. - ///How many shots can the weapon shoot in burst? Anything less than 2 and you cannot toggle burst. - var/burst_amount = 1 - ///The delay in between shots. Lower = less delay = faster. - var/burst_delay = 1 + ///How many shots can the weapon shoot in burst? Anything less than 2 and you cannot toggle burst. Use modify_burst_amount and set_burst_amount instead of modifying this + VAR_PROTECTED/burst_amount = 1 + ///The delay in between shots. Lower = less delay = faster. Use modify_burst_delay and set_burst_delay instead of modifying this + VAR_PROTECTED/burst_delay = 1 ///When burst-firing, this number is extra time before the weapon can fire again. Depends on number of rounds fired. var/extra_delay = 0 ///When PB burst firing and handing off to /fire after a target moves out of range, this is how many bullets have been fired. @@ -124,22 +124,13 @@ // Full auto ///Whether or not the gun is firing full-auto var/fa_firing = FALSE - ///How many shots have been fired using full-auto. Used to figure out scatter - var/fa_shots = 0 ///How many full-auto shots to get to max scatter? - var/fa_scatter_peak = 8 + var/fa_scatter_peak = 4 ///How bad does the scatter get on full auto? - var/fa_max_scatter = 5 - ///The delay when firing full-auto - var/fa_delay = 2.5 - ///The atom we're shooting at while full-autoing - var/atom/fa_target = null + var/fa_max_scatter = 8.5 ///Click parameters to use when firing full-auto var/fa_params = null - //Targeting. - ///List of who yer targeting. - var/tmp/list/mob/living/target ///Used to fire faster at more than one person. var/tmp/mob/living/last_moved_mob var/tmp/lock_time = -100 @@ -223,6 +214,21 @@ // Set to TRUE or FALSE, it overrides the is_civilian_usable check with its value. Does nothing if null. var/civilian_usable_override = null + ///Current selected firemode of the gun. + var/gun_firemode = GUN_FIREMODE_SEMIAUTO + ///List of allowed firemodes. + var/list/gun_firemode_list = list() + ///How many bullets the gun fired while bursting/auto firing + var/shots_fired = 0 + /// Currently selected target to fire at. Set with set_target() + VAR_PRIVATE/atom/target + /// Current user (holding) of the gun. Set with set_gun_user() + VAR_PRIVATE/mob/gun_user + /// If this gun should spawn with semi-automatic fire. Protected due to it never needing to be edited. + 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 + /** * An assoc list where the keys are fire delay group string defines @@ -253,11 +259,13 @@ else current_mag = new current_mag(src, spawn_empty? 1:0) replace_ammo(null, current_mag) - else ammo = GLOB.ammo_list[ammo] //If they don't have a mag, they fire off their own thing. + else + ammo = GLOB.ammo_list[ammo] //If they don't have a mag, they fire off their own thing. set_gun_attachment_offsets() set_gun_config_values() set_bullet_traits() + setup_firemodes() update_force_list() //This gives the gun some unique attack verbs for attacking. handle_starting_attachment() handle_random_attachments() @@ -265,6 +273,8 @@ if(auto_retrieval_slot) 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. /obj/item/weapon/gun/proc/set_gun_attachment_offsets() attachable_offset = null @@ -288,8 +298,8 @@ attachments = null attachable_overlays = null QDEL_NULL(active_attachable) - fa_target = null GLOB.gun_list -= src + set_gun_user(null) . = ..() /* @@ -299,12 +309,12 @@ * This makes reading each gun's values MUCH easier. */ /obj/item/weapon/gun/proc/set_gun_config_values() - fire_delay = FIRE_DELAY_TIER_5 + set_fire_delay(FIRE_DELAY_TIER_5) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 burst_scatter_mult = SCATTER_AMOUNT_TIER_7 - burst_amount = BURST_AMOUNT_TIER_1 + set_burst_amount(BURST_AMOUNT_TIER_5) scatter_unwielded = SCATTER_AMOUNT_TIER_6 damage_mult = BASE_BULLET_DAMAGE_MULT damage_falloff_mult = DAMAGE_FALLOFF_TIER_10 @@ -378,8 +388,9 @@ //Add attachment bonuses for(var/slot in attachments) var/obj/item/attachable/R = attachments[slot] - if(!R) continue - fire_delay += R.delay_mod + if(!R) + continue + modify_fire_delay(R.delay_mod) accuracy_mult += R.accuracy_mod accuracy_mult_unwielded += R.accuracy_unwielded_mod scatter += R.scatter_mod @@ -392,7 +403,7 @@ effective_range_max += R.range_max_mod recoil += R.recoil_mod burst_scatter_mult += R.burst_scatter_mod - burst_amount += R.burst_mod + modify_burst_amount(R.burst_mod) recoil_unwielded += R.recoil_unwielded_mod aim_slowdown += R.aim_speed_mod wield_delay += R.wield_delay_mod @@ -471,6 +482,10 @@ for(var/obj/O in contents) O.emp_act(severity) +/* +Note: pickup and dropped on weapons must have both the ..() to update zoom AND twohanded, +As sniper rifles have both and weapon mods can change them as well. ..() deals with zoom only. +*/ /obj/item/weapon/gun/equipped(mob/user, slot) if(flags_item & NODROP) return @@ -480,8 +495,31 @@ pull_time += 3 guaranteed_delay_time = world.time + WEAPON_GUARANTEED_DELAY + var/delay_left = (last_fired + fire_delay + additional_fire_group_delay) - world.time + if(fire_delay_group && delay_left > 0) + for(var/group in fire_delay_group) + LAZYSET(user.fire_delay_next_fire, group, world.time + delay_left) + + if(slot in list(WEAR_L_HAND, WEAR_R_HAND)) + set_gun_user(user) + else + set_gun_user(null) + return ..() +/obj/item/weapon/gun/dropped(mob/user) + . = ..() + + disconnect_light_from_mob(user) + + var/delay_left = (last_fired + fire_delay + additional_fire_group_delay) - world.time + if(fire_delay_group && delay_left > 0) + for(var/group in fire_delay_group) + LAZYSET(user.fire_delay_next_fire, group, world.time + delay_left) + + unwield(user) + set_gun_user(null) + /obj/item/weapon/gun/update_icon() if(overlays) overlays.Cut() @@ -675,8 +713,8 @@ data["penetration_max"] = ARMOR_PENETRATION_TIER_10 data["punch_max"] = 5 data["glob_armourbreak"] = GLOB.xeno_general.armor_ignore_integrity - data["automatic"] = flags_gun_features & GUN_HAS_FULL_AUTO - data["auto_only"] = flags_gun_features & GUN_FULL_AUTO_ONLY + data["automatic"] = (GUN_FIREMODE_AUTOMATIC in gun_firemode_list) + data["auto_only"] = ((length(gun_firemode_list) == 1) && (GUN_FIREMODE_AUTOMATIC in gun_firemode_list)) return data @@ -724,14 +762,10 @@ else wield_time -= 2*user.skills.get_skill_level(SKILL_FIREARMS) - if(flags_gun_features & GUN_FULL_AUTO_ON) - ADD_TRAIT(user, TRAIT_OVERRIDE_CLICKDRAG, TRAIT_SOURCE_WEAPON) - return 1 /obj/item/weapon/gun/unwield(mob/user) . = ..() - REMOVE_TRAIT(user, TRAIT_OVERRIDE_CLICKDRAG, TRAIT_SOURCE_WEAPON) if(.) slowdown = initial(slowdown) @@ -892,33 +926,6 @@ User can be passed as null, (a gun reloading itself for instance), so we need to // \\ //---------------------------------------------------------- -/obj/item/weapon/gun/afterattack(atom/A, mob/living/user, flag, params) - if(active_attachable && (active_attachable.flags_attach_features & ATTACH_MELEE)) //this is expected to do something in melee. - active_attachable.fire_attachment(A, src, user) - return TRUE - if(flag) - return FALSE //It's adjacent, is the user, or is on the user's person - if(!istype(A)) - return FALSE - // If firing full-auto, the firing starts when the mouse is clicked, not when it's released - // so the gun should already be shooting - if(fa_firing) - fa_firing = FALSE - return TRUE - if(flags_gun_features & GUN_BURST_FIRING) - return FALSE - if(!user || !user.client || !user.client.prefs) - return FALSE - else if(user.client?.prefs?.toggle_prefs & TOGGLE_HELP_INTENT_SAFETY && (user.a_intent == INTENT_HELP)) - if (world.time % 3) // Limits how often this message pops up, saw this somewhere else and thought it was clever - //Absolutely SCREAM this at people so they don't get killed by it - to_chat(user, SPAN_HIGHDANGER("Help intent safety is on! Switch to another intent to fire your weapon.")) - click_empty(user) - return FALSE - else - Fire(A,user,params) //Otherwise, fire normally. - return TRUE - /** load_into_chamber(), reload_into_chamber(), and clear_jam() do all of the heavy lifting. If you need to change up how a gun fires, just change these procs for that subtype @@ -1056,17 +1063,11 @@ and you're good to go. // \\ //---------------------------------------------------------- -/obj/item/weapon/gun/proc/Fire(atom/target, mob/living/user, params, reflex = 0, dual_wield) - set waitfor = 0 - - if(!able_to_fire(user) || !target) - return +/obj/item/weapon/gun/proc/Fire(atom/target, mob/living/user, params, reflex = FALSE, dual_wield) + set waitfor = FALSE - var/turf/curloc = get_turf(user) //In case the target or we are expired. - var/turf/targloc = get_turf(target) - if(!targloc || !curloc) - return //Something has gone wrong... - var/atom/original_target = target //This is for burst mode, in case the target changes per scatter chance in between fired bullets. + if(!able_to_fire(user) || !target || !get_turf(user) || !get_turf(target)) + return NONE /* This is where the grenade launcher and flame thrower function as attachments. @@ -1074,12 +1075,10 @@ and you're good to go. */ var/check_for_attachment_fire = 0 - //Number of bullets based on burst. If an active attachable is shooting, bursting is always zero. - var/bullets_to_fire = 1 if(active_attachable?.flags_attach_features & ATTACH_WEAPON) //Attachment activated and is a weapon. check_for_attachment_fire = 1 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) + if((active_attachable.current_rounds <= 0) && !(active_attachable.flags_attach_features & ATTACH_IGNORE_EMPTY)) click_empty(user) //If it's empty, let them know. to_chat(user, SPAN_WARNING("[active_attachable] is empty!")) to_chat(user, SPAN_NOTICE("You disable [active_attachable].")) @@ -1087,18 +1086,16 @@ and you're good to go. else active_attachable.fire_attachment(target, src, user) //Fire it. active_attachable.last_fired = world.time - return + return NONE //If there's more to the attachment, it will be processed farther down, through in_chamber and regular bullet act. /* This is where burst is established for the proceeding section. Which just means the proc loops around that many times. If burst = 1, you must null it if you ever RETURN during the for() cycle. If for whatever reason burst is left on while the gun is not firing, it will break a lot of stuff. BREAK is fine, as it will null it. */ - else if((flags_gun_features & GUN_BURST_ON) && burst_amount > 1) - bullets_to_fire = burst_amount + else if((gun_firemode == GUN_FIREMODE_BURSTFIRE) && burst_amount > BURST_AMOUNT_TIER_1) flags_gun_features |= GUN_BURST_FIRING if(PB_burst_bullets_fired) //Has a burst been carried over from a PB? - bullets_to_fire -= PB_burst_bullets_fired PB_burst_bullets_fired = 0 //Don't need this anymore. The torch is passed. //Dual wielding. Do we have a gun in the other hand, is it loaded, and is it the same category? @@ -1114,109 +1111,110 @@ and you're good to go. else akimbo.Fire(target,user,params, 0, TRUE) - var/bullets_fired - for(bullets_fired = 1 to bullets_to_fire) - if(loc != user || (flags_gun_features & GUN_WIELDED_FIRING_ONLY && !(flags_item & WIELDED))) - break //If you drop it while bursting, for example. + var/fire_return = handle_fire(target, user, params, reflex, dual_wield, check_for_attachment_fire) + if(!fire_return) + return fire_return - if (bullets_fired > 1 && !(flags_gun_features & GUN_BURST_FIRING)) // No longer burst firing somehow - break - - //The gun should return the bullet that it already loaded from the end cycle of the last Fire(). - var/obj/item/projectile/projectile_to_fire = load_into_chamber(user) //Load a bullet in or check for existing one. - if(!projectile_to_fire) //If there is nothing to fire, click. - click_empty(user) - flags_gun_features &= ~GUN_BURST_FIRING - return + flags_gun_features &= ~GUN_BURST_FIRING // We always want to turn off bursting when we're done, mainly for when we break early mid-burstfire. + return AUTOFIRE_CONTINUE - apply_bullet_effects(projectile_to_fire, user, bullets_fired, reflex, dual_wield) //User can be passed as null. - SEND_SIGNAL(projectile_to_fire, COMSIG_BULLET_USER_EFFECTS, user) +/obj/item/weapon/gun/proc/handle_fire(atom/target, mob/living/user, params, reflex = FALSE, dual_wield, check_for_attachment_fire) + var/turf/curloc = get_turf(user) //In case the target or we are expired. + var/turf/targloc = get_turf(target) - curloc = get_turf(user) - if(QDELETED(original_target)) //If the target's destroyed, shoot at where it was last. - target = targloc - else - target = original_target - targloc = get_turf(target) - - projectile_to_fire.original = target - - // turf-targeted projectiles are fired without scatter, because proc would raytrace them further away - var/ammo_flags = projectile_to_fire.ammo.flags_ammo_behavior | projectile_to_fire.projectile_override_flags - if(!(ammo_flags & AMMO_HITS_TARGET_TURF)) - target = simulate_scatter(projectile_to_fire, target, curloc, targloc, user, bullets_fired) - - var/bullet_velocity = projectile_to_fire?.ammo?.shell_speed + velocity_add - - if(params) // Apply relative clicked position from the mouse info to offset projectile - if(!params["click_catcher"]) - if(params["vis-x"]) - projectile_to_fire.p_x = text2num(params["vis-x"]) - else if(params["icon-x"]) - projectile_to_fire.p_x = text2num(params["icon-x"]) - if(params["vis-y"]) - projectile_to_fire.p_y = text2num(params["vis-y"]) - else if(params["icon-y"]) - projectile_to_fire.p_y = text2num(params["icon-y"]) - var/atom/movable/clicked_target = original_target - if(istype(clicked_target)) - projectile_to_fire.p_x -= clicked_target.bound_width / 2 - projectile_to_fire.p_y -= clicked_target.bound_height / 2 - else - projectile_to_fire.p_x -= world.icon_size / 2 - projectile_to_fire.p_y -= world.icon_size / 2 - else - projectile_to_fire.p_x -= world.icon_size / 2 - projectile_to_fire.p_y -= world.icon_size / 2 + var/atom/original_target = target //This is for burst mode, in case the target changes per scatter chance in between fired bullets. - //Finally, make with the pew pew! - if(QDELETED(projectile_to_fire) || !isobj(projectile_to_fire)) - to_chat(user, "ERROR CODE I1: Gun malfunctioned due to invalid chambered projectile, clearing it. AHELP if this persists.") - log_debug("ERROR CODE I1: projectile malfunctioned while firing. User: [user] Weapon: [src] Magazine: [current_mag]") - flags_gun_features &= ~GUN_BURST_FIRING - in_chamber = null - click_empty(user) - return + if(loc != user || (flags_gun_features & GUN_WIELDED_FIRING_ONLY && !(flags_item & WIELDED))) + return TRUE - if(targloc != curloc) - simulate_recoil(dual_wield, user, target) + //The gun should return the bullet that it already loaded from the end cycle of the last Fire(). + var/obj/item/projectile/projectile_to_fire = load_into_chamber(user) //Load a bullet in or check for existing one. + if(!projectile_to_fire) //If there is nothing to fire, click. + click_empty(user) + flags_gun_features &= ~GUN_BURST_FIRING + return NONE - //This is where the projectile leaves the barrel and deals with projectile code only. - //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - in_chamber = null // It's not in the gun anymore - INVOKE_ASYNC(projectile_to_fire, TYPE_PROC_REF(/obj/item/projectile, fire_at), target, user, src, projectile_to_fire?.ammo?.max_range, bullet_velocity, original_target) - projectile_to_fire = null // Important: firing might have made projectile collide early and ALREADY have deleted it. We clear it too. - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + apply_bullet_effects(projectile_to_fire, user, reflex, dual_wield) //User can be passed as null. + SEND_SIGNAL(projectile_to_fire, COMSIG_BULLET_USER_EFFECTS, user) - if(check_for_attachment_fire) - active_attachable.last_fired = world.time + curloc = get_turf(user) + if(QDELETED(original_target)) //If the target's destroyed, shoot at where it was last. + target = targloc + else + target = original_target + targloc = get_turf(target) + + projectile_to_fire.original = target + + // turf-targeted projectiles are fired without scatter, because proc would raytrace them further away + var/ammo_flags = projectile_to_fire.ammo.flags_ammo_behavior | projectile_to_fire.projectile_override_flags + if(!(ammo_flags & AMMO_HITS_TARGET_TURF)) + target = simulate_scatter(projectile_to_fire, target, curloc, targloc, user) + + var/bullet_velocity = projectile_to_fire?.ammo?.shell_speed + velocity_add + + if(params) // Apply relative clicked position from the mouse info to offset projectile + if(!params["click_catcher"]) + if(params["vis-x"]) + projectile_to_fire.p_x = text2num(params["vis-x"]) + else if(params["icon-x"]) + projectile_to_fire.p_x = text2num(params["icon-x"]) + if(params["vis-y"]) + projectile_to_fire.p_y = text2num(params["vis-y"]) + else if(params["icon-y"]) + projectile_to_fire.p_y = text2num(params["icon-y"]) + var/atom/movable/clicked_target = original_target + if(istype(clicked_target)) + projectile_to_fire.p_x -= clicked_target.bound_width / 2 + projectile_to_fire.p_y -= clicked_target.bound_height / 2 else - last_fired = world.time - SEND_SIGNAL(user, COMSIG_MOB_FIRED_GUN, src) - . = TRUE + projectile_to_fire.p_x -= world.icon_size / 2 + projectile_to_fire.p_y -= world.icon_size / 2 + else + projectile_to_fire.p_x -= world.icon_size / 2 + projectile_to_fire.p_y -= world.icon_size / 2 + + //Finally, make with the pew pew! + if(QDELETED(projectile_to_fire) || !isobj(projectile_to_fire)) + to_chat(user, "ERROR CODE I1: Gun malfunctioned due to invalid chambered projectile, clearing it. AHELP if this persists.") + log_debug("ERROR CODE I1: projectile malfunctioned while firing. User: [user] Weapon: [src] Magazine: [current_mag]") + flags_gun_features &= ~GUN_BURST_FIRING + in_chamber = null + click_empty(user) + return NONE - if(flags_gun_features & GUN_FULL_AUTO_ON) - fa_shots++ + if(targloc != curloc) + simulate_recoil(dual_wield, user, target) - 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) - break + //This is where the projectile leaves the barrel and deals with projectile code only. + //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + in_chamber = null // It's not in the gun anymore + INVOKE_ASYNC(projectile_to_fire, TYPE_PROC_REF(/obj/item/projectile, fire_at), target, user, src, projectile_to_fire?.ammo?.max_range, bullet_velocity, original_target) + projectile_to_fire = null // Important: firing might have made projectile collide early and ALREADY have deleted it. We clear it too. + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - //>>POST PROCESSING AND CLEANUP BEGIN HERE.<< - var/angle = round(Get_Angle(user,target)) //Let's do a muzzle flash. - muzzle_flash(angle,user) + if(check_for_attachment_fire) + active_attachable.last_fired = world.time + else + last_fired = world.time + SEND_SIGNAL(user, COMSIG_MOB_FIRED_GUN, src) + . = TRUE - //This is where we load the next bullet in the chamber. We check for attachments too, since we don't want to load anything if an attachment is active. - if(!check_for_attachment_fire && !reload_into_chamber(user)) // It has to return a bullet, otherwise it's empty. Unless it's an undershotgun. - click_empty(user) - break //Nothing else to do here, time to cancel out. + shots_fired++ - if(bullets_fired < bullets_to_fire) // We still have some bullets to fire. - extra_delay = fire_delay * 0.5 - sleep(burst_delay) + 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) + return TRUE - flags_gun_features &= ~GUN_BURST_FIRING // We always want to turn off bursting when we're done, mainly for when we break early mid-burstfire. - display_ammo(user) + //>>POST PROCESSING AND CLEANUP BEGIN HERE.<< + var/angle = round(Get_Angle(user,target)) //Let's do a muzzle flash. + muzzle_flash(angle,user) + + //This is where we load the next bullet in the chamber. We check for attachments too, since we don't want to load anything if an attachment is active. + if(!check_for_attachment_fire && !reload_into_chamber(user)) // It has to return a bullet, otherwise it's empty. Unless it's an undershotgun. + click_empty(user) + return TRUE //Nothing else to do here, time to cancel out. + return TRUE #define EXECUTION_CHECK (attacked_mob.stat == UNCONSCIOUS || attacked_mob.is_mob_restrained()) && ((user.a_intent == INTENT_GRAB)||(user.a_intent == INTENT_DISARM)) @@ -1335,7 +1333,7 @@ and you're good to go. var/bullets_to_fire = 1 - if(!check_for_attachment_fire && (flags_gun_features & GUN_BURST_ON) && burst_amount > 1) + if(!check_for_attachment_fire && (gun_firemode == GUN_FIREMODE_BURSTFIRE) && burst_amount > BURST_AMOUNT_TIER_1) bullets_to_fire = burst_amount flags_gun_features |= GUN_BURST_FIRING @@ -1470,6 +1468,8 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed */ if(flags_gun_features & GUN_BURST_FIRING) + return TRUE + if(user.is_mob_incapacitated()) return if(world.time < guaranteed_delay_time) return @@ -1540,12 +1540,15 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed if(active_attachable) return - if(flags_gun_features & GUN_AMMO_COUNTER && !(flags_gun_features & GUN_BURST_FIRING) && current_mag) + if(!user) + user = gun_user + + if(flags_gun_features & GUN_AMMO_COUNTER && current_mag) var/chambered = in_chamber ? TRUE : FALSE to_chat(user, SPAN_DANGER("[current_mag.current_rounds][chambered ? "+1" : ""] / [current_mag.max_rounds] ROUNDS REMAINING")) //This proc applies some bonus effects to the shot/makes the message when a bullet is actually fired. -/obj/item/weapon/gun/proc/apply_bullet_effects(obj/item/projectile/projectile_to_fire, mob/user, bullets_fired = 1, reflex = 0, dual_wield = 0) +/obj/item/weapon/gun/proc/apply_bullet_effects(obj/item/projectile/projectile_to_fire, mob/user, reflex = 0, dual_wield = 0) var/actual_sound = fire_sound if(isnull(fire_sound)) actual_sound = pick(fire_sounds) @@ -1626,8 +1629,8 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed var/fire_angle = Get_Angle(curloc, targloc) var/total_scatter_angle = projectile_to_fire.scatter - if(flags_gun_features & GUN_BURST_ON && bullets_fired > 1)//Much higher scatter on burst. Each additional bullet adds scatter - var/bullet_amt_scat = min(bullets_fired-1, SCATTER_AMOUNT_TIER_6)//capped so we don't penalize large bursts too much. + if((gun_firemode == GUN_FIREMODE_BURSTFIRE))//Much higher scatter on burst. Each additional bullet adds scatter + var/bullet_amt_scat = min(burst_amount - 1, SCATTER_AMOUNT_TIER_6)//capped so we don't penalize large bursts too much. if(flags_item & WIELDED) total_scatter_angle += max(0, bullet_amt_scat * burst_scatter_mult) else @@ -1635,9 +1638,9 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed // Full auto fucks your scatter up big time // Note that full auto uses burst scatter multipliers - if(flags_gun_features & GUN_FULL_AUTO_ON) + if(gun_firemode == GUN_FIREMODE_AUTOMATIC) // The longer you fire full-auto, the worse the scatter gets - var/bullet_amt_scat = min((fa_shots/fa_scatter_peak) * fa_max_scatter, fa_max_scatter) + var/bullet_amt_scat = min((shots_fired / fa_scatter_peak) * fa_max_scatter, fa_max_scatter) if(flags_item & WIELDED) total_scatter_angle += max(0, bullet_amt_scat * burst_scatter_mult) else @@ -1730,3 +1733,152 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed xeno.animation_attack_on(src) xeno.visible_message(SPAN_XENOWARNING("\The [xeno] slashes the lights on \the [src]!"), SPAN_XENONOTICE("You slash the lights on \the [src]!")) return XENO_ATTACK_ACTION + +/// Setter proc to toggle burst firing +/obj/item/weapon/gun/proc/set_bursting(bursting = FALSE) + if(bursting) + flags_gun_features |= GUN_BURST_FIRING + else + flags_gun_features &= ~GUN_BURST_FIRING + +///Clean all references +/obj/item/weapon/gun/proc/reset_fire() + shots_fired = 0//Let's clean everything + set_target(null) + set_auto_firing(FALSE) + +/// adder for fire_delay +/obj/item/weapon/gun/proc/modify_fire_delay(value) + fire_delay += value + SEND_SIGNAL(src, COMSIG_GUN_AUTOFIREDELAY_MODIFIED, fire_delay) + +/// setter for fire_delay +/obj/item/weapon/gun/proc/set_fire_delay(value) + fire_delay = value + SEND_SIGNAL(src, COMSIG_GUN_AUTOFIREDELAY_MODIFIED, fire_delay) + +/// getter for fire_delay +/obj/item/weapon/gun/proc/get_fire_delay(value) + return fire_delay + +/// setter for burst_amount +/obj/item/weapon/gun/proc/set_burst_amount(value, mob/user) + burst_amount = value + SEND_SIGNAL(src, COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED, burst_amount) + setup_firemodes() + +/// adder for burst_amount +/obj/item/weapon/gun/proc/modify_burst_amount(value, mob/user) + burst_amount += value + SEND_SIGNAL(src, COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED, burst_amount) + setup_firemodes() + +/// Adder for burst_delay +/obj/item/weapon/gun/proc/modify_burst_delay(value, mob/user) + burst_delay += value + SEND_SIGNAL(src, COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED, burst_delay) + +/// Setter for burst_delay +/obj/item/weapon/gun/proc/set_burst_delay(value, mob/user) + burst_delay = value + SEND_SIGNAL(src, COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED, burst_delay) + +///Set the target and take care of hard delete +/obj/item/weapon/gun/proc/set_target(atom/object) + active_attachable?.set_target(object) + if(object == target || object == loc) + return + if(target) + UnregisterSignal(target, COMSIG_PARENT_QDELETING) + target = object + if(target) + RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clean_target)) + +///Set the target to its turf, so we keep shooting even when it was qdeled +/obj/item/weapon/gun/proc/clean_target() + SIGNAL_HANDLER + active_attachable?.clean_target() + target = get_turf(target) + +/obj/item/weapon/gun/proc/stop_fire() + SIGNAL_HANDLER + if(!target || (gun_user.get_active_hand() != src)) + return + + if(gun_firemode == GUN_FIREMODE_AUTOMATIC) + reset_fire() + display_ammo() + SEND_SIGNAL(src, COMSIG_GUN_STOP_FIRE) + +/obj/item/weapon/gun/proc/set_gun_user(mob/to_set) + if(to_set == gun_user) + return + if(gun_user) + UnregisterSignal(gun_user, list(COMSIG_MOB_MOUSEUP, COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEDRAG)) + + gun_user = to_set + RegisterSignal(gun_user, COMSIG_MOB_MOUSEDOWN, PROC_REF(start_fire)) + RegisterSignal(gun_user, COMSIG_MOB_MOUSEDRAG, PROC_REF(change_target)) + RegisterSignal(gun_user, COMSIG_MOB_MOUSEUP, PROC_REF(stop_fire)) + +///Update the target if you draged your mouse +/obj/item/weapon/gun/proc/change_target(datum/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params) + SIGNAL_HANDLER + set_target(get_turf_on_clickcatcher(over_object, gun_user, params)) + gun_user?.face_atom(target) + +///Check if the gun can fire and add it to bucket auto_fire system if needed, or just fire the gun if not +/obj/item/weapon/gun/proc/start_fire(datum/source, atom/object, turf/location, control, params, bypass_checks = FALSE) + SIGNAL_HANDLER + + var/list/modifiers = params2list(params) + if(modifiers["shift"] || modifiers["middle"] || modifiers["right"]) + return + + // Don't allow doing anything else if inside a container of some sort, like a locker. + if(!isturf(gun_user.loc)) + return + + if(istype(object, /atom/movable/screen)) + return + + if(!bypass_checks) + if(gun_user.hand && !isgun(gun_user.l_hand) || !gun_user.hand && !isgun(gun_user.r_hand)) // If the object in our active hand is not a gun, abort + return + + if(gun_user.throw_mode) + return + + if(gun_user.Adjacent(object)) //Dealt with by attack code + return + + if(QDELETED(object)) + return + + if(gun_user.client?.prefs?.toggle_prefs & TOGGLE_HELP_INTENT_SAFETY && (gun_user.a_intent == INTENT_HELP)) + if(world.time % 3) // Limits how often this message pops up, saw this somewhere else and thought it was clever + //Absolutely SCREAM this at people so they don't get killed by it + to_chat(gun_user, SPAN_HIGHDANGER("Help intent safety is on! Switch to another intent to fire your weapon.")) + click_empty(gun_user) + return FALSE + + set_target(get_turf_on_clickcatcher(object, gun_user, params)) + if((gun_firemode == GUN_FIREMODE_SEMIAUTO) || active_attachable) + Fire(object, gun_user, modifiers) + reset_fire() + display_ammo() + return + SEND_SIGNAL(src, COMSIG_GUN_FIRE) + +/// Wrapper proc for the autofire subsystem to ensure the important args aren't null +/obj/item/weapon/gun/proc/fire_wrapper(atom/target, mob/living/user, params, reflex = FALSE, dual_wield) + SHOULD_NOT_OVERRIDE(TRUE) + if(!target) + target = src.target + if(!user) + user = src.gun_user + return Fire(target, user, params, reflex, dual_wield) + +/// Setter proc for fa_firing +/obj/item/weapon/gun/proc/set_auto_firing(auto = FALSE) + fa_firing = auto diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm index 17dc435210c9..001cd9fbe10c 100644 --- a/code/modules/projectiles/gun_attachables.dm +++ b/code/modules/projectiles/gun_attachables.dm @@ -131,8 +131,7 @@ Defined in conflicts.dm of the #defines folder. G.attachments[slot] = src G.recalculate_attachment_bonuses() - if(G.burst_amount <= 1) - G.flags_gun_features &= ~GUN_BURST_ON //Remove burst if they can no longer use it. + G.setup_firemodes() G.update_force_list() //This updates the gun to use proper force verbs. var/mob/living/living @@ -855,7 +854,7 @@ Defined in conflicts.dm of the #defines folder. /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 - G.fire_delay += delay_scoped_nerf + G.modify_fire_delay(delay_scoped_nerf) G.damage_falloff_mult += damage_falloff_scoped_buff using_scope = TRUE RegisterSignal(user, COMSIG_LIVING_ZOOM_OUT, PROC_REF(remove_scoped_buff)) @@ -865,7 +864,7 @@ Defined in conflicts.dm of the #defines folder. UnregisterSignal(user, COMSIG_LIVING_ZOOM_OUT) using_scope = FALSE G.accuracy_mult -= accuracy_scoped_buff - G.fire_delay -= delay_scoped_nerf + G.modify_fire_delay(-delay_scoped_nerf) G.damage_falloff_mult -= damage_falloff_scoped_buff /obj/item/attachable/scope/activate_attachment(obj/item/weapon/gun/G, mob/living/carbon/user, turn_off) @@ -1926,18 +1925,34 @@ Defined in conflicts.dm of the #defines folder. /// An assoc list in the format list(/datum/element/bullet_trait_to_give = list(...args)) /// that will be given to the projectiles of the attached gun var/list/list/traits_to_give_attached + /// Current target we're firing at + var/mob/target -/obj/item/attachable/attached_gun/New() //Let's make sure if something needs an ammo type, it spawns with one. - ..() +/obj/item/attachable/attached_gun/Initialize(mapload, ...) //Let's make sure if something needs an ammo type, it spawns with one. + . = ..() if(ammo) ammo = GLOB.ammo_list[ammo] /obj/item/attachable/attached_gun/Destroy() ammo = null - . = ..() - + target = null + return ..() +/// setter for target +/obj/item/attachable/attached_gun/proc/set_target(atom/object) + if(object == target) + return + if(target) + UnregisterSignal(target, COMSIG_PARENT_QDELETING) + target = object + if(target) + RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clean_target)) + +///Set the target to its turf, so we keep shooting even when it was qdeled +/obj/item/attachable/attached_gun/proc/clean_target() + SIGNAL_HANDLER + target = get_turf(target) /obj/item/attachable/attached_gun/activate_attachment(obj/item/weapon/gun/G, mob/living/user, turn_off) if(G.active_attachable == src) @@ -2414,7 +2429,7 @@ Defined in conflicts.dm of the #defines folder. attach_icon = "flamer_nozzle_a_1" w_class = SIZE_MEDIUM slot = "under" - flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION|ATTACH_WEAPON|ATTACH_MELEE + flags_attach_features = ATTACH_REMOVABLE|ATTACH_ACTIVATION|ATTACH_WEAPON|ATTACH_MELEE|ATTACH_IGNORE_EMPTY pixel_shift_x = 4 pixel_shift_y = 14 @@ -2442,7 +2457,7 @@ Defined in conflicts.dm of the #defines folder. /obj/item/attachable/attached_gun/flamer_nozzle/fire_attachment(atom/target, obj/item/weapon/gun/gun, mob/living/user) . = ..() - if(world.time < gun.last_fired + gun.fire_delay) + if(world.time < gun.last_fired + gun.get_fire_delay()) return if((gun.flags_gun_features & GUN_WIELDED_FIRING_ONLY) && !(gun.flags_item & WIELDED)) diff --git a/code/modules/projectiles/gun_helpers.dm b/code/modules/projectiles/gun_helpers.dm index 62f7378191a5..a60773c88be7 100644 --- a/code/modules/projectiles/gun_helpers.dm +++ b/code/modules/projectiles/gun_helpers.dm @@ -136,29 +136,6 @@ DEFINES in setup.dm, referenced here. else ..() -/* -Note: pickup and dropped on weapons must have both the ..() to update zoom AND twohanded, -As sniper rifles have both and weapon mods can change them as well. ..() deals with zoom only. -*/ -/obj/item/weapon/gun/dropped(mob/user) - . = ..() - - disconnect_light_from_mob(user) - - var/delay_left = (last_fired + fire_delay + additional_fire_group_delay) - world.time - if(fire_delay_group && delay_left > 0) - for(var/group in fire_delay_group) - LAZYSET(user.fire_delay_next_fire, group, world.time + delay_left) - - unwield(user) - -/obj/item/weapon/gun/equipped(mob/user, slot) - . = ..() - - var/delay_left = (last_fired + fire_delay + additional_fire_group_delay) - world.time - if(fire_delay_group && delay_left > 0) - for(var/group in fire_delay_group) - LAZYSET(user.fire_delay_next_fire, group, world.time + delay_left) /// This function disconnects the luminosity from the mob and back to the gun /obj/item/weapon/gun/proc/disconnect_light_from_mob(mob/bearer) @@ -687,72 +664,71 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w playsound(src, 'sound/handling/attachment_remove.ogg', 15, 1, 4) update_icon() -/obj/item/weapon/gun/proc/toggle_burst(mob/user) - //Burst of 1 doesn't mean anything. The weapon will only fire once regardless. - //Just a good safety to have all weapons that can equip a scope with 1 burst_amount. - if(burst_amount < 2 && !(flags_gun_features & GUN_HAS_FULL_AUTO)) - to_chat(user, SPAN_WARNING("This weapon does not have a burst fire mode!")) - return - +/obj/item/weapon/gun/proc/do_toggle_firemode(datum/source, datum/keybinding, new_firemode) + SIGNAL_HANDLER if(flags_gun_features & GUN_BURST_FIRING)//can't toggle mid burst return - if(flags_gun_features & GUN_BURST_ONLY) - if(!(flags_gun_features & GUN_BURST_ON)) - stack_trace("[src] has GUN_BURST_ONLY flag but not GUN_BURST_ON.") - flags_gun_features |= GUN_BURST_ON - return + if(!length(gun_firemode_list)) + CRASH("[src] called do_toggle_firemode() with an empty gun_firemode_list") - to_chat(user, SPAN_NOTICE("\The [src] can only be fired in bursts!")) + if(length(gun_firemode_list) == 1) + to_chat(source, SPAN_NOTICE("[icon2html(src, source)] This gun only has one firemode.")) return - if(flags_gun_features & GUN_FULL_AUTO_ONLY) - if(!(flags_gun_features & GUN_FULL_AUTO_ON)) - stack_trace("[src] has GUN_FULL_AUTO_ONLY flag but not GUN_FULL_AUTO_ON.") - flags_gun_features |= GUN_FULL_AUTO_ON - RegisterSignal(user.client, COMSIG_CLIENT_LMB_DOWN, PROC_REF(full_auto_start)) - RegisterSignal(user.client, COMSIG_CLIENT_LMB_UP, PROC_REF(full_auto_stop)) - RegisterSignal(user.client, COMSIG_CLIENT_LMB_DRAG, PROC_REF(full_auto_new_target)) - return + if(new_firemode) + if(!(new_firemode in gun_firemode_list)) + CRASH("[src] called do_toggle_firemode() with [new_firemode] new_firemode, not on gun_firemode_list") + gun_firemode = new_firemode + else + var/mode_index = gun_firemode_list.Find(gun_firemode) + if(++mode_index <= length(gun_firemode_list)) + gun_firemode = gun_firemode_list[mode_index] + else + gun_firemode = gun_firemode_list[1] - to_chat(user, SPAN_NOTICE("\The [src] can only be fired in full auto mode!")) - return + playsound(source, 'sound/weapons/handling/gun_burst_toggle.ogg', 15, 1) - playsound(user, 'sound/weapons/handling/gun_burst_toggle.ogg', 15, 1) + if(ishuman(source)) + to_chat(source, SPAN_NOTICE("[icon2html(src, source)] You switch to [gun_firemode].")) + SEND_SIGNAL(src, COMSIG_GUN_FIRE_MODE_TOGGLE, gun_firemode) - if(flags_gun_features & GUN_HAS_FULL_AUTO) - if((flags_gun_features & GUN_BURST_ON) || (burst_amount < 2 && !(flags_gun_features & GUN_FULL_AUTO_ON))) - flags_gun_features &= ~GUN_BURST_ON - flags_gun_features |= GUN_FULL_AUTO_ON +/obj/item/weapon/gun/proc/add_firemode(added_firemode, mob/user) + gun_firemode_list |= added_firemode - // Register the full auto click listeners - RegisterSignal(user.client, COMSIG_CLIENT_LMB_DOWN, PROC_REF(full_auto_start)) - RegisterSignal(user.client, COMSIG_CLIENT_LMB_UP, PROC_REF(full_auto_stop)) - RegisterSignal(user.client, COMSIG_CLIENT_LMB_DRAG, PROC_REF(full_auto_new_target)) + if(!length(gun_firemode_list)) + CRASH("add_firemode called with a resulting gun_firemode_list length of [length(gun_firemode_list)].") - to_chat(user, SPAN_NOTICE("[icon2html(src, user)] You set [src] to full auto mode.")) - return - else if(flags_gun_features & GUN_FULL_AUTO_ON) - flags_gun_features &= ~GUN_FULL_AUTO_ON - REMOVE_TRAIT(user, TRAIT_OVERRIDE_CLICKDRAG, TRAIT_SOURCE_WEAPON) - full_auto_stop() // If the LMBUP hasn't been called for any reason. - UnregisterSignal(user.client, list( - COMSIG_CLIENT_LMB_DOWN, - COMSIG_CLIENT_LMB_UP, - COMSIG_CLIENT_LMB_DRAG, - )) - - to_chat(user, SPAN_NOTICE("[icon2html(src, user)] You set [src] to single fire mode.")) - return +/obj/item/weapon/gun/proc/remove_firemode(removed_firemode, mob/user) + if(!length(gun_firemode_list) || (length(gun_firemode_list) == 1)) + CRASH("remove_firemode called with gun_firemode_list length [length(gun_firemode_list)].") + + gun_firemode_list -= removed_firemode + if(gun_firemode == removed_firemode) + gun_firemode = gun_firemode_list[1] + do_toggle_firemode(user, gun_firemode) - flags_gun_features ^= GUN_BURST_ON - to_chat(user, SPAN_NOTICE("[icon2html(src, user)] You [flags_gun_features & GUN_BURST_ON ? "enable" : "disable"] [src]'s burst fire mode.")) +/obj/item/weapon/gun/proc/setup_firemodes() + gun_firemode_list.len = 0 + if(start_semiauto) + gun_firemode_list |= GUN_FIREMODE_SEMIAUTO + + if(burst_amount > BURST_AMOUNT_TIER_1) + gun_firemode_list |= GUN_FIREMODE_BURSTFIRE + + if(start_automatic) + gun_firemode_list |= GUN_FIREMODE_AUTOMATIC + + if(!length(gun_firemode_list)) + CRASH("[src] called setup_firemodes() with an empty gun_firemode_list") + else + gun_firemode = gun_firemode_list[1] /obj/item/weapon/gun/verb/use_toggle_burst() set category = "Weapons" - set name = "Toggle Burst Fire Mode" - set desc = "Toggle on or off your weapon burst mode, if it has one. Greatly reduces accuracy." + set name = "Toggle Firemode" + set desc = "Cycles through your gun's firemodes. Automatic modes greatly reduce accuracy." set src = usr.contents var/obj/item/weapon/gun/active_firearm = get_active_firearm(usr) @@ -760,7 +736,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w return src = active_firearm - toggle_burst(usr) + do_toggle_firemode(usr) /obj/item/weapon/gun/verb/empty_mag() set category = "Weapons" @@ -966,3 +942,12 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w return TRUE return FALSE + +///Helper proc that processes a clicked target, if the target is not black tiles, it will not change it. If they are it will return the turf of the black tiles. It will return null if the object is a screen object other than black tiles. +/proc/get_turf_on_clickcatcher(atom/target, mob/user, params) + var/list/modifiers = params2list(params) + if(!istype(target, /atom/movable/screen)) + return target + if(!istype(target, /atom/movable/screen/click_catcher)) + return null + return params2turf(modifiers["screen-loc"], get_turf(user), user.client) diff --git a/code/modules/projectiles/guns/boltaction.dm b/code/modules/projectiles/guns/boltaction.dm index c34e9d44a626..a558d3dd7969 100644 --- a/code/modules/projectiles/guns/boltaction.dm +++ b/code/modules/projectiles/guns/boltaction.dm @@ -56,8 +56,8 @@ /obj/item/weapon/gun/boltaction/set_gun_config_values() ..() - burst_amount = 0 - fire_delay = FIRE_DELAY_TIER_4 + set_burst_amount(0) + set_fire_delay(FIRE_DELAY_TIER_4) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_6 diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 12f1976e186e..25efbd420ec6 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -90,6 +90,7 @@ to_firer = "[round((cell.charge / charge_cost), 1)] / [max_shots] SHOTS REMAINING" user.visible_message(SPAN_DANGER("[user] fires \the [src]!"), SPAN_DANGER("[to_firer]"), message_flags = CHAT_TYPE_WEAPON_USE) + return AUTOFIRE_CONTINUE /obj/item/weapon/gun/energy/reload_into_chamber() update_icon() @@ -132,7 +133,7 @@ /obj/item/weapon/gun/energy/rxfm5_eva/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_8 + set_fire_delay(FIRE_DELAY_TIER_8) accuracy_mult = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_3 scatter = SCATTER_AMOUNT_TIER_7 damage_mult = BASE_BULLET_DAMAGE_MULT @@ -183,9 +184,9 @@ /obj/item/weapon/gun/energy/laz_uzi/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_SMG - burst_delay = FIRE_DELAY_TIER_SMG - burst_amount = BURST_AMOUNT_TIER_2 + set_fire_delay(FIRE_DELAY_TIER_SMG) + set_burst_delay(FIRE_DELAY_TIER_SMG) + set_burst_amount(BURST_AMOUNT_TIER_2) accuracy_mult = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_3 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_5 @@ -217,7 +218,7 @@ /obj/item/weapon/gun/energy/taser/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_7 + set_fire_delay(FIRE_DELAY_TIER_7) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT damage_mult = BASE_BULLET_DAMAGE_MULT diff --git a/code/modules/projectiles/guns/flamer/flamer.dm b/code/modules/projectiles/guns/flamer/flamer.dm index c5a0c8ee2f8c..f327a92ffc9c 100644 --- a/code/modules/projectiles/guns/flamer/flamer.dm +++ b/code/modules/projectiles/guns/flamer/flamer.dm @@ -51,7 +51,7 @@ /obj/item/weapon/gun/flamer/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_4 * 5 + set_fire_delay(FIRE_DELAY_TIER_4 * 5) /obj/item/weapon/gun/flamer/unique_action(mob/user) toggle_gun_safety() @@ -92,7 +92,7 @@ . = ..() if(.) if(!current_mag || !current_mag.current_rounds) - return + return NONE /obj/item/weapon/gun/flamer/proc/get_fire_sound() var/list/fire_sounds = list( @@ -102,20 +102,20 @@ return pick(fire_sounds) /obj/item/weapon/gun/flamer/Fire(atom/target, mob/living/user, params, reflex) - set waitfor = 0 + set waitfor = FALSE if(!able_to_fire(user)) - return + return NONE var/turf/curloc = get_turf(user) //In case the target or we are expired. var/turf/targloc = get_turf(target) if (!targloc || !curloc) - return //Something has gone wrong... + return NONE //Something has gone wrong... if(active_attachable && active_attachable.flags_attach_features & ATTACH_WEAPON) //Attachment activated and is a weapon. if(active_attachable.flags_attach_features & ATTACH_PROJECTILE) return - if(active_attachable.current_rounds <= 0) + if((active_attachable.current_rounds <= 0) && !(active_attachable.flags_attach_features & ATTACH_IGNORE_EMPTY)) click_empty(user) //If it's empty, let them know. to_chat(user, SPAN_WARNING("[active_attachable] is empty!")) to_chat(user, SPAN_NOTICE("You disable [active_attachable].")) @@ -123,20 +123,22 @@ else active_attachable.fire_attachment(target, src, user) //Fire it. active_attachable.last_fired = world.time - return + return NONE if(flags_gun_features & GUN_TRIGGER_SAFETY) to_chat(user, SPAN_WARNING("\The [src] isn't lit!")) - return + return NONE if(!current_mag) - return + return NONE if(current_mag.current_rounds <= 0) click_empty(user) else user.track_shot(initial(name)) unleash_flame(target, user) + return AUTOFIRE_CONTINUE + return NONE /obj/item/weapon/gun/flamer/reload(mob/user, obj/item/ammo_magazine/magazine) if(!magazine || !istype(magazine)) @@ -321,7 +323,7 @@ unload(user, drop_override = TRUE) current_mag = fuelpack.active_fuel update_icon() - ..() + return ..() /obj/item/weapon/gun/flamer/M240T/reload(mob/user, obj/item/ammo_magazine/magazine) @@ -360,6 +362,16 @@ return TRUE return FALSE +/obj/item/weapon/gun/flamer/M240T/auto // With NEW advances in science, we've learned how to drain a pyro's tank in 6 seconds, or your money back! + name = "\improper M240-T2 incinerator unit" + desc = "A prototyped model of the M240-T incinerator unit, it was discontinued after its automatic mode was deemed too expensive to deploy in the field." + start_semiauto = FALSE + start_automatic = TRUE + +/obj/item/weapon/gun/flamer/M240T/auto/set_gun_config_values() + . = ..() + set_fire_delay(FIRE_DELAY_TIER_3) + GLOBAL_LIST_EMPTY(flamer_particles) /particles/flamer_fire icon = 'icons/effects/particles/fire.dmi' diff --git a/code/modules/projectiles/guns/lever_action.dm b/code/modules/projectiles/guns/lever_action.dm index 259c6170ae48..986f42716e64 100644 --- a/code/modules/projectiles/guns/lever_action.dm +++ b/code/modules/projectiles/guns/lever_action.dm @@ -45,7 +45,7 @@ their unique feature is that a direct hit will buff your damage and firerate /obj/item/weapon/gun/lever_action/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_1 + FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_1 + FIRE_DELAY_TIER_10) lever_delay = FIRE_DELAY_TIER_3 accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_5 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 @@ -118,12 +118,12 @@ their unique feature is that a direct hit will buff your damage and firerate last_fired = world.time - buff_fire_reduc //to shoot the next round faster lever_delay = FIRE_DELAY_TIER_10 damage_mult = initial(damage_mult) + BULLET_DAMAGE_MULT_TIER_10 - fire_delay = FIRE_DELAY_TIER_5 + set_fire_delay(FIRE_DELAY_TIER_5) for(var/slot in attachments) var/obj/item/attachable/AM = attachments[slot] if(AM.damage_mod || AM.delay_mod) damage_mult += AM.damage_mod - fire_delay += AM.delay_mod + modify_fire_delay(AM.delay_mod) wield_delay = 0 //for one-handed levering /obj/item/weapon/gun/lever_action/proc/reset_hit_buff(mob/user, one_hand_lever) @@ -137,7 +137,7 @@ their unique feature is that a direct hit will buff your damage and firerate cur_onehand_chance = initial(cur_onehand_chance) //these are init configs and so cannot be initial() lever_delay = FIRE_DELAY_TIER_3 - fire_delay = FIRE_DELAY_TIER_1 + set_fire_delay(FIRE_DELAY_TIER_1) damage_mult = BASE_BULLET_DAMAGE_MULT recalculate_attachment_bonuses() //stock wield delay if(one_hand_lever) @@ -392,7 +392,7 @@ their unique feature is that a direct hit will buff your damage and firerate /obj/item/weapon/gun/lever_action/xm88/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_1 + set_fire_delay(FIRE_DELAY_TIER_1) lever_delay = FIRE_DELAY_TIER_3 accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_5 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 @@ -478,7 +478,7 @@ their unique feature is that a direct hit will buff your damage and firerate lever_sound = lever_super_sound lever_message = "You quickly press the [lever_name]!" last_fired = world.time - buff_fire_reduc //to shoot the next round faster - fire_delay = FIRE_DELAY_TIER_3 + set_fire_delay(FIRE_DELAY_TIER_3) damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_4 if(floating_penetration < floating_penetration_upper_limit) @@ -488,12 +488,12 @@ their unique feature is that a direct hit will buff your damage and firerate var/obj/item/attachable/AM = attachments[slot] if(AM && (AM.damage_mod || AM.delay_mod)) damage_mult += AM.damage_mod - fire_delay += AM.delay_mod + modify_fire_delay(AM.delay_mod) wield_delay = 0 //for one-handed levering /obj/item/weapon/gun/lever_action/xm88/Fire(atom/target, mob/living/user, params, reflex, dual_wield) if(!able_to_fire(user) || !target) //checks here since we don't want to fuck up applying the increase - return + return NONE if(floating_penetration && in_chamber) //has to go before actual firing var/obj/item/projectile/P = in_chamber switch(floating_penetration) @@ -529,7 +529,7 @@ their unique feature is that a direct hit will buff your damage and firerate P.ammo = GLOB.ammo_list[/datum/ammo/bullet/lever_action/xm88] floating_penetration = FLOATING_PENETRATION_TIER_0 //these are init configs and so cannot be initial() - fire_delay = FIRE_DELAY_TIER_1 + FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_1 + FIRE_DELAY_TIER_10) lever_delay = FIRE_DELAY_TIER_3 damage_mult = BASE_BULLET_DAMAGE_MULT recalculate_attachment_bonuses() //stock wield delay diff --git a/code/modules/projectiles/guns/misc.dm b/code/modules/projectiles/guns/misc.dm index 4a84f99d7c62..2aa6b2dfc4d3 100644 --- a/code/modules/projectiles/guns/misc.dm +++ b/code/modules/projectiles/guns/misc.dm @@ -13,8 +13,10 @@ current_mag = /obj/item/ammo_magazine/minigun w_class = SIZE_HUGE force = 20 - flags_gun_features = GUN_AUTO_EJECTOR|GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_RECOIL_BUILDUP|GUN_HAS_FULL_AUTO|GUN_CAN_POINTBLANK + flags_gun_features = GUN_AUTO_EJECTOR|GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_RECOIL_BUILDUP|GUN_CAN_POINTBLANK gun_category = GUN_CATEGORY_HEAVY + start_semiauto = FALSE + start_automatic = TRUE /obj/item/weapon/gun/minigun/Initialize(mapload, spawn_empty) . = ..() @@ -22,7 +24,7 @@ /obj/item/weapon/gun/minigun/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 @@ -45,7 +47,7 @@ /obj/item/weapon/gun/minigun/upp name = "\improper GSh-7.62 rotary machine gun" desc = "A gas-operated rotary machine gun used by UPP heavies. Its enormous volume of fire and ammunition capacity allows the suppression of large concentrations of enemy forces. Heavy weapons training is required control its recoil." - flags_gun_features = GUN_AUTO_EJECTOR|GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_RECOIL_BUILDUP|GUN_HAS_FULL_AUTO|GUN_CAN_POINTBLANK + flags_gun_features = GUN_AUTO_EJECTOR|GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER|GUN_RECOIL_BUILDUP|GUN_CAN_POINTBLANK /obj/item/weapon/gun/minigun/upp/able_to_fire(mob/living/user) . = ..() @@ -72,7 +74,7 @@ current_mag = /obj/item/ammo_magazine/m60 w_class = SIZE_LARGE force = 25 - flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_HAS_FULL_AUTO|GUN_FULL_AUTO_ON|GUN_FULL_AUTO_ONLY|GUN_CAN_POINTBLANK + flags_gun_features = GUN_WIELDED_FIRING_ONLY|GUN_CAN_POINTBLANK gun_category = GUN_CATEGORY_HEAVY attachable_allowed = list( /obj/item/attachable/m60barrel, @@ -82,6 +84,8 @@ /obj/item/attachable/m60barrel, /obj/item/attachable/bipod/m60, ) + start_semiauto = FALSE + start_automatic = TRUE var/cover_open = FALSE //if the gun's feed-cover is open or not. @@ -96,9 +100,9 @@ /obj/item/weapon/gun/m60/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_10 - burst_amount = BURST_AMOUNT_TIER_5 - burst_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_10) + set_burst_amount(BURST_AMOUNT_TIER_5) + set_burst_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_10 diff --git a/code/modules/projectiles/guns/pistols.dm b/code/modules/projectiles/guns/pistols.dm index cc4207724b60..47b80f7b9218 100644 --- a/code/modules/projectiles/guns/pistols.dm +++ b/code/modules/projectiles/guns/pistols.dm @@ -72,7 +72,7 @@ /obj/item/weapon/gun/pistol/m4a3/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 @@ -93,7 +93,7 @@ /obj/item/weapon/gun/pistol/m4a3/custom/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 @@ -122,7 +122,7 @@ /obj/item/weapon/gun/pistol/m1911/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_8 + set_fire_delay(FIRE_DELAY_TIER_8) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 @@ -140,7 +140,7 @@ /obj/item/weapon/gun/pistol/m1911/socom/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_8 + set_fire_delay(FIRE_DELAY_TIER_8) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_2 scatter = SCATTER_AMOUNT_TIER_8 @@ -171,14 +171,14 @@ BFA.flags_attach_features &= ~ATTACH_REMOVABLE BFA.Attach(src) update_attachable(BFA.slot) - flags_gun_features |= GUN_BURST_ON + add_firemode(GUN_FIREMODE_BURSTFIRE) /obj/item/weapon/gun/pistol/b92fs/set_gun_attachment_offsets() attachable_offset = list("muzzle_x" = 28, "muzzle_y" = 20,"rail_x" = 10, "rail_y" = 22, "under_x" = 21, "under_y" = 17, "stock_x" = 21, "stock_y" = 17) /obj/item/weapon/gun/pistol/b92fs/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_5 accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_7 @@ -218,9 +218,9 @@ /obj/item/weapon/gun/pistol/heavy/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_4 - burst_amount = BURST_AMOUNT_TIER_2 - burst_delay = FIRE_DELAY_TIER_7 + set_fire_delay(FIRE_DELAY_TIER_4) + set_burst_amount(BURST_AMOUNT_TIER_2) + set_burst_delay(FIRE_DELAY_TIER_7) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_5 scatter = SCATTER_AMOUNT_TIER_6 @@ -242,7 +242,7 @@ /obj/item/weapon/gun/pistol/heavy/co/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_5 + set_fire_delay(FIRE_DELAY_TIER_5) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_6 @@ -285,7 +285,7 @@ /obj/item/weapon/gun/pistol/c99/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 scatter = SCATTER_AMOUNT_TIER_6 @@ -337,7 +337,7 @@ /obj/item/weapon/gun/pistol/kt42/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_1 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_2 scatter = SCATTER_AMOUNT_TIER_6 @@ -373,7 +373,7 @@ /obj/item/weapon/gun/pistol/holdout/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 @@ -410,7 +410,7 @@ /obj/item/weapon/gun/pistol/clfpistol/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 @@ -462,8 +462,8 @@ if(!manually_slided) click_empty() to_chat(user, SPAN_DANGER("\The [src] makes a clicking noise! You need to manually rack the slide after loading in a new magazine!")) - return - ..() + return NONE + return ..() /obj/item/weapon/gun/pistol/highpower/unique_action(mob/user) if(!manually_slided) @@ -488,7 +488,7 @@ /obj/item/weapon/gun/pistol/highpower/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_5 + set_fire_delay(FIRE_DELAY_TIER_5) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_3 scatter = SCATTER_AMOUNT_TIER_6 @@ -552,9 +552,9 @@ /obj/item/weapon/gun/pistol/mod88/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_7 @@ -651,9 +651,9 @@ /obj/item/weapon/gun/pistol/vp78/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_4 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_4) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 @@ -683,9 +683,9 @@ It is a modified Beretta 93R, and can fire three-round burst or single fire. Whe /obj/item/weapon/gun/pistol/auto9/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_7 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_7) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 @@ -715,9 +715,9 @@ It is a modified Beretta 93R, and can fire three-round burst or single fire. Whe /obj/item/weapon/gun/pistol/chimp/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_8 - burst_delay = FIRE_DELAY_TIER_9 - burst_amount = BURST_AMOUNT_TIER_2 + set_fire_delay(FIRE_DELAY_TIER_8) + set_burst_delay(FIRE_DELAY_TIER_9) + set_burst_amount(BURST_AMOUNT_TIER_2) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 @@ -747,9 +747,9 @@ It is a modified Beretta 93R, and can fire three-round burst or single fire. Whe /obj/item/weapon/gun/pistol/smart/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_10 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_10) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 @@ -776,7 +776,7 @@ It is a modified Beretta 93R, and can fire three-round burst or single fire. Whe fire_sound = 'sound/weapons/gun_skorpion.ogg' current_mag = /obj/item/ammo_magazine/pistol/skorpion - flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_ONE_HAND_WIELDED|GUN_HAS_FULL_AUTO|GUN_FULL_AUTO_ON|GUN_FULL_AUTO_ONLY + flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_ONE_HAND_WIELDED attachable_allowed = list( /obj/item/attachable/reddot, //Rail /obj/item/attachable/reflex, @@ -787,14 +787,16 @@ It is a modified Beretta 93R, and can fire three-round burst or single fire. Whe /obj/item/attachable/heavy_barrel, /obj/item/attachable/lasersight, //Underbarrel /obj/item/attachable/burstfire_assembly, - ) + ) + start_semiauto = FALSE + start_automatic = TRUE /obj/item/weapon/gun/pistol/skorpion/set_gun_attachment_offsets() attachable_offset = list("muzzle_x" = 29, "muzzle_y" = 18,"rail_x" = 16, "rail_y" = 21, "under_x" = 23, "under_y" = 15, "stock_x" = 23, "stock_y" = 15) /obj/item/weapon/gun/pistol/skorpion/set_gun_config_values() ..() - fa_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) fa_scatter_peak = 15 //shots fa_max_scatter = SCATTER_AMOUNT_TIER_4 diff --git a/code/modules/projectiles/guns/revolvers.dm b/code/modules/projectiles/guns/revolvers.dm index 3553ae880d7d..022a8cabd349 100644 --- a/code/modules/projectiles/guns/revolvers.dm +++ b/code/modules/projectiles/guns/revolvers.dm @@ -33,7 +33,7 @@ /obj/item/weapon/gun/revolver/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_5 + set_fire_delay(FIRE_DELAY_TIER_5) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_3 scatter = SCATTER_AMOUNT_TIER_8 @@ -318,7 +318,7 @@ /obj/item/weapon/gun/revolver/m44/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_7 + set_fire_delay(FIRE_DELAY_TIER_7) accuracy_mult = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_8 damage_mult = BASE_BULLET_DAMAGE_MULT @@ -375,7 +375,7 @@ ..() accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_2 - fire_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) /obj/item/weapon/gun/revolver/m44/custom/pkd_special/k2049 name = "\improper M2049 Blaster" @@ -414,9 +414,9 @@ ..() accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_2 - fire_delay = FIRE_DELAY_TIER_9 - burst_amount = BURST_AMOUNT_TIER_2 - burst_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_9) + set_burst_amount(BURST_AMOUNT_TIER_2) + set_burst_delay(FIRE_DELAY_TIER_10) /obj/item/weapon/gun/revolver/m44/custom/webley //Van Bandolier's Webley. @@ -469,7 +469,7 @@ /obj/item/weapon/gun/revolver/nagant/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_8 + set_fire_delay(FIRE_DELAY_TIER_8) accuracy_mult = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_1 @@ -504,7 +504,7 @@ /obj/item/weapon/gun/revolver/small/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6 + set_fire_delay(FIRE_DELAY_TIER_6) accuracy_mult = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_5 @@ -596,9 +596,9 @@ /obj/item/weapon/gun/revolver/mateba/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_2 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_7 + set_fire_delay(FIRE_DELAY_TIER_2) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_7) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_2 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_5 scatter = SCATTER_AMOUNT_TIER_7 @@ -699,14 +699,14 @@ /obj/item/weapon/gun/revolver/cmb/Fire(atom/target, mob/living/user, params, reflex = 0, dual_wield) playsound('sound/weapons/gun_cmb_bass.ogg') // badass shooting bass - . = ..() + return ..() /obj/item/weapon/gun/revolver/cmb/set_gun_attachment_offsets() attachable_offset = list("muzzle_x" = 29, "muzzle_y" = 22,"rail_x" = 11, "rail_y" = 25, "under_x" = 20, "under_y" = 18, "stock_x" = 20, "stock_y" = 18) /obj/item/weapon/gun/revolver/cmb/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6 + set_fire_delay(FIRE_DELAY_TIER_6) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_4 scatter = SCATTER_AMOUNT_TIER_7 diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm index ab2602204f72..09a0e2b683cf 100644 --- a/code/modules/projectiles/guns/rifles.dm +++ b/code/modules/projectiles/guns/rifles.dm @@ -18,9 +18,9 @@ /obj/item/weapon/gun/rifle/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_5 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_5) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_6 @@ -82,12 +82,13 @@ /obj/item/weapon/gun/rifle/m41a/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_9) 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 @@ -137,7 +138,7 @@ /obj/item/attachable/scope/mini/nsg23, ) - flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_BURST_ON|GUN_BURST_ONLY|GUN_WY_RESTRICTED + flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_WY_RESTRICTED random_spawn_muzzle = list( /obj/item/attachable/suppressor, @@ -148,6 +149,7 @@ /obj/item/attachable/scope/mini/nsg23, /obj/item/attachable/attached_gun/flamer/advanced, ) + start_semiauto = FALSE /obj/item/weapon/gun/rifle/nsg23/Initialize(mapload, spawn_empty) . = ..() @@ -158,9 +160,9 @@ /obj/item/weapon/gun/rifle/nsg23/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_7 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_8 + set_fire_delay(FIRE_DELAY_TIER_7) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_8) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_10 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_9 @@ -182,7 +184,7 @@ starting_attachment_types = list() //starts with the stock anyways due to handle_starting_attachment() /obj/item/weapon/gun/rifle/nsg23/no_lock - flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_BURST_ON|GUN_BURST_ONLY + flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER starting_attachment_types = list( /obj/item/attachable/scope/mini/nsg23, /obj/item/attachable/attached_gun/flamer,//non-op flamer for normal spawns @@ -230,9 +232,9 @@ /obj/item/weapon/gun/rifle/m41a/elite/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 - burst_amount = BURST_AMOUNT_TIER_2 - burst_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_9) + set_burst_amount(BURST_AMOUNT_TIER_2) + set_burst_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_10 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_4 scatter = SCATTER_AMOUNT_TIER_10 @@ -291,7 +293,7 @@ indestructible = TRUE current_mag = /obj/item/ammo_magazine/rifle/xm40/heap - flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER|GUN_BURST_ON + flags_gun_features = GUN_AUTO_EJECTOR|GUN_CAN_POINTBLANK|GUN_AMMO_COUNTER aim_slowdown = SLOWDOWN_ADS_QUICK wield_delay = WIELD_DELAY_FAST map_specific_decoration = FALSE @@ -344,9 +346,9 @@ /obj/item/weapon/gun/rifle/m41a/elite/xm40/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_9) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_10 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_4 scatter = SCATTER_AMOUNT_TIER_10 @@ -388,9 +390,9 @@ /obj/item/weapon/gun/rifle/m41aMK1/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 - burst_amount = BURST_AMOUNT_TIER_4 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) + set_burst_amount(BURST_AMOUNT_TIER_4) + set_burst_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_9 @@ -496,6 +498,7 @@ LAZYADD(traits_to_give, list( BULLET_TRAIT_ENTRY_ID("iff", /datum/element/bullet_trait_iff) )) + recalculate_attachment_bonuses() /obj/item/weapon/gun/rifle/m46c/Destroy() linked_human = null @@ -515,9 +518,9 @@ /obj/item/weapon/gun/rifle/m46c/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_8 - burst_amount = BURST_AMOUNT_TIER_4 - burst_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_8) + set_burst_amount(BURST_AMOUNT_TIER_4) + set_burst_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_8 scatter = SCATTER_AMOUNT_TIER_8 @@ -614,6 +617,7 @@ to_chat(usr, SPAN_WARNING("[icon2html(src, usr)] Action denied by [src]. Unauthorized user.")) return + gun_firemode = GUN_FIREMODE_SEMIAUTO iff_enabled = !iff_enabled to_chat(usr, SPAN_NOTICE("[icon2html(src, usr)] You [iff_enabled? "enable": "disable"] the IFF on [src].")) playsound(loc,'sound/machines/click.ogg', 25, 1) @@ -627,10 +631,11 @@ /obj/item/weapon/gun/rifle/m46c/recalculate_attachment_bonuses() . = ..() if(iff_enabled) - fire_delay += FIRE_DELAY_TIER_10 - burst_amount -= BURST_AMOUNT_TIER_6 + modify_fire_delay(FIRE_DELAY_TIER_10) + remove_firemode(GUN_FIREMODE_BURSTFIRE) - flags_gun_features &= ~GUN_BURST_ON //Gun loses some combat ability in return for IFF, as well as burst fire mode + else + add_firemode(GUN_FIREMODE_BURSTFIRE) /obj/item/weapon/gun/rifle/m46c/proc/name_after_co(mob/living/carbon/human/H) @@ -723,9 +728,9 @@ /obj/item/weapon/gun/rifle/mar40/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_7 - burst_amount = BURST_AMOUNT_TIER_4 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_7) + set_burst_amount(BURST_AMOUNT_TIER_4) + set_burst_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_6 @@ -796,7 +801,7 @@ /obj/item/weapon/gun/rifle/mar40/carbine/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_8 + set_fire_delay(FIRE_DELAY_TIER_8) accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_4 damage_mult = BASE_BULLET_DAMAGE_MULT - BULLET_DAMAGE_MULT_TIER_2 scatter_unwielded = SCATTER_AMOUNT_TIER_4 @@ -842,9 +847,9 @@ /obj/item/weapon/gun/rifle/mar40/lmg/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_8 - burst_amount = BURST_AMOUNT_TIER_5 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_8) + set_burst_amount(BURST_AMOUNT_TIER_5) + set_burst_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_6 @@ -935,9 +940,9 @@ /obj/item/weapon/gun/rifle/m16/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_7 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_10 @@ -1046,9 +1051,9 @@ /obj/item/weapon/gun/rifle/xm177/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_SMG - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_SMG + set_fire_delay(FIRE_DELAY_TIER_SMG) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_SMG) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_6 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_3 scatter = SCATTER_AMOUNT_TIER_8 @@ -1123,9 +1128,9 @@ /obj/item/weapon/gun/rifle/ar10/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_7 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_7 + set_fire_delay(FIRE_DELAY_TIER_7) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_7) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_8 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_9 @@ -1185,9 +1190,9 @@ /obj/item/weapon/gun/rifle/xm177/dutch/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_SMG - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_SMG + set_fire_delay(FIRE_DELAY_TIER_SMG) + set_burst_amount(BURST_AMOUNT_TIER_3) + set_burst_delay(FIRE_DELAY_TIER_SMG) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_6 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_3 scatter = SCATTER_AMOUNT_TIER_8 @@ -1236,10 +1241,9 @@ /obj/item/weapon/gun/rifle/lmg/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_LMG - burst_amount = BURST_AMOUNT_TIER_5 - burst_delay = FIRE_DELAY_TIER_LMG - fa_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_LMG) + set_burst_amount(BURST_AMOUNT_TIER_5) + set_burst_delay(FIRE_DELAY_TIER_LMG) fa_scatter_peak = FULL_AUTO_SCATTER_PEAK_TIER_3 fa_max_scatter = SCATTER_AMOUNT_TIER_4 accuracy_mult = BASE_ACCURACY_MULT @@ -1299,9 +1303,9 @@ /obj/item/weapon/gun/rifle/type71/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 - burst_amount = BURST_AMOUNT_TIER_4 - burst_delay = FIRE_DELAY_TIER_8 + set_fire_delay(FIRE_DELAY_TIER_9) + set_burst_amount(BURST_AMOUNT_TIER_4) + set_burst_delay(FIRE_DELAY_TIER_8) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_7 scatter = SCATTER_AMOUNT_TIER_6 @@ -1414,7 +1418,7 @@ /obj/item/weapon/gun/rifle/type71/carbine/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) damage_mult = BASE_BULLET_DAMAGE_MULT - BULLET_DAMAGE_MULT_TIER_2 scatter_unwielded = SCATTER_AMOUNT_TIER_5 recoil_unwielded = RECOIL_AMOUNT_TIER_4 @@ -1479,8 +1483,8 @@ ..() accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_7 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_4 - fire_delay = FIRE_DELAY_TIER_9 - burst_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_9) + set_burst_delay(FIRE_DELAY_TIER_10) scatter = SCATTER_AMOUNT_TIER_8 //------------------------------------------------------- @@ -1526,8 +1530,8 @@ /obj/item/weapon/gun/rifle/m4ra/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_8 - burst_amount = 0 + set_fire_delay(FIRE_DELAY_TIER_8) + set_burst_amount(0) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_5 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_4 damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_6 @@ -1590,8 +1594,8 @@ /obj/item/weapon/gun/rifle/l42a/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_8 - burst_amount = 0 + set_fire_delay(FIRE_DELAY_TIER_8) + set_burst_amount(0) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_5 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_4 damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_6 diff --git a/code/modules/projectiles/guns/shotguns.dm b/code/modules/projectiles/guns/shotguns.dm index d844498c2c02..8903be95db95 100644 --- a/code/modules/projectiles/guns/shotguns.dm +++ b/code/modules/projectiles/guns/shotguns.dm @@ -35,7 +35,7 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_5 + set_fire_delay(FIRE_DELAY_TIER_5) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_6 @@ -199,9 +199,9 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/merc/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6*2 - burst_amount = BURST_AMOUNT_TIER_2 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_6*2) + set_burst_amount(BURST_AMOUNT_TIER_2) + set_burst_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_6 @@ -222,8 +222,8 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/merc/damaged/set_gun_config_values() ..() - fire_delay = 1.5 SECONDS - burst_amount = BURST_AMOUNT_TIER_1 + set_fire_delay(1.5 SECONDS) + set_burst_amount(BURST_AMOUNT_TIER_1) accuracy_mult = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_6 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_5 @@ -279,7 +279,7 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/combat/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_5*2 + set_fire_delay(FIRE_DELAY_TIER_5*2) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_6 @@ -324,9 +324,9 @@ can cause issues with ammo types getting mixed up during the burst. current_mag = /obj/item/ammo_magazine/internal/shotgun/buckshot flags_equip_slot = SLOT_WAIST|SLOT_BACK - flags_gun_features = GUN_CAN_POINTBLANK|GUN_INTERNAL_MAG|GUN_HAS_FULL_AUTO|GUN_FULL_AUTO_ON - fa_delay = FIRE_DELAY_TIER_6 + flags_gun_features = GUN_CAN_POINTBLANK|GUN_INTERNAL_MAG auto_retrieval_slot = WEAR_J_STORE + start_automatic = TRUE /obj/item/weapon/gun/shotgun/combat/marsoc/Initialize(mapload, spawn_empty) . = ..() @@ -347,7 +347,7 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/combat/marsoc/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_5*2 + set_fire_delay(FIRE_DELAY_TIER_6) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 accuracy_mult_unwielded = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 - HIT_ACCURACY_MULT_TIER_5 scatter = SCATTER_AMOUNT_TIER_6 @@ -395,7 +395,7 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/type23/set_gun_config_values() ..() - fire_delay = 2.5 SECONDS + set_fire_delay(2.5 SECONDS) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_4 @@ -521,8 +521,8 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/double/set_gun_config_values() ..() - burst_amount = BURST_AMOUNT_TIER_2 - fire_delay = FIRE_DELAY_TIER_9 + set_burst_amount(BURST_AMOUNT_TIER_2) + set_fire_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_6 @@ -632,8 +632,8 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/double/damaged/set_gun_config_values() ..() - burst_amount = BURST_AMOUNT_TIER_1 - fire_delay = 0.9 SECONDS + set_burst_amount(BURST_AMOUNT_TIER_1) + set_fire_delay(0.9 SECONDS) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_7 @@ -655,7 +655,7 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/double/sawn/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 - HIT_ACCURACY_MULT_TIER_5 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_6 @@ -701,8 +701,8 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/double/cane/set_gun_config_values() ..() - burst_amount = BURST_AMOUNT_TIER_1 - fire_delay = FIRE_DELAY_TIER_7 + set_burst_amount(BURST_AMOUNT_TIER_1) + set_fire_delay(FIRE_DELAY_TIER_7) accuracy_mult_unwielded = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_10 scatter_unwielded = SCATTER_AMOUNT_TIER_7 damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_5 @@ -788,8 +788,8 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/double/mou53/set_gun_config_values() ..() - burst_amount = BURST_AMOUNT_TIER_1 - fire_delay = FIRE_DELAY_TIER_8 + set_burst_amount(BURST_AMOUNT_TIER_1) + set_fire_delay(FIRE_DELAY_TIER_8) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_10 @@ -879,8 +879,8 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/double/twobore/set_gun_config_values() ..() - burst_amount = BURST_AMOUNT_TIER_1 - fire_delay = 2 SECONDS //Less than the stun time, but you still have to brace to fire safely. + set_burst_amount(BURST_AMOUNT_TIER_1) + set_fire_delay(2 SECONDS )//Less than the stun time, but you still have to brace to fire safely. accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_5 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_8 @@ -935,9 +935,9 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/double/twobore/Fire(atom/target, mob/living/carbon/human/user, params, reflex = 0, dual_wield) //Using this instead of apply_bullet_effects() as RPG does so I get more granular angles than just user direction. var/prefire_rounds = current_mag.current_rounds //How many rounds do we have before we fire? - ..() + . = ..() if(current_mag.current_rounds == prefire_rounds) //We didn't fire a shot. - return + return NONE var/target_angle = Get_Compass_Dir(user, target) //More precise than get_dir(). fired_shots++ twobore_recoil(user, target_angle) @@ -1111,8 +1111,8 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/pump/set_gun_config_values() ..() - burst_amount = BURST_AMOUNT_TIER_1 - fire_delay = FIRE_DELAY_TIER_7 * 5 + set_burst_amount(BURST_AMOUNT_TIER_1) + set_fire_delay(FIRE_DELAY_TIER_7 * 5) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_6 @@ -1220,7 +1220,7 @@ 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/toggle_burst() +/obj/item/weapon/gun/shotgun/pump/dual_tube/set_bursting() var/obj/item/weapon/gun/shotgun/pump/dual_tube/shotgun = get_active_firearm(usr) if(shotgun == src) swap_tube(usr) @@ -1257,7 +1257,7 @@ can cause issues with ammo types getting mixed up during the burst. /obj/item/weapon/gun/shotgun/pump/dual_tube/cmb/set_gun_config_values() ..() - fire_delay = 1.6 SECONDS + set_fire_delay(1.6 SECONDS) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_3 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = SCATTER_AMOUNT_TIER_6 diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index c73d9c0f6423..859f99b17908 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -59,10 +59,12 @@ /obj/item/attachable/flashlight, ) - flags_gun_features = GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY|GUN_HAS_FULL_AUTO|GUN_FULL_AUTO_ON|GUN_FULL_AUTO_ONLY + flags_gun_features = GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY gun_category = GUN_CATEGORY_HEAVY starting_attachment_types = list(/obj/item/attachable/smartbarrel) auto_retrieval_slot = WEAR_J_STORE + start_semiauto = FALSE + start_automatic = TRUE /obj/item/weapon/gun/smartgun/Initialize(mapload, ...) @@ -85,10 +87,7 @@ /obj/item/weapon/gun/smartgun/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_10 - burst_amount = BURST_AMOUNT_TIER_3 - burst_delay = FIRE_DELAY_TIER_9 - fa_delay = FIRE_DELAY_TIER_SG + set_fire_delay(FIRE_DELAY_TIER_SG) fa_scatter_peak = FULL_AUTO_SCATTER_PEAK_TIER_8 fa_max_scatter = SCATTER_AMOUNT_TIER_9 if(accuracy_improvement) @@ -101,7 +100,6 @@ else scatter = SCATTER_AMOUNT_TIER_6 recoil = RECOIL_AMOUNT_TIER_3 - burst_scatter_mult = SCATTER_AMOUNT_TIER_8 damage_mult = BASE_BULLET_DAMAGE_MULT /obj/item/weapon/gun/smartgun/set_bullet_traits() @@ -364,15 +362,13 @@ /obj/item/weapon/gun/smartgun/Fire(atom/target, mob/living/user, params, reflex = 0, dual_wield) if(!requires_battery) - ..() - return + return ..() if(battery) if(!requires_power) - ..() - return + return ..() if(drain_battery()) - ..() + return ..() /obj/item/weapon/gun/smartgun/proc/drain_battery(override_drain) @@ -672,7 +668,7 @@ ammo = /obj/item/ammo_magazine/smartgun/dirty ammo_primary = /datum/ammo/bullet/smartgun/dirty//Toggled ammo type ammo_secondary = /datum/ammo/bullet/smartgun/dirty/armor_piercing///Toggled ammo type - flags_gun_features = GUN_WY_RESTRICTED|GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY|GUN_HAS_FULL_AUTO|GUN_FULL_AUTO_ON|GUN_FULL_AUTO_ONLY + flags_gun_features = GUN_WY_RESTRICTED|GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY /obj/item/weapon/gun/smartgun/dirty/Initialize(mapload, ...) . = ..() @@ -690,12 +686,12 @@ /obj/item/weapon/gun/smartgun/dirty/elite/set_gun_config_values() ..() - burst_amount = BURST_AMOUNT_TIER_5 - burst_delay = FIRE_DELAY_TIER_10 + set_burst_amount(BURST_AMOUNT_TIER_5) + set_burst_delay(FIRE_DELAY_TIER_10) if(!recoil_compensation) scatter = SCATTER_AMOUNT_TIER_8 burst_scatter_mult = SCATTER_AMOUNT_TIER_10 - fa_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_10) fa_scatter_peak = FULL_AUTO_SCATTER_PEAK_TIER_10 fa_max_scatter = SCATTER_AMOUNT_NONE diff --git a/code/modules/projectiles/guns/smgs.dm b/code/modules/projectiles/guns/smgs.dm index 0c3e7f42fe72..699f05ed318c 100644 --- a/code/modules/projectiles/guns/smgs.dm +++ b/code/modules/projectiles/guns/smgs.dm @@ -75,9 +75,9 @@ /obj/item/weapon/gun/smg/m39/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_SMG - burst_delay = FIRE_DELAY_TIER_SMG - burst_amount = BURST_AMOUNT_TIER_3 + set_fire_delay(FIRE_DELAY_TIER_SMG) + set_burst_delay(FIRE_DELAY_TIER_SMG) + set_burst_amount(BURST_AMOUNT_TIER_3) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_5 scatter = SCATTER_AMOUNT_TIER_4 @@ -124,7 +124,7 @@ /obj/item/weapon/gun/smg/m39/elite/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_SMG + set_fire_delay(FIRE_DELAY_TIER_SMG) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_7 accuracy_mult_unwielded = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_9 @@ -176,9 +176,9 @@ /obj/item/weapon/gun/smg/mp5/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 - burst_delay = FIRE_DELAY_TIER_SMG - burst_amount = BURST_AMOUNT_TIER_3 + set_fire_delay(FIRE_DELAY_TIER_9) + set_burst_delay(FIRE_DELAY_TIER_SMG) + set_burst_amount(BURST_AMOUNT_TIER_3) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_4 @@ -227,9 +227,9 @@ /obj/item/weapon/gun/smg/mp27/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_SMG - burst_delay = FIRE_DELAY_TIER_SMG - burst_amount = BURST_AMOUNT_TIER_2 + set_fire_delay(FIRE_DELAY_TIER_SMG) + set_burst_delay(FIRE_DELAY_TIER_SMG) + set_burst_amount(BURST_AMOUNT_TIER_2) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_2 scatter = SCATTER_AMOUNT_TIER_4 + (SCATTER_AMOUNT_TIER_10 * 0.5) @@ -260,9 +260,9 @@ /obj/item/weapon/gun/smg/ppsh/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_SMG - burst_delay = FIRE_DELAY_TIER_SMG - burst_amount = BURST_AMOUNT_TIER_3 + set_fire_delay(FIRE_DELAY_TIER_SMG) + set_burst_delay(FIRE_DELAY_TIER_SMG) + set_burst_amount(BURST_AMOUNT_TIER_3) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_5 scatter = SCATTER_AMOUNT_TIER_4 @@ -283,15 +283,15 @@ playsound(src, 'sound/weapons/handling/gun_jam_click.ogg', 35, TRUE) to_chat(user, SPAN_WARNING("Your gun is jammed! Mash Unique-Action to unjam it!")) balloon_alert(user, "*jammed*") - return + return NONE else if(prob(ppsh_mag?.jam_chance)) jammed = TRUE playsound(src, 'sound/weapons/handling/gun_jam_initial_click.ogg', 50, FALSE) user.visible_message(SPAN_DANGER("[src] makes a noticeable clicking noise!"), SPAN_HIGHDANGER("\The [src] suddenly jams and refuses to fire! Mash Unique-Action to unjam it.")) balloon_alert(user, "*jammed*") - return + return NONE else - . = ..() + return ..() /obj/item/weapon/gun/smg/ppsh/unique_action(mob/user) if(jammed) @@ -361,6 +361,7 @@ ) 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) @@ -368,13 +369,9 @@ /obj/item/weapon/gun/smg/mac15/set_gun_config_values() ..() - /* commented out until better fullauto code - fa_delay = FIRE_DELAY_TIER_10 fa_scatter_peak = FULL_AUTO_SCATTER_PEAK_TIER_7 fa_max_scatter = SCATTER_AMOUNT_TIER_3 - */ - - fire_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_5 burst_scatter_mult = SCATTER_AMOUNT_TIER_8 @@ -413,6 +410,7 @@ ) 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() @@ -421,13 +419,9 @@ /obj/item/weapon/gun/smg/uzi/set_gun_config_values() ..() - /* commented out until better fullauto code - fa_delay = FIRE_DELAY_TIER_9 fa_scatter_peak = FULL_AUTO_SCATTER_PEAK_TIER_5 fa_max_scatter = SCATTER_AMOUNT_TIER_5 - */ - - fire_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_2 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_2 scatter = SCATTER_AMOUNT_TIER_6 @@ -444,15 +438,15 @@ playsound(src, 'sound/weapons/handling/gun_jam_click.ogg', 35, TRUE) to_chat(user, SPAN_WARNING("Your gun is jammed! Mash Unique-Action to unjam it!")) balloon_alert(user, "*jammed*") - return + return NONE else if(prob(uzi_mag.jam_chance)) jammed = TRUE playsound(src, 'sound/weapons/handling/gun_jam_initial_click.ogg', 35, TRUE) user.visible_message(SPAN_DANGER("[src] makes a noticeable clicking noise!"), SPAN_HIGHDANGER("\The [src] suddenly jams and refuses to fire! Mash Unique-Action to unjam it.")) balloon_alert(user, "*jammed*") - return + return NONE else - . = ..() + return ..() /obj/item/weapon/gun/smg/uzi/unique_action(mob/user) if(jammed) @@ -515,9 +509,9 @@ /obj/item/weapon/gun/smg/fp9000/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_SMG - burst_delay = FIRE_DELAY_TIER_SMG - burst_amount = BURST_AMOUNT_TIER_3 + set_fire_delay(FIRE_DELAY_TIER_SMG) + set_burst_delay(FIRE_DELAY_TIER_SMG) + set_burst_amount(BURST_AMOUNT_TIER_3) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_5 accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_5 scatter = SCATTER_AMOUNT_TIER_6 @@ -578,7 +572,7 @@ /obj/item/weapon/gun/smg/nailgun/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_5 accuracy_mult_unwielded = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_4 diff --git a/code/modules/projectiles/guns/souto.dm b/code/modules/projectiles/guns/souto.dm index fbc1a39124b8..8d7a1b2550a4 100644 --- a/code/modules/projectiles/guns/souto.dm +++ b/code/modules/projectiles/guns/souto.dm @@ -27,14 +27,14 @@ to_chat(user, "You must equip the specialized Backpack Souto Vending Machine to use the Souto Slinger Supremo!") click_empty(user) unlink_soutopack() - return + return NONE if(soutopack) if(!current_mag) current_mag = soutopack.internal_mag // Check we're actually firing the right fuel tank if(current_mag != soutopack.internal_mag) current_mag = soutopack.internal_mag - ..() + return ..() /obj/item/weapon/gun/souto/reload(mob/user, obj/item/ammo_magazine/magazine) to_chat(user, SPAN_WARNING("The [src] feed system cannot be reloaded manually.")) diff --git a/code/modules/projectiles/guns/specialist.dm b/code/modules/projectiles/guns/specialist.dm index be1bf5068a54..22fb290878e9 100644 --- a/code/modules/projectiles/guns/specialist.dm +++ b/code/modules/projectiles/guns/specialist.dm @@ -267,7 +267,7 @@ if(toggling_action) toggling_action.update_button_icon() -/obj/item/weapon/gun/rifle/sniper/toggle_burst(mob/user) +/obj/item/weapon/gun/rifle/sniper/set_bursting(mob/user) if(has_aimed_shot) toggle_laser(user) else @@ -321,8 +321,8 @@ /obj/item/weapon/gun/rifle/sniper/M42A/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6*3 - burst_amount = BURST_AMOUNT_TIER_1 + set_fire_delay(FIRE_DELAY_TIER_6*3) + set_burst_amount(BURST_AMOUNT_TIER_1) accuracy_mult = BASE_ACCURACY_MULT * 3 //you HAVE to be able to hit scatter = SCATTER_AMOUNT_TIER_8 damage_mult = BASE_BULLET_DAMAGE_MULT @@ -365,9 +365,9 @@ /obj/item/weapon/gun/rifle/sniper/XM42B/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6 * 6 //Big boy damage, but it takes a lot of time to fire a shot. + set_fire_delay(FIRE_DELAY_TIER_6 * 6 )//Big boy damage, but it takes a lot of time to fire a shot. //Kaga: Adjusted from 56 (Tier 4, 7*8) -> 30 (Tier 6, 5*6) ticks. 95 really wasn't big-boy damage anymore, although I updated it to 125 to remain consistent with the other 10x99mm caliber weapon (M42C). Now takes only twice as long as the M42A. - burst_amount = BURST_AMOUNT_TIER_1 + set_burst_amount(BURST_AMOUNT_TIER_1) accuracy_mult = BASE_ACCURACY_MULT + 2*HIT_ACCURACY_MULT_TIER_10 //Who coded this like this, and why? It just calculates out to 1+1=2. Leaving a note here to check back later. scatter = SCATTER_AMOUNT_TIER_10 damage_mult = BASE_BULLET_DAMAGE_MULT @@ -430,8 +430,8 @@ /obj/item/weapon/gun/rifle/sniper/elite/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6*5 - burst_amount = BURST_AMOUNT_TIER_1 + set_fire_delay(FIRE_DELAY_TIER_6*5) + set_burst_amount(BURST_AMOUNT_TIER_1) accuracy_mult = BASE_ACCURACY_MULT * 3 //Was previously BAM + HAMT10, similar to the XM42B, and coming out to 1.5? Changed to be consistent with M42A. -Kaga scatter = SCATTER_AMOUNT_TIER_10 //Was previously 8, changed to be consistent with the XM42B. damage_mult = BASE_BULLET_DAMAGE_MULT @@ -507,9 +507,9 @@ /obj/item/weapon/gun/rifle/sniper/svd/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6 - burst_amount = BURST_AMOUNT_TIER_2 - burst_delay = FIRE_DELAY_TIER_9 + set_fire_delay(FIRE_DELAY_TIER_6) + set_burst_amount(BURST_AMOUNT_TIER_2) + set_burst_delay(FIRE_DELAY_TIER_9) accuracy_mult = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_8 burst_scatter_mult = SCATTER_AMOUNT_TIER_6 @@ -584,9 +584,9 @@ /obj/item/weapon/gun/rifle/m4ra_custom/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6 - burst_amount = BURST_AMOUNT_TIER_2 - burst_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_6) + set_burst_amount(BURST_AMOUNT_TIER_2) + set_burst_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT + HIT_ACCURACY_MULT_TIER_2 scatter = SCATTER_AMOUNT_TIER_8 burst_scatter_mult = SCATTER_AMOUNT_TIER_8 @@ -922,7 +922,7 @@ /obj/item/weapon/gun/launcher/grenade/m92/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_4*4 + set_fire_delay(FIRE_DELAY_TIER_4*4) /obj/item/weapon/gun/launcher/grenade/m92/able_to_fire(mob/living/user) . = ..() @@ -949,7 +949,7 @@ /obj/item/weapon/gun/launcher/grenade/m81/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_4 * 1.5 + set_fire_delay(FIRE_DELAY_TIER_4 * 1.5) /obj/item/weapon/gun/launcher/grenade/m81/on_pocket_removal() ..() @@ -1058,7 +1058,7 @@ /obj/item/weapon/gun/launcher/rocket/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_6*2 + set_fire_delay(FIRE_DELAY_TIER_6*2) accuracy_mult = BASE_ACCURACY_MULT scatter = SCATTER_AMOUNT_TIER_6 damage_mult = BASE_BULLET_DAMAGE_MULT @@ -1225,9 +1225,9 @@ /obj/item/weapon/gun/launcher/rocket/m57a4/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_5 - burst_delay = FIRE_DELAY_TIER_7 - burst_amount = BURST_AMOUNT_TIER_4 + set_fire_delay(FIRE_DELAY_TIER_5) + set_burst_delay(FIRE_DELAY_TIER_7) + set_burst_amount(BURST_AMOUNT_TIER_4) accuracy_mult = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_4 scatter = SCATTER_AMOUNT_TIER_6 damage_mult = BASE_BULLET_DAMAGE_MULT @@ -1372,7 +1372,7 @@ /obj/item/weapon/gun/flare/set_gun_config_values() ..() - fire_delay = FIRE_DELAY_TIER_10 + set_fire_delay(FIRE_DELAY_TIER_10) accuracy_mult = BASE_ACCURACY_MULT accuracy_mult_unwielded = BASE_ACCURACY_MULT - HIT_ACCURACY_MULT_TIER_10 scatter = 0 diff --git a/colonialmarines.dme b/colonialmarines.dme index 4a5798995693..44d7ab6db1d6 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -33,6 +33,7 @@ #include "code\__DEFINES\admin.dm" #include "code\__DEFINES\ARES.dm" #include "code\__DEFINES\atmospherics.dm" +#include "code\__DEFINES\autofire.dm" #include "code\__DEFINES\autolathe.dm" #include "code\__DEFINES\blood.dm" #include "code\__DEFINES\bsql.config.dm" @@ -228,6 +229,7 @@ #include "code\controllers\subsystem\admin.dm" #include "code\controllers\subsystem\assets.dm" #include "code\controllers\subsystem\atoms.dm" +#include "code\controllers\subsystem\autofire.dm" #include "code\controllers\subsystem\cellauto.dm" #include "code\controllers\subsystem\chat.dm" #include "code\controllers\subsystem\communications.dm" @@ -372,6 +374,8 @@ #include "code\datums\components\toxin_buildup.dm" #include "code\datums\components\weed_damage_reduction.dm" #include "code\datums\components\weed_food.dm" +#include "code\datums\components\autofire\_automated_fire.dm" +#include "code\datums\components\autofire\autofire.dm" #include "code\datums\components\xeno\shield_slash.dm" #include "code\datums\construction\construction_template.dm" #include "code\datums\construction\xenomorph\construction_template_xenomorph.dm" @@ -2065,7 +2069,6 @@ #include "code\modules\power\turbine.dm" #include "code\modules\projectiles\ammo_datums.dm" #include "code\modules\projectiles\ammunition.dm" -#include "code\modules\projectiles\full_auto.dm" #include "code\modules\projectiles\gun.dm" #include "code\modules\projectiles\gun_attachables.dm" #include "code\modules\projectiles\gun_helpers.dm"