From d44efadd67bdb4c571481e530b8ab5d141082749 Mon Sep 17 00:00:00 2001 From: Morrow Date: Fri, 13 Oct 2023 15:28:41 -0400 Subject: [PATCH] Smartgun IFF changes and buff! --- .../__DEFINES/dcs/signals/atom/signals_gun.dm | 31 ++++++++ .../dcs/signals/atom/signals_item.dm | 27 ------- code/modules/projectiles/ammo_datums.dm | 4 +- code/modules/projectiles/gun.dm | 68 +++++++++++------- code/modules/projectiles/guns/smartgun.dm | 59 +++++++++++++-- colonialmarines.dme | 1 + sound/weapons/smartgun_fail.ogg | Bin 0 -> 15723 bytes 7 files changed, 131 insertions(+), 59 deletions(-) create mode 100644 code/__DEFINES/dcs/signals/atom/signals_gun.dm create mode 100644 sound/weapons/smartgun_fail.ogg diff --git a/code/__DEFINES/dcs/signals/atom/signals_gun.dm b/code/__DEFINES/dcs/signals/atom/signals_gun.dm new file mode 100644 index 0000000000..51b8c25fce --- /dev/null +++ b/code/__DEFINES/dcs/signals/atom/signals_gun.dm @@ -0,0 +1,31 @@ +#define COMSIG_GUN_FIRE "gun_fire" +#define COMSIG_GUN_STOP_FIRE "gun_stop_fire" +#define COMSIG_GUN_FIRE_MODE_TOGGLE "gun_fire_mode_toggle" +#define COMSIG_GUN_AUTOFIREDELAY_MODIFIED "gun_autofiredelay_modified" +#define COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED "gun_burst_shots_to_fire_modified" +#define COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED "gun_burst_shot_delay_modified" + +#define COMSIG_GUN_VULTURE_FIRED_ONEHAND "gun_vulture_fired_onehand" +#define COMSIG_VULTURE_SCOPE_MOVED "vulture_scope_moved" +#define COMSIG_VULTURE_SCOPE_SCOPED "vulture_scope_scoped" +#define COMSIG_VULTURE_SCOPE_UNSCOPED "vulture_scope_unscoped" + +/// from /obj/item/weapon/gun/proc/recalculate_attachment_bonuses() : () +#define COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES "gun_recalculate_attachment_bonuses" + +/// from /obj/item/weapon/gun/proc/load_into_chamber() : () +#define COMSIG_GUN_INTERRUPT_FIRE "gun_interrupt_fire" + +//Signals for automatic fire at component +#define COMSIG_AUTOMATIC_SHOOTER_START_SHOOTING_AT "start_shooting_at" +#define COMSIG_AUTOMATIC_SHOOTER_STOP_SHOOTING_AT "stop_shooting_at" +#define COMSIG_AUTOMATIC_SHOOTER_SHOOT "shoot" + +//Signals for gun auto fire component +#define COMSIG_GET_BURST_FIRE "get_burst_fire" + #define BURST_FIRING (1<<0) + +/// Called before a gun fires a projectile, note NOT point blanks, /obj/item/weapon/gun/proc/handle_fire() +#define COMSIG_GUN_BEFORE_FIRE "gun_before_fire" + #define COMPONENT_CANCEL_GUN_BEFORE_FIRE (1<<0) //continue full-auto/burst attempts + #define COMPONENT_HARD_CANCEL_GUN_BEFORE_FIRE (1<<1) //hard stop firing diff --git a/code/__DEFINES/dcs/signals/atom/signals_item.dm b/code/__DEFINES/dcs/signals/atom/signals_item.dm index 6c31b77f76..9c2f3b92ba 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_item.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_item.dm @@ -38,30 +38,3 @@ #define COMSIG_ITEM_ZOOM "item_zoom" /// from /obj/item/proc/unzoom() : (mob/user) #define COMSIG_ITEM_UNZOOM "item_unzoom" - -//Signals for automatic fire at component -#define COMSIG_AUTOMATIC_SHOOTER_START_SHOOTING_AT "start_shooting_at" -#define COMSIG_AUTOMATIC_SHOOTER_STOP_SHOOTING_AT "stop_shooting_at" -#define COMSIG_AUTOMATIC_SHOOTER_SHOOT "shoot" - -//Signals for gun auto fire component -#define COMSIG_GET_BURST_FIRE "get_burst_fire" - #define BURST_FIRING (1<<0) - -#define COMSIG_GUN_FIRE "gun_fire" -#define COMSIG_GUN_STOP_FIRE "gun_stop_fire" -#define COMSIG_GUN_FIRE_MODE_TOGGLE "gun_fire_mode_toggle" -#define COMSIG_GUN_AUTOFIREDELAY_MODIFIED "gun_autofiredelay_modified" -#define COMSIG_GUN_BURST_SHOTS_TO_FIRE_MODIFIED "gun_burst_shots_to_fire_modified" -#define COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED "gun_burst_shot_delay_modified" - -#define COMSIG_GUN_VULTURE_FIRED_ONEHAND "gun_vulture_fired_onehand" -#define COMSIG_VULTURE_SCOPE_MOVED "vulture_scope_moved" -#define COMSIG_VULTURE_SCOPE_SCOPED "vulture_scope_scoped" -#define COMSIG_VULTURE_SCOPE_UNSCOPED "vulture_scope_unscoped" - -/// from /obj/item/weapon/gun/proc/recalculate_attachment_bonuses() : () -#define COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES "gun_recalculate_attachment_bonuses" - -/// from /obj/item/weapon/gun/proc/load_into_chamber() : () -#define COMSIG_GUN_INTERRUPT_FIRE "gun_interrupt_fire" diff --git a/code/modules/projectiles/ammo_datums.dm b/code/modules/projectiles/ammo_datums.dm index 783b982f10..a6f60281e8 100644 --- a/code/modules/projectiles/ammo_datums.dm +++ b/code/modules/projectiles/ammo_datums.dm @@ -1773,7 +1773,7 @@ max_range = 12 accuracy = HIT_ACCURACY_TIER_4 - damage = 30 + damage = 36 penetration = 0 /datum/ammo/bullet/smartgun/armor_piercing @@ -1782,7 +1782,7 @@ accurate_range = 12 accuracy = HIT_ACCURACY_TIER_2 - damage = 20 + damage = 24 penetration = ARMOR_PENETRATION_TIER_8 damage_armor_punch = 1 diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index e9ab9aecc3..35aed4c9c3 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1191,6 +1191,17 @@ and you're good to go. click_empty(user) return NONE + var/before_fire_cancel = SEND_SIGNAL(src, COMSIG_GUN_BEFORE_FIRE, projectile_to_fire, target, user) + + if(before_fire_cancel) + if(before_fire_cancel & COMPONENT_CANCEL_GUN_BEFORE_FIRE) + return TRUE + + if(before_fire_cancel & COMPONENT_HARD_CANCEL_GUN_BEFORE_FIRE) + return NONE + + play_firing_sounds(projectile_to_fire, user) + if(targloc != curloc) simulate_recoil(dual_wield, user, target) @@ -1410,6 +1421,8 @@ and you're good to go. user.track_shot(initial(name)) apply_bullet_effects(projectile_to_fire, user, bullets_fired, dual_wield) //We add any damage effects that we need. + play_firing_sounds(projectile_to_fire, user) + SEND_SIGNAL(projectile_to_fire, COMSIG_BULLET_USER_EFFECTS, user) SEND_SIGNAL(user, COMSIG_BULLET_DIRECT_HIT, attacked_mob) simulate_recoil(1, user) @@ -1610,12 +1623,6 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed //This proc applies some bonus effects to the shot/makes the message when a bullet is actually fired. /obj/item/weapon/gun/proc/apply_bullet_effects(obj/projectile/projectile_to_fire, mob/user, reflex = 0, dual_wield = 0) - var/actual_sound = fire_sound - if(isnull(fire_sound)) - actual_sound = pick(fire_sounds) - if(projectile_to_fire.ammo && projectile_to_fire.ammo.sound_override) - actual_sound = projectile_to_fire.ammo.sound_override - var/gun_accuracy_mult = accuracy_mult_unwielded var/gun_scatter = scatter_unwielded @@ -1666,26 +1673,39 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed projectile_to_fire.shot_from = src - if(user) //The gun only messages when fired by a user. - projectile_to_fire.firer = user - if(isliving(user)) projectile_to_fire.def_zone = user.zone_selected - //Guns with low ammo have their firing sound - var/firing_sndfreq = (current_mag && (current_mag.current_rounds / current_mag.max_rounds) > GUN_LOW_AMMO_PERCENTAGE) ? FALSE : SOUND_FREQ_HIGH - //firing from an attachment - if(active_attachable && active_attachable.flags_attach_features & ATTACH_PROJECTILE) - if(active_attachable.fire_sound) //If we're firing from an attachment, use that noise instead. - playsound(user, active_attachable.fire_sound, 50) - else - if(!(flags_gun_features & GUN_SILENCED)) - if (firing_sndfreq && fire_rattle) - playsound(user, fire_rattle, firesound_volume, FALSE)//if the gun has a unique 'mag rattle' SFX play that instead of pitch shifting. - else - playsound(user, actual_sound, firesound_volume, firing_sndfreq) - else - playsound(user, actual_sound, 25, firing_sndfreq) - return 1 +/obj/item/weapon/gun/proc/play_firing_sounds(obj/projectile/projectile_to_fire, mob/user) + if(!user) //The gun only messages when fired by a user. + return + + var/actual_sound = fire_sound + if(isnull(fire_sound)) + actual_sound = pick(fire_sounds) + + if(projectile_to_fire.ammo && projectile_to_fire.ammo.sound_override) + actual_sound = projectile_to_fire.ammo.sound_override + + projectile_to_fire.firer = user + if(isliving(user)) + projectile_to_fire.def_zone = user.zone_selected + + //Guns with low ammo have their firing sound + var/firing_sndfreq = (current_mag && (current_mag.current_rounds / current_mag.max_rounds) > GUN_LOW_AMMO_PERCENTAGE) ? FALSE : SOUND_FREQ_HIGH + + //firing from an attachment + if(active_attachable && active_attachable.flags_attach_features & ATTACH_PROJECTILE) + if(active_attachable.fire_sound) //If we're firing from an attachment, use that noise instead. + playsound(user, active_attachable.fire_sound, 50) + else + if(!(flags_gun_features & GUN_SILENCED)) + if (firing_sndfreq && fire_rattle) + playsound(user, fire_rattle, firesound_volume, FALSE)//if the gun has a unique 'mag rattle' SFX play that instead of pitch shifting. + else + playsound(user, actual_sound, firesound_volume, firing_sndfreq) + else + playsound(user, actual_sound, 25, firing_sndfreq) + /obj/item/weapon/gun/proc/simulate_scatter(obj/projectile/projectile_to_fire, atom/target, turf/curloc, turf/targloc, mob/user, bullets_fired = 1) var/fire_angle = Get_Angle(curloc, targloc) var/total_scatter_angle = projectile_to_fire.scatter diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index 830882add8..8c6ff50b30 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -28,15 +28,15 @@ ammo = /datum/ammo/bullet/smartgun actions_types = list( /datum/action/item_action/smartgun/toggle_accuracy_improvement, - ///datum/action/item_action/smartgun/toggle_ammo_type, + /datum/action/item_action/smartgun/toggle_ammo_type, /datum/action/item_action/smartgun/toggle_auto_fire, - ///datum/action/item_action/smartgun/toggle_lethal_mode, + /datum/action/item_action/smartgun/toggle_lethal_mode, ///datum/action/item_action/smartgun/toggle_motion_detector, /datum/action/item_action/smartgun/toggle_recoil_compensation, ) var/datum/ammo/ammo_primary = /datum/ammo/bullet/smartgun //Toggled ammo type var/datum/ammo/ammo_secondary = /datum/ammo/bullet/smartgun/armor_piercing //Toggled ammo type - var/iff_enabled = FALSE //Begin with the safety on. + var/iff_enabled = TRUE //Begin with the safety on. var/secondary_toggled = 0 //which ammo we use var/recoil_compensation = 0 var/accuracy_improvement = 0 @@ -51,6 +51,9 @@ var/recycletime = 120 var/cover_open = FALSE + /// Cooldown used for the delay on sound and to_chat() when IFF encounters a friendly target while trying to fire + COOLDOWN_DECLARE(iff_halt_cooldown) + unacidable = 1 indestructible = 1 @@ -106,6 +109,7 @@ LAZYADD(traits_to_give, list( BULLET_TRAIT_ENTRY_ID("iff", /datum/element/bullet_trait_iff) )) + RegisterSignal(src, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) /obj/item/weapon/gun/smartgun/get_examine_text(mob/user) . = ..() @@ -114,7 +118,7 @@ rounds = current_mag.current_rounds var/message = "[rounds ? "Ammo counter shows [rounds] round\s remaining." : "It's dry."]" . += message - //. += "The restriction system is [iff_enabled ? "on" : "off"]." + . += "The restriction system is [iff_enabled ? "on" : "off"]." if(battery && get_dist(user, src) <= 1) . += "A small gauge on [battery] reads: Power: [battery.power_cell.charge] / [battery.power_cell.maxcharge]." @@ -325,6 +329,47 @@ to_chat(H, SPAN_WARNING("You can't fire \the [src] with the feed cover open! (alt-click to close)")) return FALSE +#define SMARTGUN_IFF_RANGE_CHECK 7 +#define SMARTGUN_IFF_HALT_COOLDOWN (0.5 SECONDS) + +/obj/item/weapon/gun/smartgun/proc/check_firing_lane(obj/item/weapon/gun/smartgun/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) + SIGNAL_HANDLER + + var/angle = get_angle(user, target) + + var/range_to_check = SMARTGUN_IFF_RANGE_CHECK + + var/extended_target_turf = get_angle_target_turf(user, angle, range_to_check) + + var/turf/current_turf = get_turf(user) + + if(!current_turf || !extended_target_turf) + return COMPONENT_CANCEL_GUN_BEFORE_FIRE + + var/list/checked_turfs = getline2(current_turf, extended_target_turf) + + checked_turfs -= current_turf + + for(var/turf/checked_turf as anything in checked_turfs) + + //Wall, should block the bullet so we're good to stop checking. + if(istype(checked_turf, /turf/closed)) + return + + for(var/mob/living/checked_living in checked_turf) + if(!checked_living.lying && checked_living.get_target_lock(user.faction_group)) + if(COOLDOWN_FINISHED(src, iff_halt_cooldown)) + playsound_client(user.client, 'sound/weapons/smartgun_fail.ogg', src, 25) + to_chat(user, SPAN_WARNING("[src] halts firing as an IFF marked target crosses your field of fire!")) + COOLDOWN_START(src, iff_halt_cooldown, SMARTGUN_IFF_HALT_COOLDOWN) + + return COMPONENT_CANCEL_GUN_BEFORE_FIRE + + return //if we have a target we *can* hit and find it before any IFF targets we want to fire + +#undef SMARTGUN_IFF_RANGE_CHECK +#undef SMARTGUN_IFF_HALT_COOLDOWN + /obj/item/weapon/gun/smartgun/unique_action(mob/user) if(isobserver(usr) || isxeno(usr)) return @@ -353,10 +398,12 @@ secondary_toggled = FALSE if(iff_enabled) add_bullet_trait(BULLET_TRAIT_ENTRY_ID("iff", /datum/element/bullet_trait_iff)) + RegisterSignal(src, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) drain += 10 MD.iff_signal = initial(MD.iff_signal) if(!iff_enabled) remove_bullet_trait("iff") + UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) drain -= 10 MD.iff_signal = null @@ -654,8 +701,8 @@ . += SPAN_NOTICE("It is registered to [linked_human] but has its fire restrictions unlocked.") else . += SPAN_NOTICE("It's unregistered. Pick it up to register yourself as its owner.") -// if(!iff_enabled) -// . += SPAN_WARNING("Its IFF restrictions are disabled.") + if(!iff_enabled) + . += SPAN_WARNING("Its IFF restrictions are disabled.") /obj/item/weapon/gun/smartgun/co/proc/remove_idlock() SIGNAL_HANDLER diff --git a/colonialmarines.dme b/colonialmarines.dme index 890a339b19..87b0abd4db 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -123,6 +123,7 @@ s// DM Environment file for colonialmarines.dme. #include "code\__DEFINES\dcs\signals\signals_global.dm" #include "code\__DEFINES\dcs\signals\signals_subsystem.dm" #include "code\__DEFINES\dcs\signals\atom\signals_atom.dm" +#include "code\__DEFINES\dcs\signals\atom\signals_gun.dm" #include "code\__DEFINES\dcs\signals\atom\signals_item.dm" #include "code\__DEFINES\dcs\signals\atom\signals_movable.dm" #include "code\__DEFINES\dcs\signals\atom\signals_obj.dm" diff --git a/sound/weapons/smartgun_fail.ogg b/sound/weapons/smartgun_fail.ogg new file mode 100644 index 0000000000000000000000000000000000000000..2d33cf7d132495ed7117405b7ac498e652dad5b5 GIT binary patch literal 15723 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�Nq-Y5Tc=f6bAD8^NdNSq} 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