mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-26 06:29:23 +01:00
Fully automatic weaponry implementation [semi, burst, automatic] (#4301)
* FULLY AUTOMATIC REIFLES RHEUASBVHDSA * a * a * SHITCODE BEGONE * a * EEEE * Update gun.dm * a * Update gun.dm * aaaa * Update gun.dm * Update gun.dm * a * Update gun.dm * a * a * aaa * Update gun.dm * Update gun.dm * Update gun.dm * Update code/modules/projectiles/gun.dm * Update code/modules/projectiles/gun.dm * aaa * tests * a * wew * aaaa * aaaaa * aa * aa * Update gun.dm * aaaa * Update gun.dm * aaaa * Update fullauto.dm * aaaaaaa * Update master.dm * Update master.dm * Update master.dm
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
#define SELECT_SEMI_AUTOMATIC 1
|
||||
#define SELECT_BURST_SHOT 2
|
||||
#define SELECT_FULLY_AUTOMATIC 3
|
||||
@@ -1,9 +1,15 @@
|
||||
// Movable signals
|
||||
//Movable signals
|
||||
///When someone talks into a radio
|
||||
#define COMSIG_MOVABLE_RADIO_TALK_INTO "movable_radio_talk_into" //from radio talk_into(): (obj/item/radio/radio, message, channel, list/spans, datum/language/language, direct)
|
||||
// Mob signals
|
||||
|
||||
// Living signals
|
||||
//Mob signals
|
||||
///Resting position for living mob updated
|
||||
#define COMSIG_LIVING_UPDATED_RESTING "living_updated_resting" //from base of (/mob/living/proc/update_resting): (resting)
|
||||
|
||||
//Horror form bombastic flag
|
||||
///Horror form bombastic flag
|
||||
#define COMSIG_HORRORFORM_EXPLODE "horrorform_explode"
|
||||
|
||||
//Gun signals
|
||||
///When a gun is switched to automatic fire mode
|
||||
#define COMSIG_GUN_AUTOFIRE_SELECTED "gun_autofire_selected"
|
||||
///When a gun is switched off of automatic fire mode
|
||||
#define COMSIG_GUN_AUTOFIRE_DESELECTED "gun_autofire_deselected"
|
||||
|
||||
@@ -201,6 +201,8 @@
|
||||
name = "Toggle Hood"
|
||||
|
||||
/datum/action/item_action/toggle_firemode
|
||||
icon_icon = 'modular_skyrat/master_files/icons/mob/actions/actions_items.dmi' //SKYRAT EDIT ADDITION
|
||||
button_icon_state = "fireselect_no" //SKYRAT EDIT ADDITION
|
||||
name = "Toggle Firemode"
|
||||
|
||||
/datum/action/item_action/rcl_col
|
||||
@@ -675,7 +677,7 @@
|
||||
desc = "Activates the jump boot's internal propulsion system, allowing the user to dash over 4-wide gaps."
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "jetboot"
|
||||
|
||||
|
||||
/datum/action/item_action/bhop/brocket
|
||||
name = "Activate Rocket Boots"
|
||||
desc = "Activates the boot's rocket propulsion system, allowing the user to hurl themselves great distances."
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR FULLAUTO.DM
|
||||
#define AUTOFIRE_MOUSEUP 0
|
||||
#define AUTOFIRE_MOUSEDOWN 1
|
||||
|
||||
@@ -275,3 +276,4 @@
|
||||
|
||||
#undef AUTOFIRE_MOUSEUP
|
||||
#undef AUTOFIRE_MOUSEDOWN
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR GUN.DM
|
||||
#define DUALWIELD_PENALTY_EXTRA_MULTIPLIER 1.4
|
||||
#define FIRING_PIN_REMOVAL_DELAY 50
|
||||
|
||||
@@ -718,3 +718,4 @@
|
||||
|
||||
#undef FIRING_PIN_REMOVAL_DELAY
|
||||
#undef DUALWIELD_PENALTY_EXTRA_MULTIPLIER
|
||||
*/
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR AUTOMATIC.DM
|
||||
/obj/item/gun/ballistic/automatic
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
can_suppress = TRUE
|
||||
@@ -63,7 +64,7 @@
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/c20r //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
|
||||
/obj/item/gun/ballistic/automatic/c20r
|
||||
name = "\improper C-20r SMG"
|
||||
desc = "A bullpup three-round burst .45 SMG, designated 'C-20r'. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp."
|
||||
icon_state = "c20r"
|
||||
@@ -136,7 +137,7 @@
|
||||
mag_display = TRUE
|
||||
rack_sound = 'sound/weapons/gun/pistol/slide_lock.ogg'
|
||||
|
||||
/obj/item/gun/ballistic/automatic/m90 //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE
|
||||
/obj/item/gun/ballistic/automatic/m90
|
||||
name = "\improper M-90gl Carbine"
|
||||
desc = "A three-round burst 5.56 toploading carbine, designated 'M-90gl'. Has an attached underbarrel grenade launcher which can be fired using right click."
|
||||
icon_state = "m90"
|
||||
@@ -275,7 +276,6 @@
|
||||
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/AltClick(mob/user)
|
||||
. = ..() //SKYRAT EDIT ADDITION - GUNSGALORE
|
||||
if(!user.canUseTopic(src))
|
||||
return
|
||||
cover_open = !cover_open
|
||||
@@ -359,8 +359,7 @@
|
||||
|
||||
/obj/item/gun/ballistic/automatic/surplus
|
||||
name = "Surplus Rifle"
|
||||
// desc = "One of countless obsolete ballistic rifles that still sees use as a cheap deterrent. Uses 10mm ammo and its bulky frame prevents one-hand firing." // SKYRAT EDIT: Original
|
||||
desc = "One of countless obsolete ballistic rifles that still sees use as a cheap deterrent. Uses 10mm Magnum ammo and its bulky frame prevents one-hand firing." // SKYRAT EDIT: Calibre rename
|
||||
desc = "One of countless obsolete ballistic rifles that still sees use as a cheap deterrent. Uses 10mm ammo and its bulky frame prevents one-hand firing."
|
||||
icon_state = "surplus"
|
||||
inhand_icon_state = "moistnugget"
|
||||
worn_icon_state = null
|
||||
@@ -391,3 +390,4 @@
|
||||
actions_types = list()
|
||||
fire_sound = 'sound/weapons/laser.ogg'
|
||||
casing_ejector = FALSE
|
||||
*/
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
mag_type = /obj/item/ammo_box/magazine/m75
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
actions_types = list()
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC) //SKYRAT EDIT CHANGE
|
||||
casing_ejector = FALSE
|
||||
|
||||
/obj/item/gun/ballistic/rocketlauncher
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
can_suppress = TRUE
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
actions_types = list()
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC) //SKYRAT EDIT CHANGE
|
||||
bolt_type = BOLT_TYPE_LOCKING
|
||||
fire_sound = 'sound/weapons/gun/pistol/shot.ogg'
|
||||
dry_fire_sound = 'sound/weapons/gun/pistol/dry_fire.ogg'
|
||||
@@ -81,7 +81,7 @@
|
||||
burst_size = 3
|
||||
fire_delay = 1
|
||||
spread = 10
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
//actions_types = list(/datum/action/item_action/toggle_firemode) SKYRAT EDIT REMOVAL
|
||||
suppressor_x_offset = 6
|
||||
|
||||
/obj/item/gun/ballistic/automatic/pistol/stickman
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
fire_delay = 0
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
fire_sound = 'sound/weapons/gun/shotgun/shot_alt.ogg'
|
||||
actions_types = list()
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC) //SKYRAT EDIT CHANGE
|
||||
mag_display = TRUE
|
||||
empty_indicator = TRUE
|
||||
empty_alarm = TRUE
|
||||
|
||||
@@ -109,6 +109,8 @@
|
||||
item_flags = NEEDS_PERMIT | SLOWS_WHILE_IN_HAND
|
||||
can_charge = FALSE
|
||||
var/obj/item/minigunpack/ammo_pack
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)//SKYRAT EDIT ADDITION
|
||||
|
||||
|
||||
/obj/item/gun/energy/minigun/Initialize()
|
||||
if(istype(loc, /obj/item/minigunpack)) //We should spawn inside an ammo pack so let's use that one.
|
||||
@@ -121,7 +123,7 @@
|
||||
/obj/item/gun/energy/minigun/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/update_icon_blocker)
|
||||
AddComponent(/datum/component/automatic_fire, 0.2 SECONDS)
|
||||
//AddComponent(/datum/component/automatic_fire, 0.2 SECONDS) SKYRAT EDIT REMOVAL
|
||||
|
||||
/obj/item/gun/energy/minigun/attack_self(mob/living/user)
|
||||
return
|
||||
|
||||
@@ -380,4 +380,4 @@
|
||||
|
||||
/obj/item/gun/energy/tesla_cannon/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/automatic_fire, 0.1 SECONDS)
|
||||
//AddComponent(/datum/component/automatic_fire, 0.1 SECONDS) SKYRAT EDIT REMOVAL
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
#define AUTOFIRE_MOUSEUP 0
|
||||
#define AUTOFIRE_MOUSEDOWN 1
|
||||
|
||||
/datum/component/automatic_fire
|
||||
var/client/clicker
|
||||
var/mob/living/shooter
|
||||
var/atom/target
|
||||
var/turf/target_loc //For dealing with locking on targets due to BYOND engine limitations (the mouse input only happening when mouse moves).
|
||||
var/autofire_stat = AUTOFIRE_STAT_IDLE
|
||||
var/mouse_parameters
|
||||
var/autofire_shot_delay = 0.3 SECONDS //Time between individual shots.
|
||||
var/mouse_status = AUTOFIRE_MOUSEUP //This seems hacky but there can be two MouseDown() without a MouseUp() in between if the user holds click and uses alt+tab, printscreen or similar.
|
||||
|
||||
COOLDOWN_DECLARE(next_shot_cd)
|
||||
|
||||
/datum/component/automatic_fire/Initialize(_autofire_shot_delay)
|
||||
. = ..()
|
||||
if(!isgun(parent))
|
||||
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(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))
|
||||
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))
|
||||
return //We've updated the firemode. No need for more.
|
||||
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/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_ALERT|AUTOFIRE_STAT_FIRING))
|
||||
return
|
||||
autofire_stat = AUTOFIRE_STAT_ALERT
|
||||
clicker = usercli
|
||||
shooter = clicker.mob
|
||||
RegisterSignal(clicker, COMSIG_CLIENT_MOUSEDOWN, .proc/on_mouse_down)
|
||||
RegisterSignal(shooter, COMSIG_MOB_LOGOUT, .proc/autofire_off)
|
||||
if(!QDELETED(shooter))
|
||||
UnregisterSignal(shooter, COMSIG_MOB_LOGIN)
|
||||
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))
|
||||
return
|
||||
if(autofire_stat & AUTOFIRE_STAT_FIRING)
|
||||
stop_autofiring()
|
||||
|
||||
autofire_stat = AUTOFIRE_STAT_IDLE
|
||||
|
||||
if(!QDELETED(clicker))
|
||||
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_LOGIN, .proc/on_client_login)
|
||||
if(!QDELETED(shooter))
|
||||
UnregisterSignal(shooter, COMSIG_MOB_LOGOUT)
|
||||
shooter = null
|
||||
parent.UnregisterSignal(parent, COMSIG_AUTOFIRE_SHOT)
|
||||
parent.UnregisterSignal(src, COMSIG_AUTOFIRE_ONMOUSEDOWN)
|
||||
|
||||
/datum/component/automatic_fire/proc/on_client_login(mob/source)
|
||||
SIGNAL_HANDLER
|
||||
if(!source.client)
|
||||
return
|
||||
if(source.is_holding(parent))
|
||||
autofire_on(source.client)
|
||||
|
||||
/datum/component/automatic_fire/proc/on_mouse_down(client/source, atom/_target, turf/location, control, params)
|
||||
var/list/modifiers = params2list(params) //If they're shift+clicking, for example, let's not have them accidentally shoot.
|
||||
|
||||
if(LAZYACCESS(modifiers, SHIFT_CLICK))
|
||||
return
|
||||
if(LAZYACCESS(modifiers, CTRL_CLICK))
|
||||
return
|
||||
if(LAZYACCESS(modifiers, MIDDLE_CLICK))
|
||||
return
|
||||
if(LAZYACCESS(modifiers, RIGHT_CLICK))
|
||||
return
|
||||
if(LAZYACCESS(modifiers, ALT_CLICK))
|
||||
return
|
||||
if(source.mob.throw_mode)
|
||||
return
|
||||
if(!isturf(source.mob.loc)) //No firing inside lockers and stuff.
|
||||
return
|
||||
if(get_dist(source.mob, _target) < 2) //Adjacent clicking.
|
||||
return
|
||||
|
||||
if(isnull(location)) //Clicking on a screen object.
|
||||
if(_target.plane != CLICKCATCHER_PLANE) //The clickcatcher is a special case. We want the click to trigger then, under it.
|
||||
return //If we click and drag on our worn backpack, for example, we want it to open instead.
|
||||
_target = params2turf(modifiers["screen-loc"], get_turf(source.eye), source)
|
||||
if(!_target)
|
||||
CRASH("Failed to get the turf under clickcatcher")
|
||||
|
||||
if(SEND_SIGNAL(src, COMSIG_AUTOFIRE_ONMOUSEDOWN, source, _target, location, control, params) & COMPONENT_AUTOFIRE_ONMOUSEDOWN_BYPASS)
|
||||
return
|
||||
|
||||
source.click_intercept_time = world.time //From this point onwards Click() will no longer be triggered.
|
||||
|
||||
if(autofire_stat & (AUTOFIRE_STAT_IDLE))
|
||||
CRASH("on_mouse_down() called with [autofire_stat] autofire_stat")
|
||||
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
|
||||
target_loc = get_turf(target)
|
||||
mouse_parameters = params
|
||||
start_autofiring()
|
||||
|
||||
|
||||
//Dakka-dakka
|
||||
/datum/component/automatic_fire/proc/start_autofiring()
|
||||
if(autofire_stat == AUTOFIRE_STAT_FIRING)
|
||||
return //Already pew-pewing.
|
||||
autofire_stat = AUTOFIRE_STAT_FIRING
|
||||
|
||||
clicker.mouse_override_icon = 'icons/effects/mouse_pointers/weapon_pointer.dmi'
|
||||
clicker.mouse_pointer_icon = clicker.mouse_override_icon
|
||||
|
||||
if(mouse_status == AUTOFIRE_MOUSEUP) //See mouse_status definition for the reason for this.
|
||||
RegisterSignal(clicker, COMSIG_CLIENT_MOUSEUP, .proc/on_mouse_up)
|
||||
mouse_status = AUTOFIRE_MOUSEDOWN
|
||||
|
||||
RegisterSignal(shooter, COMSIG_MOB_SWAP_HANDS, .proc/stop_autofiring)
|
||||
|
||||
if(isgun(parent))
|
||||
var/obj/item/gun/shoota = parent
|
||||
if(!shoota.on_autofire_start(shooter)) //This is needed because the minigun has a do_after before firing and signals are async.
|
||||
stop_autofiring()
|
||||
return
|
||||
if(autofire_stat != AUTOFIRE_STAT_FIRING)
|
||||
return //Things may have changed while on_autofire_start() was being processed, due to do_after's sleep.
|
||||
|
||||
if(!process_shot()) //First shot is processed instantly.
|
||||
return //If it fails, such as when the gun is empty, then there's no need to schedule a second shot.
|
||||
|
||||
START_PROCESSING(SSprojectiles, src)
|
||||
RegisterSignal(clicker, COMSIG_CLIENT_MOUSEDRAG, .proc/on_mouse_drag)
|
||||
|
||||
|
||||
/datum/component/automatic_fire/proc/on_mouse_up(datum/source, atom/object, turf/location, control, params)
|
||||
SIGNAL_HANDLER
|
||||
UnregisterSignal(clicker, COMSIG_CLIENT_MOUSEUP)
|
||||
mouse_status = AUTOFIRE_MOUSEUP
|
||||
if(autofire_stat == AUTOFIRE_STAT_FIRING)
|
||||
stop_autofiring()
|
||||
return COMPONENT_CLIENT_MOUSEUP_INTERCEPT
|
||||
|
||||
|
||||
/datum/component/automatic_fire/proc/stop_autofiring(datum/source, atom/object, turf/location, control, params)
|
||||
SIGNAL_HANDLER
|
||||
switch(autofire_stat)
|
||||
if(AUTOFIRE_STAT_IDLE, AUTOFIRE_STAT_ALERT)
|
||||
return
|
||||
STOP_PROCESSING(SSprojectiles, src)
|
||||
autofire_stat = AUTOFIRE_STAT_ALERT
|
||||
if(clicker)
|
||||
clicker.mouse_override_icon = null
|
||||
clicker.mouse_pointer_icon = clicker.mouse_override_icon
|
||||
UnregisterSignal(clicker, COMSIG_CLIENT_MOUSEDRAG)
|
||||
if(!QDELETED(shooter))
|
||||
UnregisterSignal(shooter, COMSIG_MOB_SWAP_HANDS)
|
||||
target = null
|
||||
target_loc = null
|
||||
mouse_parameters = null
|
||||
|
||||
/datum/component/automatic_fire/proc/on_mouse_drag(client/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params)
|
||||
SIGNAL_HANDLER
|
||||
if(isnull(over_location)) //This happens when the mouse is over an inventory or screen object, or on entering deep darkness, for example.
|
||||
var/list/modifiers = params2list(params)
|
||||
var/new_target = params2turf(modifiers["screen-loc"], get_turf(source.eye), source)
|
||||
mouse_parameters = params
|
||||
if(!new_target)
|
||||
if(QDELETED(target)) //No new target acquired, and old one was deleted, get us out of here.
|
||||
stop_autofiring()
|
||||
CRASH("on_mouse_drag failed to get the turf under screen object [over_object.type]. Old target was incidentally QDELETED.")
|
||||
target = get_turf(target) //If previous target wasn't a turf, let's turn it into one to avoid locking onto a potentially moving target.
|
||||
target_loc = target
|
||||
CRASH("on_mouse_drag failed to get the turf under screen object [over_object.type]")
|
||||
target = new_target
|
||||
target_loc = new_target
|
||||
return
|
||||
target = over_object
|
||||
target_loc = get_turf(over_object)
|
||||
mouse_parameters = params
|
||||
|
||||
|
||||
/datum/component/automatic_fire/proc/process_shot()
|
||||
if(autofire_stat != AUTOFIRE_STAT_FIRING)
|
||||
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)
|
||||
target = get_step(shooter, shooter.dir) //Shoot in the direction faced if the mouse is on the same tile as we are.
|
||||
target_loc = target
|
||||
else if(!in_view_range(shooter, target))
|
||||
stop_autofiring() //Elvis has left the building.
|
||||
return FALSE
|
||||
shooter.face_atom(target)
|
||||
COOLDOWN_START(src, next_shot_cd, autofire_shot_delay)
|
||||
if(SEND_SIGNAL(parent, COMSIG_AUTOFIRE_SHOT, target, shooter, mouse_parameters) & COMPONENT_AUTOFIRE_SHOT_SUCCESS)
|
||||
return TRUE
|
||||
stop_autofiring()
|
||||
return FALSE
|
||||
|
||||
// Gun procs.
|
||||
|
||||
/obj/item/gun/proc/on_autofire_start(mob/living/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))
|
||||
to_chat(shooter, "<span class='warning'>You need two hands to fire [src]!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/gun/proc/autofire_bypass_check(datum/source, client/clicker, atom/target, turf/location, control, params)
|
||||
SIGNAL_HANDLER
|
||||
if(clicker.mob.get_active_held_item() != src)
|
||||
return COMPONENT_AUTOFIRE_ONMOUSEDOWN_BYPASS
|
||||
|
||||
|
||||
/obj/item/gun/proc/do_autofire(datum/source, atom/target, mob/living/shooter, params)
|
||||
SIGNAL_HANDLER_DOES_SLEEP
|
||||
if(!can_shoot())
|
||||
shoot_with_empty_chamber(shooter)
|
||||
return NONE
|
||||
var/obj/item/gun/akimbo_gun = shooter.get_inactive_held_item()
|
||||
var/bonus_spread = 0
|
||||
if(istype(akimbo_gun) && weapon_weight < WEAPON_MEDIUM)
|
||||
if(akimbo_gun.weapon_weight < WEAPON_MEDIUM && akimbo_gun.can_trigger_gun(shooter))
|
||||
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
|
||||
@@ -0,0 +1,328 @@
|
||||
/obj/item/gun/ballistic/automatic
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
can_suppress = TRUE
|
||||
burst_size = 3
|
||||
fire_delay = 2
|
||||
semi_auto = TRUE
|
||||
fire_sound = 'sound/weapons/gun/smg/shot.ogg'
|
||||
fire_sound_volume = 90
|
||||
vary_fire_sound = FALSE
|
||||
rack_sound = 'sound/weapons/gun/smg/smgrack.ogg'
|
||||
suppressed_sound = 'sound/weapons/gun/smg/shot_suppressed.ogg'
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_BURST_SHOT, SELECT_FULLY_AUTOMATIC)
|
||||
|
||||
/obj/item/gun/ballistic/automatic/proto
|
||||
name = "\improper Nanotrasen Saber SMG"
|
||||
desc = "A prototype three-round burst 9mm submachine gun, designated 'SABR'. Has a threaded barrel for suppressors."
|
||||
icon_state = "saber"
|
||||
selector_switch_icon = TRUE
|
||||
mag_display = TRUE
|
||||
empty_indicator = TRUE
|
||||
mag_type = /obj/item/ammo_box/magazine/smgm9mm
|
||||
pin = null
|
||||
bolt_type = BOLT_TYPE_LOCKING
|
||||
show_bolt_icon = FALSE
|
||||
|
||||
/obj/item/gun/ballistic/automatic/proto/unrestricted
|
||||
pin = /obj/item/firing_pin
|
||||
|
||||
/obj/item/gun/ballistic/automatic/c20r
|
||||
name = "\improper C-20r SMG"
|
||||
desc = "A bullpup three-round burst .45 SMG, designated 'C-20r'. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp."
|
||||
icon_state = "c20r"
|
||||
inhand_icon_state = "c20r"
|
||||
selector_switch_icon = TRUE
|
||||
mag_type = /obj/item/ammo_box/magazine/smgm45
|
||||
fire_delay = 2
|
||||
burst_size = 3
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
can_bayonet = TRUE
|
||||
knife_x_offset = 26
|
||||
knife_y_offset = 12
|
||||
mag_display = TRUE
|
||||
mag_display_ammo = TRUE
|
||||
empty_indicator = TRUE
|
||||
|
||||
/obj/item/gun/ballistic/automatic/c20r/update_overlays()
|
||||
. = ..()
|
||||
if(!chambered && empty_indicator)
|
||||
. += "[icon_state]_empty"
|
||||
|
||||
/obj/item/gun/ballistic/automatic/c20r/unrestricted
|
||||
pin = /obj/item/firing_pin
|
||||
|
||||
/obj/item/gun/ballistic/automatic/c20r/Initialize()
|
||||
. = ..()
|
||||
update_appearance()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/wt550
|
||||
name = "security auto rifle"
|
||||
desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Automatic Rifle."
|
||||
icon_state = "wt550"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
inhand_icon_state = "arg"
|
||||
mag_type = /obj/item/ammo_box/magazine/wt550m9
|
||||
fire_delay = 2
|
||||
can_suppress = FALSE
|
||||
burst_size = 0
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
|
||||
can_bayonet = TRUE
|
||||
knife_x_offset = 25
|
||||
knife_y_offset = 12
|
||||
mag_display = TRUE
|
||||
mag_display_ammo = TRUE
|
||||
empty_indicator = TRUE
|
||||
|
||||
/obj/item/gun/ballistic/automatic/plastikov
|
||||
name = "\improper PP-95 SMG"
|
||||
desc = "An ancient 9mm submachine gun pattern updated and simplified to lower costs, though perhaps simplified too much."
|
||||
icon_state = "plastikov"
|
||||
inhand_icon_state = "plastikov"
|
||||
mag_type = /obj/item/ammo_box/magazine/plastikov9mm
|
||||
burst_size = 5
|
||||
spread = 25
|
||||
can_suppress = FALSE
|
||||
projectile_damage_multiplier = 0.35 //It's like 10.5 damage per bullet, it's close enough to 10 shots
|
||||
mag_display = TRUE
|
||||
empty_indicator = TRUE
|
||||
fire_sound = 'sound/weapons/gun/smg/shot_alt.ogg'
|
||||
|
||||
/obj/item/gun/ballistic/automatic/mini_uzi
|
||||
name = "\improper Type U3 Uzi"
|
||||
desc = "A lightweight, burst-fire submachine gun, for when you really want someone dead. Uses 9mm rounds."
|
||||
icon_state = "miniuzi"
|
||||
mag_type = /obj/item/ammo_box/magazine/uzim9mm
|
||||
burst_size = 2
|
||||
bolt_type = BOLT_TYPE_OPEN
|
||||
show_bolt_icon = FALSE
|
||||
mag_display = TRUE
|
||||
rack_sound = 'sound/weapons/gun/pistol/slide_lock.ogg'
|
||||
|
||||
/obj/item/gun/ballistic/automatic/m90
|
||||
name = "\improper M-90gl Carbine"
|
||||
desc = "A three-round burst 5.56 toploading carbine, designated 'M-90gl'. Has an attached underbarrel grenade launcher which can be fired using right click."
|
||||
icon_state = "m90"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
inhand_icon_state = "m90"
|
||||
selector_switch_icon = TRUE
|
||||
mag_type = /obj/item/ammo_box/magazine/m556
|
||||
can_suppress = FALSE
|
||||
var/obj/item/gun/ballistic/revolver/grenadelauncher/underbarrel
|
||||
burst_size = 3
|
||||
fire_delay = 2
|
||||
spread = 5
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
mag_display = TRUE
|
||||
empty_indicator = TRUE
|
||||
fire_sound = 'sound/weapons/gun/smg/shot_alt.ogg'
|
||||
|
||||
/obj/item/gun/ballistic/automatic/m90/Initialize()
|
||||
. = ..()
|
||||
underbarrel = new /obj/item/gun/ballistic/revolver/grenadelauncher(src)
|
||||
update_appearance()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/m90/unrestricted
|
||||
pin = /obj/item/firing_pin
|
||||
|
||||
/obj/item/gun/ballistic/automatic/m90/unrestricted/Initialize()
|
||||
. = ..()
|
||||
underbarrel = new /obj/item/gun/ballistic/revolver/grenadelauncher/unrestricted(src)
|
||||
update_appearance()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/m90/afterattack_secondary(atom/target, mob/living/user, flag, params)
|
||||
underbarrel.afterattack(target, user, flag, params)
|
||||
return SECONDARY_ATTACK_CONTINUE_CHAIN
|
||||
|
||||
/obj/item/gun/ballistic/automatic/m90/attackby(obj/item/A, mob/user, params)
|
||||
if(istype(A, /obj/item/ammo_casing))
|
||||
if(istype(A, underbarrel.magazine.ammo_type))
|
||||
underbarrel.attack_self(user)
|
||||
underbarrel.attackby(A, user, params)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/tommygun
|
||||
name = "\improper Thompson SMG"
|
||||
desc = "Based on the classic 'Chicago Typewriter'."
|
||||
icon_state = "tommygun"
|
||||
inhand_icon_state = "shotgun"
|
||||
selector_switch_icon = TRUE
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = 0
|
||||
mag_type = /obj/item/ammo_box/magazine/tommygunm45
|
||||
can_suppress = FALSE
|
||||
burst_size = 4
|
||||
fire_delay = 1
|
||||
bolt_type = BOLT_TYPE_OPEN
|
||||
empty_indicator = TRUE
|
||||
show_bolt_icon = FALSE
|
||||
|
||||
/obj/item/gun/ballistic/automatic/ar
|
||||
name = "\improper NT-ARG 'Boarder'"
|
||||
desc = "A robust assault rifle used by Nanotrasen fighting forces."
|
||||
icon_state = "arg"
|
||||
inhand_icon_state = "arg"
|
||||
slot_flags = 0
|
||||
mag_type = /obj/item/ammo_box/magazine/m556
|
||||
can_suppress = FALSE
|
||||
burst_size = 3
|
||||
fire_delay = 1
|
||||
|
||||
|
||||
// L6 SAW //
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw
|
||||
name = "\improper L6 SAW"
|
||||
desc = "A heavily modified 7.12x82mm light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the receiver below the designation."
|
||||
icon_state = "l6"
|
||||
inhand_icon_state = "l6"
|
||||
base_icon_state = "l6"
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
slot_flags = 0
|
||||
mag_type = /obj/item/ammo_box/magazine/mm712x82
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
burst_size = 1
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)
|
||||
can_suppress = FALSE
|
||||
spread = 7
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
bolt_type = BOLT_TYPE_OPEN
|
||||
show_bolt_icon = FALSE
|
||||
mag_display = TRUE
|
||||
mag_display_ammo = TRUE
|
||||
tac_reloads = FALSE
|
||||
fire_sound = 'sound/weapons/gun/l6/shot.ogg'
|
||||
rack_sound = 'sound/weapons/gun/l6/l6_rack.ogg'
|
||||
suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg'
|
||||
var/cover_open = FALSE
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/unrestricted
|
||||
pin = /obj/item/firing_pin
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/ComponentInitialize()
|
||||
. = ..()
|
||||
AddElement(/datum/element/update_icon_updates_onmob)
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<b>alt + click</b> to [cover_open ? "close" : "open"] the dust cover."
|
||||
if(cover_open && magazine)
|
||||
. += "<span class='notice'>It seems like you could use an <b>empty hand</b> to remove the magazine.</span>"
|
||||
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/AltClick(mob/user)
|
||||
. = ..()
|
||||
if(!user.canUseTopic(src))
|
||||
return
|
||||
cover_open = !cover_open
|
||||
to_chat(user, "<span class='notice'>You [cover_open ? "open" : "close"] [src]'s cover.</span>")
|
||||
playsound(src, 'sound/weapons/gun/l6/l6_door.ogg', 60, TRUE)
|
||||
update_appearance()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/update_icon_state()
|
||||
. = ..()
|
||||
inhand_icon_state = "[base_icon_state][cover_open ? "open" : "closed"][magazine ? "mag":"nomag"]"
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/update_overlays()
|
||||
. = ..()
|
||||
. += "l6_door_[cover_open ? "open" : "closed"]"
|
||||
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params)
|
||||
if(cover_open)
|
||||
to_chat(user, "<span class='warning'>[src]'s cover is open! Close it before firing!</span>")
|
||||
return
|
||||
else
|
||||
. = ..()
|
||||
update_appearance()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/attack_hand(mob/user, list/modifiers)
|
||||
if (loc != user)
|
||||
..()
|
||||
return
|
||||
if (!cover_open)
|
||||
to_chat(user, "<span class='warning'>[src]'s cover is closed! Open it before trying to remove the magazine!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/gun/ballistic/automatic/l6_saw/attackby(obj/item/A, mob/user, params)
|
||||
if(!cover_open && istype(A, mag_type))
|
||||
to_chat(user, "<span class='warning'>[src]'s dust cover prevents a magazine from being fit.</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
// SNIPER //
|
||||
|
||||
/obj/item/gun/ballistic/automatic/sniper_rifle
|
||||
name = "sniper rifle"
|
||||
desc = "A long ranged weapon that does significant damage. No, you can't quickscope."
|
||||
icon_state = "sniper"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
inhand_icon_state = "sniper"
|
||||
worn_icon_state = null
|
||||
fire_sound = 'sound/weapons/gun/sniper/shot.ogg'
|
||||
fire_sound_volume = 90
|
||||
vary_fire_sound = FALSE
|
||||
load_sound = 'sound/weapons/gun/sniper/mag_insert.ogg'
|
||||
rack_sound = 'sound/weapons/gun/sniper/rack.ogg'
|
||||
suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg'
|
||||
recoil = 2
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
mag_type = /obj/item/ammo_box/magazine/sniper_rounds
|
||||
fire_delay = 40
|
||||
burst_size = 1
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
zoomable = TRUE
|
||||
zoom_amt = 10 //Long range, enough to see in front of you, but no tiles behind you.
|
||||
zoom_out_amt = 5
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
|
||||
mag_display = TRUE
|
||||
suppressor_x_offset = 3
|
||||
suppressor_y_offset = 3
|
||||
|
||||
/obj/item/gun/ballistic/automatic/sniper_rifle/syndicate
|
||||
name = "syndicate sniper rifle"
|
||||
desc = "An illegally modified .50 cal sniper rifle with suppression compatibility. Quickscoping still doesn't work."
|
||||
can_suppress = TRUE
|
||||
can_unsuppress = TRUE
|
||||
pin = /obj/item/firing_pin/implant/pindicate
|
||||
|
||||
// Old Semi-Auto Rifle //
|
||||
|
||||
/obj/item/gun/ballistic/automatic/surplus
|
||||
name = "Surplus Rifle"
|
||||
desc = "One of countless obsolete ballistic rifles that still sees use as a cheap deterrent. Uses 10mm Magnum ammo and its bulky frame prevents one-hand firing."
|
||||
icon_state = "surplus"
|
||||
inhand_icon_state = "moistnugget"
|
||||
worn_icon_state = null
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
mag_type = /obj/item/ammo_box/magazine/m10mm/rifle
|
||||
fire_delay = 30
|
||||
burst_size = 1
|
||||
can_unsuppress = TRUE
|
||||
can_suppress = TRUE
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
//actions_types = list() SKYRAT EDIT REMOVAL
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
|
||||
mag_display = TRUE
|
||||
|
||||
// Laser rifle (rechargeable magazine) //
|
||||
|
||||
/obj/item/gun/ballistic/automatic/laser
|
||||
name = "laser rifle"
|
||||
desc = "Though sometimes mocked for the relatively weak firepower of their energy weapons, the logistic miracle of rechargeable ammunition has given Nanotrasen a decisive edge over many a foe."
|
||||
icon_state = "oldrifle"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
inhand_icon_state = "arg"
|
||||
mag_type = /obj/item/ammo_box/magazine/recharge
|
||||
mag_display_ammo = TRUE
|
||||
fire_delay = 2
|
||||
can_suppress = FALSE
|
||||
burst_size = 0
|
||||
//actions_types = list() SKYRAT EDIT REMOVAL
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
|
||||
fire_sound = 'sound/weapons/laser.ogg'
|
||||
casing_ejector = FALSE
|
||||
@@ -0,0 +1,833 @@
|
||||
|
||||
#define DUALWIELD_PENALTY_EXTRA_MULTIPLIER 1.4
|
||||
#define FIRING_PIN_REMOVAL_DELAY 50
|
||||
|
||||
/obj/item/gun
|
||||
name = "gun"
|
||||
desc = "It's a gun. It's pretty terrible, though."
|
||||
icon = 'icons/obj/guns/ballistic.dmi'
|
||||
icon_state = "detective"
|
||||
inhand_icon_state = "gun"
|
||||
worn_icon_state = "gun"
|
||||
flags_1 = CONDUCT_1
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
custom_materials = list(/datum/material/iron=2000)
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
throwforce = 5
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
force = 5
|
||||
item_flags = NEEDS_PERMIT
|
||||
attack_verb_continuous = list("strikes", "hits", "bashes")
|
||||
attack_verb_simple = list("strike", "hit", "bash")
|
||||
|
||||
var/gun_flags = NONE
|
||||
var/fire_sound = 'sound/weapons/gun/pistol/shot.ogg'
|
||||
var/vary_fire_sound = TRUE
|
||||
var/fire_sound_volume = 50
|
||||
var/dry_fire_sound = 'sound/weapons/gun/general/dry_fire.ogg'
|
||||
var/suppressed = null //whether or not a message is displayed when fired
|
||||
var/can_suppress = FALSE
|
||||
var/suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg'
|
||||
var/suppressed_volume = 60
|
||||
var/can_unsuppress = TRUE
|
||||
var/recoil = 0 //boom boom shake the room
|
||||
var/clumsy_check = TRUE
|
||||
var/obj/item/ammo_casing/chambered = null
|
||||
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/burst_size = 1 //how large a burst is
|
||||
var/fire_delay = 0 //rate of fire for burst firing and semi auto
|
||||
var/firing_burst = 0 //Prevent the weapon from firing again while already firing
|
||||
var/semicd = 0 //cooldown handler
|
||||
var/weapon_weight = WEAPON_LIGHT
|
||||
var/dual_wield_spread = 24 //additional spread when dual wielding
|
||||
|
||||
/// Just 'slightly' snowflakey way to modify projectile damage for projectiles fired from this gun.
|
||||
var/projectile_damage_multiplier = 1
|
||||
|
||||
var/spread = 0 //Spread induced by the gun itself.
|
||||
var/randomspread = 1 //Set to 0 for shotguns. This is used for weapons that don't fire all their bullets at once.
|
||||
|
||||
lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
|
||||
|
||||
var/obj/item/firing_pin/pin = /obj/item/firing_pin //standard firing pin for most guns
|
||||
|
||||
var/can_flashlight = FALSE //if a flashlight can be added or removed if it already has one.
|
||||
var/obj/item/flashlight/seclite/gun_light
|
||||
var/datum/action/item_action/toggle_gunlight/alight
|
||||
var/gunlight_state = "flight"
|
||||
|
||||
var/can_bayonet = FALSE //if a bayonet can be added or removed if it already has one.
|
||||
var/obj/item/kitchen/knife/bayonet
|
||||
var/knife_x_offset = 0
|
||||
var/knife_y_offset = 0
|
||||
|
||||
var/ammo_x_offset = 0 //used for positioning ammo count overlay on sprite
|
||||
var/ammo_y_offset = 0
|
||||
var/flight_x_offset = 0
|
||||
var/flight_y_offset = 0
|
||||
|
||||
//Zooming
|
||||
var/zoomable = FALSE //whether the gun generates a Zoom action on creation
|
||||
var/zoomed = FALSE //Zoom toggle
|
||||
var/zoom_amt = 3 //Distance in TURFs to move the user's screen forward (the "zoom" effect)
|
||||
var/zoom_out_amt = 0
|
||||
var/datum/action/toggle_scope_zoom/azoom
|
||||
var/pb_knockback = 0
|
||||
|
||||
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
|
||||
var/datum/action/item_action/toggle_safety/tsafety
|
||||
|
||||
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
|
||||
var/fire_select_index = 1
|
||||
///What modes does this weapon have? Put SELECT_FULLY_AUTOMATIC in here to enable fully automatic behaviours.
|
||||
var/list/fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
|
||||
///if i`1t has an icon for a selector switch indicating current firemode.
|
||||
var/selector_switch_icon = FALSE
|
||||
|
||||
/datum/action/item_action/toggle_safety
|
||||
name = "Toggle Safety"
|
||||
icon_icon = 'modular_skyrat/modules/gunsafety/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))
|
||||
fire_select()
|
||||
else if(istype(actiontype, tsafety))
|
||||
toggle_safety(user)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/gun/Initialize()
|
||||
. = ..()
|
||||
if(pin)
|
||||
pin = new pin(src)
|
||||
|
||||
if(gun_light)
|
||||
alight = new(src)
|
||||
|
||||
build_zooming()
|
||||
|
||||
if(has_gun_safety)
|
||||
safety = TRUE
|
||||
tsafety = new(src)
|
||||
|
||||
if(burst_size > 1 && !(SELECT_BURST_SHOT in fire_select_modes))
|
||||
fire_select_modes.Add(SELECT_BURST_SHOT)
|
||||
else if(burst_size <= 1 && (SELECT_BURST_SHOT in fire_select_modes))
|
||||
fire_select_modes.Remove(SELECT_BURST_SHOT)
|
||||
|
||||
burst_size = 1
|
||||
|
||||
sortList(fire_select_modes, /proc/cmp_numeric_asc)
|
||||
|
||||
if(fire_select_modes.len > 1)
|
||||
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)
|
||||
AddComponent(/datum/component/automatic_fire, fire_delay)
|
||||
|
||||
/obj/item/gun/Destroy()
|
||||
if(isobj(pin)) //Can still be the initial path, then we skip
|
||||
QDEL_NULL(pin)
|
||||
if(gun_light)
|
||||
QDEL_NULL(gun_light)
|
||||
if(bayonet)
|
||||
QDEL_NULL(bayonet)
|
||||
if(chambered) //Not all guns are chambered (EMP'ed energy guns etc)
|
||||
QDEL_NULL(chambered)
|
||||
if(azoom)
|
||||
QDEL_NULL(azoom)
|
||||
if(suppressed)
|
||||
QDEL_NULL(suppressed)
|
||||
if(tsafety)
|
||||
QDEL_NULL(tsafety)
|
||||
if(firemode_action)
|
||||
QDEL_NULL(firemode_action)
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/handle_atom_del(atom/A)
|
||||
if(A == pin)
|
||||
pin = null
|
||||
if(A == chambered)
|
||||
chambered = null
|
||||
update_appearance()
|
||||
if(A == bayonet)
|
||||
clear_bayonet()
|
||||
if(A == gun_light)
|
||||
clear_gunlight()
|
||||
if(A == suppressed)
|
||||
clear_suppressor()
|
||||
. = ..()
|
||||
|
||||
///Clears var and updates icon. In the case of ballistic weapons, also updates the gun's weight.
|
||||
/obj/item/gun/proc/clear_suppressor()
|
||||
if(!can_unsuppress)
|
||||
return
|
||||
suppressed = null
|
||||
update_appearance()
|
||||
|
||||
/obj/item/gun/examine(mob/user)
|
||||
. = ..()
|
||||
if(pin)
|
||||
. += "It has \a [pin] installed."
|
||||
. += "<span class='info'>[pin] looks like it could be removed with some <b>tools</b>.</span>"
|
||||
else
|
||||
. += "It doesn't have a <b>firing pin</b> installed, and won't fire."
|
||||
|
||||
if(gun_light)
|
||||
. += "It has \a [gun_light] [can_flashlight ? "" : "permanently "]mounted on it."
|
||||
if(can_flashlight) //if it has a light and this is false, the light is permanent.
|
||||
. += "<span class='info'>[gun_light] looks like it can be <b>unscrewed</b> from [src].</span>"
|
||||
else if(can_flashlight)
|
||||
. += "It has a mounting point for a <b>seclite</b>."
|
||||
|
||||
if(bayonet)
|
||||
. += "It has \a [bayonet] [can_bayonet ? "" : "permanently "]affixed to it."
|
||||
if(can_bayonet) //if it has a bayonet and this is false, the bayonet is permanent.
|
||||
. += "<span class='info'>[bayonet] looks like it can be <b>unscrewed</b> from [src].</span>"
|
||||
if(can_bayonet)
|
||||
. += "It has a <b>bayonet</b> lug on it."
|
||||
if(has_gun_safety)
|
||||
. += "<span>The safety is [safety ? "<font color='#00ff15'>ON</font>" : "<font color='#ff0000'>OFF</font>"].</span>"
|
||||
|
||||
/obj/item/gun/equipped(mob/living/user, slot)
|
||||
. = ..()
|
||||
if(zoomed && user.get_active_held_item() != src)
|
||||
zoom(user, user.dir, FALSE) //we can only stay zoomed in if it's in our hands //yeah and we only unzoom if we're actually zoomed using the gun!!
|
||||
|
||||
/obj/item/gun/proc/fire_select()
|
||||
var/mob/living/carbon/human/user = usr
|
||||
|
||||
var/max_mode = fire_select_modes.len
|
||||
|
||||
if(max_mode <= 1)
|
||||
to_chat(user, "<span class='warning'>[src] is not capable of switching firemodes!</span>")
|
||||
return
|
||||
|
||||
fire_select_index = 1 + fire_select_index % max_mode //Magic math to cycle through this shit!
|
||||
|
||||
fire_select = fire_select_modes[fire_select_index]
|
||||
|
||||
switch(fire_select)
|
||||
if(SELECT_SEMI_AUTOMATIC)
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
SEND_SIGNAL(src, COMSIG_GUN_AUTOFIRE_DESELECTED, user)
|
||||
to_chat(user, "<span class='notice'>You switch [src] to semi-automatic.</span>")
|
||||
if(SELECT_BURST_SHOT)
|
||||
burst_size = initial(burst_size)
|
||||
fire_delay = initial(fire_delay)
|
||||
SEND_SIGNAL(src, COMSIG_GUN_AUTOFIRE_DESELECTED, user)
|
||||
to_chat(user, "<span class='notice'>You switch [src] to [burst_size]-round burst.</span>")
|
||||
if(SELECT_FULLY_AUTOMATIC)
|
||||
burst_size = 1
|
||||
SEND_SIGNAL(src, COMSIG_GUN_AUTOFIRE_SELECTED, user)
|
||||
to_chat(user, "<span class='notice'>You switch [src] to automatic.</span>")
|
||||
|
||||
playsound(user, 'sound/weapons/empty.ogg', 100, TRUE)
|
||||
update_appearance()
|
||||
firemode_action.button_icon_state = "fireselect_[fire_select]"
|
||||
firemode_action.UpdateButtonIcon()
|
||||
return TRUE
|
||||
|
||||
//called after the gun has successfully fired its chambered ammo.
|
||||
/obj/item/gun/proc/process_chamber()
|
||||
return FALSE
|
||||
|
||||
//check if there's enough ammo/energy/whatever to shoot one time
|
||||
//i.e if clicking would make it shoot
|
||||
/obj/item/gun/proc/can_shoot()
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/proc/shoot_with_empty_chamber(mob/living/user as mob|obj)
|
||||
to_chat(user, "<span class='danger'>*click*</span>")
|
||||
playsound(src, dry_fire_sound, 30, TRUE)
|
||||
|
||||
|
||||
/obj/item/gun/proc/shoot_live_shot(mob/living/user, pointblank = 0, atom/pbtarget = null, message = 1)
|
||||
if(recoil)
|
||||
shake_camera(user, recoil + 1, recoil)
|
||||
|
||||
if(suppressed)
|
||||
playsound(user, suppressed_sound, suppressed_volume, vary_fire_sound, ignore_walls = FALSE, extrarange = SILENCED_SOUND_EXTRARANGE, falloff_distance = 0)
|
||||
else
|
||||
playsound(user, fire_sound, fire_sound_volume, vary_fire_sound)
|
||||
if(message)
|
||||
if(pointblank)
|
||||
user.visible_message("<span class='danger'>[user] fires [src] point blank at [pbtarget]!</span>", \
|
||||
"<span class='danger'>You fire [src] point blank at [pbtarget]!</span>", \
|
||||
"<span class='hear'>You hear a gunshot!</span>", COMBAT_MESSAGE_RANGE, pbtarget)
|
||||
to_chat(pbtarget, "<span class='userdanger'>[user] fires [src] point blank at you!</span>")
|
||||
if(pb_knockback > 0 && ismob(pbtarget))
|
||||
var/mob/PBT = pbtarget
|
||||
var/atom/throw_target = get_edge_target_turf(PBT, user.dir)
|
||||
PBT.throw_at(throw_target, pb_knockback, 2)
|
||||
else
|
||||
user.visible_message("<span class='danger'>[user] fires [src]!</span>", \
|
||||
"<span class='danger'>You fire [src]!</span>", \
|
||||
"<span class='hear'>You hear a gunshot!</span>", COMBAT_MESSAGE_RANGE)
|
||||
|
||||
/obj/item/gun/emp_act(severity)
|
||||
. = ..()
|
||||
if(!(. & EMP_PROTECT_CONTENTS))
|
||||
for(var/obj/O in contents)
|
||||
O.emp_act(severity)
|
||||
|
||||
/obj/item/gun/attack_secondary(mob/living/victim, mob/living/user, params)
|
||||
if(user.GetComponent(/datum/component/gunpoint))
|
||||
to_chat(user, "<span class='warning'>You are already holding someone up!</span>")
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
if(user == victim)
|
||||
to_chat(user,"<span class='warning'>You can't hold yourself up!</span>")
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
user.AddComponent(/datum/component/gunpoint, victim, src)
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/item/gun/afterattack(atom/target, mob/living/user, flag, params)
|
||||
. = ..()
|
||||
if(QDELETED(target))
|
||||
return
|
||||
if(firing_burst)
|
||||
return
|
||||
if(flag) //It's adjacent, is the user, or is on the user's person
|
||||
if(target in user.contents) //can't shoot stuff inside us.
|
||||
return
|
||||
if(!ismob(target) || user.combat_mode) //melee attack
|
||||
return
|
||||
if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected)
|
||||
return
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
for(var/i in C.all_wounds)
|
||||
var/datum/wound/W = i
|
||||
if(W.try_treating(src, user))
|
||||
return // another coward cured!
|
||||
|
||||
if(istype(user))//Check if the user can use the gun, if the user isn't alive(turrets) assume it can.
|
||||
var/mob/living/L = user
|
||||
if(!can_trigger_gun(L))
|
||||
return
|
||||
if(flag)
|
||||
if(user.zone_selected == BODY_ZONE_PRECISE_MOUTH)
|
||||
handle_suicide(user, target, params)
|
||||
return
|
||||
|
||||
if(!can_shoot()) //Just because you can pull the trigger doesn't mean it can shoot.
|
||||
shoot_with_empty_chamber(user)
|
||||
return
|
||||
|
||||
if(check_botched(user))
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/other_hand = user.has_hand_for_held_index(user.get_inactive_hand_index()) //returns non-disabled inactive hands
|
||||
if(weapon_weight == WEAPON_HEAVY && (user.get_inactive_held_item() || !other_hand))
|
||||
to_chat(user, "<span class='warning'>You need two hands to fire [src]!</span>")
|
||||
return
|
||||
//DUAL (or more!) WIELDING
|
||||
var/bonus_spread = 0
|
||||
var/loop_counter = 0
|
||||
if(ishuman(user) && user.combat_mode)
|
||||
var/mob/living/carbon/human/H = user
|
||||
for(var/obj/item/gun/G in H.held_items)
|
||||
if(G == src || G.weapon_weight >= WEAPON_MEDIUM)
|
||||
continue
|
||||
else if(G.can_trigger_gun(user))
|
||||
bonus_spread += dual_wield_spread
|
||||
loop_counter++
|
||||
addtimer(CALLBACK(G, /obj/item/gun.proc/process_fire, target, user, TRUE, params, null, bonus_spread), loop_counter)
|
||||
|
||||
return process_fire(target, user, TRUE, params, null, bonus_spread)
|
||||
|
||||
/obj/item/gun/proc/check_botched(mob/living/user, params)
|
||||
if(clumsy_check)
|
||||
if(istype(user))
|
||||
if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(40))
|
||||
to_chat(user, "<span class='userdanger'>You shoot yourself in the foot with [src]!</span>")
|
||||
var/shot_leg = pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
process_fire(user, user, FALSE, params, shot_leg)
|
||||
SEND_SIGNAL(user, COMSIG_MOB_CLUMSY_SHOOT_FOOT)
|
||||
user.dropItemToGround(src, TRUE)
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/can_trigger_gun(mob/living/user)
|
||||
. = ..()
|
||||
if(!handle_pins(user))
|
||||
return FALSE
|
||||
if(has_gun_safety && safety)
|
||||
to_chat(user, "<span class='warning'>The safety is on!</span>")
|
||||
return FALSE
|
||||
|
||||
/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
|
||||
tsafety.button_icon_state = "safety_[safety ? "on" : "off"]"
|
||||
tsafety.UpdateButtonIcon()
|
||||
playsound(src, 'sound/weapons/empty.ogg', 100, TRUE)
|
||||
user.visible_message("<span class='notice'>[user] toggles [src]'s safety [safety ? "<font color='#00ff15'>ON</font>" : "<font color='#ff0000'>OFF</font>"].",
|
||||
"<span class='notice'>You toggle [src]'s safety [safety ? "<font color='#00ff15'>ON</font>" : "<font color='#ff0000'>OFF</font>"].</span>")
|
||||
|
||||
/obj/item/gun/proc/handle_pins(mob/living/user)
|
||||
if(pin)
|
||||
if(pin.pin_auth(user) || (pin.obj_flags & EMAGGED))
|
||||
return TRUE
|
||||
else
|
||||
pin.auth_fail(user)
|
||||
return FALSE
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[src]'s trigger is locked. This weapon doesn't have a firing pin installed!</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/item/gun/proc/recharge_newshot()
|
||||
return
|
||||
|
||||
/obj/item/gun/proc/process_burst(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
|
||||
if(!user || !firing_burst)
|
||||
firing_burst = FALSE
|
||||
return FALSE
|
||||
if(!issilicon(user))
|
||||
if(iteration > 1 && !(user.is_holding(src))) //for burst firing
|
||||
firing_burst = FALSE
|
||||
return FALSE
|
||||
if(chambered?.loaded_projectile)
|
||||
if(HAS_TRAIT(user, TRAIT_PACIFISM)) // 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.
|
||||
if(chambered.harmful) // Is the bullet chambered harmful?
|
||||
to_chat(user, "<span class='warning'>[src] is lethally chambered! You don't want to risk harming anyone...</span>")
|
||||
return
|
||||
if(randomspread)
|
||||
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
|
||||
else //Smart spread
|
||||
sprd = round((((rand_spr/burst_size) * iteration) - (0.5 + (rand_spr * 0.25))) * (randomized_gun_spread + randomized_bonus_spread))
|
||||
before_firing(target,user)
|
||||
if(!chambered.fire_casing(target, user, params, ,suppressed, zone_override, sprd, src))
|
||||
shoot_with_empty_chamber(user)
|
||||
firing_burst = FALSE
|
||||
return FALSE
|
||||
else
|
||||
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
|
||||
shoot_live_shot(user, 1, target, message)
|
||||
else
|
||||
shoot_live_shot(user, 0, target, message)
|
||||
if (iteration >= burst_size)
|
||||
firing_burst = FALSE
|
||||
else
|
||||
shoot_with_empty_chamber(user)
|
||||
firing_burst = FALSE
|
||||
return FALSE
|
||||
process_chamber()
|
||||
update_appearance()
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
if(user)
|
||||
if(HAS_TRAIT(user, TRAIT_POOR_AIM)) //nice shootin' tex
|
||||
target = pick(orange(2, target))
|
||||
SEND_SIGNAL(user, COMSIG_MOB_FIRED_GUN, user, target, params, zone_override)
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_GUN_FIRED, user, target, params, zone_override)
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
if(semicd)
|
||||
return
|
||||
|
||||
var/sprd = 0
|
||||
var/randomized_gun_spread = 0
|
||||
var/rand_spr = rand()
|
||||
if(spread)
|
||||
randomized_gun_spread = rand(0,spread)
|
||||
var/randomized_bonus_spread = rand(0, bonus_spread)
|
||||
|
||||
if(burst_size > 1)
|
||||
firing_burst = TRUE
|
||||
for(var/i = 1 to burst_size)
|
||||
addtimer(CALLBACK(src, .proc/process_burst, user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i), fire_delay * (i - 1))
|
||||
else
|
||||
if(chambered)
|
||||
if(HAS_TRAIT(user, TRAIT_PACIFISM)) // 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.
|
||||
if(chambered.harmful) // Is the bullet chambered harmful?
|
||||
to_chat(user, "<span class='warning'>[src] is lethally chambered! You don't want to risk harming anyone...</span>")
|
||||
return
|
||||
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
|
||||
before_firing(target,user)
|
||||
if(!chambered.fire_casing(target, user, params, , suppressed, zone_override, sprd, src))
|
||||
shoot_with_empty_chamber(user)
|
||||
return
|
||||
else
|
||||
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
|
||||
shoot_live_shot(user, 1, target, message)
|
||||
else
|
||||
shoot_live_shot(user, 0, target, message)
|
||||
else
|
||||
shoot_with_empty_chamber(user)
|
||||
return
|
||||
process_chamber()
|
||||
update_appearance()
|
||||
semicd = TRUE
|
||||
addtimer(CALLBACK(src, .proc/reset_semicd), fire_delay)
|
||||
|
||||
if(user)
|
||||
user.update_inv_hands()
|
||||
SSblackbox.record_feedback("tally", "gun_fired", 1, type)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/proc/reset_semicd()
|
||||
semicd = FALSE
|
||||
|
||||
/obj/item/gun/attack(mob/M, mob/living/user)
|
||||
if(user.combat_mode) //Flogging
|
||||
if(bayonet)
|
||||
M.attackby(bayonet, user)
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
return
|
||||
|
||||
/obj/item/gun/attack_obj(obj/O, mob/living/user, params)
|
||||
if(user.combat_mode)
|
||||
if(bayonet)
|
||||
O.attackby(bayonet, user)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/attackby(obj/item/I, mob/living/user, params)
|
||||
if(user.combat_mode)
|
||||
return ..()
|
||||
else if(istype(I, /obj/item/flashlight/seclite))
|
||||
if(!can_flashlight)
|
||||
return ..()
|
||||
var/obj/item/flashlight/seclite/S = I
|
||||
if(!gun_light)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You click [S] into place on [src].</span>")
|
||||
set_gun_light(S)
|
||||
update_gunlight()
|
||||
alight = new(src)
|
||||
if(loc == user)
|
||||
alight.Grant(user)
|
||||
else if(istype(I, /obj/item/kitchen/knife))
|
||||
var/obj/item/kitchen/knife/K = I
|
||||
if(!can_bayonet || !K.bayonet || bayonet) //ensure the gun has an attachment point available, and that the knife is compatible with it.
|
||||
return ..()
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You attach [K] to [src]'s bayonet lug.</span>")
|
||||
bayonet = K
|
||||
update_appearance()
|
||||
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/screwdriver_act(mob/living/user, obj/item/I)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
return
|
||||
if((can_flashlight && gun_light) && (can_bayonet && bayonet)) //give them a choice instead of removing both
|
||||
var/list/possible_items = list(gun_light, bayonet)
|
||||
var/obj/item/item_to_remove = input(user, "Select an attachment to remove", "Attachment Removal") as null|obj in sortNames(possible_items)
|
||||
if(!item_to_remove || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
return
|
||||
return remove_gun_attachment(user, I, item_to_remove)
|
||||
|
||||
else if(gun_light && can_flashlight) //if it has a gun_light and can_flashlight is false, the flashlight is permanently attached.
|
||||
return remove_gun_attachment(user, I, gun_light, "unscrewed")
|
||||
|
||||
else if(bayonet && can_bayonet) //if it has a bayonet, and the bayonet can be removed
|
||||
return remove_gun_attachment(user, I, bayonet, "unfix")
|
||||
|
||||
else if(pin && user.is_holding(src))
|
||||
user.visible_message("<span class='warning'>[user] attempts to remove [pin] from [src] with [I].</span>",
|
||||
"<span class='notice'>You attempt to remove [pin] from [src]. (It will take [DisplayTimeText(FIRING_PIN_REMOVAL_DELAY)].)</span>", null, 3)
|
||||
if(I.use_tool(src, user, FIRING_PIN_REMOVAL_DELAY, volume = 50))
|
||||
if(!pin) //check to see if the pin is still there, or we can spam messages by clicking multiple times during the tool delay
|
||||
return
|
||||
user.visible_message("<span class='notice'>[pin] is pried out of [src] by [user], destroying the pin in the process.</span>",
|
||||
"<span class='warning'>You pry [pin] out with [I], destroying the pin in the process.</span>", null, 3)
|
||||
QDEL_NULL(pin)
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/welder_act(mob/living/user, obj/item/I)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
return
|
||||
if(pin && user.is_holding(src))
|
||||
user.visible_message("<span class='warning'>[user] attempts to remove [pin] from [src] with [I].</span>",
|
||||
"<span class='notice'>You attempt to remove [pin] from [src]. (It will take [DisplayTimeText(FIRING_PIN_REMOVAL_DELAY)].)</span>", null, 3)
|
||||
if(I.use_tool(src, user, FIRING_PIN_REMOVAL_DELAY, 5, volume = 50))
|
||||
if(!pin) //check to see if the pin is still there, or we can spam messages by clicking multiple times during the tool delay
|
||||
return
|
||||
user.visible_message("<span class='notice'>[pin] is spliced out of [src] by [user], melting part of the pin in the process.</span>",
|
||||
"<span class='warning'>You splice [pin] out of [src] with [I], melting part of the pin in the process.</span>", null, 3)
|
||||
QDEL_NULL(pin)
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/wirecutter_act(mob/living/user, obj/item/I)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
|
||||
return
|
||||
if(pin && user.is_holding(src))
|
||||
user.visible_message("<span class='warning'>[user] attempts to remove [pin] from [src] with [I].</span>",
|
||||
"<span class='notice'>You attempt to remove [pin] from [src]. (It will take [DisplayTimeText(FIRING_PIN_REMOVAL_DELAY)].)</span>", null, 3)
|
||||
if(I.use_tool(src, user, FIRING_PIN_REMOVAL_DELAY, volume = 50))
|
||||
if(!pin) //check to see if the pin is still there, or we can spam messages by clicking multiple times during the tool delay
|
||||
return
|
||||
user.visible_message("<span class='notice'>[pin] is ripped out of [src] by [user], mangling the pin in the process.</span>",
|
||||
"<span class='warning'>You rip [pin] out of [src] with [I], mangling the pin in the process.</span>", null, 3)
|
||||
QDEL_NULL(pin)
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/proc/remove_gun_attachment(mob/living/user, obj/item/tool_item, obj/item/item_to_remove, removal_verb)
|
||||
if(tool_item)
|
||||
tool_item.play_tool_sound(src)
|
||||
to_chat(user, "<span class='notice'>You [removal_verb ? removal_verb : "remove"] [item_to_remove] from [src].</span>")
|
||||
item_to_remove.forceMove(drop_location())
|
||||
|
||||
if(Adjacent(user) && !issilicon(user))
|
||||
user.put_in_hands(item_to_remove)
|
||||
|
||||
if(item_to_remove == bayonet)
|
||||
return clear_bayonet()
|
||||
else if(item_to_remove == gun_light)
|
||||
return clear_gunlight()
|
||||
|
||||
/obj/item/gun/proc/clear_bayonet()
|
||||
if(!bayonet)
|
||||
return
|
||||
bayonet = null
|
||||
update_appearance()
|
||||
return TRUE
|
||||
|
||||
/obj/item/gun/proc/clear_gunlight()
|
||||
if(!gun_light)
|
||||
return
|
||||
var/obj/item/flashlight/seclite/removed_light = gun_light
|
||||
set_gun_light(null)
|
||||
update_gunlight()
|
||||
removed_light.update_brightness()
|
||||
QDEL_NULL(alight)
|
||||
return TRUE
|
||||
|
||||
|
||||
/**
|
||||
* Swaps the gun's seclight, dropping the old seclight if it has not been qdel'd.
|
||||
*
|
||||
* Returns the former gun_light that has now been replaced by this proc.
|
||||
* Arguments:
|
||||
* * new_light - The new light to attach to the weapon. Can be null, which will mean the old light is removed with no replacement.
|
||||
*/
|
||||
/obj/item/gun/proc/set_gun_light(obj/item/flashlight/seclite/new_light)
|
||||
// Doesn't look like this should ever happen? We're replacing our old light with our old light?
|
||||
if(gun_light == new_light)
|
||||
CRASH("Tried to set a new gun light when the old gun light was also the new gun light.")
|
||||
|
||||
. = gun_light
|
||||
|
||||
// If there's an old gun light that isn't being QDELETED, detatch and drop it to the floor.
|
||||
if(!QDELETED(gun_light))
|
||||
gun_light.set_light_flags(gun_light.light_flags & ~LIGHT_ATTACHED)
|
||||
if(gun_light.loc == src)
|
||||
gun_light.forceMove(get_turf(src))
|
||||
|
||||
// If there's a new gun light to be added, attach and move it to the gun.
|
||||
if(new_light)
|
||||
new_light.set_light_flags(new_light.light_flags | LIGHT_ATTACHED)
|
||||
if(new_light.loc != src)
|
||||
new_light.forceMove(src)
|
||||
|
||||
gun_light = new_light
|
||||
|
||||
/obj/item/gun/ui_action_click(mob/user, actiontype)
|
||||
if(istype(actiontype, alight))
|
||||
toggle_gunlight()
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/gun/proc/toggle_gunlight()
|
||||
if(!gun_light)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/user = usr
|
||||
gun_light.on = !gun_light.on
|
||||
gun_light.update_brightness()
|
||||
to_chat(user, "<span class='notice'>You toggle the gunlight [gun_light.on ? "on":"off"].</span>")
|
||||
|
||||
playsound(user, 'sound/weapons/empty.ogg', 100, TRUE)
|
||||
update_gunlight()
|
||||
|
||||
/obj/item/gun/proc/update_gunlight()
|
||||
update_appearance()
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
|
||||
/obj/item/gun/pickup(mob/user)
|
||||
. = ..()
|
||||
if(azoom)
|
||||
azoom.Grant(user)
|
||||
if(w_class > WEIGHT_CLASS_SMALL && !suppressed)
|
||||
user.visible_message("<span class='warning'>[user] grabs <b>[src]</b>!</span>",
|
||||
"<span class='warning'>You grab [src]!</span>")
|
||||
|
||||
/obj/item/gun/dropped(mob/user)
|
||||
. = ..()
|
||||
if(azoom)
|
||||
azoom.Remove(user)
|
||||
if(zoomed)
|
||||
zoom(user, user.dir)
|
||||
|
||||
/obj/item/gun/update_overlays()
|
||||
. = ..()
|
||||
if(gun_light)
|
||||
var/mutable_appearance/flashlight_overlay
|
||||
var/state = "[gunlight_state][gun_light.on? "_on":""]" //Generic state.
|
||||
if(gun_light.icon_state in icon_states('icons/obj/guns/flashlights.dmi')) //Snowflake state?
|
||||
state = gun_light.icon_state
|
||||
flashlight_overlay = mutable_appearance('icons/obj/guns/flashlights.dmi', state)
|
||||
flashlight_overlay.pixel_x = flight_x_offset
|
||||
flashlight_overlay.pixel_y = flight_y_offset
|
||||
. += flashlight_overlay
|
||||
|
||||
if(bayonet)
|
||||
var/mutable_appearance/knife_overlay
|
||||
var/state = "bayonet" //Generic state.
|
||||
if(bayonet.icon_state in icon_states('icons/obj/guns/bayonets.dmi')) //Snowflake state?
|
||||
state = bayonet.icon_state
|
||||
var/icon/bayonet_icons = 'icons/obj/guns/bayonets.dmi'
|
||||
knife_overlay = mutable_appearance(bayonet_icons, state)
|
||||
knife_overlay.pixel_x = knife_x_offset
|
||||
knife_overlay.pixel_y = knife_y_offset
|
||||
. += knife_overlay
|
||||
|
||||
/obj/item/gun/proc/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params, bypass_timer)
|
||||
if(!ishuman(user) || !ishuman(target))
|
||||
return
|
||||
|
||||
if(semicd)
|
||||
return
|
||||
|
||||
if(user == target)
|
||||
target.visible_message("<span class='warning'>[user] sticks [src] in [user.p_their()] mouth, ready to pull the trigger...</span>", \
|
||||
"<span class='userdanger'>You stick [src] in your mouth, ready to pull the trigger...</span>")
|
||||
else
|
||||
target.visible_message("<span class='warning'>[user] points [src] at [target]'s head, ready to pull the trigger...</span>", \
|
||||
"<span class='userdanger'>[user] points [src] at your head, ready to pull the trigger...</span>")
|
||||
|
||||
semicd = TRUE
|
||||
|
||||
if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH))
|
||||
if(user)
|
||||
if(user == target)
|
||||
user.visible_message("<span class='notice'>[user] decided not to shoot.</span>")
|
||||
else if(target?.Adjacent(user))
|
||||
target.visible_message("<span class='notice'>[user] has decided to spare [target]</span>", "<span class='notice'>[user] has decided to spare your life!</span>")
|
||||
semicd = FALSE
|
||||
return
|
||||
|
||||
semicd = FALSE
|
||||
|
||||
target.visible_message("<span class='warning'>[user] pulls the trigger!</span>", "<span class='userdanger'>[(user == target) ? "You pull" : "[user] pulls"] the trigger!</span>")
|
||||
|
||||
if(chambered?.loaded_projectile)
|
||||
chambered.loaded_projectile.damage *= 5
|
||||
if(chambered.loaded_projectile.wound_bonus != CANT_WOUND)
|
||||
chambered.loaded_projectile.wound_bonus += 5 // much more dramatic on multiple pellet'd projectiles really
|
||||
|
||||
var/fired = process_fire(target, user, TRUE, params, BODY_ZONE_HEAD)
|
||||
if(!fired && chambered?.loaded_projectile)
|
||||
chambered.loaded_projectile.damage /= 5
|
||||
if(chambered.loaded_projectile.wound_bonus != CANT_WOUND)
|
||||
chambered.loaded_projectile.wound_bonus -= 5
|
||||
|
||||
/obj/item/gun/proc/unlock() //used in summon guns and as a convience for admins
|
||||
if(pin)
|
||||
qdel(pin)
|
||||
pin = new /obj/item/firing_pin
|
||||
|
||||
//Happens before the actual projectile creation
|
||||
/obj/item/gun/proc/before_firing(atom/target,mob/user)
|
||||
return
|
||||
|
||||
/////////////
|
||||
// ZOOMING //
|
||||
/////////////
|
||||
|
||||
/datum/action/toggle_scope_zoom
|
||||
name = "Toggle Scope"
|
||||
check_flags = AB_CHECK_CONSCIOUS|AB_CHECK_HANDS_BLOCKED|AB_CHECK_IMMOBILE|AB_CHECK_LYING
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "sniper_zoom"
|
||||
var/obj/item/gun/gun = null
|
||||
|
||||
/datum/action/toggle_scope_zoom/Trigger()
|
||||
gun.zoom(owner, owner.dir)
|
||||
|
||||
/datum/action/toggle_scope_zoom/IsAvailable()
|
||||
. = ..()
|
||||
if(!. && gun)
|
||||
gun.zoom(owner, owner.dir, FALSE)
|
||||
|
||||
/datum/action/toggle_scope_zoom/Remove(mob/living/L)
|
||||
gun.zoom(L, L.dir, FALSE)
|
||||
..()
|
||||
|
||||
/obj/item/gun/proc/rotate(atom/thing, old_dir, new_dir)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(ismob(thing))
|
||||
var/mob/lad = thing
|
||||
lad.client.view_size.zoomOut(zoom_out_amt, zoom_amt, new_dir)
|
||||
|
||||
/obj/item/gun/proc/zoom(mob/living/user, direc, forced_zoom)
|
||||
if(!user || !user.client)
|
||||
return
|
||||
|
||||
if(isnull(forced_zoom))
|
||||
zoomed = !zoomed
|
||||
else
|
||||
zoomed = forced_zoom
|
||||
|
||||
if(zoomed)
|
||||
RegisterSignal(user, COMSIG_ATOM_DIR_CHANGE, .proc/rotate)
|
||||
user.client.view_size.zoomOut(zoom_out_amt, zoom_amt, direc)
|
||||
else
|
||||
UnregisterSignal(user, COMSIG_ATOM_DIR_CHANGE)
|
||||
user.client.view_size.zoomIn()
|
||||
return zoomed
|
||||
|
||||
//Proc, so that gun accessories/scopes/etc. can easily add zooming.
|
||||
/obj/item/gun/proc/build_zooming()
|
||||
if(azoom)
|
||||
return
|
||||
|
||||
if(zoomable)
|
||||
azoom = new()
|
||||
azoom.gun = src
|
||||
|
||||
#undef FIRING_PIN_REMOVAL_DELAY
|
||||
#undef DUALWIELD_PENALTY_EXTRA_MULTIPLIER
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 637 B |
@@ -48,7 +48,6 @@
|
||||
can_suppress = FALSE
|
||||
burst_size = 5
|
||||
spread = 3
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
mag_display = TRUE
|
||||
mag_display_ammo = TRUE
|
||||
realistic = TRUE
|
||||
@@ -86,7 +85,6 @@
|
||||
can_suppress = FALSE
|
||||
burst_size = 8
|
||||
spread = 5
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
mag_display = TRUE
|
||||
mag_display_ammo = FALSE
|
||||
realistic = TRUE
|
||||
|
||||
@@ -142,12 +142,12 @@
|
||||
|
||||
/obj/item/ammo_casing/energy/laser/accelerator
|
||||
fire_sound = 'modular_skyrat/modules/aesthetics/guns/sound/laser_cannon_fire.ogg'
|
||||
|
||||
|
||||
/obj/item/gun/ballistic/automatic/sniper_rifle
|
||||
icon = 'modular_skyrat/modules/aesthetics/guns/icons/guns_gubman2.dmi'
|
||||
icon_state = "sniper"
|
||||
fire_delay = 60
|
||||
|
||||
|
||||
/obj/item/gun/ballistic/automatic/sniper_rifle/syndicate
|
||||
icon = 'modular_skyrat/modules/aesthetics/guns/icons/guns_gubman2.dmi'
|
||||
icon_state = "sniper2"
|
||||
@@ -198,7 +198,7 @@
|
||||
zoom_amt = 10 //Long range, enough to see in front of you, but no tiles behind you.
|
||||
zoom_out_amt = 5
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
actions_types = list()
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC) //SKYRAT EDIT CHANGE
|
||||
mag_display = TRUE
|
||||
|
||||
/obj/item/gun/ballistic/automatic/ar/modular
|
||||
@@ -223,6 +223,6 @@
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
can_suppress = FALSE
|
||||
weapon_weight = WEAPON_HEAVY
|
||||
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator
|
||||
icon = 'modular_skyrat/modules/aesthetics/guns/icons/energy.dmi'
|
||||
|
||||
@@ -1,58 +1,3 @@
|
||||
//WATCH YOUR TRIGGER FINGER FRANK
|
||||
/obj/item/gun
|
||||
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
|
||||
var/datum/action/item_action/toggle_safety/tsafety
|
||||
|
||||
/obj/item/gun/Initialize()
|
||||
. = ..()
|
||||
if(has_gun_safety)
|
||||
safety = TRUE
|
||||
tsafety = new(src)
|
||||
|
||||
/obj/item/gun/Destroy()
|
||||
if(tsafety)
|
||||
QDEL_NULL(tsafety)
|
||||
return ..()
|
||||
|
||||
/datum/action/item_action/toggle_safety
|
||||
name = "Toggle Safety"
|
||||
icon_icon = 'modular_skyrat/modules/gunsafety/icons/hud/actions.dmi'
|
||||
button_icon_state = "safety_on"
|
||||
|
||||
/obj/item/gun/ui_action_click(mob/user, actiontype)
|
||||
if(istype(actiontype, tsafety))
|
||||
toggle_safety(user)
|
||||
else
|
||||
..()
|
||||
|
||||
/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
|
||||
tsafety.button_icon_state = "safety_[safety ? "on" : "off"]"
|
||||
tsafety.UpdateButtonIcon()
|
||||
playsound(src, 'sound/weapons/empty.ogg', 100, TRUE)
|
||||
user.visible_message("<span class='notice'>[user] toggles [src]'s safety [safety ? "<font color='#00ff15'>ON</font>" : "<font color='#ff0000'>OFF</font>"].",
|
||||
"<span class='notice'>You toggle [src]'s safety [safety ? "<font color='#00ff15'>ON</font>" : "<font color='#ff0000'>OFF</font>"].</span>")
|
||||
|
||||
/obj/item/gun/afterattack(atom/target, mob/living/user, flag, params)
|
||||
if(has_gun_safety)
|
||||
if(safety)
|
||||
to_chat(user, "<span class='warning'>The safety is on!</span>")
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span>The safety is [safety ? "<font color='#00ff15'>ON</font>" : "<font color='#ff0000'>OFF</font>"].</span>"
|
||||
|
||||
/obj/item/gun/ballistic
|
||||
has_gun_safety = TRUE
|
||||
|
||||
@@ -64,6 +9,6 @@
|
||||
|
||||
/obj/item/gun/energy/kinetic_accelerator/minebot
|
||||
has_gun_safety = FALSE
|
||||
|
||||
|
||||
/obj/item/gun/ballistic/rifle/enchanted
|
||||
has_gun_safety = FALSE
|
||||
|
||||
@@ -11,12 +11,19 @@
|
||||
var/durability = 100 //How used this gun is.
|
||||
var/durability_factor = 0.1 //How quickly a gun will degrade. 0.1 = 1000 shots. Edit this to change a guns base reliability.
|
||||
|
||||
|
||||
/obj/item/gun/ballistic/Initialize()
|
||||
. = ..()
|
||||
if(realistic)
|
||||
base_spread = spread
|
||||
|
||||
/obj/item/gun/ballistic/ComponentInitialize()
|
||||
. = ..()
|
||||
if(alt_icons)
|
||||
AddElement(/datum/element/update_icon_updates_onmob)
|
||||
|
||||
/obj/item/gun/ballistic/update_overlays()
|
||||
. = ..()
|
||||
if(alt_icons)
|
||||
if(!magazine)
|
||||
if(alt_icon_state)
|
||||
@@ -32,14 +39,6 @@
|
||||
else
|
||||
inhand_icon_state = "[initial(icon_state)]"
|
||||
worn_icon_state = "[initial(icon_state)]"
|
||||
. = ..()
|
||||
|
||||
//gun pickup message
|
||||
/obj/item/gun/pickup(mob/user)
|
||||
. = ..()
|
||||
if(w_class > WEIGHT_CLASS_SMALL && !suppressed)
|
||||
user.visible_message("<span class='warning'>[user] grabs <b>[src]</b>!</span>",
|
||||
"<span class='warning'>You grab [src]!</span>")
|
||||
|
||||
/obj/item/gun/ballistic/assault_rifle
|
||||
rack_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_cock.ogg'
|
||||
@@ -76,11 +75,6 @@
|
||||
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/smg_magout.ogg'
|
||||
eject_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/smg_magout.ogg'
|
||||
|
||||
/obj/item/gun/ballistic/ComponentInitialize()
|
||||
if(alt_icons)
|
||||
AddElement(/datum/element/update_icon_updates_onmob)
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/proc/jam(unjam = FALSE, mob/living/user)
|
||||
if(unjam && jammed != TRUE)
|
||||
unjam_time = clamp((jam_chance*10)/(durability/10), 0, 50)
|
||||
@@ -94,31 +88,11 @@
|
||||
to_chat(user, "<span class='notice'>You unjam the [src]'s bolt.</span>")
|
||||
playsound(src, 'sound/weapons/gun/l6/l6_rack.ogg', 60, TRUE)
|
||||
|
||||
/obj/item/gun/ballistic/can_shoot()
|
||||
if(realistic)
|
||||
if(jammed)
|
||||
return FALSE
|
||||
else
|
||||
. = ..()
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/process_burst(mob/living/user, atom/target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, iteration)
|
||||
if(realistic)
|
||||
if(jammed)
|
||||
firing_burst = FALSE
|
||||
return FALSE
|
||||
else
|
||||
. = ..()
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/process_fire()
|
||||
if(realistic)
|
||||
if(jammed)
|
||||
shoot_with_empty_chamber()
|
||||
return
|
||||
/obj/item/gun/ballistic/can_trigger_gun(mob/living/user)
|
||||
. = ..()
|
||||
if(realistic && jammed)
|
||||
to_chat(user, "<span class='warning'>[src] is jammed!</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/item/gun/ballistic/shoot_live_shot(mob/living/user, pointblank, atom/pbtarget, message)
|
||||
if(realistic)
|
||||
@@ -161,17 +135,6 @@
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params)
|
||||
if(realistic)
|
||||
if(jammed)
|
||||
to_chat(user, "<span class='warning'>[src] is jammed, unjam it before firing!</span>")
|
||||
return
|
||||
else
|
||||
. = ..()
|
||||
update_icon()
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/item/gun/ballistic/examine(mob/user)
|
||||
. = ..()
|
||||
if(realistic)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
fire_sound_volume = 70
|
||||
alt_icons = TRUE
|
||||
realistic = TRUE
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_BURST_SHOT, SELECT_FULLY_AUTOMATIC)
|
||||
|
||||
/obj/item/ammo_box/magazine/stg
|
||||
name = "stg magazine (7.92×33mm)"
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@
|
||||
fire_delay = 5
|
||||
can_suppress = FALSE
|
||||
burst_size = 0
|
||||
actions_types = list()
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC) //SKYRAT EDIT CHANGE
|
||||
mag_display = FALSE
|
||||
mag_display_ammo = FALSE
|
||||
empty_indicator = FALSE
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
burst_size = 3
|
||||
fire_delay = 1
|
||||
spread = 10
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
realistic = TRUE
|
||||
mag_display = FALSE
|
||||
mag_display_ammo = FALSE
|
||||
@@ -167,7 +166,6 @@
|
||||
burst_size = 3
|
||||
fire_delay = 1
|
||||
spread = 5
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
realistic = TRUE
|
||||
dirt_modifier = 0.1
|
||||
can_flashlight = TRUE
|
||||
@@ -391,7 +389,6 @@
|
||||
can_suppress = FALSE
|
||||
burst_size = 3
|
||||
spread = 10
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
can_bayonet = FALSE
|
||||
mag_display = TRUE
|
||||
mag_display_ammo = TRUE
|
||||
@@ -440,7 +437,6 @@
|
||||
burst_size = 3
|
||||
fire_delay = 3
|
||||
spread = 15
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
mag_display = TRUE
|
||||
mag_display_ammo = TRUE
|
||||
realistic = TRUE
|
||||
@@ -489,7 +485,6 @@
|
||||
fire_delay = 0.7
|
||||
can_suppress = FALSE
|
||||
burst_size = 4
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
mag_display = TRUE
|
||||
mag_display_ammo = TRUE
|
||||
realistic = TRUE
|
||||
@@ -538,7 +533,7 @@
|
||||
spread = 20
|
||||
mag_display = FALSE
|
||||
mag_display_ammo = FALSE
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_BURST_SHOT)
|
||||
realistic = TRUE
|
||||
dirt_modifier = 1.7
|
||||
emp_damageable = TRUE
|
||||
@@ -578,7 +573,7 @@
|
||||
mag_display_ammo = FALSE
|
||||
burst_size = 1
|
||||
fire_delay = 0
|
||||
actions_types = list()
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
|
||||
fire_sound = 'sound/weapons/gun/rifle/shot.ogg'
|
||||
rack_sound = 'sound/weapons/gun/smg/smgrack.ogg'
|
||||
lock_back_sound = 'sound/weapons/gun/pistol/slide_lock.ogg'
|
||||
@@ -641,6 +636,7 @@
|
||||
fire_sound = 'modular_skyrat/modules/sec_haul/sound/ltrifle_fire.ogg'
|
||||
emp_damageable = TRUE
|
||||
armadyne = TRUE
|
||||
fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_BURST_SHOT)
|
||||
|
||||
/obj/item/ammo_box/magazine/multi_sprite/norwind
|
||||
name = "norwind dmr magazine (12mm)"
|
||||
@@ -675,7 +671,6 @@
|
||||
inhand_icon_state = "vintorez"
|
||||
mag_type = /obj/item/ammo_box/magazine/multi_sprite/vintorez
|
||||
can_suppress = FALSE
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
can_bayonet = FALSE
|
||||
mag_display = FALSE
|
||||
mag_display_ammo = FALSE
|
||||
@@ -729,7 +724,6 @@
|
||||
fire_delay = 1.7
|
||||
can_suppress = FALSE
|
||||
burst_size = 3
|
||||
actions_types = list(/datum/action/item_action/toggle_firemode)
|
||||
can_bayonet = FALSE
|
||||
mag_display = TRUE
|
||||
mag_display_ammo = TRUE
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
#include "code\__DEFINES\~skyrat_defines\economy.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\examine_defines.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\faction.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\gun.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\integrated_electronics.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\inventory.dm"
|
||||
#include "code\__DEFINES\~skyrat_defines\jobs.dm"
|
||||
@@ -3492,6 +3493,7 @@
|
||||
#include "modular_skyrat\master_files\code\controllers\processing\circuit.dm"
|
||||
#include "modular_skyrat\master_files\code\controllers\subsystem\statpanel.dm"
|
||||
#include "modular_skyrat\master_files\code\datums\ert.dm"
|
||||
#include "modular_skyrat\master_files\code\datums\components\fullauto.dm"
|
||||
#include "modular_skyrat\master_files\code\datums\id_trim\jobs.dm"
|
||||
#include "modular_skyrat\master_files\code\datums\id_trim\syndicate.dm"
|
||||
#include "modular_skyrat\master_files\code\datums\martial\cqcplus.dm"
|
||||
@@ -3518,6 +3520,8 @@
|
||||
#include "modular_skyrat\master_files\code\modules\mob\living\carbon\carbon_say.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\mob\living\simple_animal\friendly\bumbles.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\power\lighting.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\projectiles\guns\gun.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\projectiles\guns\ballistic\automatic.dm"
|
||||
#include "modular_skyrat\master_files\code\modules\uplink\uplink_items.dm"
|
||||
#include "modular_skyrat\modules\3516\code\3516.dm"
|
||||
#include "modular_skyrat\modules\3516\code\bodypart_autosurgeon.dm"
|
||||
|
||||
Reference in New Issue
Block a user