diff --git a/code/datums/action.dm b/code/datums/action.dm
index 304aa47baa..bfc51b0411 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -228,6 +228,11 @@
button_icon_state = "fireselect_no"
name = "Toggle Firemode"
+/datum/action/item_action/toggle_safety
+ name = "Toggle Safety"
+ icon_icon = 'icons/hud/actions.dmi'
+ button_icon_state = "safety_on"
+
/datum/action/item_action/rcl_col
name = "Change Cable Color"
icon_icon = 'icons/mob/actions/actions_items.dmi'
diff --git a/code/datums/components/fullauto.dm b/code/datums/components/fullauto.dm
index 1882d0b511..4b9c25db91 100644
--- a/code/datums/components/fullauto.dm
+++ b/code/datums/components/fullauto.dm
@@ -1,4 +1,3 @@
-
#define AUTOFIRE_MOUSEUP 0
#define AUTOFIRE_MOUSEDOWN 1
@@ -20,60 +19,69 @@
return COMPONENT_INCOMPATIBLE
var/obj/item/gun = parent
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/wake_up)
+ RegisterSignal(parent, COMSIG_GUN_AUTOFIRE_SELECTED, .proc/wake_up)
+ RegisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_ITEM_DROPPED, COMSIG_GUN_AUTOFIRE_DESELECTED), .proc/autofire_off)
if(_autofire_shot_delay)
autofire_shot_delay = _autofire_shot_delay
- if(autofire_stat == AUTOFIRE_STAT_IDLE && ismob(gun.loc))
+ if(ismob(gun.loc))
var/mob/user = gun.loc
wake_up(src, user)
/datum/component/automatic_fire/Destroy()
+ UnregisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_ITEM_DROPPED, COMSIG_GUN_AUTOFIRE_DESELECTED))
autofire_off()
return ..()
/datum/component/automatic_fire/process(delta_time)
- if(autofire_stat != AUTOFIRE_STAT_FIRING)
+ if(!(autofire_stat & AUTOFIRE_STAT_FIRING))
STOP_PROCESSING(SSprojectiles, src)
return
+
+ if(!COOLDOWN_FINISHED(src, next_shot_cd))
+ return
+
process_shot()
/datum/component/automatic_fire/proc/wake_up(datum/source, mob/user, slot)
SIGNAL_HANDLER
- if(autofire_stat == AUTOFIRE_STAT_ALERT)
+ if(autofire_stat & (AUTOFIRE_STAT_ALERT))
return //We've updated the firemode. No need for more.
- if(autofire_stat == AUTOFIRE_STAT_FIRING)
+ if(autofire_stat & AUTOFIRE_STAT_FIRING)
stop_autofiring() //Let's stop shooting to avoid issues.
return
+
+ var/obj/item/gun/G = parent
+
if(iscarbon(user))
- var/mob/living/carbon/arizona_ranger = user
- if(arizona_ranger.is_holding(parent))
- autofire_on(arizona_ranger.client)
+ var/mob/living/carbon/shooter = user
+ if(shooter.is_holding(parent) && G.fire_select == SELECT_FULLY_AUTOMATIC)
+ autofire_on(shooter.client)
+ else
+ autofire_off()
// There is a gun and there is a user wielding it. The component now waits for the mouse click.
/datum/component/automatic_fire/proc/autofire_on(client/usercli)
SIGNAL_HANDLER
-
- if(autofire_stat != AUTOFIRE_STAT_IDLE)
+ if(autofire_stat & (AUTOFIRE_STAT_ALERT|AUTOFIRE_STAT_FIRING))
return
autofire_stat = AUTOFIRE_STAT_ALERT
- if(!QDELETED(usercli))
- clicker = usercli
- shooter = clicker.mob
- RegisterSignal(clicker, COMSIG_CLIENT_MOUSEDOWN, .proc/on_mouse_down)
+ clicker = usercli
+ shooter = clicker.mob
+ RegisterSignal(clicker, COMSIG_CLIENT_MOUSEDOWN, .proc/on_mouse_down)
+ RegisterSignal(shooter, COMSIG_MOB_CLIENT_LOGOUT, .proc/autofire_off)
if(!QDELETED(shooter))
- RegisterSignal(shooter, COMSIG_MOB_CLIENT_LOGOUT, .proc/autofire_off)
UnregisterSignal(shooter, COMSIG_MOB_CLIENT_LOGIN)
- RegisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_ITEM_DROPPED), .proc/autofire_off)
parent.RegisterSignal(src, COMSIG_AUTOFIRE_ONMOUSEDOWN, /obj/item/gun/.proc/autofire_bypass_check)
parent.RegisterSignal(parent, COMSIG_AUTOFIRE_SHOT, /obj/item/gun/.proc/do_autofire)
/datum/component/automatic_fire/proc/autofire_off(datum/source)
SIGNAL_HANDLER
- if(autofire_stat == AUTOFIRE_STAT_IDLE)
+ if(autofire_stat & (AUTOFIRE_STAT_IDLE))
return
- if(autofire_stat == AUTOFIRE_STAT_FIRING)
+ if(autofire_stat & AUTOFIRE_STAT_FIRING)
stop_autofiring()
autofire_stat = AUTOFIRE_STAT_IDLE
@@ -82,10 +90,9 @@
UnregisterSignal(clicker, list(COMSIG_CLIENT_MOUSEDOWN, COMSIG_CLIENT_MOUSEUP, COMSIG_CLIENT_MOUSEDRAG))
mouse_status = AUTOFIRE_MOUSEUP //In regards to the component there's no click anymore to care about.
clicker = null
+ RegisterSignal(shooter, COMSIG_MOB_CLIENT_LOGIN, .proc/on_client_login)
if(!QDELETED(shooter))
- RegisterSignal(shooter, COMSIG_MOB_CLIENT_LOGIN, .proc/on_client_login)
UnregisterSignal(shooter, COMSIG_MOB_CLIENT_LOGOUT)
- UnregisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_ITEM_DROPPED))
shooter = null
parent.UnregisterSignal(parent, COMSIG_AUTOFIRE_SHOT)
parent.UnregisterSignal(src, COMSIG_AUTOFIRE_ONMOUSEDOWN)
@@ -129,9 +136,9 @@
source.click_intercept_time = world.time //From this point onwards Click() will no longer be triggered.
- if(autofire_stat == (AUTOFIRE_STAT_IDLE))
+ if(autofire_stat & (AUTOFIRE_STAT_IDLE))
CRASH("on_mouse_down() called with [autofire_stat] autofire_stat")
- if(autofire_stat == AUTOFIRE_STAT_FIRING)
+ if(autofire_stat & AUTOFIRE_STAT_FIRING)
stop_autofiring() //This can happen if we click and hold and then alt+tab, printscreen or other such action. MouseUp won't be called then and it will keep autofiring.
target = _target
@@ -143,7 +150,7 @@
//Dakka-dakka
/datum/component/automatic_fire/proc/start_autofiring()
if(autofire_stat == AUTOFIRE_STAT_FIRING)
- return
+ return //Already pew-pewing.
autofire_stat = AUTOFIRE_STAT_FIRING
clicker.mouse_override_icon = 'icons/effects/mouse_pointers/weapon_pointer.dmi'
@@ -181,8 +188,9 @@
/datum/component/automatic_fire/proc/stop_autofiring(datum/source, atom/object, turf/location, control, params)
SIGNAL_HANDLER
- if(autofire_stat != AUTOFIRE_STAT_FIRING)
- return
+ switch(autofire_stat)
+ if(AUTOFIRE_STAT_IDLE, AUTOFIRE_STAT_ALERT)
+ return
STOP_PROCESSING(SSprojectiles, src)
autofire_stat = AUTOFIRE_STAT_ALERT
if(clicker)
@@ -218,9 +226,7 @@
/datum/component/automatic_fire/proc/process_shot()
if(autofire_stat != AUTOFIRE_STAT_FIRING)
- return FALSE
- if(!COOLDOWN_FINISHED(src, next_shot_cd))
- return TRUE
+ return
if(QDELETED(target) || get_turf(target) != target_loc) //Target moved or got destroyed since we last aimed.
target = target_loc //So we keep firing on the emptied tile until we move our mouse and find a new target.
if(get_dist(shooter, target) <= 0)
@@ -239,10 +245,7 @@
// Gun procs.
/obj/item/gun/proc/on_autofire_start(mob/living/shooter)
- if(semicd || shooter.stat || !can_trigger_gun(shooter))
- return FALSE
- if(!can_shoot())
- shoot_with_empty_chamber(shooter)
+ if(!can_shoot(shooter) || !can_trigger_gun(shooter) || semicd)
return FALSE
var/obj/item/bodypart/other_hand = shooter.has_hand_for_held_index(shooter.get_inactive_hand_index())
if(weapon_weight == WEAPON_HEAVY && (shooter.get_inactive_held_item() || !other_hand))
@@ -258,17 +261,10 @@
/obj/item/gun/proc/do_autofire(datum/source, atom/target, mob/living/shooter, params)
- SIGNAL_HANDLER
- if(semicd || shooter.stat)
- return NONE
+ SIGNAL_HANDLER_DOES_SLEEP
if(!can_shoot())
shoot_with_empty_chamber(shooter)
return NONE
- INVOKE_ASYNC(src, .proc/do_autofire_shot, source, target, shooter, params)
- return COMPONENT_AUTOFIRE_SHOT_SUCCESS //All is well, we can continue shooting.
-
-
-/obj/item/gun/proc/do_autofire_shot(datum/source, atom/target, mob/living/shooter, params)
var/obj/item/gun/akimbo_gun = shooter.get_inactive_held_item()
var/bonus_spread = 0
if(istype(akimbo_gun) && weapon_weight < WEAPON_MEDIUM)
@@ -276,6 +272,7 @@
bonus_spread = dual_wield_spread
addtimer(CALLBACK(akimbo_gun, /obj/item/gun.proc/process_fire, target, shooter, TRUE, params, null, bonus_spread), 1)
process_fire(target, shooter, TRUE, params, null, bonus_spread)
+ return COMPONENT_AUTOFIRE_SHOT_SUCCESS //All is well, we can continue shooting.
#undef AUTOFIRE_MOUSEUP
#undef AUTOFIRE_MOUSEDOWN
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index ff8c52489b..dd54088f1f 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -22,6 +22,7 @@
var/ranged_attack_speed = CLICK_CD_RANGE
var/melee_attack_speed = CLICK_CD_MELEE
+ var/gun_flags = NONE
var/fire_sound = "gunshot"
var/suppressed = null //whether or not a message is displayed when fired
var/can_suppress = FALSE
@@ -32,6 +33,7 @@
trigger_guard = TRIGGER_GUARD_NORMAL //trigger guard on the weapon, hulks can't fire them with their big meaty fingers
var/sawn_desc = null //description change if weapon is sawn-off
var/sawn_off = FALSE
+ var/firing_burst = 0 //Prevent the weapon from firing again while already firing
/// can we be put into a turret
var/can_turret = TRUE
@@ -89,10 +91,12 @@
var/zoom_out_amt = 0
var/datum/action/item_action/toggle_scope_zoom/azoom
- var/safety = FALSE /// Internal variable for keeping track whether the safety is on or off
- var/has_gun_safety = FALSE /// Whether the gun actually has a gun safety
+ //gun safeties
+ var/safety = TRUE /// Internal variable for keeping track whether the safety is on or off
+ var/has_gun_safety = TRUE/// Whether the gun actually has a gun safety
var/datum/action/item_action/toggle_safety/toggle_safety_action
+ //Firemodes
var/datum/action/item_action/toggle_firemode/firemode_action
/// Current fire selection, can choose between burst, single, and full auto.
var/fire_select = SELECT_SEMI_AUTOMATIC
@@ -107,24 +111,18 @@
/// Just 'slightly' snowflakey way to modify projectile damage for projectiles fired from this gun.
var/projectile_damage_multiplier = 1
-
/// directional recoil multiplier
var/dir_recoil_amp = 10
-/datum/action/item_action/toggle_safety
- name = "Toggle Safety"
- icon_icon = 'icons/hud/actions.dmi'
- button_icon_state = "safety_on"
-/obj/item/gun/ui_action_click(mob/user, actiontype)
- if(istype(actiontype, /datum/action/item_action/toggle_firemode))
+/obj/item/gun/ui_action_click(mob/user, action)
+ if(istype(action, /datum/action/item_action/toggle_firemode))
fire_select()
- else if(istype(actiontype, toggle_safety_action))
+ else if(istype(action, /datum/action/item_action/toggle_safety))
toggle_safety(user)
else
..()
-
-/obj/item/gun/Initialize()
+/obj/item/gun/Initialize(mapload)
. = ..()
if(pin)
pin = new pin(src)
@@ -134,7 +132,6 @@
if(zoomable)
azoom = new (src)
-
if(has_gun_safety)
safety = TRUE
toggle_safety_action = new(src)
@@ -152,6 +149,7 @@
firemode_action = new(src)
firemode_action.button_icon_state = "fireselect_[fire_select]"
firemode_action.UpdateButtonIcon()
+
/obj/item/gun/ComponentInitialize()
. = ..()
if(SELECT_FULLY_AUTOMATIC in fire_select_modes)
@@ -166,6 +164,8 @@
QDEL_NULL(bayonet)
if(chambered)
QDEL_NULL(chambered)
+ if(azoom)
+ QDEL_NULL(azoom)
if(toggle_safety_action)
QDEL_NULL(toggle_safety_action)
if(firemode_action)
@@ -194,6 +194,8 @@
. += "[bayonet] looks like it can be unscrewed from [src]."
else if(can_bayonet)
. += "It has a bayonet lug on it."
+ if(has_gun_safety)
+ . += "The safety is [safety ? "ON" : "OFF"]."
/obj/item/gun/proc/fire_select()
var/mob/living/carbon/human/user = usr
@@ -201,10 +203,10 @@
var/max_mode = fire_select_modes.len
if(max_mode <= 1)
- balloon_alert(user, "only one firemode!")
+ to_chat(user, "[src] is not capable of switching firemodes!")
return
- fire_select_index = 1 + fire_select_index % max_mode // Magic math to cycle through this shit!
+ fire_select_index = 1 + fire_select_index % max_mode //Magic math to cycle through this shit!
fire_select = fire_select_modes[fire_select_index]
@@ -213,43 +215,23 @@
burst_size = 1
fire_delay = 0
SEND_SIGNAL(src, COMSIG_GUN_AUTOFIRE_DESELECTED, user)
- balloon_alert(user, "semi-automatic")
+ to_chat(user, "You switch [src] to semi-automatic.")
if(SELECT_BURST_SHOT)
burst_size = initial(burst_size)
fire_delay = initial(fire_delay)
SEND_SIGNAL(src, COMSIG_GUN_AUTOFIRE_DESELECTED, user)
- balloon_alert(user, "[burst_size]-round burst")
+ to_chat(user, "You switch [src] to [burst_size]-round burst.")
if(SELECT_FULLY_AUTOMATIC)
burst_size = 1
SEND_SIGNAL(src, COMSIG_GUN_AUTOFIRE_SELECTED, user)
- balloon_alert(user, "automatic")
+ to_chat(user, "You switch [src] to automatic.")
playsound(user, 'sound/weapons/empty.ogg', 100, TRUE)
update_appearance()
firemode_action.button_icon_state = "fireselect_[fire_select]"
- firemode_action.UpdateButtons()
- //SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD) I'll need this later
+ firemode_action.UpdateButtonIcon()
return TRUE
-/obj/item/gun/proc/toggle_safety(mob/user, override)
- if(!has_gun_safety)
- return
- if(override)
- if(override == "off")
- safety = FALSE
- else
- safety = TRUE
- else
- safety = !safety
- toggle_safety_action.button_icon_state = "safety_[safety ? "on" : "off"]"
- toggle_safety_action.UpdateButtons()
- playsound(src, 'sound/weapons/empty.ogg', 100, TRUE)
- user.visible_message(
- span_notice("[user] toggles [src]'s safety [safety ? "ON" : "OFF"]."),
- span_notice("You toggle [src]'s safety [safety ? "ON" : "OFF"].")
- )
- //SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD) once again, needed later
-
/obj/item/gun/equipped(mob/living/user, slot)
. = ..()
if(zoomed && user.get_active_held_item() != src)
@@ -381,6 +363,22 @@
var/stam_cost = getstamcost(user)
process_fire(target, user, TRUE, params, null, bonus_spread, stam_cost)
+/obj/item/gun/proc/toggle_safety(mob/user, override)
+ if(!has_gun_safety)
+ return
+ if(override)
+ if(override == "off")
+ safety = FALSE
+ else
+ safety = TRUE
+ else
+ safety = !safety
+ toggle_safety_action.button_icon_state = "safety_[safety ? "on" : "off"]"
+ toggle_safety_action.UpdateButtonIcon()
+ playsound(src, 'sound/weapons/empty.ogg', 100, TRUE)
+ user.visible_message("[user] toggles [src]'s safety [safety ? "ON" : "OFF"].",
+ "You toggle [src]'s safety [safety ? "ON" : "OFF"].")
+
/obj/item/gun/can_trigger_gun(mob/living/user)
. = ..()
if(!.)
@@ -390,6 +388,9 @@
if(HAS_TRAIT(user, TRAIT_PACIFISM) && chambered?.harmful) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
to_chat(user, " [src] is lethally chambered! You don't want to risk harming anyone...")
return FALSE
+ if(has_gun_safety && safety)
+ to_chat(user, "The safety is on!")
+ return FALSE
/obj/item/gun/CheckAttackCooldown(mob/user, atom/target)
if((user.a_intent == INTENT_HARM) && user.Adjacent(target)) //melee
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index f43999d62b..4d08520246 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -5,7 +5,7 @@
var/automatic_burst_overlay = TRUE
can_suppress = TRUE
burst_size = 3
- burst_shot_delay = 2
+ fire_delay = 2
fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_BURST_SHOT, SELECT_FULLY_AUTOMATIC)
/obj/item/gun/ballistic/automatic/proto
@@ -17,10 +17,6 @@
pin = null
burst_size = 1
-/obj/item/gun/ballistic/automatic/proto/Initialize()
- . = ..()
- AddComponent(/datum/component/automatic_fire, 0.2 SECONDS)
-
/obj/item/gun/ballistic/automatic/proto/unrestricted
pin = /obj/item/firing_pin
@@ -60,34 +56,6 @@
else
to_chat(user, "You cannot seem to get \the [src] out of your hands!")
-/obj/item/gun/ballistic/automatic/ui_action_click(mob/user, action)
- if(istype(action, /datum/action/item_action/toggle_firemode))
- burst_select()
- else
- return ..()
-
-/obj/item/gun/ballistic/automatic/proc/burst_select()
- var/mob/living/carbon/human/user = usr
- select = !select
- if(!select)
- disable_burst()
- to_chat(user, "You switch to semi-automatic.")
- else
- enable_burst()
- to_chat(user, "You switch to [burst_size]-rnd burst.")
-
- playsound(user, 'sound/weapons/empty.ogg', 100, 1)
- update_icon()
- for(var/X in actions)
- var/datum/action/A = X
- A.UpdateButtonIcon()
-
-/obj/item/gun/ballistic/automatic/proc/enable_burst()
- burst_size = initial(burst_size)
-
-/obj/item/gun/ballistic/automatic/proc/disable_burst()
- burst_size = 1
-
/obj/item/gun/ballistic/automatic/can_shoot()
return get_ammo()
@@ -141,18 +109,10 @@
knife_y_offset = 12
automatic_burst_overlay = FALSE
-/obj/item/gun/ballistic/automatic/wt550/enable_burst()
- . = ..()
- spread = 15
-
/obj/item/gun/ballistic/automatic/wt550/afterattack()
. = ..()
empty_alarm()
-/obj/item/gun/ballistic/automatic/wt550/disable_burst()
- . = ..()
- spread = 0
-
/obj/item/gun/ballistic/automatic/wt550/update_icon_state()
icon_state = "wt550[magazine ? "-[CEILING(((get_ammo(FALSE) / magazine.max_ammo) * 20) /4, 1)*4]" : "-0"]" //Sprites only support up to 20.
@@ -216,6 +176,7 @@
/obj/item/gun/ballistic/automatic/m90/update_icon_state()
icon_state = "[initial(icon_state)][magazine ? "" : "-e"]"
+/*
/obj/item/gun/ballistic/automatic/m90/burst_select()
var/mob/living/carbon/human/user = usr
switch(select)
@@ -233,6 +194,7 @@
playsound(user, 'sound/weapons/empty.ogg', 100, 1)
update_icon()
return
+*/
/obj/item/gun/ballistic/automatic/tommygun
name = "\improper Thompson SMG"