From 332c096423d420dc26ea0d19903e9d5a8bfefbc7 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Tue, 17 Oct 2023 13:47:46 +0300 Subject: [PATCH 01/31] 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 | 48 ++++++++++++- colonialmarines.dme | 1 + sound/weapons/smartgun_fail.ogg | Bin 0 -> 15723 bytes 7 files changed, 125 insertions(+), 54 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 000000000000..51b8c25fce7e --- /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 6c31b77f76a4..9c2f3b92ba05 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 783b982f10bd..a6f60281e804 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 e9ab9aecc3c2..35aed4c9c36c 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 22f10cafb35b..a32ac36e38c4 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -31,7 +31,6 @@ /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_motion_detector, /datum/action/item_action/smartgun/toggle_recoil_compensation, ) var/datum/ammo/ammo_primary = /datum/ammo/bullet/smartgun //Toggled ammo type @@ -51,6 +50,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 +108,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) . = ..() @@ -325,6 +328,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 +397,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 diff --git a/colonialmarines.dme b/colonialmarines.dme index 63140be5e458..d8b72a50a1d4 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -122,6 +122,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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 Date: Fri, 13 Oct 2023 16:31:08 -0400 Subject: [PATCH 02/31] Smartgun IFF weird fixes --- code/modules/projectiles/guns/smartgun.dm | 29 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index a32ac36e38c4..be465f88777b 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -340,14 +340,30 @@ var/extended_target_turf = get_angle_target_turf(user, angle, range_to_check) - var/turf/current_turf = get_turf(user) + var/turf/user_turf = get_turf(user) - if(!current_turf || !extended_target_turf) + if(!user_turf || !extended_target_turf) return COMPONENT_CANCEL_GUN_BEFORE_FIRE - var/list/checked_turfs = getline2(current_turf, extended_target_turf) + var/list/checked_turfs = getline2(user_turf, extended_target_turf) - checked_turfs -= current_turf + checked_turfs -= user_turf + + //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user + //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise + if(projectile_to_fire.original) + var/turf/original_target_turf = get_turf(projectile_to_fire.original) + + if(original_target_turf && !(original_target_turf in checked_turfs)) + var/user_to_target_dist = get_dist(user_turf, original_target_turf) + var/list/temp_checked_turfs = checked_turfs + checked_turfs = list() + + for(var/turf/checked_turf as anything in temp_checked_turfs) + if(!(original_target_turf in checked_turfs) && user_to_target_dist < get_dist(user_turf, checked_turf)) + checked_turfs += original_target_turf + + checked_turfs += checked_turf for(var/turf/checked_turf as anything in checked_turfs) @@ -356,7 +372,10 @@ return for(var/mob/living/checked_living in checked_turf) - if(!checked_living.lying && checked_living.get_target_lock(user.faction_group)) + if(checked_living.lying && projectile_to_fire.original != checked_living) + continue + + if(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!")) From 95764fe7a109f557f612dc067ef82e7ce9e9c81d Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Wed, 18 Oct 2023 14:05:49 +0300 Subject: [PATCH 03/31] test --- code/modules/projectiles/gun.dm | 59 +++++++++++++++++++ code/modules/projectiles/gun_attachables.dm | 65 ++++++++++++--------- code/modules/projectiles/guns/rifles.dm | 2 + code/modules/projectiles/guns/smartgun.dm | 63 -------------------- 4 files changed, 99 insertions(+), 90 deletions(-) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 35aed4c9c36c..0edc051ba3c7 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -233,6 +233,10 @@ var/projectile_type = /obj/projectile /// The multiplier for how much slower this should fire in automatic mode. 1 is normal, 1.2 is 20% slower, 2 is 100% slower, etc. Protected due to it never needing to be edited. VAR_PROTECTED/autofire_slow_mult = 1 + /// IFF stuff, if enabled, range in which we check targets and firedelay if there are friendlies + COOLDOWN_DECLARE(iff_halt_cooldown) + var/iff_range = 7 + var/iff_cooldown = 0.5 SECONDS /** @@ -1984,3 +1988,58 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed /// Getter for gun_user /obj/item/weapon/gun/proc/get_gun_user() return gun_user + +/obj/item/weapon/gun/proc/check_firing_lane(obj/projectile/projectile_to_fire, atom/target, mob/living/user) + SIGNAL_HANDLER + + var/angle = get_angle(user, target) + + var/range_to_check = iff_range + var/cooldown = iff_cooldown + + var/extended_target_turf = get_angle_target_turf(user, angle, range_to_check) + + var/turf/user_turf = get_turf(user) + + if(!user_turf || !extended_target_turf) + return COMPONENT_CANCEL_GUN_BEFORE_FIRE + + var/list/checked_turfs = getline2(extended_target_turf, user_turf) + + checked_turfs -= user_turf + + //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user + //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise + if(projectile_to_fire.original) + var/turf/original_target_turf = get_turf(projectile_to_fire.original) + + if(original_target_turf && !(original_target_turf in checked_turfs)) + var/user_to_target_dist = get_dist(user_turf, original_target_turf) + var/list/temp_checked_turfs = checked_turfs + checked_turfs = list() + + for(var/turf/checked_turf as anything in temp_checked_turfs) + if(!(original_target_turf in checked_turfs) && user_to_target_dist < get_dist(user_turf, checked_turf)) + checked_turfs += original_target_turf + + checked_turfs += checked_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 && projectile_to_fire.original != checked_living) + continue + + if(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, 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 diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm index 20781639a579..88273f8fc972 100644 --- a/code/modules/projectiles/gun_attachables.dm +++ b/code/modules/projectiles/gun_attachables.dm @@ -121,7 +121,7 @@ Defined in conflicts.dm of the #defines folder. */ if(G.attachments[slot]) var/obj/item/attachable/A = G.attachments[slot] - A.Detach(detaching_gub = G) + A.Detach(detaching_gun = G) if(ishuman(loc)) var/mob/living/carbon/human/M = src.loc @@ -165,32 +165,32 @@ Defined in conflicts.dm of the #defines folder. // Apply bullet traits from attachment to gun's current projectile G.in_chamber.apply_bullet_trait(L) -/obj/item/attachable/proc/Detach(mob/user, obj/item/weapon/gun/detaching_gub) - if(!istype(detaching_gub)) return //Guns only +/obj/item/attachable/proc/Detach(mob/user, obj/item/weapon/gun/detaching_gun) + if(!istype(detaching_gun)) return //Guns only - detaching_gub.on_detach(user) + detaching_gun.on_detach(user) if(flags_attach_features & ATTACH_ACTIVATION) - activate_attachment(detaching_gub, null, TRUE) + activate_attachment(detaching_gun, null, TRUE) - detaching_gub.attachments[slot] = null - detaching_gub.recalculate_attachment_bonuses() + detaching_gun.attachments[slot] = null + detaching_gun.recalculate_attachment_bonuses() - for(var/X in detaching_gub.actions) + for(var/X in detaching_gun.actions) var/datum/action/DA = X if(DA.target == src) qdel(X) break - forceMove(get_turf(detaching_gub)) + forceMove(get_turf(detaching_gun)) if(sharp) - detaching_gub.sharp = 0 + detaching_gun.sharp = 0 for(var/trait in gun_traits) - REMOVE_TRAIT(detaching_gub, trait, TRAIT_SOURCE_ATTACHMENT(slot)) + REMOVE_TRAIT(detaching_gun, trait, TRAIT_SOURCE_ATTACHMENT(slot)) for(var/entry in traits_to_give) - if(!detaching_gub.in_chamber) + if(!detaching_gun.in_chamber) break var/list/L if(istext(entry)) @@ -198,7 +198,7 @@ Defined in conflicts.dm of the #defines folder. else L = list(entry) + traits_to_give[entry] // Remove bullet traits of attachment from gun's current projectile - detaching_gub.in_chamber._RemoveElement(L) + detaching_gun.in_chamber._RemoveElement(L) /obj/item/attachable/ui_action_click(mob/living/user, obj/item/weapon/gun/G) activate_attachment(G, user) @@ -556,9 +556,9 @@ Defined in conflicts.dm of the #defines folder. ..() G.attachable_offset["muzzle_x"] = 27 -/obj/item/attachable/mateba/Detach(mob/user, obj/item/weapon/gun/detaching_gub) +/obj/item/attachable/mateba/Detach(mob/user, obj/item/weapon/gun/detaching_gun) ..() - detaching_gub.attachable_offset["muzzle_x"] = 20 + detaching_gun.attachable_offset["muzzle_x"] = 20 /obj/item/attachable/mateba/dark icon_state = "mateba_medium_a" @@ -847,9 +847,9 @@ Defined in conflicts.dm of the #defines folder. . = ..() G.AddElement(/datum/element/drop_retrieval/gun, retrieval_slot) -/obj/item/attachable/magnetic_harness/Detach(mob/user, obj/item/weapon/gun/detaching_gub) +/obj/item/attachable/magnetic_harness/Detach(mob/user, obj/item/weapon/gun/detaching_gun) . = ..() - detaching_gub.RemoveElement(/datum/element/drop_retrieval/gun, retrieval_slot) + detaching_gun.RemoveElement(/datum/element/drop_retrieval/gun, retrieval_slot) /obj/item/attachable/magnetic_harness/lever_sling name = "R4T magnetic sling" //please don't make this attachable to any other guns... @@ -871,10 +871,10 @@ Defined in conflicts.dm of the #defines folder. G.attachable_offset["under_y"] = 12 -/obj/item/attachable/magnetic_harness/lever_sling/Detach(mob/user, obj/item/weapon/gun/detaching_gub) +/obj/item/attachable/magnetic_harness/lever_sling/Detach(mob/user, obj/item/weapon/gun/detaching_gun) . = ..() - detaching_gub.attachable_offset["under_x"] = 24 - detaching_gub.attachable_offset["under_y"] = 16 + detaching_gun.attachable_offset["under_x"] = 24 + detaching_gun.attachable_offset["under_y"] = 16 /obj/item/attachable/magnetic_harness/lever_sling/select_gamemode_skin(expected_type, list/override_icon_state, list/override_protection) . = ..() @@ -923,9 +923,9 @@ Defined in conflicts.dm of the #defines folder. . = ..() RegisterSignal(gun, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES, PROC_REF(handle_attachment_recalc)) -/obj/item/attachable/scope/Detach(mob/user, obj/item/weapon/gun/detaching_gub) +/obj/item/attachable/scope/Detach(mob/user, obj/item/weapon/gun/detaching_gun) . = ..() - UnregisterSignal(detaching_gub, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES) + UnregisterSignal(detaching_gun, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES) /// Due to the bipod's interesting way of handling stat modifications, this is necessary to prevent exploits. @@ -1167,11 +1167,22 @@ Defined in conflicts.dm of the #defines folder. . = ..() if(G.zoom) G.slowdown += dynamic_aim_slowdown + G.iff_range = 13 /obj/item/attachable/scope/mini_iff/remove_scoped_buff(mob/living/carbon/user, obj/item/weapon/gun/G) G.slowdown -= dynamic_aim_slowdown + G.iff_range = 7 ..() +/obj/item/attachable/scope/mini_iff/Attach(obj/item/weapon/gun/gun) + . = ..() + RegisterSignal(gun, COMSIG_GUN_BEFORE_FIRE, TYPE_PROC_REF(/obj/item/weapon/gun, check_firing_lane)) + + +/obj/item/attachable/scope/mini_iff/Detach(mob/user, obj/item/weapon/gun/detaching_gun) + . = ..() + UnregisterSignal(detaching_gun, COMSIG_GUN_BEFORE_FIRE) + /obj/item/attachable/scope/slavic icon_state = "slavicscope" attach_icon = "slavicscope" @@ -2533,9 +2544,9 @@ Defined in conflicts.dm of the #defines folder. R.flags_equip_slot &= ~SLOT_WAIST //Can't wear it on the belt slot with stock on when we attach it first time. // When taking it off we want to undo everything not statwise -/obj/item/attachable/stock/revolver/Detach(mob/user, obj/item/weapon/gun/detaching_gub) +/obj/item/attachable/stock/revolver/Detach(mob/user, obj/item/weapon/gun/detaching_gun) ..() - var/obj/item/weapon/gun/revolver/m44/R = detaching_gub + var/obj/item/weapon/gun/revolver/m44/R = detaching_gun if(!istype(R)) return 0 @@ -3260,11 +3271,11 @@ Defined in conflicts.dm of the #defines folder. RegisterSignal(G, COMSIG_ITEM_DROPPED, PROC_REF(handle_drop)) -/obj/item/attachable/bipod/Detach(mob/user, obj/item/weapon/gun/detaching_gub) - UnregisterSignal(detaching_gub, COMSIG_ITEM_DROPPED) +/obj/item/attachable/bipod/Detach(mob/user, obj/item/weapon/gun/detaching_gun) + UnregisterSignal(detaching_gun, COMSIG_ITEM_DROPPED) if(bipod_deployed) - undeploy_bipod(detaching_gub) + undeploy_bipod(detaching_gun) ..() /obj/item/attachable/bipod/update_icon() diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm index 65e4a6f2b7b3..6c9eb4aa3baf 100644 --- a/code/modules/projectiles/guns/rifles.dm +++ b/code/modules/projectiles/guns/rifles.dm @@ -630,8 +630,10 @@ recalculate_attachment_bonuses() 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)) else remove_bullet_trait("iff") + UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) /obj/item/weapon/gun/rifle/m46c/recalculate_attachment_bonuses() . = ..() diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index be465f88777b..f2c25b22142b 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -50,9 +50,6 @@ 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 @@ -328,66 +325,6 @@ 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/user_turf = get_turf(user) - - if(!user_turf || !extended_target_turf) - return COMPONENT_CANCEL_GUN_BEFORE_FIRE - - var/list/checked_turfs = getline2(user_turf, extended_target_turf) - - checked_turfs -= user_turf - - //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user - //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise - if(projectile_to_fire.original) - var/turf/original_target_turf = get_turf(projectile_to_fire.original) - - if(original_target_turf && !(original_target_turf in checked_turfs)) - var/user_to_target_dist = get_dist(user_turf, original_target_turf) - var/list/temp_checked_turfs = checked_turfs - checked_turfs = list() - - for(var/turf/checked_turf as anything in temp_checked_turfs) - if(!(original_target_turf in checked_turfs) && user_to_target_dist < get_dist(user_turf, checked_turf)) - checked_turfs += original_target_turf - - checked_turfs += checked_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 && projectile_to_fire.original != checked_living) - continue - - if(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 From 7062da8d122c01931d1a6be33e2a2f32125297e8 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Wed, 18 Oct 2023 14:25:36 +0300 Subject: [PATCH 04/31] oops --- code/modules/projectiles/gun.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 0edc051ba3c7..1784ffa42f4e 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1989,7 +1989,7 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed /obj/item/weapon/gun/proc/get_gun_user() return gun_user -/obj/item/weapon/gun/proc/check_firing_lane(obj/projectile/projectile_to_fire, atom/target, mob/living/user) +/obj/item/weapon/gun/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) From ee43ac2d530238834a50e4ea05bec58c13bc51d5 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Wed, 18 Oct 2023 14:27:03 +0300 Subject: [PATCH 05/31] bruh --- code/modules/projectiles/gun.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 1784ffa42f4e..feed837b8eaf 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1989,7 +1989,7 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed /obj/item/weapon/gun/proc/get_gun_user() return gun_user -/obj/item/weapon/gun/proc/check_firing_lane(obj/item/weapon/gun/smartgun/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) +/obj/item/weapon/gun/proc/check_firing_lane(obj/item/weapon/gun/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) SIGNAL_HANDLER var/angle = get_angle(user, target) From 2fca683f9c10b56255d7875244c54e2301165d6d Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Wed, 18 Oct 2023 15:08:26 +0300 Subject: [PATCH 06/31] ok --- code/modules/cm_marines/smartgun_mount.dm | 60 +++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/code/modules/cm_marines/smartgun_mount.dm b/code/modules/cm_marines/smartgun_mount.dm index 5fa83d1fa06b..0ef1526ce328 100644 --- a/code/modules/cm_marines/smartgun_mount.dm +++ b/code/modules/cm_marines/smartgun_mount.dm @@ -483,6 +483,7 @@ var/shoot_degree = 80 /// Semi auto cooldown COOLDOWN_DECLARE(semiauto_fire_cooldown) + COOLDOWN_DECLARE(iff_halt_cooldown) /// How long between semi-auto shots this should wait, to reduce possible spam var/semiauto_cooldown_time = 0.2 SECONDS @@ -516,6 +517,7 @@ update_icon() AddComponent(/datum/component/automatedfire/autofire, fire_delay, burst_fire_delay, burst_amount, gun_firemode, autofire_slow_mult, CALLBACK(src, PROC_REF(set_burst_firing)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(try_fire)), CALLBACK(src, PROC_REF(display_ammo)), CALLBACK(src, PROC_REF(set_auto_firing))) + /obj/structure/machinery/m56d_hmg/Destroy() //Make sure we pick up our trash. if(operator) operator.unset_interaction() @@ -724,6 +726,15 @@ final_angle += rand(-total_scatter_angle, total_scatter_angle) target = get_angle_target_turf(T, final_angle, 30) + var/before_fire_cancel = SEND_SIGNAL(src, COMSIG_GUN_BEFORE_FIRE, target, operator) + + if(before_fire_cancel) + if(before_fire_cancel & COMPONENT_CANCEL_GUN_BEFORE_FIRE) + return AUTOFIRE_CONTINUE + + if(before_fire_cancel & COMPONENT_HARD_CANCEL_GUN_BEFORE_FIRE) + return + in_chamber.weapon_cause_data = create_cause_data(initial(name), operator) in_chamber.setDir(dir) in_chamber.def_zone = pick("chest","chest","chest","head") @@ -839,6 +850,7 @@ /obj/structure/machinery/m56d_hmg/on_set_interaction(mob/user) RegisterSignal(user, list(COMSIG_MOB_MG_EXIT, COMSIG_MOB_RESISTED, COMSIG_MOB_DEATH, COMSIG_MOB_KNOCKED_DOWN), PROC_REF(exit_interaction)) + RegisterSignal(src, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) flags_atom |= RELAY_CLICK user.status_flags |= IMMOBILE_ACTION user.visible_message(SPAN_NOTICE("[user] mans \the [src]."),SPAN_NOTICE("You man \the [src], locked and loaded!")) @@ -859,6 +871,7 @@ user.visible_message(SPAN_NOTICE("[user] lets go of \the [src]."),SPAN_NOTICE("You let go of \the [src], letting the gun rest.")) user.unfreeze() UnregisterSignal(user, list(COMSIG_MOB_MOUSEUP, COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEDRAG)) + UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) user.reset_view(null) user.remove_temp_pass_flags(PASS_MOB_THRU) // this is necessary because being knocked over while using the gun makes you incorporeal user.Move(get_step(src, reverse_direction(src.dir))) @@ -1102,3 +1115,50 @@ deployment_system.deployed_mg = null deployment_system = null return ..() + +/obj/structure/machinery/m56d_hmg/proc/check_firing_lane(obj/structure/machinery/m56d_hmg/m56d, atom/target, mob/living/user) + SIGNAL_HANDLER + log_debug("TEST") + var/angle = get_angle(src, target) + + var/range_to_check = 9 + var/cooldown = 0.5 + + var/extended_target_turf = get_angle_target_turf(src, angle, range_to_check) + + var/turf/m56d_turf = get_turf(src) + + if(!m56d_turf || !extended_target_turf) + log_debug("CANCEL") + return COMPONENT_CANCEL_GUN_BEFORE_FIRE + + var/list/checked_turfs = getline2(extended_target_turf, m56d_turf) + + checked_turfs -= m56d_turf + + var/i = 0 + for(var/turf/checked_turf as anything in checked_turfs) + i++ + log_debug("[i]") + //Wall, should block the bullet so we're good to stop checking. + if(istype(checked_turf, /turf/closed)) + log_debug("wall?") + return + + for(var/mob/living/checked_living in checked_turf) + log_debug("[checked_living]") + + if(checked_living.lying && target != checked_living) + log_debug("skip") + continue + + if(checked_living.get_target_lock(user.faction_group)) + log_debug("same faction!") + 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, cooldown) + log_debug("CANCEL") + 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 From 1dcf38a67ee8c056ba5de5663d0d330741d651b6 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 12:24:51 +0300 Subject: [PATCH 07/31] almost there --- code/_onclick/hud/fullscreen.dm | 7 ++ code/datums/components/iff_fire_prevention.dm | 88 +++++++++++++++++++ code/modules/cm_marines/smartgun_mount.dm | 57 +----------- code/modules/projectiles/ammo_datums.dm | 4 +- code/modules/projectiles/gun.dm | 60 ------------- code/modules/projectiles/gun_attachables.dm | 9 +- code/modules/projectiles/guns/pistols.dm | 1 + code/modules/projectiles/guns/rifles.dm | 4 +- code/modules/projectiles/guns/smartgun.dm | 6 +- colonialmarines.dme | 1 + 10 files changed, 111 insertions(+), 126 deletions(-) create mode 100644 code/datums/components/iff_fire_prevention.dm diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index 0bd2206091ba..c8947e206256 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -61,6 +61,13 @@ else client.remove_from_screen(screen) +//Get the distance to the farthest edge of the screen +/mob/proc/get_maximum_view_range() + if(!client) + return 7 + + var/offset = client.pixel_x || client.pixel_y + return client.view + abs(offset / 32) /atom/movable/screen/fullscreen icon = 'icons/mob/hud/screen1_full.dmi' diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm new file mode 100644 index 000000000000..55db97bf348a --- /dev/null +++ b/code/datums/components/iff_fire_prevention.dm @@ -0,0 +1,88 @@ +#define IFF_HALT_COOLDOWN 0.5 SECONDS + +/datum/component/iff_fire_prevention + var/obj/parent_gun + var/iff_additional_fire_delay + COOLDOWN_DECLARE(iff_halt_cooldown) + +/datum/component/iff_fire_prevention/Initialize(additional_fire_delay = 0) + . = ..() + parent_gun = parent + iff_additional_fire_delay = additional_fire_delay + + +/datum/component/iff_fire_prevention/RegisterWithParent() + . = ..() + RegisterSignal(parent_gun, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) + +/datum/component/iff_fire_prevention/UnregisterFromParent() + . = ..() + UnregisterSignal(parent_gun, COMSIG_GUN_BEFORE_FIRE) + +/datum/component/iff_fire_prevention/Destroy(force, silent) + handle_qdel() + . = ..() + +/datum/component/iff_fire_prevention/proc/handle_qdel() + SIGNAL_HANDLER + parent_gun = null + +/datum/component/iff_fire_prevention/proc/check_firing_lane(obj/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) + SIGNAL_HANDLER + + var/angle = get_angle(user, target) + + var/range_to_check = user.get_maximum_view_range() + + var/extended_target_turf = get_angle_target_turf(user, angle, range_to_check) + + + var/turf/starting_turf = get_turf(user) + + if(!starting_turf || !extended_target_turf) + return COMPONENT_CANCEL_GUN_BEFORE_FIRE + + var/list/checked_turfs = getline2(starting_turf, extended_target_turf) + + checked_turfs -= starting_turf + + //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user + //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise + if(projectile_to_fire.original) + var/turf/original_target_turf = get_turf(projectile_to_fire.original) + + if(original_target_turf && !(original_target_turf in checked_turfs)) + var/user_to_target_dist = get_dist(starting_turf, original_target_turf) + var/list/temp_checked_turfs = checked_turfs + checked_turfs = list() + + for(var/turf/checked_turf as anything in temp_checked_turfs) + if(!(original_target_turf in checked_turfs) && user_to_target_dist < get_dist(starting_turf, checked_turf)) + checked_turfs += original_target_turf + + checked_turfs += checked_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 && projectile_to_fire.original != checked_living) + continue + + if(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("[firing_weapon] halts firing as an IFF marked target crosses your field of fire!")) + COOLDOWN_START(src, iff_halt_cooldown, IFF_HALT_COOLDOWN) + if(iff_additional_fire_delay) + var/obj/item/weapon/gun/gun = firing_weapon + if(istype(gun)) + gun.modify_fire_delay(iff_additional_fire_delay) + 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 IFF_HALT_COOLDOWN diff --git a/code/modules/cm_marines/smartgun_mount.dm b/code/modules/cm_marines/smartgun_mount.dm index 0ef1526ce328..e4c486449431 100644 --- a/code/modules/cm_marines/smartgun_mount.dm +++ b/code/modules/cm_marines/smartgun_mount.dm @@ -456,9 +456,9 @@ var/user_old_y = 0 /// How much time should pass in between full auto shots, slightly higher than burst due to click delay and similar things that slow firing down - var/fire_delay = 0.3 SECONDS + var/fire_delay = 0.25 SECONDS /// How much time should pass in between burst fire shots - var/burst_fire_delay = 0.2 SECONDS + var/burst_fire_delay = 0.175 SECONDS /// How many rounds are fired per burst var/burst_amount = 3 /// How many rounds have been fired in the current burst/auto @@ -483,7 +483,6 @@ var/shoot_degree = 80 /// Semi auto cooldown COOLDOWN_DECLARE(semiauto_fire_cooldown) - COOLDOWN_DECLARE(iff_halt_cooldown) /// How long between semi-auto shots this should wait, to reduce possible spam var/semiauto_cooldown_time = 0.2 SECONDS @@ -516,6 +515,7 @@ burst_scatter_mult = SCATTER_AMOUNT_TIER_7 update_icon() AddComponent(/datum/component/automatedfire/autofire, fire_delay, burst_fire_delay, burst_amount, gun_firemode, autofire_slow_mult, CALLBACK(src, PROC_REF(set_burst_firing)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(try_fire)), CALLBACK(src, PROC_REF(display_ammo)), CALLBACK(src, PROC_REF(set_auto_firing))) + AddComponent(/datum/component/iff_fire_prevention) /obj/structure/machinery/m56d_hmg/Destroy() //Make sure we pick up our trash. @@ -726,7 +726,7 @@ final_angle += rand(-total_scatter_angle, total_scatter_angle) target = get_angle_target_turf(T, final_angle, 30) - var/before_fire_cancel = SEND_SIGNAL(src, COMSIG_GUN_BEFORE_FIRE, target, operator) + var/before_fire_cancel = SEND_SIGNAL(src, COMSIG_GUN_BEFORE_FIRE, in_chamber, target, operator) if(before_fire_cancel) if(before_fire_cancel & COMPONENT_CANCEL_GUN_BEFORE_FIRE) @@ -850,7 +850,6 @@ /obj/structure/machinery/m56d_hmg/on_set_interaction(mob/user) RegisterSignal(user, list(COMSIG_MOB_MG_EXIT, COMSIG_MOB_RESISTED, COMSIG_MOB_DEATH, COMSIG_MOB_KNOCKED_DOWN), PROC_REF(exit_interaction)) - RegisterSignal(src, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) flags_atom |= RELAY_CLICK user.status_flags |= IMMOBILE_ACTION user.visible_message(SPAN_NOTICE("[user] mans \the [src]."),SPAN_NOTICE("You man \the [src], locked and loaded!")) @@ -871,7 +870,6 @@ user.visible_message(SPAN_NOTICE("[user] lets go of \the [src]."),SPAN_NOTICE("You let go of \the [src], letting the gun rest.")) user.unfreeze() UnregisterSignal(user, list(COMSIG_MOB_MOUSEUP, COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEDRAG)) - UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) user.reset_view(null) user.remove_temp_pass_flags(PASS_MOB_THRU) // this is necessary because being knocked over while using the gun makes you incorporeal user.Move(get_step(src, reverse_direction(src.dir))) @@ -1115,50 +1113,3 @@ deployment_system.deployed_mg = null deployment_system = null return ..() - -/obj/structure/machinery/m56d_hmg/proc/check_firing_lane(obj/structure/machinery/m56d_hmg/m56d, atom/target, mob/living/user) - SIGNAL_HANDLER - log_debug("TEST") - var/angle = get_angle(src, target) - - var/range_to_check = 9 - var/cooldown = 0.5 - - var/extended_target_turf = get_angle_target_turf(src, angle, range_to_check) - - var/turf/m56d_turf = get_turf(src) - - if(!m56d_turf || !extended_target_turf) - log_debug("CANCEL") - return COMPONENT_CANCEL_GUN_BEFORE_FIRE - - var/list/checked_turfs = getline2(extended_target_turf, m56d_turf) - - checked_turfs -= m56d_turf - - var/i = 0 - for(var/turf/checked_turf as anything in checked_turfs) - i++ - log_debug("[i]") - //Wall, should block the bullet so we're good to stop checking. - if(istype(checked_turf, /turf/closed)) - log_debug("wall?") - return - - for(var/mob/living/checked_living in checked_turf) - log_debug("[checked_living]") - - if(checked_living.lying && target != checked_living) - log_debug("skip") - continue - - if(checked_living.get_target_lock(user.faction_group)) - log_debug("same faction!") - 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, cooldown) - log_debug("CANCEL") - 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 diff --git a/code/modules/projectiles/ammo_datums.dm b/code/modules/projectiles/ammo_datums.dm index a6f60281e804..da51d43baba6 100644 --- a/code/modules/projectiles/ammo_datums.dm +++ b/code/modules/projectiles/ammo_datums.dm @@ -547,7 +547,7 @@ flags_ammo_behavior = AMMO_BALLISTIC accuracy = HIT_ACCURACY_TIER_8 - damage = 30 + damage = 36 penetration = 20 shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 @@ -1860,7 +1860,7 @@ icon_state = "bullet" // Keeping it bog standard with the turret but allows it to be changed accurate_range = 12 - damage = 35 + damage = 36 penetration= ARMOR_PENETRATION_TIER_10 //Bumped the penetration to serve a different role from sentries, MGs are a bit more offensive accuracy = HIT_ACCURACY_TIER_3 diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index feed837b8eaf..b2c905541326 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -233,11 +233,6 @@ var/projectile_type = /obj/projectile /// The multiplier for how much slower this should fire in automatic mode. 1 is normal, 1.2 is 20% slower, 2 is 100% slower, etc. Protected due to it never needing to be edited. VAR_PROTECTED/autofire_slow_mult = 1 - /// IFF stuff, if enabled, range in which we check targets and firedelay if there are friendlies - COOLDOWN_DECLARE(iff_halt_cooldown) - var/iff_range = 7 - var/iff_cooldown = 0.5 SECONDS - /** * An assoc list where the keys are fire delay group string defines @@ -1988,58 +1983,3 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed /// Getter for gun_user /obj/item/weapon/gun/proc/get_gun_user() return gun_user - -/obj/item/weapon/gun/proc/check_firing_lane(obj/item/weapon/gun/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) - SIGNAL_HANDLER - - var/angle = get_angle(user, target) - - var/range_to_check = iff_range - var/cooldown = iff_cooldown - - var/extended_target_turf = get_angle_target_turf(user, angle, range_to_check) - - var/turf/user_turf = get_turf(user) - - if(!user_turf || !extended_target_turf) - return COMPONENT_CANCEL_GUN_BEFORE_FIRE - - var/list/checked_turfs = getline2(extended_target_turf, user_turf) - - checked_turfs -= user_turf - - //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user - //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise - if(projectile_to_fire.original) - var/turf/original_target_turf = get_turf(projectile_to_fire.original) - - if(original_target_turf && !(original_target_turf in checked_turfs)) - var/user_to_target_dist = get_dist(user_turf, original_target_turf) - var/list/temp_checked_turfs = checked_turfs - checked_turfs = list() - - for(var/turf/checked_turf as anything in temp_checked_turfs) - if(!(original_target_turf in checked_turfs) && user_to_target_dist < get_dist(user_turf, checked_turf)) - checked_turfs += original_target_turf - - checked_turfs += checked_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 && projectile_to_fire.original != checked_living) - continue - - if(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, 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 diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm index 88273f8fc972..0cb129d731a6 100644 --- a/code/modules/projectiles/gun_attachables.dm +++ b/code/modules/projectiles/gun_attachables.dm @@ -1145,7 +1145,6 @@ Defined in conflicts.dm of the #defines folder. /obj/item/attachable/scope/mini_iff/New() ..() - damage_mod = -BULLET_DAMAGE_MULT_TIER_4 movement_onehanded_acc_penalty_mod = MOVEMENT_ACCURACY_PENALTY_MULT_TIER_6 accuracy_unwielded_mod = 0 @@ -1159,7 +1158,7 @@ Defined in conflicts.dm of the #defines folder. )) /obj/item/attachable/scope/mini_iff/activate_attachment(obj/item/weapon/gun/G, mob/living/carbon/user, turn_off) - if(do_after(user, 8, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) + if(do_after(user, 4, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) allows_movement = 1 . = ..() @@ -1167,21 +1166,19 @@ Defined in conflicts.dm of the #defines folder. . = ..() if(G.zoom) G.slowdown += dynamic_aim_slowdown - G.iff_range = 13 /obj/item/attachable/scope/mini_iff/remove_scoped_buff(mob/living/carbon/user, obj/item/weapon/gun/G) G.slowdown -= dynamic_aim_slowdown - G.iff_range = 7 ..() /obj/item/attachable/scope/mini_iff/Attach(obj/item/weapon/gun/gun) . = ..() - RegisterSignal(gun, COMSIG_GUN_BEFORE_FIRE, TYPE_PROC_REF(/obj/item/weapon/gun, check_firing_lane)) + gun.AddComponent(/datum/component/iff_fire_prevention, FIRE_DELAY_TIER_5) /obj/item/attachable/scope/mini_iff/Detach(mob/user, obj/item/weapon/gun/detaching_gun) . = ..() - UnregisterSignal(detaching_gun, COMSIG_GUN_BEFORE_FIRE) + detaching_gun.GetExactComponent(/datum/component/iff_fire_prevention).RemoveComponent() /obj/item/attachable/scope/slavic icon_state = "slavicscope" diff --git a/code/modules/projectiles/guns/pistols.dm b/code/modules/projectiles/guns/pistols.dm index c17ca5bca739..a35738f9c1a1 100644 --- a/code/modules/projectiles/guns/pistols.dm +++ b/code/modules/projectiles/guns/pistols.dm @@ -829,6 +829,7 @@ It is a modified Beretta 93R, and can fire three-round burst or single fire. Whe LAZYADD(traits_to_give, list( BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff) )) + AddComponent(/datum/component/iff_fire_prevention) //------------------------------------------------------- //SKORPION //Based on the same thing. diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm index 6c9eb4aa3baf..a9a1d7051748 100644 --- a/code/modules/projectiles/guns/rifles.dm +++ b/code/modules/projectiles/guns/rifles.dm @@ -630,10 +630,10 @@ recalculate_attachment_bonuses() 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)) + AddComponent(/datum/component/iff_fire_prevention) else remove_bullet_trait("iff") - UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) + GetExactComponent(/datum/component/iff_fire_prevention).RemoveComponent() /obj/item/weapon/gun/rifle/m46c/recalculate_attachment_bonuses() . = ..() diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index f2c25b22142b..a52c54b4741b 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -105,7 +105,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)) + AddComponent(/datum/component/iff_fire_prevention) /obj/item/weapon/gun/smartgun/get_examine_text(mob/user) . = ..() @@ -353,12 +353,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)) + AddComponent(/datum/component/iff_fire_prevention) drain += 10 MD.iff_signal = initial(MD.iff_signal) if(!iff_enabled) remove_bullet_trait("iff") - UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) + GetExactComponent(/datum/component/iff_fire_prevention).RemoveComponent() drain -= 10 MD.iff_signal = null diff --git a/colonialmarines.dme b/colonialmarines.dme index d8b72a50a1d4..3df17dd14ca1 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -368,6 +368,7 @@ s// DM Environment file for colonialmarines.dme. #include "code\datums\components\footstep.dm" #include "code\datums\components\healing_reduction.dm" #include "code\datums\components\id_lock.dm" +#include "code\datums\components\iff_fire_prevention.dm" #include "code\datums\components\label.dm" #include "code\datums\components\orbiter.dm" #include "code\datums\components\overlay_lighting.dm" From 475db0ab9c7d4d02ab57413c93adab2f2721b0b5 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 12:59:07 +0300 Subject: [PATCH 08/31] oops --- code/datums/components/iff_fire_prevention.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm index 55db97bf348a..13b3919766c9 100644 --- a/code/datums/components/iff_fire_prevention.dm +++ b/code/datums/components/iff_fire_prevention.dm @@ -80,7 +80,7 @@ if(iff_additional_fire_delay) var/obj/item/weapon/gun/gun = firing_weapon if(istype(gun)) - gun.modify_fire_delay(iff_additional_fire_delay) + LAZYSET(user.fire_delay_next_fire, gun, world.time + iff_additional_fire_delay) 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 From 7eb7131860a6dbe83a3f9aa6c402a04149cd1d18 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Tue, 17 Oct 2023 13:47:46 +0300 Subject: [PATCH 09/31] Smartgun IFF changes and buff! --- .../__DEFINES/dcs/signals/atom/signals_gun.dm | 31 ++++++++ .../dcs/signals/atom/signals_item.dm | 27 ------- code/modules/projectiles/gun.dm | 68 +++++++++++------- code/modules/projectiles/guns/smartgun.dm | 48 ++++++++++++- colonialmarines.dme | 1 + sound/weapons/smartgun_fail.ogg | Bin 0 -> 15723 bytes 6 files changed, 123 insertions(+), 52 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 000000000000..51b8c25fce7e --- /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 6c31b77f76a4..9c2f3b92ba05 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/gun.dm b/code/modules/projectiles/gun.dm index 9d16574aa9da..958190346154 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1195,6 +1195,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) @@ -1414,6 +1425,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) @@ -1614,12 +1627,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 @@ -1670,26 +1677,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 22f10cafb35b..a32ac36e38c4 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -31,7 +31,6 @@ /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_motion_detector, /datum/action/item_action/smartgun/toggle_recoil_compensation, ) var/datum/ammo/ammo_primary = /datum/ammo/bullet/smartgun //Toggled ammo type @@ -51,6 +50,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 +108,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) . = ..() @@ -325,6 +328,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 +397,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 diff --git a/colonialmarines.dme b/colonialmarines.dme index ee6bcd1a0aab..2c35fdbfe799 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -122,6 +122,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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 Date: Fri, 13 Oct 2023 16:31:08 -0400 Subject: [PATCH 10/31] Smartgun IFF weird fixes --- code/modules/projectiles/guns/smartgun.dm | 29 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index a32ac36e38c4..be465f88777b 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -340,14 +340,30 @@ var/extended_target_turf = get_angle_target_turf(user, angle, range_to_check) - var/turf/current_turf = get_turf(user) + var/turf/user_turf = get_turf(user) - if(!current_turf || !extended_target_turf) + if(!user_turf || !extended_target_turf) return COMPONENT_CANCEL_GUN_BEFORE_FIRE - var/list/checked_turfs = getline2(current_turf, extended_target_turf) + var/list/checked_turfs = getline2(user_turf, extended_target_turf) - checked_turfs -= current_turf + checked_turfs -= user_turf + + //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user + //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise + if(projectile_to_fire.original) + var/turf/original_target_turf = get_turf(projectile_to_fire.original) + + if(original_target_turf && !(original_target_turf in checked_turfs)) + var/user_to_target_dist = get_dist(user_turf, original_target_turf) + var/list/temp_checked_turfs = checked_turfs + checked_turfs = list() + + for(var/turf/checked_turf as anything in temp_checked_turfs) + if(!(original_target_turf in checked_turfs) && user_to_target_dist < get_dist(user_turf, checked_turf)) + checked_turfs += original_target_turf + + checked_turfs += checked_turf for(var/turf/checked_turf as anything in checked_turfs) @@ -356,7 +372,10 @@ return for(var/mob/living/checked_living in checked_turf) - if(!checked_living.lying && checked_living.get_target_lock(user.faction_group)) + if(checked_living.lying && projectile_to_fire.original != checked_living) + continue + + if(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!")) From 1ce8b4097bc4c01608035fd4ed94c5d93c1e108b Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Wed, 18 Oct 2023 14:05:49 +0300 Subject: [PATCH 11/31] test --- code/modules/projectiles/gun.dm | 59 +++++++++++++++++++ code/modules/projectiles/gun_attachables.dm | 65 ++++++++++++--------- code/modules/projectiles/guns/rifles.dm | 2 + code/modules/projectiles/guns/smartgun.dm | 63 -------------------- 4 files changed, 99 insertions(+), 90 deletions(-) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 958190346154..4154d102dc2a 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -233,6 +233,10 @@ var/projectile_type = /obj/projectile /// The multiplier for how much slower this should fire in automatic mode. 1 is normal, 1.2 is 20% slower, 2 is 100% slower, etc. Protected due to it never needing to be edited. VAR_PROTECTED/autofire_slow_mult = 1 + /// IFF stuff, if enabled, range in which we check targets and firedelay if there are friendlies + COOLDOWN_DECLARE(iff_halt_cooldown) + var/iff_range = 7 + var/iff_cooldown = 0.5 SECONDS /** @@ -1988,3 +1992,58 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed /// Getter for gun_user /obj/item/weapon/gun/proc/get_gun_user() return gun_user + +/obj/item/weapon/gun/proc/check_firing_lane(obj/projectile/projectile_to_fire, atom/target, mob/living/user) + SIGNAL_HANDLER + + var/angle = get_angle(user, target) + + var/range_to_check = iff_range + var/cooldown = iff_cooldown + + var/extended_target_turf = get_angle_target_turf(user, angle, range_to_check) + + var/turf/user_turf = get_turf(user) + + if(!user_turf || !extended_target_turf) + return COMPONENT_CANCEL_GUN_BEFORE_FIRE + + var/list/checked_turfs = getline2(extended_target_turf, user_turf) + + checked_turfs -= user_turf + + //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user + //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise + if(projectile_to_fire.original) + var/turf/original_target_turf = get_turf(projectile_to_fire.original) + + if(original_target_turf && !(original_target_turf in checked_turfs)) + var/user_to_target_dist = get_dist(user_turf, original_target_turf) + var/list/temp_checked_turfs = checked_turfs + checked_turfs = list() + + for(var/turf/checked_turf as anything in temp_checked_turfs) + if(!(original_target_turf in checked_turfs) && user_to_target_dist < get_dist(user_turf, checked_turf)) + checked_turfs += original_target_turf + + checked_turfs += checked_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 && projectile_to_fire.original != checked_living) + continue + + if(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, 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 diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm index 20781639a579..88273f8fc972 100644 --- a/code/modules/projectiles/gun_attachables.dm +++ b/code/modules/projectiles/gun_attachables.dm @@ -121,7 +121,7 @@ Defined in conflicts.dm of the #defines folder. */ if(G.attachments[slot]) var/obj/item/attachable/A = G.attachments[slot] - A.Detach(detaching_gub = G) + A.Detach(detaching_gun = G) if(ishuman(loc)) var/mob/living/carbon/human/M = src.loc @@ -165,32 +165,32 @@ Defined in conflicts.dm of the #defines folder. // Apply bullet traits from attachment to gun's current projectile G.in_chamber.apply_bullet_trait(L) -/obj/item/attachable/proc/Detach(mob/user, obj/item/weapon/gun/detaching_gub) - if(!istype(detaching_gub)) return //Guns only +/obj/item/attachable/proc/Detach(mob/user, obj/item/weapon/gun/detaching_gun) + if(!istype(detaching_gun)) return //Guns only - detaching_gub.on_detach(user) + detaching_gun.on_detach(user) if(flags_attach_features & ATTACH_ACTIVATION) - activate_attachment(detaching_gub, null, TRUE) + activate_attachment(detaching_gun, null, TRUE) - detaching_gub.attachments[slot] = null - detaching_gub.recalculate_attachment_bonuses() + detaching_gun.attachments[slot] = null + detaching_gun.recalculate_attachment_bonuses() - for(var/X in detaching_gub.actions) + for(var/X in detaching_gun.actions) var/datum/action/DA = X if(DA.target == src) qdel(X) break - forceMove(get_turf(detaching_gub)) + forceMove(get_turf(detaching_gun)) if(sharp) - detaching_gub.sharp = 0 + detaching_gun.sharp = 0 for(var/trait in gun_traits) - REMOVE_TRAIT(detaching_gub, trait, TRAIT_SOURCE_ATTACHMENT(slot)) + REMOVE_TRAIT(detaching_gun, trait, TRAIT_SOURCE_ATTACHMENT(slot)) for(var/entry in traits_to_give) - if(!detaching_gub.in_chamber) + if(!detaching_gun.in_chamber) break var/list/L if(istext(entry)) @@ -198,7 +198,7 @@ Defined in conflicts.dm of the #defines folder. else L = list(entry) + traits_to_give[entry] // Remove bullet traits of attachment from gun's current projectile - detaching_gub.in_chamber._RemoveElement(L) + detaching_gun.in_chamber._RemoveElement(L) /obj/item/attachable/ui_action_click(mob/living/user, obj/item/weapon/gun/G) activate_attachment(G, user) @@ -556,9 +556,9 @@ Defined in conflicts.dm of the #defines folder. ..() G.attachable_offset["muzzle_x"] = 27 -/obj/item/attachable/mateba/Detach(mob/user, obj/item/weapon/gun/detaching_gub) +/obj/item/attachable/mateba/Detach(mob/user, obj/item/weapon/gun/detaching_gun) ..() - detaching_gub.attachable_offset["muzzle_x"] = 20 + detaching_gun.attachable_offset["muzzle_x"] = 20 /obj/item/attachable/mateba/dark icon_state = "mateba_medium_a" @@ -847,9 +847,9 @@ Defined in conflicts.dm of the #defines folder. . = ..() G.AddElement(/datum/element/drop_retrieval/gun, retrieval_slot) -/obj/item/attachable/magnetic_harness/Detach(mob/user, obj/item/weapon/gun/detaching_gub) +/obj/item/attachable/magnetic_harness/Detach(mob/user, obj/item/weapon/gun/detaching_gun) . = ..() - detaching_gub.RemoveElement(/datum/element/drop_retrieval/gun, retrieval_slot) + detaching_gun.RemoveElement(/datum/element/drop_retrieval/gun, retrieval_slot) /obj/item/attachable/magnetic_harness/lever_sling name = "R4T magnetic sling" //please don't make this attachable to any other guns... @@ -871,10 +871,10 @@ Defined in conflicts.dm of the #defines folder. G.attachable_offset["under_y"] = 12 -/obj/item/attachable/magnetic_harness/lever_sling/Detach(mob/user, obj/item/weapon/gun/detaching_gub) +/obj/item/attachable/magnetic_harness/lever_sling/Detach(mob/user, obj/item/weapon/gun/detaching_gun) . = ..() - detaching_gub.attachable_offset["under_x"] = 24 - detaching_gub.attachable_offset["under_y"] = 16 + detaching_gun.attachable_offset["under_x"] = 24 + detaching_gun.attachable_offset["under_y"] = 16 /obj/item/attachable/magnetic_harness/lever_sling/select_gamemode_skin(expected_type, list/override_icon_state, list/override_protection) . = ..() @@ -923,9 +923,9 @@ Defined in conflicts.dm of the #defines folder. . = ..() RegisterSignal(gun, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES, PROC_REF(handle_attachment_recalc)) -/obj/item/attachable/scope/Detach(mob/user, obj/item/weapon/gun/detaching_gub) +/obj/item/attachable/scope/Detach(mob/user, obj/item/weapon/gun/detaching_gun) . = ..() - UnregisterSignal(detaching_gub, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES) + UnregisterSignal(detaching_gun, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES) /// Due to the bipod's interesting way of handling stat modifications, this is necessary to prevent exploits. @@ -1167,11 +1167,22 @@ Defined in conflicts.dm of the #defines folder. . = ..() if(G.zoom) G.slowdown += dynamic_aim_slowdown + G.iff_range = 13 /obj/item/attachable/scope/mini_iff/remove_scoped_buff(mob/living/carbon/user, obj/item/weapon/gun/G) G.slowdown -= dynamic_aim_slowdown + G.iff_range = 7 ..() +/obj/item/attachable/scope/mini_iff/Attach(obj/item/weapon/gun/gun) + . = ..() + RegisterSignal(gun, COMSIG_GUN_BEFORE_FIRE, TYPE_PROC_REF(/obj/item/weapon/gun, check_firing_lane)) + + +/obj/item/attachable/scope/mini_iff/Detach(mob/user, obj/item/weapon/gun/detaching_gun) + . = ..() + UnregisterSignal(detaching_gun, COMSIG_GUN_BEFORE_FIRE) + /obj/item/attachable/scope/slavic icon_state = "slavicscope" attach_icon = "slavicscope" @@ -2533,9 +2544,9 @@ Defined in conflicts.dm of the #defines folder. R.flags_equip_slot &= ~SLOT_WAIST //Can't wear it on the belt slot with stock on when we attach it first time. // When taking it off we want to undo everything not statwise -/obj/item/attachable/stock/revolver/Detach(mob/user, obj/item/weapon/gun/detaching_gub) +/obj/item/attachable/stock/revolver/Detach(mob/user, obj/item/weapon/gun/detaching_gun) ..() - var/obj/item/weapon/gun/revolver/m44/R = detaching_gub + var/obj/item/weapon/gun/revolver/m44/R = detaching_gun if(!istype(R)) return 0 @@ -3260,11 +3271,11 @@ Defined in conflicts.dm of the #defines folder. RegisterSignal(G, COMSIG_ITEM_DROPPED, PROC_REF(handle_drop)) -/obj/item/attachable/bipod/Detach(mob/user, obj/item/weapon/gun/detaching_gub) - UnregisterSignal(detaching_gub, COMSIG_ITEM_DROPPED) +/obj/item/attachable/bipod/Detach(mob/user, obj/item/weapon/gun/detaching_gun) + UnregisterSignal(detaching_gun, COMSIG_ITEM_DROPPED) if(bipod_deployed) - undeploy_bipod(detaching_gub) + undeploy_bipod(detaching_gun) ..() /obj/item/attachable/bipod/update_icon() diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm index 65e4a6f2b7b3..6c9eb4aa3baf 100644 --- a/code/modules/projectiles/guns/rifles.dm +++ b/code/modules/projectiles/guns/rifles.dm @@ -630,8 +630,10 @@ recalculate_attachment_bonuses() 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)) else remove_bullet_trait("iff") + UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) /obj/item/weapon/gun/rifle/m46c/recalculate_attachment_bonuses() . = ..() diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index be465f88777b..f2c25b22142b 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -50,9 +50,6 @@ 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 @@ -328,66 +325,6 @@ 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/user_turf = get_turf(user) - - if(!user_turf || !extended_target_turf) - return COMPONENT_CANCEL_GUN_BEFORE_FIRE - - var/list/checked_turfs = getline2(user_turf, extended_target_turf) - - checked_turfs -= user_turf - - //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user - //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise - if(projectile_to_fire.original) - var/turf/original_target_turf = get_turf(projectile_to_fire.original) - - if(original_target_turf && !(original_target_turf in checked_turfs)) - var/user_to_target_dist = get_dist(user_turf, original_target_turf) - var/list/temp_checked_turfs = checked_turfs - checked_turfs = list() - - for(var/turf/checked_turf as anything in temp_checked_turfs) - if(!(original_target_turf in checked_turfs) && user_to_target_dist < get_dist(user_turf, checked_turf)) - checked_turfs += original_target_turf - - checked_turfs += checked_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 && projectile_to_fire.original != checked_living) - continue - - if(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 From 17eca83e799985d415d0eb9a62f7cd134a564c08 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Wed, 18 Oct 2023 14:25:36 +0300 Subject: [PATCH 12/31] oops --- code/modules/projectiles/gun.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 4154d102dc2a..0a9a1892028a 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1993,7 +1993,7 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed /obj/item/weapon/gun/proc/get_gun_user() return gun_user -/obj/item/weapon/gun/proc/check_firing_lane(obj/projectile/projectile_to_fire, atom/target, mob/living/user) +/obj/item/weapon/gun/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) From e564781601445d13ab0cc560e7a129c9d38c57b9 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Wed, 18 Oct 2023 14:27:03 +0300 Subject: [PATCH 13/31] bruh --- code/modules/projectiles/gun.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 0a9a1892028a..29c6d1c8b5fd 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1993,7 +1993,7 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed /obj/item/weapon/gun/proc/get_gun_user() return gun_user -/obj/item/weapon/gun/proc/check_firing_lane(obj/item/weapon/gun/smartgun/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) +/obj/item/weapon/gun/proc/check_firing_lane(obj/item/weapon/gun/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) SIGNAL_HANDLER var/angle = get_angle(user, target) From 8bc3232c4934155e35e12032828661a444c9b058 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Wed, 18 Oct 2023 15:08:26 +0300 Subject: [PATCH 14/31] ok --- code/modules/cm_marines/smartgun_mount.dm | 60 +++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/code/modules/cm_marines/smartgun_mount.dm b/code/modules/cm_marines/smartgun_mount.dm index 5fa83d1fa06b..0ef1526ce328 100644 --- a/code/modules/cm_marines/smartgun_mount.dm +++ b/code/modules/cm_marines/smartgun_mount.dm @@ -483,6 +483,7 @@ var/shoot_degree = 80 /// Semi auto cooldown COOLDOWN_DECLARE(semiauto_fire_cooldown) + COOLDOWN_DECLARE(iff_halt_cooldown) /// How long between semi-auto shots this should wait, to reduce possible spam var/semiauto_cooldown_time = 0.2 SECONDS @@ -516,6 +517,7 @@ update_icon() AddComponent(/datum/component/automatedfire/autofire, fire_delay, burst_fire_delay, burst_amount, gun_firemode, autofire_slow_mult, CALLBACK(src, PROC_REF(set_burst_firing)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(try_fire)), CALLBACK(src, PROC_REF(display_ammo)), CALLBACK(src, PROC_REF(set_auto_firing))) + /obj/structure/machinery/m56d_hmg/Destroy() //Make sure we pick up our trash. if(operator) operator.unset_interaction() @@ -724,6 +726,15 @@ final_angle += rand(-total_scatter_angle, total_scatter_angle) target = get_angle_target_turf(T, final_angle, 30) + var/before_fire_cancel = SEND_SIGNAL(src, COMSIG_GUN_BEFORE_FIRE, target, operator) + + if(before_fire_cancel) + if(before_fire_cancel & COMPONENT_CANCEL_GUN_BEFORE_FIRE) + return AUTOFIRE_CONTINUE + + if(before_fire_cancel & COMPONENT_HARD_CANCEL_GUN_BEFORE_FIRE) + return + in_chamber.weapon_cause_data = create_cause_data(initial(name), operator) in_chamber.setDir(dir) in_chamber.def_zone = pick("chest","chest","chest","head") @@ -839,6 +850,7 @@ /obj/structure/machinery/m56d_hmg/on_set_interaction(mob/user) RegisterSignal(user, list(COMSIG_MOB_MG_EXIT, COMSIG_MOB_RESISTED, COMSIG_MOB_DEATH, COMSIG_MOB_KNOCKED_DOWN), PROC_REF(exit_interaction)) + RegisterSignal(src, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) flags_atom |= RELAY_CLICK user.status_flags |= IMMOBILE_ACTION user.visible_message(SPAN_NOTICE("[user] mans \the [src]."),SPAN_NOTICE("You man \the [src], locked and loaded!")) @@ -859,6 +871,7 @@ user.visible_message(SPAN_NOTICE("[user] lets go of \the [src]."),SPAN_NOTICE("You let go of \the [src], letting the gun rest.")) user.unfreeze() UnregisterSignal(user, list(COMSIG_MOB_MOUSEUP, COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEDRAG)) + UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) user.reset_view(null) user.remove_temp_pass_flags(PASS_MOB_THRU) // this is necessary because being knocked over while using the gun makes you incorporeal user.Move(get_step(src, reverse_direction(src.dir))) @@ -1102,3 +1115,50 @@ deployment_system.deployed_mg = null deployment_system = null return ..() + +/obj/structure/machinery/m56d_hmg/proc/check_firing_lane(obj/structure/machinery/m56d_hmg/m56d, atom/target, mob/living/user) + SIGNAL_HANDLER + log_debug("TEST") + var/angle = get_angle(src, target) + + var/range_to_check = 9 + var/cooldown = 0.5 + + var/extended_target_turf = get_angle_target_turf(src, angle, range_to_check) + + var/turf/m56d_turf = get_turf(src) + + if(!m56d_turf || !extended_target_turf) + log_debug("CANCEL") + return COMPONENT_CANCEL_GUN_BEFORE_FIRE + + var/list/checked_turfs = getline2(extended_target_turf, m56d_turf) + + checked_turfs -= m56d_turf + + var/i = 0 + for(var/turf/checked_turf as anything in checked_turfs) + i++ + log_debug("[i]") + //Wall, should block the bullet so we're good to stop checking. + if(istype(checked_turf, /turf/closed)) + log_debug("wall?") + return + + for(var/mob/living/checked_living in checked_turf) + log_debug("[checked_living]") + + if(checked_living.lying && target != checked_living) + log_debug("skip") + continue + + if(checked_living.get_target_lock(user.faction_group)) + log_debug("same faction!") + 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, cooldown) + log_debug("CANCEL") + 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 From 55acaafe35c2994da32126bdbf0cb2093055a6f5 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 12:24:51 +0300 Subject: [PATCH 15/31] almost there --- code/_onclick/hud/fullscreen.dm | 7 ++ code/datums/components/iff_fire_prevention.dm | 88 +++++++++++++++++++ code/modules/cm_marines/smartgun_mount.dm | 57 +----------- code/modules/projectiles/gun.dm | 60 ------------- code/modules/projectiles/gun_attachables.dm | 9 +- code/modules/projectiles/guns/pistols.dm | 1 + code/modules/projectiles/guns/rifles.dm | 4 +- code/modules/projectiles/guns/smartgun.dm | 6 +- colonialmarines.dme | 1 + 9 files changed, 109 insertions(+), 124 deletions(-) create mode 100644 code/datums/components/iff_fire_prevention.dm diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index 0bd2206091ba..c8947e206256 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -61,6 +61,13 @@ else client.remove_from_screen(screen) +//Get the distance to the farthest edge of the screen +/mob/proc/get_maximum_view_range() + if(!client) + return 7 + + var/offset = client.pixel_x || client.pixel_y + return client.view + abs(offset / 32) /atom/movable/screen/fullscreen icon = 'icons/mob/hud/screen1_full.dmi' diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm new file mode 100644 index 000000000000..55db97bf348a --- /dev/null +++ b/code/datums/components/iff_fire_prevention.dm @@ -0,0 +1,88 @@ +#define IFF_HALT_COOLDOWN 0.5 SECONDS + +/datum/component/iff_fire_prevention + var/obj/parent_gun + var/iff_additional_fire_delay + COOLDOWN_DECLARE(iff_halt_cooldown) + +/datum/component/iff_fire_prevention/Initialize(additional_fire_delay = 0) + . = ..() + parent_gun = parent + iff_additional_fire_delay = additional_fire_delay + + +/datum/component/iff_fire_prevention/RegisterWithParent() + . = ..() + RegisterSignal(parent_gun, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) + +/datum/component/iff_fire_prevention/UnregisterFromParent() + . = ..() + UnregisterSignal(parent_gun, COMSIG_GUN_BEFORE_FIRE) + +/datum/component/iff_fire_prevention/Destroy(force, silent) + handle_qdel() + . = ..() + +/datum/component/iff_fire_prevention/proc/handle_qdel() + SIGNAL_HANDLER + parent_gun = null + +/datum/component/iff_fire_prevention/proc/check_firing_lane(obj/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) + SIGNAL_HANDLER + + var/angle = get_angle(user, target) + + var/range_to_check = user.get_maximum_view_range() + + var/extended_target_turf = get_angle_target_turf(user, angle, range_to_check) + + + var/turf/starting_turf = get_turf(user) + + if(!starting_turf || !extended_target_turf) + return COMPONENT_CANCEL_GUN_BEFORE_FIRE + + var/list/checked_turfs = getline2(starting_turf, extended_target_turf) + + checked_turfs -= starting_turf + + //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user + //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise + if(projectile_to_fire.original) + var/turf/original_target_turf = get_turf(projectile_to_fire.original) + + if(original_target_turf && !(original_target_turf in checked_turfs)) + var/user_to_target_dist = get_dist(starting_turf, original_target_turf) + var/list/temp_checked_turfs = checked_turfs + checked_turfs = list() + + for(var/turf/checked_turf as anything in temp_checked_turfs) + if(!(original_target_turf in checked_turfs) && user_to_target_dist < get_dist(starting_turf, checked_turf)) + checked_turfs += original_target_turf + + checked_turfs += checked_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 && projectile_to_fire.original != checked_living) + continue + + if(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("[firing_weapon] halts firing as an IFF marked target crosses your field of fire!")) + COOLDOWN_START(src, iff_halt_cooldown, IFF_HALT_COOLDOWN) + if(iff_additional_fire_delay) + var/obj/item/weapon/gun/gun = firing_weapon + if(istype(gun)) + gun.modify_fire_delay(iff_additional_fire_delay) + 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 IFF_HALT_COOLDOWN diff --git a/code/modules/cm_marines/smartgun_mount.dm b/code/modules/cm_marines/smartgun_mount.dm index 0ef1526ce328..e4c486449431 100644 --- a/code/modules/cm_marines/smartgun_mount.dm +++ b/code/modules/cm_marines/smartgun_mount.dm @@ -456,9 +456,9 @@ var/user_old_y = 0 /// How much time should pass in between full auto shots, slightly higher than burst due to click delay and similar things that slow firing down - var/fire_delay = 0.3 SECONDS + var/fire_delay = 0.25 SECONDS /// How much time should pass in between burst fire shots - var/burst_fire_delay = 0.2 SECONDS + var/burst_fire_delay = 0.175 SECONDS /// How many rounds are fired per burst var/burst_amount = 3 /// How many rounds have been fired in the current burst/auto @@ -483,7 +483,6 @@ var/shoot_degree = 80 /// Semi auto cooldown COOLDOWN_DECLARE(semiauto_fire_cooldown) - COOLDOWN_DECLARE(iff_halt_cooldown) /// How long between semi-auto shots this should wait, to reduce possible spam var/semiauto_cooldown_time = 0.2 SECONDS @@ -516,6 +515,7 @@ burst_scatter_mult = SCATTER_AMOUNT_TIER_7 update_icon() AddComponent(/datum/component/automatedfire/autofire, fire_delay, burst_fire_delay, burst_amount, gun_firemode, autofire_slow_mult, CALLBACK(src, PROC_REF(set_burst_firing)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(try_fire)), CALLBACK(src, PROC_REF(display_ammo)), CALLBACK(src, PROC_REF(set_auto_firing))) + AddComponent(/datum/component/iff_fire_prevention) /obj/structure/machinery/m56d_hmg/Destroy() //Make sure we pick up our trash. @@ -726,7 +726,7 @@ final_angle += rand(-total_scatter_angle, total_scatter_angle) target = get_angle_target_turf(T, final_angle, 30) - var/before_fire_cancel = SEND_SIGNAL(src, COMSIG_GUN_BEFORE_FIRE, target, operator) + var/before_fire_cancel = SEND_SIGNAL(src, COMSIG_GUN_BEFORE_FIRE, in_chamber, target, operator) if(before_fire_cancel) if(before_fire_cancel & COMPONENT_CANCEL_GUN_BEFORE_FIRE) @@ -850,7 +850,6 @@ /obj/structure/machinery/m56d_hmg/on_set_interaction(mob/user) RegisterSignal(user, list(COMSIG_MOB_MG_EXIT, COMSIG_MOB_RESISTED, COMSIG_MOB_DEATH, COMSIG_MOB_KNOCKED_DOWN), PROC_REF(exit_interaction)) - RegisterSignal(src, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) flags_atom |= RELAY_CLICK user.status_flags |= IMMOBILE_ACTION user.visible_message(SPAN_NOTICE("[user] mans \the [src]."),SPAN_NOTICE("You man \the [src], locked and loaded!")) @@ -871,7 +870,6 @@ user.visible_message(SPAN_NOTICE("[user] lets go of \the [src]."),SPAN_NOTICE("You let go of \the [src], letting the gun rest.")) user.unfreeze() UnregisterSignal(user, list(COMSIG_MOB_MOUSEUP, COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEDRAG)) - UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) user.reset_view(null) user.remove_temp_pass_flags(PASS_MOB_THRU) // this is necessary because being knocked over while using the gun makes you incorporeal user.Move(get_step(src, reverse_direction(src.dir))) @@ -1115,50 +1113,3 @@ deployment_system.deployed_mg = null deployment_system = null return ..() - -/obj/structure/machinery/m56d_hmg/proc/check_firing_lane(obj/structure/machinery/m56d_hmg/m56d, atom/target, mob/living/user) - SIGNAL_HANDLER - log_debug("TEST") - var/angle = get_angle(src, target) - - var/range_to_check = 9 - var/cooldown = 0.5 - - var/extended_target_turf = get_angle_target_turf(src, angle, range_to_check) - - var/turf/m56d_turf = get_turf(src) - - if(!m56d_turf || !extended_target_turf) - log_debug("CANCEL") - return COMPONENT_CANCEL_GUN_BEFORE_FIRE - - var/list/checked_turfs = getline2(extended_target_turf, m56d_turf) - - checked_turfs -= m56d_turf - - var/i = 0 - for(var/turf/checked_turf as anything in checked_turfs) - i++ - log_debug("[i]") - //Wall, should block the bullet so we're good to stop checking. - if(istype(checked_turf, /turf/closed)) - log_debug("wall?") - return - - for(var/mob/living/checked_living in checked_turf) - log_debug("[checked_living]") - - if(checked_living.lying && target != checked_living) - log_debug("skip") - continue - - if(checked_living.get_target_lock(user.faction_group)) - log_debug("same faction!") - 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, cooldown) - log_debug("CANCEL") - 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 diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 29c6d1c8b5fd..297f821b5242 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -233,11 +233,6 @@ var/projectile_type = /obj/projectile /// The multiplier for how much slower this should fire in automatic mode. 1 is normal, 1.2 is 20% slower, 2 is 100% slower, etc. Protected due to it never needing to be edited. VAR_PROTECTED/autofire_slow_mult = 1 - /// IFF stuff, if enabled, range in which we check targets and firedelay if there are friendlies - COOLDOWN_DECLARE(iff_halt_cooldown) - var/iff_range = 7 - var/iff_cooldown = 0.5 SECONDS - /** * An assoc list where the keys are fire delay group string defines @@ -1992,58 +1987,3 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed /// Getter for gun_user /obj/item/weapon/gun/proc/get_gun_user() return gun_user - -/obj/item/weapon/gun/proc/check_firing_lane(obj/item/weapon/gun/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) - SIGNAL_HANDLER - - var/angle = get_angle(user, target) - - var/range_to_check = iff_range - var/cooldown = iff_cooldown - - var/extended_target_turf = get_angle_target_turf(user, angle, range_to_check) - - var/turf/user_turf = get_turf(user) - - if(!user_turf || !extended_target_turf) - return COMPONENT_CANCEL_GUN_BEFORE_FIRE - - var/list/checked_turfs = getline2(extended_target_turf, user_turf) - - checked_turfs -= user_turf - - //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user - //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise - if(projectile_to_fire.original) - var/turf/original_target_turf = get_turf(projectile_to_fire.original) - - if(original_target_turf && !(original_target_turf in checked_turfs)) - var/user_to_target_dist = get_dist(user_turf, original_target_turf) - var/list/temp_checked_turfs = checked_turfs - checked_turfs = list() - - for(var/turf/checked_turf as anything in temp_checked_turfs) - if(!(original_target_turf in checked_turfs) && user_to_target_dist < get_dist(user_turf, checked_turf)) - checked_turfs += original_target_turf - - checked_turfs += checked_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 && projectile_to_fire.original != checked_living) - continue - - if(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, 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 diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm index 88273f8fc972..0cb129d731a6 100644 --- a/code/modules/projectiles/gun_attachables.dm +++ b/code/modules/projectiles/gun_attachables.dm @@ -1145,7 +1145,6 @@ Defined in conflicts.dm of the #defines folder. /obj/item/attachable/scope/mini_iff/New() ..() - damage_mod = -BULLET_DAMAGE_MULT_TIER_4 movement_onehanded_acc_penalty_mod = MOVEMENT_ACCURACY_PENALTY_MULT_TIER_6 accuracy_unwielded_mod = 0 @@ -1159,7 +1158,7 @@ Defined in conflicts.dm of the #defines folder. )) /obj/item/attachable/scope/mini_iff/activate_attachment(obj/item/weapon/gun/G, mob/living/carbon/user, turn_off) - if(do_after(user, 8, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) + if(do_after(user, 4, INTERRUPT_ALL, BUSY_ICON_HOSTILE)) allows_movement = 1 . = ..() @@ -1167,21 +1166,19 @@ Defined in conflicts.dm of the #defines folder. . = ..() if(G.zoom) G.slowdown += dynamic_aim_slowdown - G.iff_range = 13 /obj/item/attachable/scope/mini_iff/remove_scoped_buff(mob/living/carbon/user, obj/item/weapon/gun/G) G.slowdown -= dynamic_aim_slowdown - G.iff_range = 7 ..() /obj/item/attachable/scope/mini_iff/Attach(obj/item/weapon/gun/gun) . = ..() - RegisterSignal(gun, COMSIG_GUN_BEFORE_FIRE, TYPE_PROC_REF(/obj/item/weapon/gun, check_firing_lane)) + gun.AddComponent(/datum/component/iff_fire_prevention, FIRE_DELAY_TIER_5) /obj/item/attachable/scope/mini_iff/Detach(mob/user, obj/item/weapon/gun/detaching_gun) . = ..() - UnregisterSignal(detaching_gun, COMSIG_GUN_BEFORE_FIRE) + detaching_gun.GetExactComponent(/datum/component/iff_fire_prevention).RemoveComponent() /obj/item/attachable/scope/slavic icon_state = "slavicscope" diff --git a/code/modules/projectiles/guns/pistols.dm b/code/modules/projectiles/guns/pistols.dm index c17ca5bca739..a35738f9c1a1 100644 --- a/code/modules/projectiles/guns/pistols.dm +++ b/code/modules/projectiles/guns/pistols.dm @@ -829,6 +829,7 @@ It is a modified Beretta 93R, and can fire three-round burst or single fire. Whe LAZYADD(traits_to_give, list( BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff) )) + AddComponent(/datum/component/iff_fire_prevention) //------------------------------------------------------- //SKORPION //Based on the same thing. diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm index 6c9eb4aa3baf..a9a1d7051748 100644 --- a/code/modules/projectiles/guns/rifles.dm +++ b/code/modules/projectiles/guns/rifles.dm @@ -630,10 +630,10 @@ recalculate_attachment_bonuses() 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)) + AddComponent(/datum/component/iff_fire_prevention) else remove_bullet_trait("iff") - UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) + GetExactComponent(/datum/component/iff_fire_prevention).RemoveComponent() /obj/item/weapon/gun/rifle/m46c/recalculate_attachment_bonuses() . = ..() diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index f2c25b22142b..a52c54b4741b 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -105,7 +105,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)) + AddComponent(/datum/component/iff_fire_prevention) /obj/item/weapon/gun/smartgun/get_examine_text(mob/user) . = ..() @@ -353,12 +353,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)) + AddComponent(/datum/component/iff_fire_prevention) drain += 10 MD.iff_signal = initial(MD.iff_signal) if(!iff_enabled) remove_bullet_trait("iff") - UnregisterSignal(src, COMSIG_GUN_BEFORE_FIRE) + GetExactComponent(/datum/component/iff_fire_prevention).RemoveComponent() drain -= 10 MD.iff_signal = null diff --git a/colonialmarines.dme b/colonialmarines.dme index 2c35fdbfe799..e16986aaee77 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -383,6 +383,7 @@ s// DM Environment file for colonialmarines.dme. #include "code\datums\components\footstep.dm" #include "code\datums\components\healing_reduction.dm" #include "code\datums\components\id_lock.dm" +#include "code\datums\components\iff_fire_prevention.dm" #include "code\datums\components\label.dm" #include "code\datums\components\orbiter.dm" #include "code\datums\components\overlay_lighting.dm" From 385ba5de59d30d78c4c5e50caf3942abdc0f1dd2 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 12:59:07 +0300 Subject: [PATCH 16/31] oops --- code/datums/components/iff_fire_prevention.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm index 55db97bf348a..13b3919766c9 100644 --- a/code/datums/components/iff_fire_prevention.dm +++ b/code/datums/components/iff_fire_prevention.dm @@ -80,7 +80,7 @@ if(iff_additional_fire_delay) var/obj/item/weapon/gun/gun = firing_weapon if(istype(gun)) - gun.modify_fire_delay(iff_additional_fire_delay) + LAZYSET(user.fire_delay_next_fire, gun, world.time + iff_additional_fire_delay) 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 From ecdb4c6c03c8f3c8e80b1c59f054480d3f964a7b Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 13:33:21 +0300 Subject: [PATCH 17/31] eeeeh --- code/modules/projectiles/ammo_datums.dm | 3447 ----------------------- 1 file changed, 3447 deletions(-) delete mode 100644 code/modules/projectiles/ammo_datums.dm diff --git a/code/modules/projectiles/ammo_datums.dm b/code/modules/projectiles/ammo_datums.dm deleted file mode 100644 index da51d43baba6..000000000000 --- a/code/modules/projectiles/ammo_datums.dm +++ /dev/null @@ -1,3447 +0,0 @@ -/datum/ammo - var/name = "generic bullet" - var/headshot_state = null //Icon state when a human is permanently killed with it by execution/suicide. - var/icon = 'icons/obj/items/weapons/projectiles.dmi' - var/icon_state = "bullet" - var/ping = "ping_b" //The icon that is displayed when the bullet bounces off something. - var/sound_hit //When it deals damage. - var/sound_armor //When it's blocked by human armor. - var/sound_miss //When it misses someone. - var/sound_bounce //When it bounces off something. - var/sound_shield_hit //When the bullet is absorbed by a xeno_shield - - var/accurate_range_min = 0 // Snipers use this to simulate poor accuracy at close ranges - var/scatter = 0 // How much the ammo scatters when burst fired, added to gun scatter, along with other mods - var/stamina_damage = 0 - var/damage = 0 // This is the base damage of the bullet as it is fired - var/damage_type = BRUTE // BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here - var/penetration = 0 // How much armor it ignores before calculations take place - var/shrapnel_chance = 0 // The % chance it will imbed in a human - var/shrapnel_type = 0 // The shrapnel type the ammo will embed, if the chance rolls - var/bonus_projectiles_type // Type path of the extra projectiles - var/bonus_projectiles_amount = 0 // How many extra projectiles it shoots out. Works kind of like firing on burst, but all of the projectiles travel together - var/debilitate[] = null // Stun,knockdown,knockout,irradiate,stutter,eyeblur,drowsy,agony - var/pen_armor_punch = 0.5 // how much armor breaking will be done per point of penetration. This is for weapons that penetrate with their shape (like needle bullets) - var/damage_armor_punch = 0.5 // how much armor breaking is done by sheer weapon force. This is for big blunt weapons - var/sound_override = null // if we should play a special sound when firing. - var/flags_ammo_behavior = NO_FLAGS - - var/accuracy = HIT_ACCURACY_TIER_1 // This is added to the bullet's base accuracy. - var/accuracy_var_low = PROJECTILE_VARIANCE_TIER_9 // How much the accuracy varies when fired. // This REDUCES the lower bound of accuracy variance by 2%, to 96%. - var/accuracy_var_high = PROJECTILE_VARIANCE_TIER_9 // This INCREASES the upper bound of accuracy variance by 2%, to 107%. - var/accurate_range = 6 // For most guns, this is where the bullet dramatically looses accuracy. Not for snipers though. - var/max_range = 22 // This will de-increment a counter on the bullet. - var/damage_var_low = PROJECTILE_VARIANCE_TIER_9 // Same as with accuracy variance. - var/damage_var_high = PROJECTILE_VARIANCE_TIER_9 // This INCREASES the upper bound of damage variance by 2%, to 107%. - var/damage_falloff = DAMAGE_FALLOFF_TIER_10 // How much damage the bullet loses per turf traveled after the effective range - var/damage_buildup = DAMAGE_BUILDUP_TIER_1 // How much damage the bullet loses per turf away before the effective range - var/effective_range_min = EFFECTIVE_RANGE_OFF //What minimum range the ammo deals full damage, builds up the closer you get. 0 for no minimum. Added onto gun range as a modifier. - var/effective_range_max = EFFECTIVE_RANGE_OFF //What maximum range the ammo deals full damage, tapers off using damage_falloff after hitting this value. 0 for no maximum. Added onto gun range as a modifier. - var/shell_speed = AMMO_SPEED_TIER_1 // How fast the projectile moves. - - var/handful_type = /obj/item/ammo_magazine/handful - var/handful_color - var/handful_state = "bullet" //custom handful sprite, for shotgun shells or etc. - var/multiple_handful_name //so handfuls say 'buckshot shells' not 'shell' - - /// Does this apply xenomorph behaviour delegate? - var/apply_delegate = TRUE - - /// An assoc list in the format list(/datum/element/bullet_trait_to_give = list(...args)) - /// that will be given to a projectile with the current ammo datum - var/list/list/traits_to_give - - var/flamer_reagent_type = /datum/reagent/napalm/ut - - /// The flicker that plays when a bullet hits a target. Usually red. Can be nulled so it doesn't show up at all. - var/hit_effect_color = "#FF0000" - -/datum/ammo/New() - set_bullet_traits() - -/datum/ammo/proc/on_bullet_generation(obj/projectile/generated_projectile, mob/bullet_generator) //NOT used on New(), applied to the projectiles. - return - -/// Populate traits_to_give in this proc -/datum/ammo/proc/set_bullet_traits() - return - -/datum/ammo/can_vv_modify() - return FALSE - -/datum/ammo/proc/do_at_half_range(obj/projectile/P) - SHOULD_NOT_SLEEP(TRUE) - return - -/datum/ammo/proc/on_embed(mob/embedded_mob, obj/limb/target_organ) - return - -/datum/ammo/proc/do_at_max_range(obj/projectile/P) - SHOULD_NOT_SLEEP(TRUE) - return - -/datum/ammo/proc/on_shield_block(mob/M, obj/projectile/P) //Does it do something special when shield blocked? Ie. a flare or grenade that still blows up. - return - -/datum/ammo/proc/on_hit_turf(turf/T, obj/projectile/P) //Special effects when hitting dense turfs. - SHOULD_NOT_SLEEP(TRUE) - return - -/datum/ammo/proc/on_hit_mob(mob/M, obj/projectile/P, mob/user) //Special effects when hitting mobs. - SHOULD_NOT_SLEEP(TRUE) - return - -///Special effects when pointblanking mobs. Ultimately called from /living/attackby(). Return TRUE to end the PB attempt. -/datum/ammo/proc/on_pointblank(mob/living/L, obj/projectile/P, mob/living/user, obj/item/weapon/gun/fired_from) - return - -/datum/ammo/proc/on_hit_obj(obj/O, obj/projectile/P) //Special effects when hitting objects. - SHOULD_NOT_SLEEP(TRUE) - return - -/datum/ammo/proc/on_near_target(turf/T, obj/projectile/P) //Special effects when passing near something. Range of things that triggers it is controlled by other ammo flags. - return 0 //return 0 means it flies even after being near something. Return 1 means it stops - -/datum/ammo/proc/knockback(mob/living/living_mob, obj/projectile/fired_projectile, max_range = 2) - if(!living_mob || living_mob == fired_projectile.firer) - return - if(fired_projectile.distance_travelled > max_range || living_mob.lying) - return //Two tiles away or more, basically. - - if(living_mob.mob_size >= MOB_SIZE_BIG) - return //Big xenos are not affected. - - shake_camera(living_mob, 3, 4) - knockback_effects(living_mob, fired_projectile) - slam_back(living_mob, fired_projectile) - -/datum/ammo/proc/slam_back(mob/living/living_mob, obj/projectile/fired_projectile) - //Either knockback or slam them into an obstacle. - var/direction = Get_Compass_Dir(fired_projectile.z ? fired_projectile : fired_projectile.firer, living_mob) //More precise than get_dir. - if(!direction) //Same tile. - return - if(!step(living_mob, direction)) - living_mob.animation_attack_on(get_step(living_mob, direction)) - playsound(living_mob.loc, "punch", 25, 1) - living_mob.visible_message(SPAN_DANGER("[living_mob] slams into an obstacle!"), - isxeno(living_mob) ? SPAN_XENODANGER("You slam into an obstacle!") : SPAN_HIGHDANGER("You slam into an obstacle!"), null, 4, CHAT_TYPE_TAKING_HIT) - living_mob.apply_damage(MELEE_FORCE_TIER_2) - -///The applied effects for knockback(), overwrite to change slow/stun amounts for different ammo datums -/datum/ammo/proc/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile) - if(iscarbonsizexeno(living_mob)) - var/mob/living/carbon/xenomorph/target = living_mob - target.apply_effect(0.7, WEAKEN) // 0.9 seconds of stun, per agreement from Balance Team when switched from MC stuns to exact stuns - target.apply_effect(1, SUPERSLOW) - target.apply_effect(2, SLOW) - to_chat(target, SPAN_XENODANGER("You are shaken by the sudden impact!")) - else - living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) - -/datum/ammo/proc/pushback(mob/target_mob, obj/projectile/fired_projectile, max_range = 2) - if(!target_mob || target_mob == fired_projectile.firer || fired_projectile.distance_travelled > max_range || target_mob.lying) - return - - if(target_mob.mob_size >= MOB_SIZE_BIG) - return //too big to push - - to_chat(target_mob, isxeno(target_mob) ? SPAN_XENODANGER("You are pushed back by the sudden impact!") : SPAN_HIGHDANGER("You are pushed back by the sudden impact!"), null, 4, CHAT_TYPE_TAKING_HIT) - slam_back(target_mob, fired_projectile, max_range) - -/datum/ammo/proc/burst(atom/target, obj/projectile/P, damage_type = BRUTE, range = 1, damage_div = 2, show_message = SHOW_MESSAGE_VISIBLE) //damage_div says how much we divide damage - if(!target || !P) return - for(var/mob/living/carbon/M in orange(range,target)) - if(P.firer == M) - continue - if(show_message) - var/msg = "You are hit by backlash from \a [P.name]!" - M.visible_message(SPAN_DANGER("[M] is hit by backlash from \a [P.name]!"),isxeno(M) ? SPAN_XENODANGER("[msg]"):SPAN_HIGHDANGER("[msg]")) - var/damage = P.damage/damage_div - - var/mob/living/carbon/xenomorph/XNO = null - - if(isxeno(M)) - XNO = M - var/total_explosive_resistance = XNO.caste.xeno_explosion_resistance + XNO.armor_explosive_buff - damage = armor_damage_reduction(GLOB.xeno_explosive, damage, total_explosive_resistance , 60, 0, 0.5, XNO.armor_integrity) - var/armor_punch = armor_break_calculation(GLOB.xeno_explosive, damage, total_explosive_resistance, 60, 0, 0.5, XNO.armor_integrity) - XNO.apply_armorbreak(armor_punch) - - M.apply_damage(damage,damage_type) - - if(XNO && XNO.xeno_shields.len) - P.play_shielded_hit_effect(M) - else - P.play_hit_effect(M) - -/datum/ammo/proc/fire_bonus_projectiles(obj/projectile/original_P) - set waitfor = 0 - - var/turf/curloc = get_turf(original_P.shot_from) - var/initial_angle = Get_Angle(curloc, original_P.target_turf) - - for(var/i in 1 to bonus_projectiles_amount) //Want to run this for the number of bonus projectiles. - var/final_angle = initial_angle - - var/obj/projectile/P = new /obj/projectile(curloc, original_P.weapon_cause_data) - P.generate_bullet(GLOB.ammo_list[bonus_projectiles_type]) //No bonus damage or anything. - P.accuracy = round(P.accuracy * original_P.accuracy/initial(original_P.accuracy)) //if the gun changes the accuracy of the main projectile, it also affects the bonus ones. - original_P.give_bullet_traits(P) - - var/total_scatter_angle = P.scatter - final_angle += rand(-total_scatter_angle, total_scatter_angle) - var/turf/new_target = get_angle_target_turf(curloc, final_angle, 30) - - P.fire_at(new_target, original_P.firer, original_P.shot_from, P.ammo.max_range, P.ammo.shell_speed, original_P.original) //Fire! - -/datum/ammo/proc/drop_flame(turf/T, datum/cause_data/cause_data) // ~Art updated fire 20JAN17 - if(!istype(T)) - return - if(locate(/obj/flamer_fire) in T) - return - - var/datum/reagent/R = new flamer_reagent_type() - new /obj/flamer_fire(T, cause_data, R) - - -/* -//====== - Default Ammo -//====== -*/ -//Only when things screw up do we use this as a placeholder. -/datum/ammo/bullet - name = "default bullet" - icon_state = "bullet" - headshot_state = HEADSHOT_OVERLAY_LIGHT - flags_ammo_behavior = AMMO_BALLISTIC - sound_hit = "ballistic_hit" - sound_armor = "ballistic_armor" - sound_miss = "ballistic_miss" - sound_bounce = "ballistic_bounce" - sound_shield_hit = "ballistic_shield_hit" - - accurate_range_min = 0 - damage = 10 - shrapnel_chance = SHRAPNEL_CHANCE_TIER_1 - shrapnel_type = /obj/item/shard/shrapnel - shell_speed = AMMO_SPEED_TIER_4 - -/datum/ammo/bullet/proc/handle_battlefield_execution(datum/ammo/firing_ammo, mob/living/hit_mob, obj/projectile/firing_projectile, mob/living/user, obj/item/weapon/gun/fired_from) - SIGNAL_HANDLER - - if(!user || hit_mob == user || user.zone_selected != "head" || user.a_intent != INTENT_HARM || !ishuman_strict(hit_mob)) - return - - if(!skillcheck(user, SKILL_EXECUTION, SKILL_EXECUTION_TRAINED)) - to_chat(user, SPAN_DANGER("You don't know how to execute someone correctly.")) - return - - var/mob/living/carbon/human/execution_target = hit_mob - - if(execution_target.status_flags & PERMANENTLY_DEAD) - to_chat(user, SPAN_DANGER("[execution_target] has already been executed!")) - return - - INVOKE_ASYNC(src, PROC_REF(attempt_battlefield_execution), src, execution_target, firing_projectile, user, fired_from) - - return COMPONENT_CANCEL_AMMO_POINT_BLANK - -/datum/ammo/bullet/proc/attempt_battlefield_execution(datum/ammo/firing_ammo, mob/living/carbon/human/execution_target, obj/projectile/firing_projectile, mob/living/user, obj/item/weapon/gun/fired_from) - user.affected_message(execution_target, - SPAN_HIGHDANGER("You aim \the [fired_from] at [execution_target]'s head!"), - SPAN_HIGHDANGER("[user] aims \the [fired_from] directly at your head!"), - SPAN_DANGER("[user] aims \the [fired_from] at [execution_target]'s head!")) - - user.next_move += 1.1 SECONDS //PB has no click delay; readding it here to prevent people accidentally queuing up multiple executions. - - if(!do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE) || !user.Adjacent(execution_target)) - fired_from.delete_bullet(firing_projectile, TRUE) - return - - if(!(fired_from.flags_gun_features & GUN_SILENCED)) - playsound(user, fired_from.fire_sound, fired_from.firesound_volume, FALSE) - else - playsound(user, fired_from.fire_sound, 25, FALSE) - - shake_camera(user, 1, 2) - - execution_target.apply_damage(damage * 3, BRUTE, "head", no_limb_loss = TRUE, permanent_kill = TRUE) //Apply gobs of damage and make sure they can't be revived later... - execution_target.apply_damage(200, OXY) //...fill out the rest of their health bar with oxyloss... - execution_target.death(create_cause_data("execution", user)) //...make certain they're properly dead... - shake_camera(execution_target, 3, 4) - execution_target.update_headshot_overlay(headshot_state) //...and add a gory headshot overlay. - - execution_target.visible_message(SPAN_HIGHDANGER(uppertext("[execution_target] WAS EXECUTED!")), \ - SPAN_HIGHDANGER("You WERE EXECUTED!")) - - user.count_niche_stat(STATISTICS_NICHE_EXECUTION, 1, firing_projectile.weapon_cause_data?.cause_name) - - var/area/execution_area = get_area(execution_target) - - msg_admin_attack(FONT_SIZE_HUGE("[key_name(usr)] has battlefield executed [key_name(execution_target)] in [get_area(usr)] ([usr.loc.x],[usr.loc.y],[usr.loc.z])."), usr.loc.x, usr.loc.y, usr.loc.z) - log_attack("[key_name(usr)] battlefield executed [key_name(execution_target)] at [execution_area.name].") - - if(flags_ammo_behavior & AMMO_EXPLOSIVE) - execution_target.gib() - - -/* -//====== - Pistol Ammo -//====== -*/ - -// Used by M4A3, M4A3 Custom and B92FS -/datum/ammo/bullet/pistol - name = "pistol bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - accuracy = -HIT_ACCURACY_TIER_3 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - damage = 40 - penetration= ARMOR_PENETRATION_TIER_2 - shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 - -/datum/ammo/bullet/pistol/tiny - name = "light pistol bullet" - -/datum/ammo/bullet/pistol/tranq - name = "tranquilizer bullet" - flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST - stamina_damage = 30 - damage = 15 - -//2020 rebalance: is supposed to counter runners and lurkers, dealing high damage to the only castes with no armor. -//Limited by its lack of versatility and lower supply, so marines finally have an answer for flanker castes that isn't just buckshot. - -/datum/ammo/bullet/pistol/hollow - name = "hollowpoint pistol bullet" - - damage = 55 //hollowpoint is strong - penetration = 0 //hollowpoint can't pierce armor! - shrapnel_chance = SHRAPNEL_CHANCE_TIER_3 //hollowpoint causes shrapnel - -// Used by M4A3 AP and mod88 -/datum/ammo/bullet/pistol/ap - name = "armor-piercing pistol bullet" - - damage = 25 - accuracy = HIT_ACCURACY_TIER_2 - penetration= ARMOR_PENETRATION_TIER_8 - shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 - -/datum/ammo/bullet/pistol/ap/penetrating - name = "wall-penetrating pistol bullet" - shrapnel_chance = 0 - - damage = 30 - penetration = ARMOR_PENETRATION_TIER_10 - -/datum/ammo/bullet/pistol/ap/penetrating/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) - )) - -/datum/ammo/bullet/pistol/ap/toxin - name = "toxic pistol bullet" - var/acid_per_hit = 10 - var/organic_damage_mult = 3 - -/datum/ammo/bullet/pistol/ap/toxin/on_hit_mob(mob/M, obj/projectile/P) - . = ..() - M.AddComponent(/datum/component/toxic_buildup, acid_per_hit) - -/datum/ammo/bullet/pistol/ap/toxin/on_hit_turf(turf/T, obj/projectile/P) - . = ..() - if(T.flags_turf & TURF_ORGANIC) - P.damage *= organic_damage_mult - -/datum/ammo/bullet/pistol/ap/toxin/on_hit_obj(obj/O, obj/projectile/P) - . = ..() - if(O.flags_obj & OBJ_ORGANIC) - P.damage *= organic_damage_mult - -/datum/ammo/bullet/pistol/le - name = "armor-shredding pistol bullet" - - damage = 15 - penetration = ARMOR_PENETRATION_TIER_4 - pen_armor_punch = 3 - -/datum/ammo/bullet/pistol/rubber - name = "rubber pistol bullet" - sound_override = 'sound/weapons/gun_c99.ogg' - - damage = 0 - stamina_damage = 25 - shrapnel_chance = 0 - -// Reskinned rubber bullet used for the ES-4 CL pistol. -/datum/ammo/bullet/pistol/rubber/stun - name = "stun pistol bullet" - sound_override = null - -// Used by M1911, Deagle and KT-42 -/datum/ammo/bullet/pistol/heavy - name = "heavy pistol bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - accuracy = -HIT_ACCURACY_TIER_3 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - damage = 55 - penetration = ARMOR_PENETRATION_TIER_3 - shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 - -/datum/ammo/bullet/pistol/heavy/super //Commander's variant - name = ".50 heavy pistol bullet" - damage = 60 - damage_var_low = PROJECTILE_VARIANCE_TIER_8 - damage_var_high = PROJECTILE_VARIANCE_TIER_6 - penetration = ARMOR_PENETRATION_TIER_4 - -/datum/ammo/bullet/pistol/heavy/super/highimpact - name = ".50 high-impact pistol bullet" - penetration = ARMOR_PENETRATION_TIER_1 - debilitate = list(0,1.5,0,0,0,1,0,0) - flags_ammo_behavior = AMMO_BALLISTIC - -/datum/ammo/bullet/pistol/heavy/super/highimpact/ap - name = ".50 high-impact armor piercing pistol bullet" - penetration = ARMOR_PENETRATION_TIER_10 - damage = 45 - -/datum/ammo/bullet/pistol/heavy/super/highimpact/upp - name = "high-impact pistol bullet" - sound_override = 'sound/weapons/gun_DE50.ogg' - penetration = ARMOR_PENETRATION_TIER_6 - debilitate = list(0,1.5,0,0,0,1,0,0) - flags_ammo_behavior = AMMO_BALLISTIC - -/datum/ammo/bullet/pistol/heavy/super/highimpact/New() - ..() - RegisterSignal(src, COMSIG_AMMO_POINT_BLANK, PROC_REF(handle_battlefield_execution)) - -/datum/ammo/bullet/pistol/heavy/super/highimpact/on_hit_mob(mob/M, obj/projectile/P) - knockback(M, P, 4) - -/datum/ammo/bullet/pistol/deagle - name = ".50 heavy pistol bullet" - damage = 45 - headshot_state = HEADSHOT_OVERLAY_HEAVY - accuracy = -HIT_ACCURACY_TIER_3 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - penetration = ARMOR_PENETRATION_TIER_6 - shrapnel_chance = SHRAPNEL_CHANCE_TIER_5 - -/datum/ammo/bullet/pistol/incendiary - name = "incendiary pistol bullet" - damage_type = BURN - shrapnel_chance = 0 - flags_ammo_behavior = AMMO_BALLISTIC - - accuracy = HIT_ACCURACY_TIER_3 - damage = 20 - -/datum/ammo/bullet/pistol/incendiary/set_bullet_traits() - ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -// Used by the hipower -// I know that the 'high power' in the name is supposed to mean its 'impressive' magazine capacity -// but this is CM, half our guns have baffling misconceptions and mistakes (how do you grab the type-71?) so it's on-brand. -// maybe in the far flung future of 2280 someone screwed up the design. - -/datum/ammo/bullet/pistol/highpower - name = "high-powered pistol bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - - accuracy = HIT_ACCURACY_TIER_3 - damage = 36 - penetration = ARMOR_PENETRATION_TIER_5 - damage_falloff = DAMAGE_FALLOFF_TIER_7 - -// Used by VP78 and Auto 9 -/datum/ammo/bullet/pistol/squash - name = "squash-head pistol bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - debilitate = list(0,0,0,0,0,0,0,2) - - accuracy = HIT_ACCURACY_TIER_4 - damage = 45 - penetration= ARMOR_PENETRATION_TIER_6 - shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 - damage_falloff = DAMAGE_FALLOFF_TIER_6 //"VP78 - the only pistol viable as a primary."-Vampmare, probably. - -/datum/ammo/bullet/pistol/squash/toxin - name = "toxic squash-head pistol bullet" - var/acid_per_hit = 10 - var/organic_damage_mult = 3 - -/datum/ammo/bullet/pistol/squash/toxin/on_hit_mob(mob/M, obj/projectile/P) - . = ..() - M.AddComponent(/datum/component/toxic_buildup, acid_per_hit) - -/datum/ammo/bullet/pistol/squash/toxin/on_hit_turf(turf/T, obj/projectile/P) - . = ..() - if(T.flags_turf & TURF_ORGANIC) - P.damage *= organic_damage_mult - -/datum/ammo/bullet/pistol/squash/toxin/on_hit_obj(obj/O, obj/projectile/P) - . = ..() - if(O.flags_obj & OBJ_ORGANIC) - P.damage *= organic_damage_mult - -/datum/ammo/bullet/pistol/squash/penetrating - name = "wall-penetrating squash-head pistol bullet" - shrapnel_chance = 0 - penetration = ARMOR_PENETRATION_TIER_10 - -/datum/ammo/bullet/pistol/squash/penetrating/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) - )) - -/datum/ammo/bullet/pistol/squash/incendiary - name = "incendiary squash-head pistol bullet" - damage_type = BURN - shrapnel_chance = 0 - flags_ammo_behavior = AMMO_BALLISTIC - accuracy = HIT_ACCURACY_TIER_3 - damage = 35 - -/datum/ammo/bullet/pistol/squash/incendiary/set_bullet_traits() - ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - - -/datum/ammo/bullet/pistol/mankey - name = "live monkey" - icon_state = "monkey1" - ping = null //no bounce off. - damage_type = BURN - debilitate = list(4,4,0,0,0,0,0,0) - flags_ammo_behavior = AMMO_IGNORE_ARMOR - - damage = 15 - damage_var_high = PROJECTILE_VARIANCE_TIER_5 - shell_speed = AMMO_SPEED_TIER_2 - -/datum/ammo/bullet/pistol/mankey/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/pistol/mankey/on_hit_mob(mob/M,obj/projectile/P) - if(P && P.loc && !M.stat && !istype(M,/mob/living/carbon/human/monkey)) - P.visible_message(SPAN_DANGER("The [src] chimpers furiously!")) - new /mob/living/carbon/human/monkey(P.loc) - -/datum/ammo/bullet/pistol/smart - name = "smartpistol bullet" - flags_ammo_behavior = AMMO_BALLISTIC - - accuracy = HIT_ACCURACY_TIER_8 - damage = 36 - penetration = 20 - shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 - -/* -//====== - Revolver Ammo -//====== -*/ - -/datum/ammo/bullet/revolver - name = "revolver bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - - damage = 55 - penetration = ARMOR_PENETRATION_TIER_1 - accuracy = HIT_ACCURACY_TIER_1 - -/datum/ammo/bullet/revolver/marksman - name = "marksman revolver bullet" - - shrapnel_chance = 0 - damage_falloff = 0 - accurate_range = 12 - penetration = ARMOR_PENETRATION_TIER_7 - -/datum/ammo/bullet/revolver/heavy - name = "heavy revolver bullet" - - damage = 35 - penetration = ARMOR_PENETRATION_TIER_4 - accuracy = HIT_ACCURACY_TIER_3 - -/datum/ammo/bullet/revolver/heavy/on_hit_mob(mob/M, obj/projectile/P) - knockback(M, P, 4) - -/datum/ammo/bullet/revolver/incendiary - name = "incendiary revolver bullet" - damage = 40 - -/datum/ammo/bullet/revolver/incendiary/set_bullet_traits() - ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/revolver/marksman/toxin - name = "toxic revolver bullet" - var/acid_per_hit = 10 - var/organic_damage_mult = 3 - -/datum/ammo/bullet/revolver/marksman/toxin/on_hit_mob(mob/M, obj/projectile/P) - . = ..() - M.AddComponent(/datum/component/toxic_buildup, acid_per_hit) - -/datum/ammo/bullet/revolver/marksman/toxin/on_hit_turf(turf/T, obj/projectile/P) - . = ..() - if(T.flags_turf & TURF_ORGANIC) - P.damage *= organic_damage_mult - -/datum/ammo/bullet/revolver/marksman/toxin/on_hit_obj(obj/O, obj/projectile/P) - . = ..() - if(O.flags_obj & OBJ_ORGANIC) - P.damage *= organic_damage_mult - -/datum/ammo/bullet/revolver/penetrating - name = "wall-penetrating revolver bullet" - shrapnel_chance = 0 - - penetration = ARMOR_PENETRATION_TIER_10 - -/datum/ammo/bullet/revolver/penetrating/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) - )) - -/datum/ammo/bullet/revolver/upp - name = "heavy revolver bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - penetration = ARMOR_PENETRATION_TIER_4 - damage = 70 - - -/datum/ammo/bullet/revolver/upp/shrapnel - name = "shrapnel shot" - headshot_state = HEADSHOT_OVERLAY_HEAVY //Gol-dang shotgun blow your fething head off. - debilitate = list(0,0,0,0,0,0,0,0) - icon_state = "shrapnelshot" - handful_state = "shrapnel" - bonus_projectiles_type = /datum/ammo/bullet/revolver/upp/shrapnel_bits - - max_range = 6 - damage = 40 // + TIER_4 * 3 - damage_falloff = DAMAGE_FALLOFF_TIER_7 - penetration = ARMOR_PENETRATION_TIER_8 - bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3 - shrapnel_chance = 100 - shrapnel_type = /obj/item/shard/shrapnel/upp - //roughly 90 or so damage with the additional shrapnel, around 130 in total with primary round - -/datum/ammo/bullet/revolver/upp/shrapnel/on_hit_mob(mob/M, obj/projectile/P) - pushback(M, P, 1) - -/datum/ammo/bullet/revolver/upp/shrapnel_bits - name = "small shrapnel" - icon_state = "shrapnelshot_bit" - - max_range = 6 - damage = 30 - penetration = ARMOR_PENETRATION_TIER_4 - scatter = SCATTER_AMOUNT_TIER_1 - bonus_projectiles_amount = 0 - shrapnel_type = /obj/item/shard/shrapnel/upp/bits - -/datum/ammo/bullet/revolver/small - name = "small revolver bullet" - headshot_state = HEADSHOT_OVERLAY_LIGHT - - damage = 45 - - penetration = ARMOR_PENETRATION_TIER_3 - -/datum/ammo/bullet/revolver/small/hollowpoint - name = "small hollowpoint revolver bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - - damage = 75 // way too strong because it's hard to make a good balance between HP and normal with this system, but the damage falloff is really strong - penetration = 0 - damage_falloff = DAMAGE_FALLOFF_TIER_6 - -/datum/ammo/bullet/revolver/mateba - name = ".454 heavy revolver bullet" - - damage = 60 - damage_var_low = PROJECTILE_VARIANCE_TIER_8 - damage_var_high = PROJECTILE_VARIANCE_TIER_6 - penetration = ARMOR_PENETRATION_TIER_4 - -/datum/ammo/bullet/revolver/mateba/highimpact - name = ".454 heavy high-impact revolver bullet" - debilitate = list(0,2,0,0,0,1,0,0) - penetration = ARMOR_PENETRATION_TIER_1 - flags_ammo_behavior = AMMO_BALLISTIC - -/datum/ammo/bullet/revolver/mateba/highimpact/ap - name = ".454 heavy high-impact armor piercing revolver bullet" - penetration = ARMOR_PENETRATION_TIER_10 - damage = 45 - -/datum/ammo/bullet/revolver/mateba/highimpact/New() - ..() - RegisterSignal(src, COMSIG_AMMO_POINT_BLANK, PROC_REF(handle_battlefield_execution)) - -/datum/ammo/bullet/revolver/mateba/highimpact/on_hit_mob(mob/M, obj/projectile/P) - knockback(M, P, 4) - -/datum/ammo/bullet/revolver/mateba/highimpact/explosive //if you ever put this in normal gameplay, i am going to scream - name = ".454 heavy explosive revolver bullet" - damage = 100 - damage_var_low = PROJECTILE_VARIANCE_TIER_10 - damage_var_high = PROJECTILE_VARIANCE_TIER_1 - penetration = ARMOR_PENETRATION_TIER_10 - flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_BALLISTIC - -/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_mob(mob/M, obj/projectile/P) - ..() - cell_explosion(get_turf(M), 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) - -/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_obj(obj/O, obj/projectile/P) - ..() - cell_explosion(get_turf(O), 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) - -/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_turf(turf/T, obj/projectile/P) - ..() - cell_explosion(T, 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) - -/datum/ammo/bullet/revolver/webley //Mateba round without the knockdown. - name = ".455 Webley bullet" - damage = 60 - damage_var_low = PROJECTILE_VARIANCE_TIER_8 - damage_var_high = PROJECTILE_VARIANCE_TIER_6 - penetration = ARMOR_PENETRATION_TIER_2 - -/* -//====== - SMG Ammo -//====== -*/ -//2020 SMG/ammo rebalance. default ammo actually has penetration so it can be useful, by 4khan: should be meh against t3s, better under 15 armor. Perfectly does this right now (oct 2020) -//has reduced falloff compared to the m39. this means it is best for kiting castes (mostly t2s and below admittedly) -//while the m39 ap is better for shredding them at close range, but has reduced velocity, so it's better for just running in and erasing armor-centric castes (defender, crusher) -// which i think is really interesting and good balance, giving both ammo types a reason to exist even against ravagers. -//i feel it is necessary to reflavor the default bullet, because otherwise, people won't be able to notice it has less falloff and faster bullet speed. even with a changelog, -//way too many people don't read the changelog, and after one or two months the changelog entry is all but archive, so there needs to be an ingame description of what the ammo does -//in comparison to armor-piercing rounds. - -/datum/ammo/bullet/smg - name = "submachinegun bullet" - damage = 34 - accurate_range = 4 - effective_range_max = 4 - penetration = ARMOR_PENETRATION_TIER_1 - shell_speed = AMMO_SPEED_TIER_6 - damage_falloff = DAMAGE_FALLOFF_TIER_5 - scatter = SCATTER_AMOUNT_TIER_6 - accuracy = HIT_ACCURACY_TIER_3 - -/datum/ammo/bullet/smg/m39 - name = "high-velocity submachinegun bullet" //i don't want all smgs to inherit 'high velocity' - -/datum/ammo/bullet/smg/ap - name = "armor-piercing submachinegun bullet" - - damage = 26 - penetration = ARMOR_PENETRATION_TIER_6 - shell_speed = AMMO_SPEED_TIER_4 - -/datum/ammo/bullet/smg/heap - name = "high-explosive armor-piercing submachinegun bullet" - - damage = 45 - headshot_state = HEADSHOT_OVERLAY_MEDIUM - penetration = ARMOR_PENETRATION_TIER_6 - shell_speed = AMMO_SPEED_TIER_4 - -/datum/ammo/bullet/smg/ap/toxin - name = "toxic submachinegun bullet" - var/acid_per_hit = 5 - var/organic_damage_mult = 3 - -/datum/ammo/bullet/smg/ap/toxin/on_hit_mob(mob/M, obj/projectile/P) - . = ..() - M.AddComponent(/datum/component/toxic_buildup, acid_per_hit) - -/datum/ammo/bullet/smg/ap/toxin/on_hit_turf(turf/T, obj/projectile/P) - . = ..() - if(T.flags_turf & TURF_ORGANIC) - P.damage *= organic_damage_mult - -/datum/ammo/bullet/smg/ap/toxin/on_hit_obj(obj/O, obj/projectile/P) - . = ..() - if(O.flags_obj & OBJ_ORGANIC) - P.damage *= organic_damage_mult - -/datum/ammo/bullet/smg/nail - name = "7x45mm plasteel nail" - icon_state = "nail-projectile" - - damage = 25 - penetration = ARMOR_PENETRATION_TIER_5 - damage_falloff = DAMAGE_FALLOFF_TIER_6 - accurate_range = 5 - shell_speed = AMMO_SPEED_TIER_4 - -/datum/ammo/bullet/smg/incendiary - name = "incendiary submachinegun bullet" - damage_type = BURN - shrapnel_chance = 0 - flags_ammo_behavior = AMMO_BALLISTIC - - damage = 25 - accuracy = -HIT_ACCURACY_TIER_2 - -/datum/ammo/bullet/smg/incendiary/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/smg/ap/penetrating - name = "wall-penetrating submachinegun bullet" - shrapnel_chance = 0 - - damage = 30 - penetration = ARMOR_PENETRATION_TIER_10 - -/datum/ammo/bullet/smg/ap/penetrating/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) - )) - -/datum/ammo/bullet/smg/le - name = "armor-shredding submachinegun bullet" - - scatter = SCATTER_AMOUNT_TIER_10 - damage = 20 - penetration = ARMOR_PENETRATION_TIER_4 - shell_speed = AMMO_SPEED_TIER_3 - damage_falloff = DAMAGE_FALLOFF_TIER_10 - pen_armor_punch = 4 - -/datum/ammo/bullet/smg/rubber - name = "rubber submachinegun bullet" - sound_override = 'sound/weapons/gun_c99.ogg' - - damage = 0 - stamina_damage = 10 - shrapnel_chance = 0 - -/datum/ammo/bullet/smg/mp27 - name = "simple submachinegun bullet" - damage = 40 - accurate_range = 5 - effective_range_max = 7 - penetration = 0 - shell_speed = AMMO_SPEED_TIER_6 - damage_falloff = DAMAGE_FALLOFF_TIER_6 - scatter = SCATTER_AMOUNT_TIER_6 - accuracy = HIT_ACCURACY_TIER_2 - -// less damage than the m39, but better falloff, range, and AP - -/datum/ammo/bullet/smg/ppsh - name = "crude submachinegun bullet" - damage = 26 - accurate_range = 7 - effective_range_max = 7 - penetration = ARMOR_PENETRATION_TIER_2 - damage_falloff = DAMAGE_FALLOFF_TIER_7 - scatter = SCATTER_AMOUNT_TIER_5 - -/datum/ammo/bullet/smg/pps43 - name = "simple submachinegun bullet" - damage = 35 - accurate_range = 7 - effective_range_max = 10 - penetration = ARMOR_PENETRATION_TIER_4 - damage_falloff = DAMAGE_FALLOFF_TIER_6 - scatter = SCATTER_AMOUNT_TIER_6 - -/* -//====== - Rifle Ammo -//====== -*/ - -/datum/ammo/bullet/rifle - name = "rifle bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - - damage = 40 - penetration = ARMOR_PENETRATION_TIER_1 - accurate_range = 16 - accuracy = HIT_ACCURACY_TIER_4 - scatter = SCATTER_AMOUNT_TIER_10 - shell_speed = AMMO_SPEED_TIER_6 - effective_range_max = 7 - damage_falloff = DAMAGE_FALLOFF_TIER_7 - max_range = 24 //So S8 users don't have their bullets magically disappaer at 22 tiles (S8 can see 24 tiles) - -/datum/ammo/bullet/rifle/holo_target - name = "holo-targeting rifle bullet" - damage = 30 - var/holo_stacks = 10 - -/datum/ammo/bullet/rifle/holo_target/on_hit_mob(mob/M, obj/projectile/P) - . = ..() - M.AddComponent(/datum/component/bonus_damage_stack, holo_stacks, world.time) - -/datum/ammo/bullet/rifle/holo_target/hunting - name = "holo-targeting hunting bullet" - damage = 25 - holo_stacks = 15 - -/datum/ammo/bullet/rifle/explosive - name = "explosive rifle bullet" - - damage = 25 - accurate_range = 22 - accuracy = 0 - shell_speed = AMMO_SPEED_TIER_4 - damage_falloff = DAMAGE_FALLOFF_TIER_9 - -/datum/ammo/bullet/rifle/explosive/on_hit_mob(mob/M, obj/projectile/P) - cell_explosion(get_turf(M), 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) - -/datum/ammo/bullet/rifle/explosive/on_hit_obj(obj/O, obj/projectile/P) - cell_explosion(get_turf(O), 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) - -/datum/ammo/bullet/rifle/explosive/on_hit_turf(turf/T, obj/projectile/P) - if(T.density) - cell_explosion(T, 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data) - -/datum/ammo/bullet/rifle/ap - name = "armor-piercing rifle bullet" - - damage = 30 - penetration = ARMOR_PENETRATION_TIER_8 - -// Basically AP but better. Focused at taking out armour temporarily -/datum/ammo/bullet/rifle/ap/toxin - name = "toxic rifle bullet" - var/acid_per_hit = 7 - var/organic_damage_mult = 3 - -/datum/ammo/bullet/rifle/ap/toxin/on_hit_mob(mob/M, obj/projectile/P) - . = ..() - M.AddComponent(/datum/component/toxic_buildup, acid_per_hit) - -/datum/ammo/bullet/rifle/ap/toxin/on_hit_turf(turf/T, obj/projectile/P) - . = ..() - if(T.flags_turf & TURF_ORGANIC) - P.damage *= organic_damage_mult - -/datum/ammo/bullet/rifle/ap/toxin/on_hit_obj(obj/O, obj/projectile/P) - . = ..() - if(O.flags_obj & OBJ_ORGANIC) - P.damage *= organic_damage_mult - - -/datum/ammo/bullet/rifle/ap/penetrating - name = "wall-penetrating rifle bullet" - shrapnel_chance = 0 - - damage = 35 - penetration = ARMOR_PENETRATION_TIER_10 - -/datum/ammo/bullet/rifle/ap/penetrating/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) - )) - -/datum/ammo/bullet/rifle/le - name = "armor-shredding rifle bullet" - - damage = 20 - penetration = ARMOR_PENETRATION_TIER_4 - pen_armor_punch = 5 - -/datum/ammo/bullet/rifle/heap - name = "high-explosive armor-piercing rifle bullet" - - headshot_state = HEADSHOT_OVERLAY_HEAVY - damage = 55//big damage, doesn't actually blow up because thats stupid. - penetration = ARMOR_PENETRATION_TIER_8 - -/datum/ammo/bullet/rifle/rubber - name = "rubber rifle bullet" - sound_override = 'sound/weapons/gun_c99.ogg' - - damage = 0 - stamina_damage = 15 - shrapnel_chance = 0 - -/datum/ammo/bullet/rifle/incendiary - name = "incendiary rifle bullet" - damage_type = BURN - shrapnel_chance = 0 - flags_ammo_behavior = AMMO_BALLISTIC - - damage = 30 - shell_speed = AMMO_SPEED_TIER_4 - accuracy = -HIT_ACCURACY_TIER_2 - damage_falloff = DAMAGE_FALLOFF_TIER_10 - -/datum/ammo/bullet/rifle/incendiary/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/rifle/m4ra - name = "A19 high velocity bullet" - shrapnel_chance = 0 - damage_falloff = 0 - flags_ammo_behavior = AMMO_BALLISTIC - accurate_range_min = 4 - - damage = 55 - scatter = -SCATTER_AMOUNT_TIER_8 - penetration= ARMOR_PENETRATION_TIER_7 - shell_speed = AMMO_SPEED_TIER_6 - -/datum/ammo/bullet/rifle/m4ra/incendiary - name = "A19 high velocity incendiary bullet" - flags_ammo_behavior = AMMO_BALLISTIC - - damage = 40 - accuracy = HIT_ACCURACY_TIER_4 - scatter = -SCATTER_AMOUNT_TIER_8 - penetration= ARMOR_PENETRATION_TIER_5 - shell_speed = AMMO_SPEED_TIER_6 - -/datum/ammo/bullet/rifle/m4ra/incendiary/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/rifle/m4ra/impact - name = "A19 high velocity impact bullet" - flags_ammo_behavior = AMMO_BALLISTIC - - damage = 40 - accuracy = -HIT_ACCURACY_TIER_2 - scatter = -SCATTER_AMOUNT_TIER_8 - penetration = ARMOR_PENETRATION_TIER_10 - shell_speed = AMMO_SPEED_TIER_6 - -/datum/ammo/bullet/rifle/m4ra/impact/on_hit_mob(mob/M, obj/projectile/P) - knockback(M, P, 32) // Can knockback basically at max range - -/datum/ammo/bullet/rifle/m4ra/impact/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile) - if(iscarbonsizexeno(living_mob)) - var/mob/living/carbon/xenomorph/target = living_mob - to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!")) - target.apply_effect(0.5, WEAKEN) - target.apply_effect(2, SUPERSLOW) - target.apply_effect(5, SLOW) - else - if(!isyautja(living_mob)) //Not predators. - living_mob.apply_effect(1, SUPERSLOW) - living_mob.apply_effect(2, SLOW) - to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!")) - living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) - -/datum/ammo/bullet/rifle/mar40 - name = "heavy rifle bullet" - - damage = 55 - -/datum/ammo/bullet/rifle/type71 - name = "heavy rifle bullet" - - damage = 55 - penetration = ARMOR_PENETRATION_TIER_3 - -/datum/ammo/bullet/rifle/type71/ap - name = "heavy armor-piercing rifle bullet" - - damage = 40 - penetration = ARMOR_PENETRATION_TIER_10 - -/datum/ammo/bullet/rifle/type71/heap - name = "heavy high-explosive armor-piercing rifle bullet" - - headshot_state = HEADSHOT_OVERLAY_HEAVY - damage = 65 - penetration = ARMOR_PENETRATION_TIER_10 - -/* -//====== - Shotgun Ammo -//====== -*/ - -/datum/ammo/bullet/shotgun - headshot_state = HEADSHOT_OVERLAY_HEAVY - -/datum/ammo/bullet/shotgun/slug - name = "shotgun slug" - handful_state = "slug_shell" - - accurate_range = 6 - max_range = 8 - damage = 70 - penetration = ARMOR_PENETRATION_TIER_4 - damage_armor_punch = 2 - handful_state = "slug_shell" - -/datum/ammo/bullet/shotgun/slug/on_hit_mob(mob/M,obj/projectile/P) - knockback(M, P, 6) - -/datum/ammo/bullet/shotgun/slug/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile) - if(iscarbonsizexeno(living_mob)) - var/mob/living/carbon/xenomorph/target = living_mob - to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!")) - target.apply_effect(0.5, WEAKEN) - target.apply_effect(1, SUPERSLOW) - target.apply_effect(3, SLOW) - else - if(!isyautja(living_mob)) //Not predators. - living_mob.apply_effect(1, SUPERSLOW) - living_mob.apply_effect(2, SLOW) - to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!")) - living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) - -/datum/ammo/bullet/shotgun/beanbag - name = "beanbag slug" - headshot_state = HEADSHOT_OVERLAY_LIGHT //It's not meant to kill people... but if you put it in your mouth, it will. - handful_state = "beanbag_slug" - icon_state = "beanbag" - flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST - sound_override = 'sound/weapons/gun_shotgun_riot.ogg' - - max_range = 12 - shrapnel_chance = 0 - damage = 0 - stamina_damage = 45 - accuracy = HIT_ACCURACY_TIER_3 - shell_speed = AMMO_SPEED_TIER_3 - handful_state = "beanbag_slug" - -/datum/ammo/bullet/shotgun/beanbag/on_hit_mob(mob/M, obj/projectile/P) - if(!M || M == P.firer) return - if(ishuman(M)) - var/mob/living/carbon/human/H = M - shake_camera(H, 2, 1) - - -/datum/ammo/bullet/shotgun/incendiary - name = "incendiary slug" - handful_state = "incendiary_slug" - damage_type = BURN - flags_ammo_behavior = AMMO_BALLISTIC - - accuracy = -HIT_ACCURACY_TIER_2 - max_range = 12 - damage = 55 - penetration= ARMOR_PENETRATION_TIER_1 - handful_state = "incendiary_slug" - -/datum/ammo/bullet/shotgun/incendiary/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/shotgun/incendiary/on_hit_mob(mob/M,obj/projectile/P) - burst(get_turf(M),P,damage_type) - knockback(M,P) - -/datum/ammo/bullet/shotgun/incendiary/on_hit_obj(obj/O,obj/projectile/P) - burst(get_turf(P),P,damage_type) - -/datum/ammo/bullet/shotgun/incendiary/on_hit_turf(turf/T,obj/projectile/P) - burst(get_turf(T),P,damage_type) - - -/datum/ammo/bullet/shotgun/flechette - name = "flechette shell" - icon_state = "flechette" - handful_state = "flechette_shell" - bonus_projectiles_type = /datum/ammo/bullet/shotgun/flechette_spread - - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 - max_range = 12 - damage = 30 - damage_var_low = PROJECTILE_VARIANCE_TIER_8 - damage_var_high = PROJECTILE_VARIANCE_TIER_8 - penetration = ARMOR_PENETRATION_TIER_7 - bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3 - handful_state = "flechette_shell" - multiple_handful_name = TRUE - -/datum/ammo/bullet/shotgun/flechette_spread - name = "additional flechette" - icon_state = "flechette" - - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 - max_range = 12 - damage = 30 - damage_var_low = PROJECTILE_VARIANCE_TIER_8 - damage_var_high = PROJECTILE_VARIANCE_TIER_8 - penetration = ARMOR_PENETRATION_TIER_7 - scatter = SCATTER_AMOUNT_TIER_5 - -/datum/ammo/bullet/shotgun/buckshot - name = "buckshot shell" - icon_state = "buckshot" - handful_state = "buckshot_shell" - multiple_handful_name = TRUE - bonus_projectiles_type = /datum/ammo/bullet/shotgun/spread - - accuracy_var_low = PROJECTILE_VARIANCE_TIER_5 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_5 - accurate_range = 4 - max_range = 4 - damage = 65 - damage_var_low = PROJECTILE_VARIANCE_TIER_8 - damage_var_high = PROJECTILE_VARIANCE_TIER_8 - penetration = ARMOR_PENETRATION_TIER_1 - bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3 - shell_speed = AMMO_SPEED_TIER_2 - damage_armor_punch = 0 - pen_armor_punch = 0 - handful_state = "buckshot_shell" - multiple_handful_name = TRUE - -/datum/ammo/bullet/shotgun/buckshot/incendiary - name = "incendiary buckshot shell" - handful_state = "incen_buckshot" - handful_type = /obj/item/ammo_magazine/handful/shotgun/buckshot/incendiary - -/datum/ammo/bullet/shotgun/buckshot/incendiary/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/shotgun/buckshot/on_hit_mob(mob/M,obj/projectile/P) - knockback(M,P) - -//buckshot variant only used by the masterkey shotgun attachment. -/datum/ammo/bullet/shotgun/buckshot/masterkey - bonus_projectiles_type = /datum/ammo/bullet/shotgun/spread/masterkey - - damage = 55 - -/datum/ammo/bullet/shotgun/spread - name = "additional buckshot" - icon_state = "buckshot" - - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 - accurate_range = 4 - max_range = 6 - damage = 65 - damage_var_low = PROJECTILE_VARIANCE_TIER_8 - damage_var_high = PROJECTILE_VARIANCE_TIER_8 - penetration = ARMOR_PENETRATION_TIER_1 - shell_speed = AMMO_SPEED_TIER_2 - scatter = SCATTER_AMOUNT_TIER_1 - damage_armor_punch = 0 - pen_armor_punch = 0 - -/datum/ammo/bullet/shotgun/spread/masterkey - damage = 20 - -/* - 8 GAUGE SHOTGUN AMMO -*/ - -/datum/ammo/bullet/shotgun/heavy/buckshot - name = "heavy buckshot shell" - icon_state = "buckshot" - handful_state = "heavy_buckshot" - multiple_handful_name = TRUE - bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/buckshot/spread - bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3 - accurate_range = 3 - max_range = 3 - damage = 75 - penetration = 0 - shell_speed = AMMO_SPEED_TIER_2 - damage_armor_punch = 0 - pen_armor_punch = 0 - -/datum/ammo/bullet/shotgun/heavy/buckshot/on_hit_mob(mob/M,obj/projectile/P) - knockback(M,P) - -/datum/ammo/bullet/shotgun/heavy/buckshot/spread - name = "additional heavy buckshot" - max_range = 4 - scatter = SCATTER_AMOUNT_TIER_1 - bonus_projectiles_amount = 0 - -//basically the same -/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath - name = "dragon's breath shell" - handful_state = "heavy_dragonsbreath" - multiple_handful_name = TRUE - damage_type = BURN - damage = 60 - accurate_range = 3 - max_range = 4 - bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/spread - -/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/spread - name = "additional dragon's breath" - bonus_projectiles_amount = 0 - accurate_range = 4 - max_range = 5 //make use of the ablaze property - shell_speed = AMMO_SPEED_TIER_4 // so they hit before the main shell stuns - - -/datum/ammo/bullet/shotgun/heavy/slug - name = "heavy shotgun slug" - handful_state = "heavy_slug" - - accurate_range = 7 - max_range = 8 - damage = 90 //ouch. - penetration = ARMOR_PENETRATION_TIER_6 - damage_armor_punch = 2 - -/datum/ammo/bullet/shotgun/heavy/slug/on_hit_mob(mob/M,obj/projectile/P) - knockback(M, P, 7) - -/datum/ammo/bullet/shotgun/heavy/slug/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile) - if(iscarbonsizexeno(living_mob)) - var/mob/living/carbon/xenomorph/target = living_mob - to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!")) - target.apply_effect(0.5, WEAKEN) - target.apply_effect(2, SUPERSLOW) - target.apply_effect(5, SLOW) - else - if(!isyautja(living_mob)) //Not predators. - living_mob.apply_effect(1, SUPERSLOW) - living_mob.apply_effect(2, SLOW) - to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!")) - living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) - -/datum/ammo/bullet/shotgun/heavy/beanbag - name = "heavy beanbag slug" - icon_state = "beanbag" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - handful_state = "heavy_beanbag" - flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST - sound_override = 'sound/weapons/gun_shotgun_riot.ogg' - - max_range = 7 - shrapnel_chance = 0 - damage = 0 - stamina_damage = 100 - accuracy = HIT_ACCURACY_TIER_2 - shell_speed = AMMO_SPEED_TIER_2 - -/datum/ammo/bullet/shotgun/heavy/beanbag/on_hit_mob(mob/M, obj/projectile/P) - if(!M || M == P.firer) - return - if(ishuman(M)) - var/mob/living/carbon/human/H = M - shake_camera(H, 2, 1) - -/datum/ammo/bullet/shotgun/heavy/flechette - name = "heavy flechette shell" - icon_state = "flechette" - handful_state = "heavy_flechette" - multiple_handful_name = TRUE - bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/flechette_spread - - accuracy_var_low = PROJECTILE_VARIANCE_TIER_3 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_3 - max_range = 12 - damage = 45 - damage_var_low = PROJECTILE_VARIANCE_TIER_8 - damage_var_high = PROJECTILE_VARIANCE_TIER_8 - penetration = ARMOR_PENETRATION_TIER_10 - bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_2 - -/datum/ammo/bullet/shotgun/heavy/flechette_spread - name = "additional heavy flechette" - icon_state = "flechette" - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 - max_range = 12 - damage = 45 - damage_var_low = PROJECTILE_VARIANCE_TIER_8 - damage_var_high = PROJECTILE_VARIANCE_TIER_8 - penetration = ARMOR_PENETRATION_TIER_10 - scatter = SCATTER_AMOUNT_TIER_4 - -//Enormous shell for Van Bandolier's superheavy double-barreled hunting gun. -/datum/ammo/bullet/shotgun/twobore - name = "two bore bullet" - icon_state = "autocannon" - handful_state = "twobore" - - accurate_range = 8 //Big low-velocity projectile; this is for blasting dangerous game at close range. - max_range = 14 //At this range, it's lost all its damage anyway. - damage = 300 //Hits like a buckshot PB. - penetration = ARMOR_PENETRATION_TIER_3 - damage_falloff = DAMAGE_FALLOFF_TIER_1 * 3 //It has a lot of energy, but the 26mm bullet drops off fast. - effective_range_max = EFFECTIVE_RANGE_MAX_TIER_2 //Full damage up to this distance, then falloff for each tile beyond. - var/hit_messages = list() - -/datum/ammo/bullet/shotgun/twobore/on_hit_mob(mob/living/M, obj/projectile/P) - var/mob/shooter = P.firer - if(shooter && ismob(shooter) && HAS_TRAIT(shooter, TRAIT_TWOBORE_TRAINING) && M.stat != DEAD && prob(40)) //Death is handled by periodic life() checks so this should have a chance to fire on a killshot. - if(!length(hit_messages)) //Pick and remove lines, refill on exhaustion. - hit_messages = list("Got you!", "Aha!", "Bullseye!", "It's curtains for you, Sonny Jim!", "Your head will look fantastic on my wall!", "I have you now!", "You miserable coward! Come and fight me like a man!", "Tally ho!") - var/message = pick_n_take(hit_messages) - shooter.say(message) - - if(P.distance_travelled > 8) - knockback(M, P, 12) - - else if(!M || M == P.firer || M.lying) //These checks are included in knockback and would be redundant above. - return - - shake_camera(M, 3, 4) - M.apply_effect(2, WEAKEN) - M.apply_effect(4, SLOW) - if(iscarbonsizexeno(M)) - to_chat(M, SPAN_XENODANGER("The impact knocks you off your feet!")) - else //This will hammer a Yautja as hard as a human. - to_chat(M, SPAN_HIGHDANGER("The impact knocks you off your feet!")) - - step(M, get_dir(P.firer, M)) - -/datum/ammo/bullet/shotgun/twobore/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile) - if(iscarbonsizexeno(living_mob)) - var/mob/living/carbon/xenomorph/target = living_mob - to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!")) - target.apply_effect(0.5, WEAKEN) - target.apply_effect(2, SUPERSLOW) - target.apply_effect(5, SLOW) - else - if(!isyautja(living_mob)) //Not predators. - living_mob.apply_effect(1, SUPERSLOW) - living_mob.apply_effect(2, SLOW) - to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!")) - living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET) - -/datum/ammo/bullet/lever_action - name = "lever-action bullet" - - damage = 80 - penetration = 0 - accuracy = HIT_ACCURACY_TIER_1 - shell_speed = AMMO_SPEED_TIER_6 - accurate_range = 14 - handful_state = "lever_action_bullet" - -//unused and not working. need to refactor MD code. Unobtainable. -//intended mechanic is to have xenos hit with it show up very frequently on any MDs around -/datum/ammo/bullet/lever_action/tracker - name = "tracking lever-action bullet" - icon_state = "redbullet" - damage = 70 - penetration = ARMOR_PENETRATION_TIER_3 - accuracy = HIT_ACCURACY_TIER_1 - handful_state = "tracking_lever_action_bullet" - -/datum/ammo/bullet/lever_action/tracker/on_hit_mob(mob/M, obj/projectile/P, mob/user) - //SEND_SIGNAL(user, COMSIG_BULLET_TRACKING, user, M) - M.visible_message(SPAN_DANGER("You hear a faint beep under [M]'s [M.mob_size > MOB_SIZE_HUMAN ? "chitin" : "skin"].")) - -/datum/ammo/bullet/lever_action/training - name = "lever-action blank" - icon_state = "blank" - damage = 70 //blanks CAN hurt you if shot very close - penetration = 0 - accuracy = HIT_ACCURACY_TIER_1 - damage_falloff = DAMAGE_FALLOFF_BLANK //not much, though (comparatively) - shell_speed = AMMO_SPEED_TIER_5 - handful_state = "training_lever_action_bullet" - -//unused, and unobtainable... for now -/datum/ammo/bullet/lever_action/marksman - name = "marksman lever-action bullet" - shrapnel_chance = 0 - damage_falloff = 0 - accurate_range = 12 - damage = 70 - penetration = ARMOR_PENETRATION_TIER_6 - shell_speed = AMMO_SPEED_TIER_6 - handful_state = "marksman_lever_action_bullet" - -/datum/ammo/bullet/lever_action/xm88 - name = ".458 SOCOM round" - - damage = 80 - penetration = ARMOR_PENETRATION_TIER_2 - accuracy = HIT_ACCURACY_TIER_1 - shell_speed = AMMO_SPEED_TIER_6 - accurate_range = 14 - handful_state = "boomslang_bullet" - -/datum/ammo/bullet/lever_action/xm88/pen20 - penetration = ARMOR_PENETRATION_TIER_4 - -/datum/ammo/bullet/lever_action/xm88/pen30 - penetration = ARMOR_PENETRATION_TIER_6 - -/datum/ammo/bullet/lever_action/xm88/pen40 - penetration = ARMOR_PENETRATION_TIER_8 - -/datum/ammo/bullet/lever_action/xm88/pen50 - penetration = ARMOR_PENETRATION_TIER_10 - -/* -//====== - Sniper Ammo -//====== -*/ - -/datum/ammo/bullet/sniper - name = "sniper bullet" - headshot_state = HEADSHOT_OVERLAY_HEAVY - damage_falloff = 0 - flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER - accurate_range_min = 4 - - accuracy = HIT_ACCURACY_TIER_8 - accurate_range = 32 - max_range = 32 - scatter = 0 - damage = 70 - penetration= ARMOR_PENETRATION_TIER_10 - shell_speed = AMMO_SPEED_TIER_6 - damage_falloff = 0 - -/datum/ammo/bullet/sniper/on_hit_mob(mob/M,obj/projectile/P) - if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) - var/mob/living/L = M - L.apply_armoured_damage(damage*2, ARMOR_BULLET, BRUTE, null, penetration) - to_chat(P.firer, SPAN_WARNING("Bullseye!")) - -/datum/ammo/bullet/sniper/incendiary - name = "incendiary sniper bullet" - damage_type = BRUTE - shrapnel_chance = 0 - flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER - - //Removed accuracy = 0, accuracy_var_high = Variance Tier 6, and scatter = 0. -Kaga - damage = 60 - penetration = ARMOR_PENETRATION_TIER_4 - -/datum/ammo/bullet/sniper/incendiary/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/sniper/incendiary/on_hit_mob(mob/M,obj/projectile/P) - if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) - var/mob/living/L = M - var/blind_duration = 5 - if(isxeno(M)) - var/mob/living/carbon/xenomorph/target = M - if(target.mob_size >= MOB_SIZE_BIG) - blind_duration = 2 - L.AdjustEyeBlur(blind_duration) - L.adjust_fire_stacks(10) - to_chat(P.firer, SPAN_WARNING("Bullseye!")) - -/datum/ammo/bullet/sniper/flak - name = "flak sniper bullet" - damage_type = BRUTE - flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER - - accuracy = HIT_ACCURACY_TIER_8 - scatter = SCATTER_AMOUNT_TIER_8 - damage = 55 - damage_var_high = PROJECTILE_VARIANCE_TIER_8 //Documenting old code: This converts to a variance of 96-109% damage. -Kaga - penetration = 0 - -/datum/ammo/bullet/sniper/flak/on_hit_mob(mob/M,obj/projectile/P) - if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) - var/slow_duration = 7 - var/mob/living/L = M - if(isxeno(M)) - var/mob/living/carbon/xenomorph/target = M - if(target.mob_size >= MOB_SIZE_BIG) - slow_duration = 4 - M.adjust_effect(slow_duration, SUPERSLOW) - L.apply_armoured_damage(damage, ARMOR_BULLET, BRUTE, null, penetration) - to_chat(P.firer, SPAN_WARNING("Bullseye!")) - else - burst(get_turf(M),P,damage_type, 2 , 2) - burst(get_turf(M),P,damage_type, 1 , 2 , 0) - -/datum/ammo/bullet/sniper/flak/on_near_target(turf/T, obj/projectile/P) - burst(T,P,damage_type, 2 , 2) - burst(T,P,damage_type, 1 , 2, 0) - return 1 - -/datum/ammo/bullet/sniper/crude - name = "crude sniper bullet" - damage = 42 - penetration = ARMOR_PENETRATION_TIER_6 - -/datum/ammo/bullet/sniper/crude/on_hit_mob(mob/M, obj/projectile/P) - . = ..() - pushback(M, P, 3) - -/datum/ammo/bullet/sniper/upp - name = "armor-piercing sniper bullet" - damage = 80 - penetration = ARMOR_PENETRATION_TIER_10 - -/datum/ammo/bullet/sniper/anti_materiel - name = "anti-materiel sniper bullet" - - shrapnel_chance = 0 // This isn't leaving any shrapnel. - accuracy = HIT_ACCURACY_TIER_8 - damage = 125 - shell_speed = AMMO_SPEED_TIER_6 - -/datum/ammo/bullet/sniper/anti_materiel/on_hit_mob(mob/M,obj/projectile/P) - if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) - var/mob/living/L = M - var/size_damage_mod = 0.8 - if(isxeno(M)) - var/mob/living/carbon/xenomorph/target = M - if(target.mob_size >= MOB_SIZE_XENO) - size_damage_mod += 0.6 - if(target.mob_size >= MOB_SIZE_BIG) - size_damage_mod += 0.6 - L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration) - // 180% damage to all targets (225), 240% (300) against non-Runner xenos, and 300% against Big xenos (375). -Kaga - to_chat(P.firer, SPAN_WARNING("Bullseye!")) - -/datum/ammo/bullet/sniper/anti_materiel/vulture - damage = 400 // Fully intended to vaporize anything smaller than a mini cooper - accurate_range_min = 10 - handful_state = "vulture_bullet" - sound_hit = 'sound/bullets/bullet_vulture_impact.ogg' - flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER|AMMO_ANTIVEHICLE - -/datum/ammo/bullet/sniper/anti_materiel/vulture/on_hit_mob(mob/hit_mob, obj/projectile/bullet) - . = ..() - knockback(hit_mob, bullet, 30) - hit_mob.apply_effect(3, SLOW) - -/datum/ammo/bullet/sniper/anti_materiel/vulture/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating/heavy) - )) - -/datum/ammo/bullet/sniper/elite - name = "supersonic sniper bullet" - - shrapnel_chance = 0 // This isn't leaving any shrapnel. - accuracy = HIT_ACCURACY_TIER_8 - damage = 150 - shell_speed = AMMO_SPEED_TIER_6 + AMMO_SPEED_TIER_2 - -/datum/ammo/bullet/sniper/elite/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating) - )) - -/datum/ammo/bullet/sniper/elite/on_hit_mob(mob/M,obj/projectile/P) - if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original) - var/mob/living/L = M - var/size_damage_mod = 0.5 - if(isxeno(M)) - var/mob/living/carbon/xenomorph/target = M - if(target.mob_size >= MOB_SIZE_XENO) - size_damage_mod += 0.5 - if(target.mob_size >= MOB_SIZE_BIG) - size_damage_mod += 1 - L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration) - else - L.apply_armoured_damage(damage, ARMOR_BULLET, BRUTE, null, penetration) - // 150% damage to runners (225), 300% against Big xenos (450), and 200% against all others (300). -Kaga - to_chat(P.firer, SPAN_WARNING("Bullseye!")) - -/datum/ammo/bullet/tank/flak - name = "flak autocannon bullet" - icon_state = "autocannon" - damage_falloff = 0 - flags_ammo_behavior = AMMO_BALLISTIC - accurate_range_min = 4 - - accuracy = HIT_ACCURACY_TIER_8 - scatter = 0 - damage = 60 - damage_var_high = PROJECTILE_VARIANCE_TIER_8 - penetration = ARMOR_PENETRATION_TIER_6 - accurate_range = 32 - max_range = 32 - shell_speed = AMMO_SPEED_TIER_6 - -/datum/ammo/bullet/tank/flak/on_hit_mob(mob/M,obj/projectile/P) - burst(get_turf(M),P,damage_type, 2 , 3) - burst(get_turf(M),P,damage_type, 1 , 3 , 0) - -/datum/ammo/bullet/tank/flak/on_near_target(turf/T, obj/projectile/P) - burst(get_turf(T),P,damage_type, 2 , 3) - burst(get_turf(T),P,damage_type, 1 , 3, 0) - return 1 - -/datum/ammo/bullet/tank/flak/on_hit_obj(obj/O,obj/projectile/P) - burst(get_turf(P),P,damage_type, 2 , 3) - burst(get_turf(P),P,damage_type, 1 , 3 , 0) - -/datum/ammo/bullet/tank/flak/on_hit_turf(turf/T,obj/projectile/P) - burst(get_turf(T),P,damage_type, 2 , 3) - burst(get_turf(T),P,damage_type, 1 , 3 , 0) - -/datum/ammo/bullet/tank/dualcannon - name = "dualcannon bullet" - icon_state = "autocannon" - damage_falloff = 0 - flags_ammo_behavior = AMMO_BALLISTIC - - accuracy = HIT_ACCURACY_TIER_8 - scatter = 0 - damage = 50 - damage_var_high = PROJECTILE_VARIANCE_TIER_8 - penetration = ARMOR_PENETRATION_TIER_3 - accurate_range = 10 - max_range = 12 - shell_speed = AMMO_SPEED_TIER_5 - -/datum/ammo/bullet/tank/dualcannon/on_hit_mob(mob/M,obj/projectile/P) - for(var/mob/living/carbon/L in get_turf(M)) - if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO) - shake_camera(L, 1, 1) - -/datum/ammo/bullet/tank/dualcannon/on_near_target(turf/T, obj/projectile/P) - for(var/mob/living/carbon/L in T) - if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO) - shake_camera(L, 1, 1) - return 1 - -/datum/ammo/bullet/tank/dualcannon/on_hit_obj(obj/O,obj/projectile/P) - for(var/mob/living/carbon/L in get_turf(O)) - if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO) - shake_camera(L, 1, 1) - -/datum/ammo/bullet/tank/dualcannon/on_hit_turf(turf/T,obj/projectile/P) - for(var/mob/living/carbon/L in T) - if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO) - shake_camera(L, 1, 1) - -/* -//====== - Special Ammo -//====== -*/ - -/datum/ammo/bullet/smartgun - name = "smartgun bullet" - icon_state = "redbullet" - flags_ammo_behavior = AMMO_BALLISTIC - - max_range = 12 - accuracy = HIT_ACCURACY_TIER_4 - damage = 36 - penetration = 0 - -/datum/ammo/bullet/smartgun/armor_piercing - name = "armor-piercing smartgun bullet" - icon_state = "bullet" - - accurate_range = 12 - accuracy = HIT_ACCURACY_TIER_2 - damage = 24 - penetration = ARMOR_PENETRATION_TIER_8 - damage_armor_punch = 1 - -/datum/ammo/bullet/smartgun/dirty - name = "irradiated smartgun bullet" - debilitate = list(0,0,0,3,0,0,0,1) - - shrapnel_chance = SHRAPNEL_CHANCE_TIER_7 - accurate_range = 32 - accuracy = HIT_ACCURACY_TIER_3 - damage = 40 - penetration = 0 - -/datum/ammo/bullet/smartgun/dirty/armor_piercing - debilitate = list(0,0,0,3,0,0,0,1) - - accurate_range = 22 - accuracy = HIT_ACCURACY_TIER_3 - damage = 30 - penetration = ARMOR_PENETRATION_TIER_7 - damage_armor_punch = 3 - -/datum/ammo/bullet/smartgun/holo_target //Royal marines smartgun bullet has only diff between regular ammo is this one does holostacks - name = "holo-targeting smartgun bullet" - damage = 30 -///Stuff for the HRP holotargetting stacks - var/holo_stacks = 15 - -/datum/ammo/bullet/smartgun/holo_target/on_hit_mob(mob/M, obj/projectile/P) - . = ..() - M.AddComponent(/datum/component/bonus_damage_stack, holo_stacks, world.time) - -/datum/ammo/bullet/smartgun/holo_target/ap - name = "armor-piercing smartgun bullet" - icon_state = "bullet" - - accurate_range = 12 - accuracy = HIT_ACCURACY_TIER_2 - damage = 20 - penetration = ARMOR_PENETRATION_TIER_8 - damage_armor_punch = 1 - -/datum/ammo/bullet/smartgun/m56_fpw - name = "\improper M56 FPW bullet" - icon_state = "redbullet" - flags_ammo_behavior = AMMO_BALLISTIC - - max_range = 7 - accuracy = HIT_ACCURACY_TIER_7 - damage = 35 - penetration = ARMOR_PENETRATION_TIER_1 - -/datum/ammo/bullet/turret - name = "autocannon bullet" - icon_state = "redbullet" //Red bullets to indicate friendly fire restriction - flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_COVER - - accurate_range = 22 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_8 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_8 - max_range = 22 - damage = 30 - penetration = ARMOR_PENETRATION_TIER_7 - damage_armor_punch = 0 - pen_armor_punch = 0 - shell_speed = 2*AMMO_SPEED_TIER_6 - accuracy = HIT_ACCURACY_TIER_5 - -/datum/ammo/bullet/turret/dumb - icon_state = "bullet" - flags_ammo_behavior = AMMO_BALLISTIC - -/datum/ammo/bullet/machinegun //Adding this for the MG Nests (~Art) - name = "machinegun bullet" - icon_state = "bullet" // Keeping it bog standard with the turret but allows it to be changed - - accurate_range = 12 - damage = 36 - penetration= ARMOR_PENETRATION_TIER_10 //Bumped the penetration to serve a different role from sentries, MGs are a bit more offensive - accuracy = HIT_ACCURACY_TIER_3 - -/datum/ammo/bullet/machinegun/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff) - )) - -/datum/ammo/bullet/machinegun/auto // for M2C, automatic variant for M56D, stats for bullet should always be moderately overtuned to fulfill its ultra-offense + flank-push purpose - name = "heavy machinegun bullet" - - accurate_range = 10 - damage = 50 - penetration = ARMOR_PENETRATION_TIER_6 - accuracy = -HIT_ACCURACY_TIER_2 // 75 accuracy - shell_speed = AMMO_SPEED_TIER_2 - max_range = 15 - effective_range_max = 7 - damage_falloff = DAMAGE_FALLOFF_TIER_8 - -/datum/ammo/bullet/machinegun/auto/set_bullet_traits() - return - -/datum/ammo/bullet/minigun - name = "minigun bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - - accuracy = -HIT_ACCURACY_TIER_3 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 - accurate_range = 12 - damage = 35 - penetration = ARMOR_PENETRATION_TIER_6 - -/datum/ammo/bullet/minigun/New() - ..() - if(SSticker.mode && MODE_HAS_FLAG(MODE_FACTION_CLASH)) - damage = 15 - else if(SSticker.current_state < GAME_STATE_PLAYING) - RegisterSignal(SSdcs, COMSIG_GLOB_MODE_PRESETUP, PROC_REF(setup_hvh_damage)) - -/datum/ammo/bullet/minigun/proc/setup_hvh_damage() - if(MODE_HAS_FLAG(MODE_FACTION_CLASH)) - damage = 15 - -/datum/ammo/bullet/minigun/tank - accuracy = -HIT_ACCURACY_TIER_1 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_8 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_8 - accurate_range = 12 - -/datum/ammo/bullet/m60 - name = "M60 bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - - accuracy = HIT_ACCURACY_TIER_2 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_8 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 - accurate_range = 12 - damage = 45 //7.62x51 is scary - penetration= ARMOR_PENETRATION_TIER_6 - shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 - -/datum/ammo/bullet/pkp - name = "machinegun bullet" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - - accuracy = HIT_ACCURACY_TIER_1 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_8 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 - accurate_range = 14 - damage = 35 - penetration= ARMOR_PENETRATION_TIER_6 - shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 - -/* -//====== - Rocket Ammo -//====== -*/ - -/datum/ammo/rocket - name = "high explosive rocket" - icon_state = "missile" - ping = null //no bounce off. - sound_bounce = "rocket_bounce" - damage_falloff = 0 - flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_STRIKES_SURFACE - var/datum/effect_system/smoke_spread/smoke - - accuracy = HIT_ACCURACY_TIER_2 - accurate_range = 7 - max_range = 7 - damage = 15 - shell_speed = AMMO_SPEED_TIER_2 - -/datum/ammo/rocket/New() - ..() - smoke = new() - -/datum/ammo/rocket/Destroy() - qdel(smoke) - smoke = null - . = ..() - -/datum/ammo/rocket/on_hit_mob(mob/M, obj/projectile/P) - cell_explosion(get_turf(M), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - smoke.set_up(1, get_turf(M)) - if(ishuman_strict(M)) // No yautya or synths. Makes humans gib on direct hit. - M.ex_act(350, P.dir, P.weapon_cause_data, 100) - smoke.start() - -/datum/ammo/rocket/on_hit_obj(obj/O, obj/projectile/P) - cell_explosion(get_turf(O), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - smoke.set_up(1, get_turf(O)) - smoke.start() - -/datum/ammo/rocket/on_hit_turf(turf/T, obj/projectile/P) - cell_explosion(T, 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - smoke.set_up(1, T) - smoke.start() - -/datum/ammo/rocket/do_at_max_range(obj/projectile/P) - cell_explosion(get_turf(P), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - smoke.set_up(1, get_turf(P)) - smoke.start() - -/datum/ammo/rocket/ap - name = "anti-armor rocket" - damage_falloff = 0 - flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET - - accuracy = HIT_ACCURACY_TIER_8 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_9 - accurate_range = 6 - max_range = 6 - damage = 10 - penetration= ARMOR_PENETRATION_TIER_10 - -/datum/ammo/rocket/ap/on_hit_mob(mob/M, obj/projectile/P) - var/turf/T = get_turf(M) - M.ex_act(150, P.dir, P.weapon_cause_data, 100) - M.apply_effect(2, WEAKEN) - M.apply_effect(2, PARALYZE) - if(ishuman_strict(M)) // No yautya or synths. Makes humans gib on direct hit. - M.ex_act(300, P.dir, P.weapon_cause_data, 100) - cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - smoke.set_up(1, T) - smoke.start() - -/datum/ammo/rocket/ap/on_hit_obj(obj/O, obj/projectile/P) - var/turf/T = get_turf(O) - O.ex_act(150, P.dir, P.weapon_cause_data, 100) - cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - smoke.set_up(1, T) - smoke.start() - -/datum/ammo/rocket/ap/on_hit_turf(turf/T, obj/projectile/P) - var/hit_something = 0 - for(var/mob/M in T) - M.ex_act(150, P.dir, P.weapon_cause_data, 100) - M.apply_effect(4, WEAKEN) - M.apply_effect(4, PARALYZE) - hit_something = 1 - continue - if(!hit_something) - for(var/obj/O in T) - if(O.density) - O.ex_act(150, P.dir, P.weapon_cause_data, 100) - hit_something = 1 - continue - if(!hit_something) - T.ex_act(150, P.dir, P.weapon_cause_data, 200) - - cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - smoke.set_up(1, T) - smoke.start() - -/datum/ammo/rocket/ap/do_at_max_range(obj/projectile/P) - var/turf/T = get_turf(P) - var/hit_something = 0 - for(var/mob/M in T) - M.ex_act(250, P.dir, P.weapon_cause_data, 100) - M.apply_effect(2, WEAKEN) - M.apply_effect(2, PARALYZE) - hit_something = 1 - continue - if(!hit_something) - for(var/obj/O in T) - if(O.density) - O.ex_act(250, P.dir, P.weapon_cause_data, 100) - hit_something = 1 - continue - if(!hit_something) - T.ex_act(250, P.dir, P.weapon_cause_data) - cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - smoke.set_up(1, T) - smoke.start() - -/datum/ammo/rocket/ap/anti_tank - name = "anti-tank rocket" - damage = 100 - var/vehicle_slowdown_time = 5 SECONDS - shrapnel_chance = 5 - shrapnel_type = /obj/item/large_shrapnel/at_rocket_dud - -/datum/ammo/rocket/ap/anti_tank/on_hit_obj(obj/O, obj/projectile/P) - if(istype(O, /obj/vehicle/multitile)) - var/obj/vehicle/multitile/M = O - M.next_move = world.time + vehicle_slowdown_time - playsound(M, 'sound/effects/meteorimpact.ogg', 35) - M.at_munition_interior_explosion_effect(cause_data = create_cause_data("Anti-Tank Rocket")) - M.interior_crash_effect() - var/turf/T = get_turf(M.loc) - M.ex_act(150, P.dir, P.weapon_cause_data, 100) - smoke.set_up(1, T) - smoke.start() - return - return ..() - - -/datum/ammo/rocket/ltb - name = "cannon round" - icon_state = "ltb" - flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_STRIKES_SURFACE - - accuracy = HIT_ACCURACY_TIER_3 - accurate_range = 32 - max_range = 32 - damage = 25 - shell_speed = AMMO_SPEED_TIER_3 - -/datum/ammo/rocket/ltb/on_hit_mob(mob/M, obj/projectile/P) - cell_explosion(get_turf(M), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - cell_explosion(get_turf(M), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - -/datum/ammo/rocket/ltb/on_hit_obj(obj/O, obj/projectile/P) - cell_explosion(get_turf(O), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - cell_explosion(get_turf(O), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - -/datum/ammo/rocket/ltb/on_hit_turf(turf/T, obj/projectile/P) - cell_explosion(get_turf(T), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - cell_explosion(get_turf(T), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - -/datum/ammo/rocket/ltb/do_at_max_range(obj/projectile/P) - cell_explosion(get_turf(P), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - cell_explosion(get_turf(P), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - -/datum/ammo/rocket/wp - name = "white phosphorous rocket" - flags_ammo_behavior = AMMO_ROCKET|AMMO_EXPLOSIVE|AMMO_STRIKES_SURFACE - damage_type = BURN - - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - accurate_range = 8 - damage = 90 - max_range = 8 - -/datum/ammo/rocket/wp/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/rocket/wp/drop_flame(turf/T, datum/cause_data/cause_data) - playsound(T, 'sound/weapons/gun_flamethrower3.ogg', 75, 1, 7) - if(!istype(T)) return - smoke.set_up(1, T) - smoke.start() - var/datum/reagent/napalm/blue/R = new() - new /obj/flamer_fire(T, cause_data, R, 3) - - var/datum/effect_system/smoke_spread/phosphorus/landingSmoke = new /datum/effect_system/smoke_spread/phosphorus - landingSmoke.set_up(3, 0, T, null, 6, cause_data) - landingSmoke.start() - landingSmoke = null - -/datum/ammo/rocket/wp/on_hit_mob(mob/M, obj/projectile/P) - drop_flame(get_turf(M), P.weapon_cause_data) - -/datum/ammo/rocket/wp/on_hit_obj(obj/O, obj/projectile/P) - drop_flame(get_turf(O), P.weapon_cause_data) - -/datum/ammo/rocket/wp/on_hit_turf(turf/T, obj/projectile/P) - drop_flame(T, P.weapon_cause_data) - -/datum/ammo/rocket/wp/do_at_max_range(obj/projectile/P) - drop_flame(get_turf(P), P.weapon_cause_data) - -/datum/ammo/rocket/wp/upp - name = "extreme-intensity incendiary rocket" - flags_ammo_behavior = AMMO_ROCKET|AMMO_EXPLOSIVE|AMMO_STRIKES_SURFACE - damage_type = BURN - - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - accurate_range = 8 - damage = 150 - max_range = 10 - -/datum/ammo/rocket/wp/upp/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/rocket/wp/upp/drop_flame(turf/T, datum/cause_data/cause_data) - playsound(T, 'sound/weapons/gun_flamethrower3.ogg', 75, 1, 7) - if(!istype(T)) return - smoke.set_up(1, T) - smoke.start() - var/datum/reagent/napalm/upp/R = new() - new /obj/flamer_fire(T, cause_data, R, 3) - -/datum/ammo/rocket/wp/upp/on_hit_mob(mob/M, obj/projectile/P) - drop_flame(get_turf(M), P.weapon_cause_data) - -/datum/ammo/rocket/wp/upp/on_hit_obj(obj/O, obj/projectile/P) - drop_flame(get_turf(O), P.weapon_cause_data) - -/datum/ammo/rocket/wp/upp/on_hit_turf(turf/T, obj/projectile/P) - drop_flame(T, P.weapon_cause_data) - -/datum/ammo/rocket/wp/upp/do_at_max_range(obj/projectile/P) - drop_flame(get_turf(P), P.weapon_cause_data) - -/datum/ammo/rocket/wp/quad - name = "thermobaric rocket" - flags_ammo_behavior = AMMO_ROCKET|AMMO_STRIKES_SURFACE - - damage = 100 - max_range = 32 - shell_speed = AMMO_SPEED_TIER_3 - -/datum/ammo/rocket/wp/quad/on_hit_mob(mob/M, obj/projectile/P) - drop_flame(get_turf(M), P.weapon_cause_data) - explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data) - -/datum/ammo/rocket/wp/quad/on_hit_obj(obj/O, obj/projectile/P) - drop_flame(get_turf(O), P.weapon_cause_data) - explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data) - -/datum/ammo/rocket/wp/quad/on_hit_turf(turf/T, obj/projectile/P) - drop_flame(T, P.weapon_cause_data) - explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data) - -/datum/ammo/rocket/wp/quad/do_at_max_range(obj/projectile/P) - drop_flame(get_turf(P), P.weapon_cause_data) - explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data) - -/datum/ammo/rocket/custom - name = "custom rocket" - -/datum/ammo/rocket/custom/proc/prime(atom/A, obj/projectile/P) - var/obj/item/weapon/gun/launcher/rocket/launcher = P.shot_from - var/obj/item/ammo_magazine/rocket/custom/rocket = launcher.current_mag - if(rocket.locked && rocket.warhead && rocket.warhead.detonator) - if(rocket.fuel && rocket.fuel.reagents.get_reagent_amount(rocket.fuel_type) >= rocket.fuel_requirement) - rocket.forceMove(P.loc) - rocket.warhead.cause_data = P.weapon_cause_data - rocket.warhead.prime() - qdel(rocket) - smoke.set_up(1, get_turf(A)) - smoke.start() - -/datum/ammo/rocket/custom/on_hit_mob(mob/M, obj/projectile/P) - prime(M, P) - -/datum/ammo/rocket/custom/on_hit_obj(obj/O, obj/projectile/P) - prime(O, P) - -/datum/ammo/rocket/custom/on_hit_turf(turf/T, obj/projectile/P) - prime(T, P) - -/datum/ammo/rocket/custom/do_at_max_range(obj/projectile/P) - prime(null, P) - -/* -//====== - Energy Ammo -//====== -*/ - -/datum/ammo/energy - ping = null //no bounce off. We can have one later. - sound_hit = "energy_hit" - sound_miss = "energy_miss" - sound_bounce = "energy_bounce" - - damage_type = BURN - flags_ammo_behavior = AMMO_ENERGY - - accuracy = HIT_ACCURACY_TIER_4 - -/datum/ammo/energy/emitter //Damage is determined in emitter.dm - name = "emitter bolt" - icon_state = "emitter" - flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_ARMOR - - accurate_range = 6 - max_range = 6 - -/datum/ammo/energy/taser - name = "taser bolt" - icon_state = "stun" - damage_type = OXY - flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST|AMMO_ALWAYS_FF //Not that ignoring will do much right now. - - stamina_damage = 45 - accuracy = HIT_ACCURACY_TIER_8 - shell_speed = AMMO_SPEED_TIER_1 // Slightly faster - hit_effect_color = "#FFFF00" - -/datum/ammo/energy/taser/on_hit_mob(mob/M, obj/projectile/P) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - H.disable_special_items() // Disables scout cloak - -/datum/ammo/energy/taser/precise - name = "precise taser bolt" - flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST|AMMO_MP - -/datum/ammo/energy/rxfm_eva - name = "laser blast" - icon_state = "laser_new" - flags_ammo_behavior = AMMO_LASER - accurate_range = 14 - max_range = 22 - damage = 45 - stamina_damage = 25 //why not - shell_speed = AMMO_SPEED_TIER_3 - -/datum/ammo/energy/rxfm_eva/on_hit_mob(mob/living/M, obj/projectile/P) - ..() - if(prob(10)) //small chance for one to ignite on hit - M.fire_act() - -/datum/ammo/energy/laz_uzi - name = "laser bolt" - icon_state = "laser_new" - flags_ammo_behavior = AMMO_ENERGY - damage = 40 - accurate_range = 5 - effective_range_max = 7 - max_range = 10 - shell_speed = AMMO_SPEED_TIER_4 - scatter = SCATTER_AMOUNT_TIER_6 - accuracy = HIT_ACCURACY_TIER_3 - damage_falloff = DAMAGE_FALLOFF_TIER_8 - -/datum/ammo/energy/yautja - headshot_state = HEADSHOT_OVERLAY_MEDIUM - accurate_range = 12 - shell_speed = AMMO_SPEED_TIER_3 - damage_type = BURN - flags_ammo_behavior = AMMO_IGNORE_RESIST - -/datum/ammo/energy/yautja/pistol - name = "plasma pistol bolt" - icon_state = "ion" - - damage = 40 - shell_speed = AMMO_SPEED_TIER_2 - -/datum/ammo/energy/yautja/pistol/incendiary - damage = 10 - -/datum/ammo/energy/yautja/pistol/incendiary/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/shrapnel/plasma - name = "plasma wave" - shrapnel_chance = 0 - penetration = ARMOR_PENETRATION_TIER_10 - accuracy = HIT_ACCURACY_TIER_MAX - damage = 15 - icon_state = "shrapnel_plasma" - damage_type = BURN - -/datum/ammo/bullet/shrapnel/plasma/on_hit_mob(mob/hit_mob, obj/projectile/hit_projectile) - hit_mob.apply_effect(2, WEAKEN) - -/datum/ammo/energy/yautja/caster - name = "root caster bolt" - icon_state = "ion" - -/datum/ammo/energy/yautja/caster/stun - name = "low power stun bolt" - debilitate = list(2,2,0,0,0,1,0,0) - - damage = 0 - flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST - -/datum/ammo/energy/yautja/caster/bolt - name = "plasma bolt" - icon_state = "pulse1" - flags_ammo_behavior = AMMO_IGNORE_RESIST - shell_speed = AMMO_SPEED_TIER_6 - damage = 35 - -/datum/ammo/energy/yautja/caster/bolt/stun - name = "high power stun bolt" - var/stun_time = 2 - - damage = 0 - flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST - -/datum/ammo/energy/yautja/caster/bolt/stun/on_hit_mob(mob/M, obj/projectile/P) - var/mob/living/carbon/C = M - var/stun_time = src.stun_time - if(istype(C)) - if(isyautja(C) || ispredalien(C)) - return - to_chat(C, SPAN_DANGER("An electric shock ripples through your body, freezing you in place!")) - log_attack("[key_name(C)] was stunned by a high power stun bolt from [key_name(P.firer)] at [get_area(P)]") - - if(ishuman(C)) - var/mob/living/carbon/human/H = C - stun_time++ - H.apply_effect(stun_time, WEAKEN) - else - M.apply_effect(stun_time, WEAKEN) - - C.apply_effect(stun_time, STUN) - ..() - -/datum/ammo/energy/yautja/caster/sphere - name = "plasma eradicator" - icon_state = "bluespace" - flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_HITS_TARGET_TURF - shell_speed = AMMO_SPEED_TIER_4 - accuracy = HIT_ACCURACY_TIER_8 - - damage = 55 - - accurate_range = 8 - max_range = 8 - - var/vehicle_slowdown_time = 5 SECONDS - -/datum/ammo/energy/yautja/caster/sphere/on_hit_mob(mob/M, obj/projectile/P) - cell_explosion(P, 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - -/datum/ammo/energy/yautja/caster/sphere/on_hit_turf(turf/T, obj/projectile/P) - cell_explosion(P, 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - -/datum/ammo/energy/yautja/caster/sphere/on_hit_obj(obj/O, obj/projectile/P) - if(istype(O, /obj/vehicle/multitile)) - var/obj/vehicle/multitile/multitile_vehicle = O - multitile_vehicle.next_move = world.time + vehicle_slowdown_time - playsound(multitile_vehicle, 'sound/effects/meteorimpact.ogg', 35) - multitile_vehicle.at_munition_interior_explosion_effect(cause_data = create_cause_data("Plasma Eradicator", P.firer)) - multitile_vehicle.interior_crash_effect() - multitile_vehicle.ex_act(150, P.dir, P.weapon_cause_data, 100) - cell_explosion(get_turf(P), 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - -/datum/ammo/energy/yautja/caster/sphere/do_at_max_range(obj/projectile/P) - cell_explosion(get_turf(P), 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data) - - -/datum/ammo/energy/yautja/caster/sphere/stun - name = "plasma immobilizer" - damage = 0 - flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST - accurate_range = 20 - max_range = 20 - - var/stun_range = 4 // Big - var/stun_time = 6 - -/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_mob(mob/M, obj/projectile/P) - do_area_stun(P) - -/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_turf(turf/T,obj/projectile/P) - do_area_stun(P) - -/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_obj(obj/O,obj/projectile/P) - do_area_stun(P) - -/datum/ammo/energy/yautja/caster/sphere/stun/do_at_max_range(obj/projectile/P) - do_area_stun(P) - -/datum/ammo/energy/yautja/caster/sphere/stun/proc/do_area_stun(obj/projectile/P) - playsound(P, 'sound/weapons/wave.ogg', 75, 1, 25) - for (var/mob/living/carbon/M in view(src.stun_range, get_turf(P))) - var/stun_time = src.stun_time - log_attack("[key_name(M)] was stunned by a plasma immobilizer from [key_name(P.firer)] at [get_area(P)]") - if (isyautja(M)) - stun_time -= 2 - if(ispredalien(M)) - continue - to_chat(M, SPAN_DANGER("A powerful electric shock ripples through your body, freezing you in place!")) - M.apply_effect(stun_time, STUN) - - if (ishuman(M)) - var/mob/living/carbon/human/H = M - H.apply_effect(stun_time, WEAKEN) - else - M.apply_effect(stun_time, WEAKEN) - -/datum/ammo/energy/yautja/rifle/bolt - name = "plasma rifle bolt" - icon_state = "ion" - damage_type = BURN - debilitate = list(0,2,0,0,0,0,0,0) - flags_ammo_behavior = AMMO_IGNORE_RESIST - - damage = 55 - penetration = ARMOR_PENETRATION_TIER_10 - -/datum/ammo/energy/yautja/rifle/bolt/on_hit_mob(mob/hit_mob, obj/projectile/hit_projectile) - if(isxeno(hit_mob)) - var/mob/living/carbon/xenomorph/xeno = hit_mob - xeno.apply_damage(damage * 0.75, BURN) - xeno.interference = 30 - -/* -//====== - Xeno Spits -//====== -*/ -/datum/ammo/xeno - icon_state = "neurotoxin" - ping = "ping_x" - damage_type = TOX - flags_ammo_behavior = AMMO_XENO - - ///used to make cooldown of the different spits vary. - var/added_spit_delay = 0 - var/spit_cost - - /// Should there be a windup for this spit? - var/spit_windup = FALSE - - /// Should there be an additional warning while winding up? (do not put to true if there is not a windup) - var/pre_spit_warn = FALSE - accuracy = HIT_ACCURACY_TIER_8*2 - max_range = 12 - -/datum/ammo/xeno/toxin - name = "neurotoxic spit" - damage_falloff = 0 - flags_ammo_behavior = AMMO_XENO|AMMO_IGNORE_RESIST - spit_cost = 25 - var/effect_power = XENO_NEURO_TIER_4 - var/datum/callback/neuro_callback - - shell_speed = AMMO_SPEED_TIER_3 - max_range = 7 - -/datum/ammo/xeno/toxin/New() - ..() - - neuro_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(apply_neuro)) - -/proc/apply_neuro(mob/M, power, insta_neuro) - if(skillcheck(M, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX) && !insta_neuro) - M.visible_message(SPAN_DANGER("[M] withstands the neurotoxin!")) - return //endurance 5 makes you immune to weak neurotoxin - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.chem_effect_flags & CHEM_EFFECT_RESIST_NEURO || H.species.flags & NO_NEURO) - H.visible_message(SPAN_DANGER("[M] shrugs off the neurotoxin!")) - return //species like zombies or synths are immune to neurotoxin - - if(!isxeno(M)) - if(insta_neuro) - if(M.knocked_down < 3) - M.adjust_effect(1 * power, WEAKEN) - return - - if(ishuman(M)) - M.apply_effect(2.5, SUPERSLOW) - M.visible_message(SPAN_DANGER("[M]'s movements are slowed.")) - - var/no_clothes_neuro = FALSE - - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(!H.wear_suit || H.wear_suit.slowdown == 0) - no_clothes_neuro = TRUE - - if(no_clothes_neuro) - if(M.knocked_down < 5) - M.adjust_effect(1 * power, WEAKEN) // KD them a bit more - M.visible_message(SPAN_DANGER("[M] falls prone.")) - -/proc/apply_scatter_neuro(mob/M) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(skillcheck(M, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX)) - M.visible_message(SPAN_DANGER("[M] withstands the neurotoxin!")) - return //endurance 5 makes you immune to weak neuro - if(H.chem_effect_flags & CHEM_EFFECT_RESIST_NEURO || H.species.flags & NO_NEURO) - H.visible_message(SPAN_DANGER("[M] shrugs off the neurotoxin!")) - return - - if(M.knocked_down < 0.7) // apply knockdown only if current knockdown is less than 0.7 second - M.apply_effect(0.7, WEAKEN) - M.visible_message(SPAN_DANGER("[M] falls prone.")) - -/datum/ammo/xeno/toxin/on_hit_mob(mob/M,obj/projectile/P) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.status_flags & XENO_HOST) - neuro_callback.Invoke(H, effect_power, TRUE) - return - - neuro_callback.Invoke(M, effect_power, FALSE) - -/datum/ammo/xeno/toxin/medium //Spitter - name = "neurotoxic spatter" - spit_cost = 50 - effect_power = 1 - - shell_speed = AMMO_SPEED_TIER_3 - -/datum/ammo/xeno/toxin/queen - name = "neurotoxic spit" - spit_cost = 50 - effect_power = 2 - - accuracy = HIT_ACCURACY_TIER_5*2 - max_range = 6 - 1 - -/datum/ammo/xeno/toxin/queen/on_hit_mob(mob/M,obj/projectile/P) - neuro_callback.Invoke(M, effect_power, TRUE) - -/datum/ammo/xeno/toxin/shotgun - name = "neurotoxic droplet" - flags_ammo_behavior = AMMO_XENO|AMMO_IGNORE_RESIST - bonus_projectiles_type = /datum/ammo/xeno/toxin/shotgun/additional - - accuracy_var_low = PROJECTILE_VARIANCE_TIER_6 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_6 - accurate_range = 5 - max_range = 5 - scatter = SCATTER_AMOUNT_NEURO - bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_4 - -/datum/ammo/xeno/toxin/shotgun/New() - ..() - - neuro_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(apply_scatter_neuro)) - -/datum/ammo/xeno/toxin/shotgun/additional - name = "additional neurotoxic droplets" - - bonus_projectiles_amount = 0 - -/*proc/neuro_flak(turf/T, obj/projectile/P, datum/callback/CB, power, insta_neuro, radius) - if(!T) return FALSE - var/firer = P.firer - var/hit_someone = FALSE - for(var/mob/living/carbon/M in orange(radius,T)) - if(isxeno(M) && isxeno(firer) && M:hivenumber == firer:hivenumber) - continue - - if(HAS_TRAIT(M, TRAIT_NESTED)) - continue - - hit_someone = TRUE - CB.Invoke(M, power, insta_neuro) - - P.play_hit_effect(M) - - return hit_someone - -/datum/ammo/xeno/toxin/burst //sentinel burst - name = "neurotoxic air splash" - effect_power = XENO_NEURO_TIER_1 - spit_cost = 50 - flags_ammo_behavior = AMMO_XENO|AMMO_IGNORE_RESIST - -/datum/ammo/xeno/toxin/burst/on_hit_mob(mob/M, obj/projectile/P) - if(isxeno(M) && isxeno(P.firer) && M:hivenumber == P.firer:hivenumber) - neuro_callback.Invoke(M, effect_power*1.5, TRUE) - - neuro_flak(get_turf(M), P, neuro_callback, effect_power, FALSE, 1) - -/datum/ammo/xeno/toxin/burst/on_near_target(turf/T, obj/projectile/P) - return neuro_flak(T, P, neuro_callback, effect_power, FALSE, 1) - -/datum/ammo/xeno/sticky - name = "sticky resin spit" - icon_state = "sticky" - ping = null - flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE - added_spit_delay = 5 - spit_cost = 40 - - shell_speed = AMMO_SPEED_TIER_3 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_4 - max_range = 32 - -/datum/ammo/xeno/sticky/on_hit_mob(mob/M,obj/projectile/P) - drop_resin(get_turf(P)) - -/datum/ammo/xeno/sticky/on_hit_obj(obj/O,obj/projectile/P) - drop_resin(get_turf(P)) - -/datum/ammo/xeno/sticky/on_hit_turf(turf/T,obj/projectile/P) - drop_resin(T) - -/datum/ammo/xeno/sticky/do_at_max_range(obj/projectile/P) - drop_resin(get_turf(P)) - -/datum/ammo/xeno/sticky/proc/drop_resin(turf/T) - if(T.density) - return - - for(var/obj/O in T.contents) - if(istype(O, /obj/item/clothing/mask/facehugger)) - return - if(istype(O, /obj/effect/alien/egg)) - return - if(istype(O, /obj/structure/mineral_door) || istype(O, /obj/effect/alien/resin) || istype(O, /obj/structure/bed)) - return - if(O.density && !(O.flags_atom & ON_BORDER)) - return - - new /obj/effect/alien/resin/sticky/thin(T) */ - -/datum/ammo/xeno/acid - name = "acid spit" - icon_state = "xeno_acid" - sound_hit = "acid_hit" - sound_bounce = "acid_bounce" - damage_type = BURN - spit_cost = 25 - flags_ammo_behavior = AMMO_ACIDIC|AMMO_XENO - accuracy = HIT_ACCURACY_TIER_5 - damage = 20 - max_range = 8 // 7 will disappear on diagonals. i love shitcode - penetration = ARMOR_PENETRATION_TIER_2 - shell_speed = AMMO_SPEED_TIER_3 - -/datum/ammo/xeno/acid/on_shield_block(mob/M, obj/projectile/P) - burst(M,P,damage_type) - -/datum/ammo/xeno/acid/on_hit_mob(mob/M, obj/projectile/P) - if(iscarbon(M)) - var/mob/living/carbon/C = M - if(C.status_flags & XENO_HOST && HAS_TRAIT(C, TRAIT_NESTED) || C.stat == DEAD) - return FALSE - ..() - -/datum/ammo/xeno/acid/spatter - name = "acid spatter" - - damage = 30 - max_range = 6 - -/datum/ammo/xeno/acid/spatter/on_hit_mob(mob/M, obj/projectile/P) - . = ..() - if(. == FALSE) - return - - new /datum/effects/acid(M, P.firer) - -/datum/ammo/xeno/acid/praetorian - name = "acid splash" - - accuracy = HIT_ACCURACY_TIER_10 + HIT_ACCURACY_TIER_5 - max_range = 8 - damage = 30 - shell_speed = AMMO_SPEED_TIER_2 - added_spit_delay = 0 - -/datum/ammo/xeno/acid/dot - name = "acid spit" - -/datum/ammo/xeno/acid/prae_nade // Used by base prae's acid nade - name = "acid scatter" - - flags_ammo_behavior = AMMO_STOPPED_BY_COVER - accuracy = HIT_ACCURACY_TIER_5 - accurate_range = 32 - max_range = 4 - damage = 25 - shell_speed = AMMO_SPEED_TIER_1 - scatter = SCATTER_AMOUNT_TIER_6 - - apply_delegate = FALSE - -/datum/ammo/xeno/acid/prae_nade/on_hit_mob(mob/M, obj/projectile/P) - if (!ishuman(M)) - return - - var/mob/living/carbon/human/H = M - - var/datum/effects/prae_acid_stacks/PAS = null - for (var/datum/effects/prae_acid_stacks/prae_acid_stacks in H.effects_list) - PAS = prae_acid_stacks - break - - if (PAS == null) - PAS = new /datum/effects/prae_acid_stacks(H) - else - PAS.increment_stack_count() - -/*datum/ammo/xeno/prae_skillshot - name = "blob of acid" - icon_state = "boiler_gas2" - ping = "ping_x" - flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE|AMMO_IGNORE_RESIST - - accuracy = HIT_ACCURACY_TIER_5 - accurate_range = 32 - max_range = 8 - damage = 20 - damage_falloff = DAMAGE_FALLOFF_TIER_10 - shell_speed = AMMO_SPEED_TIER_1 - scatter = SCATTER_AMOUNT_TIER_10 - -/datum/ammo/xeno/prae_skillshot/on_hit_mob(mob/M, obj/projectile/P) - acid_stacks_aoe(get_turf(P)) - -/datum/ammo/xeno/prae_skillshot/on_hit_obj(obj/O, obj/projectile/P) - acid_stacks_aoe(get_turf(P)) - -/datum/ammo/xeno/prae_skillshot/on_hit_turf(turf/T, obj/projectile/P) - acid_stacks_aoe(get_turf(P)) - -/datum/ammo/xeno/prae_skillshot/do_at_max_range(obj/projectile/P) - acid_stacks_aoe(get_turf(P)) - -/datum/ammo/xeno/prae_skillshot/proc/acid_stacks_aoe(turf/T) - - if (!istype(T)) - return - - for (var/mob/living/carbon/human/H in orange(1, T)) - to_chat(H, SPAN_XENODANGER("You are spattered with acid!")) - animation_flash_color(H) - var/datum/effects/prae_acid_stacks/PAS = null - for (var/datum/effects/prae_acid_stacks/prae_acid_stacks in H.effects_list) - PAS = prae_acid_stacks - break - - if (PAS == null) - PAS = new /datum/effects/prae_acid_stacks(H) - PAS.increment_stack_count() - else - PAS.increment_stack_count() - PAS.increment_stack_count() */ - -/datum/ammo/xeno/boiler_gas - name = "glob of neuro gas" - icon_state = "neuro_glob" - ping = "ping_x" - debilitate = list(2,2,0,1,11,12,1,10) // Stun,knockdown,knockout,irradiate,stutter,eyeblur,drowsy,agony - flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE|AMMO_IGNORE_RESIST|AMMO_HITS_TARGET_TURF|AMMO_ACIDIC - var/datum/effect_system/smoke_spread/smoke_system - spit_cost = 200 - pre_spit_warn = TRUE - spit_windup = 5 SECONDS - accuracy_var_high = PROJECTILE_VARIANCE_TIER_4 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_4 - accuracy = HIT_ACCURACY_TIER_2 - scatter = SCATTER_AMOUNT_TIER_4 - shell_speed = 0.75 - max_range = 16 - /// range on the smoke in tiles from center - var/smokerange = 4 - var/lifetime_mult = 1.0 - -/datum/ammo/xeno/boiler_gas/New() - ..() - set_xeno_smoke() - -/datum/ammo/xeno/boiler_gas/Destroy() - qdel(smoke_system) - smoke_system = null - . = ..() - -/datum/ammo/xeno/boiler_gas/on_hit_mob(mob/moob, obj/projectile/proj) - if(iscarbon(moob)) - var/mob/living/carbon/carbon = moob - if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD) - return - var/datum/effects/neurotoxin/neuro_effect = locate() in moob.effects_list - if(!neuro_effect) - neuro_effect = new /datum/effects/neurotoxin(moob, proj.firer) - neuro_effect.duration += 5 - moob.apply_effect(3, DAZE) - to_chat(moob, SPAN_HIGHDANGER("Neurotoxic liquid spreads all over you and immediately soaks into your pores and orifices! Oh fuck!")) // Fucked up but have a chance to escape rather than being game-ended - drop_nade(get_turf(proj), proj,TRUE) - -/datum/ammo/xeno/boiler_gas/on_hit_obj(obj/outbacksteakhouse, obj/projectile/proj) - drop_nade(get_turf(proj), proj) - -/datum/ammo/xeno/boiler_gas/on_hit_turf(turf/Turf, obj/projectile/proj) - if(Turf.density && isturf(proj.loc)) - drop_nade(proj.loc, proj) //we don't want the gas globs to land on dense turfs, they block smoke expansion. - else - drop_nade(Turf, proj) - -/datum/ammo/xeno/boiler_gas/do_at_max_range(obj/projectile/proj) - drop_nade(get_turf(proj), proj) - -/datum/ammo/xeno/boiler_gas/proc/set_xeno_smoke(obj/projectile/proj) - smoke_system = new /datum/effect_system/smoke_spread/xeno_weaken() - -/datum/ammo/xeno/boiler_gas/proc/drop_nade(turf/turf, obj/projectile/proj) - var/lifetime_mult = 1.0 - var/datum/cause_data - if(isboiler(proj.firer)) - cause_data = proj.weapon_cause_data - smoke_system.set_up(smokerange, 0, turf, new_cause_data = cause_data) - smoke_system.lifetime = 12 * lifetime_mult - smoke_system.start() - turf.visible_message(SPAN_DANGER("A glob of acid lands with a splat and explodes into noxious fumes!")) - - -/datum/ammo/xeno/boiler_gas/acid - name = "glob of acid gas" - icon_state = "acid_glob" - ping = "ping_x" - accuracy_var_high = PROJECTILE_VARIANCE_TIER_4 - smokerange = 3 - - -/datum/ammo/xeno/boiler_gas/acid/set_xeno_smoke(obj/projectile/proj) - smoke_system = new /datum/effect_system/smoke_spread/xeno_acid() - -/datum/ammo/xeno/boiler_gas/acid/on_hit_mob(mob/moob, obj/projectile/proj) - if(iscarbon(moob)) - var/mob/living/carbon/carbon = moob - if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD) - return - to_chat(moob,SPAN_HIGHDANGER("Acid covers your body! Oh fuck!")) - playsound(moob,"acid_strike",75,1) - INVOKE_ASYNC(moob, TYPE_PROC_REF(/mob, emote), "pain") // why do I need this bullshit - new /datum/effects/acid(moob, proj.firer) - drop_nade(get_turf(proj), proj,TRUE) - -/datum/ammo/xeno/bone_chips - name = "bone chips" - icon_state = "shrapnel_light" - ping = null - flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_STOPPED_BY_COVER|AMMO_IGNORE_ARMOR - damage_type = BRUTE - bonus_projectiles_type = /datum/ammo/xeno/bone_chips/spread - - damage = 8 - max_range = 6 - accuracy = HIT_ACCURACY_TIER_8 - accuracy_var_low = PROJECTILE_VARIANCE_TIER_7 - accuracy_var_high = PROJECTILE_VARIANCE_TIER_7 - bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_7 - shrapnel_type = /obj/item/shard/shrapnel/bone_chips - shrapnel_chance = 60 - -/datum/ammo/xeno/bone_chips/on_hit_mob(mob/M, obj/projectile/P) - if(iscarbon(M)) - var/mob/living/carbon/C = M - if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD) - return - if(ishuman_strict(M) || isxeno(M)) - playsound(M, 'sound/effects/spike_hit.ogg', 25, 1, 1) - if(M.slowed < 3) - M.apply_effect(3, SLOW) - -/datum/ammo/xeno/bone_chips/spread - name = "small bone chips" - - scatter = 30 // We want a wild scatter angle - max_range = 5 - bonus_projectiles_amount = 0 - -/datum/ammo/xeno/bone_chips/spread/short_range - name = "small bone chips" - - max_range = 3 // Very short range - -/datum/ammo/xeno/bone_chips/spread/runner_skillshot - name = "bone chips" - - scatter = 0 - max_range = 5 - damage = 10 - shrapnel_chance = 0 - -/datum/ammo/xeno/bone_chips/spread/runner/on_hit_mob(mob/M, obj/projectile/P) - if(iscarbon(M)) - var/mob/living/carbon/C = M - if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD) - return - if(ishuman_strict(M) || isxeno(M)) - playsound(M, 'sound/effects/spike_hit.ogg', 25, 1, 1) - if(M.slowed < 6) - M.apply_effect(6, SLOW) - -/datum/ammo/xeno/oppressor_tail - name = "tail hook" - icon_state = "none" - ping = null - flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_STOPPED_BY_COVER|AMMO_IGNORE_ARMOR - damage_type = BRUTE - - damage = XENO_DAMAGE_TIER_5 - max_range = 4 - accuracy = HIT_ACCURACY_TIER_MAX - -/datum/ammo/xeno/oppressor_tail/on_bullet_generation(obj/projectile/generated_projectile, mob/bullet_generator) - //The projectile has no icon, so the overlay shows up in FRONT of the projectile, and the beam connects to it in the middle. - var/image/hook_overlay = new(icon = 'icons/effects/beam.dmi', icon_state = "oppressor_tail_hook", layer = BELOW_MOB_LAYER) - generated_projectile.overlays += hook_overlay - -/datum/ammo/xeno/oppressor_tail/on_hit_mob(mob/target, obj/projectile/fired_proj) - var/mob/living/carbon/xenomorph/xeno_firer = fired_proj.firer - if(xeno_firer.can_not_harm(target)) - return - - shake_camera(target, 5, 0.1 SECONDS) - var/obj/effect/beam/tail_beam = fired_proj.firer.beam(target, "oppressor_tail", 'icons/effects/beam.dmi', 0.5 SECONDS, 5) - var/image/tail_image = image('icons/effects/status_effects.dmi', "hooked") - target.overlays += tail_image - - new /datum/effects/xeno_slow(target, fired_proj.firer, ttl = 0.5 SECONDS) - target.apply_effect(0.5, STUN) - INVOKE_ASYNC(target, TYPE_PROC_REF(/atom/movable, throw_atom), fired_proj.firer, get_dist(fired_proj.firer, target)-1, SPEED_VERY_FAST) - - qdel(tail_beam) - addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/ammo/xeno/oppressor_tail, remove_tail_overlay), target, tail_image), 0.5 SECONDS) //needed so it can actually be seen as it gets deleted too quickly otherwise. - -/datum/ammo/xeno/oppressor_tail/proc/remove_tail_overlay(mob/overlayed_mob, image/tail_image) - overlayed_mob.overlays -= tail_image - -/* -//====== - Shrapnel -//====== -*/ -/datum/ammo/bullet/shrapnel - name = "shrapnel" - icon_state = "buckshot" - accurate_range_min = 5 - flags_ammo_behavior = AMMO_BALLISTIC|AMMO_STOPPED_BY_COVER - - accuracy = HIT_ACCURACY_TIER_3 - accurate_range = 32 - max_range = 8 - damage = 25 - damage_var_low = -PROJECTILE_VARIANCE_TIER_6 - damage_var_high = PROJECTILE_VARIANCE_TIER_6 - penetration = ARMOR_PENETRATION_TIER_4 - shell_speed = AMMO_SPEED_TIER_2 - shrapnel_chance = 5 - -/datum/ammo/bullet/shrapnel/on_hit_obj(obj/O, obj/projectile/P) - if(istype(O, /obj/structure/barricade)) - var/obj/structure/barricade/B = O - B.health -= rand(2, 5) - B.update_health(1) - -/datum/ammo/bullet/shrapnel/rubber - name = "rubber pellets" - icon_state = "rubber_pellets" - flags_ammo_behavior = AMMO_STOPPED_BY_COVER - - damage = 0 - stamina_damage = 25 - shrapnel_chance = 0 - - -/datum/ammo/bullet/shrapnel/hornet_rounds - name = ".22 hornet round" - icon_state = "hornet_round" - flags_ammo_behavior = AMMO_BALLISTIC - damage = 20 - shrapnel_chance = 0 - shell_speed = AMMO_SPEED_TIER_3//she fast af boi - penetration = ARMOR_PENETRATION_TIER_5 - -/datum/ammo/bullet/shrapnel/hornet_rounds/on_hit_mob(mob/M, obj/projectile/P) - . = ..() - M.AddComponent(/datum/component/bonus_damage_stack, 10, world.time) - -/datum/ammo/bullet/shrapnel/incendiary - name = "flaming shrapnel" - icon_state = "beanbag" // looks suprisingly a lot like flaming shrapnel chunks - flags_ammo_behavior = AMMO_STOPPED_BY_COVER - - shell_speed = AMMO_SPEED_TIER_1 - damage = 20 - penetration = ARMOR_PENETRATION_TIER_4 - -/datum/ammo/bullet/shrapnel/incendiary/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/bullet/shrapnel/metal - name = "metal shrapnel" - icon_state = "shrapnelshot_bit" - flags_ammo_behavior = AMMO_STOPPED_BY_COVER|AMMO_BALLISTIC - shell_speed = AMMO_SPEED_TIER_1 - damage = 30 - shrapnel_chance = 15 - accuracy = HIT_ACCURACY_TIER_8 - penetration = ARMOR_PENETRATION_TIER_4 - -/datum/ammo/bullet/shrapnel/light // weak shrapnel - name = "light shrapnel" - icon_state = "shrapnel_light" - - damage = 10 - penetration = ARMOR_PENETRATION_TIER_1 - shell_speed = AMMO_SPEED_TIER_1 - shrapnel_chance = 0 - -/datum/ammo/bullet/shrapnel/light/human - name = "human bone fragments" - icon_state = "shrapnel_human" - - shrapnel_chance = 50 - shrapnel_type = /obj/item/shard/shrapnel/bone_chips/human - -/datum/ammo/bullet/shrapnel/light/human/var1 // sprite variants - icon_state = "shrapnel_human1" - -/datum/ammo/bullet/shrapnel/light/human/var2 // sprite variants - icon_state = "shrapnel_human2" - -/datum/ammo/bullet/shrapnel/light/xeno - name = "alien bone fragments" - icon_state = "shrapnel_xeno" - - shrapnel_chance = 50 - shrapnel_type = /obj/item/shard/shrapnel/bone_chips/xeno - -/datum/ammo/bullet/shrapnel/spall // weak shrapnel - name = "spall" - icon_state = "shrapnel_light" - - damage = 10 - penetration = ARMOR_PENETRATION_TIER_1 - shell_speed = AMMO_SPEED_TIER_1 - shrapnel_chance = 0 - -/datum/ammo/bullet/shrapnel/light/glass - name = "glass shrapnel" - icon_state = "shrapnel_glass" - -/datum/ammo/bullet/shrapnel/light/effect/ // no damage, but looks bright and neat - name = "sparks" - - damage = 1 // Tickle tickle - -/datum/ammo/bullet/shrapnel/light/effect/ver1 - icon_state = "shrapnel_bright1" - -/datum/ammo/bullet/shrapnel/light/effect/ver2 - icon_state = "shrapnel_bright2" - -/datum/ammo/bullet/shrapnel/jagged - shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 - accuracy = HIT_ACCURACY_TIER_MAX - -/datum/ammo/bullet/shrapnel/jagged/on_hit_mob(mob/M, obj/projectile/P) - if(isxeno(M)) - M.apply_effect(0.4, SLOW) - -/* -//======== - CAS 30mm impacters -//======== -*/ -/datum/ammo/bullet/shrapnel/gau //for the GAU to have a impact bullet instead of firecrackers - name = "30mm Multi-Purpose shell" - - damage = 1 // ALL DAMAGE IS IN dropship_ammo SO WE CAN DEAL DAMAGE TO RESTING MOBS, these will still remain however so that we can get cause_data and status effects. - damage_type = BRUTE - penetration = ARMOR_PENETRATION_TIER_2 - accuracy = HIT_ACCURACY_TIER_MAX - max_range = 0 - shrapnel_chance = 100 //the least of your problems - -/datum/ammo/bullet/shrapnel/gau/at - name = "30mm Anti-Tank shell" - - damage = 1 // ALL DAMAGE IS IN dropship_ammo SO WE CAN DEAL DAMAGE TO RESTING MOBS, these will still remain however so that we can get cause_data and status effects. - penetration = ARMOR_PENETRATION_TIER_8 - accuracy = HIT_ACCURACY_TIER_MAX -/* -//====== - Misc Ammo -//====== -*/ - -/datum/ammo/alloy_spike - name = "alloy spike" - headshot_state = HEADSHOT_OVERLAY_MEDIUM - ping = "ping_s" - icon_state = "MSpearFlight" - sound_hit = "alloy_hit" - sound_armor = "alloy_armor" - sound_bounce = "alloy_bounce" - - accuracy = HIT_ACCURACY_TIER_8 - accurate_range = 12 - max_range = 12 - damage = 30 - penetration= ARMOR_PENETRATION_TIER_10 - shrapnel_chance = SHRAPNEL_CHANCE_TIER_7 - shrapnel_type = /obj/item/shard/shrapnel - -/datum/ammo/flamethrower - name = "flame" - icon_state = "pulse0" - damage_type = BURN - flags_ammo_behavior = AMMO_IGNORE_ARMOR|AMMO_HITS_TARGET_TURF - - max_range = 6 - damage = 35 - -/datum/ammo/flamethrower/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/flamethrower/on_hit_mob(mob/M, obj/projectile/P) - drop_flame(get_turf(M), P.weapon_cause_data) - -/datum/ammo/flamethrower/on_hit_obj(obj/O, obj/projectile/P) - drop_flame(get_turf(O), P.weapon_cause_data) - -/datum/ammo/flamethrower/on_hit_turf(turf/T, obj/projectile/P) - drop_flame(T, P.weapon_cause_data) - -/datum/ammo/flamethrower/do_at_max_range(obj/projectile/P) - drop_flame(get_turf(P), P.weapon_cause_data) - -/datum/ammo/flamethrower/tank_flamer - flamer_reagent_type = /datum/reagent/napalm/blue - -/datum/ammo/flamethrower/sentry_flamer - flags_ammo_behavior = AMMO_IGNORE_ARMOR|AMMO_IGNORE_COVER|AMMO_FLAME - flamer_reagent_type = /datum/reagent/napalm/blue - - accuracy = HIT_ACCURACY_TIER_8 - accurate_range = 6 - max_range = 12 - shell_speed = AMMO_SPEED_TIER_3 - -/datum/ammo/flamethrower/sentry_flamer/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/flamethrower/sentry_flamer/glob - max_range = 14 - accurate_range = 10 - var/datum/effect_system/smoke_spread/phosphorus/smoke - -/datum/ammo/flamethrower/sentry_flamer/glob/New() - . = ..() - smoke = new() - -/datum/ammo/flamethrower/sentry_flamer/glob/drop_flame(turf/T, datum/cause_data/cause_data) - if(!istype(T)) - return - smoke.set_up(1, 0, T, new_cause_data = cause_data) - smoke.start() - -/datum/ammo/flamethrower/sentry_flamer/glob/Destroy() - qdel(smoke) - return ..() - -/datum/ammo/flamethrower/sentry_flamer/mini - name = "normal fire" - -/datum/ammo/flamethrower/sentry_flamer/mini/drop_flame(turf/T, datum/cause_data/cause_data) - if(!istype(T)) - return - var/datum/reagent/napalm/ut/R = new() - R.durationfire = BURN_TIME_INSTANT - new /obj/flamer_fire(T, cause_data, R, 0) - -/datum/ammo/flare - name = "flare" - ping = null //no bounce off. - damage_type = BURN - flags_ammo_behavior = AMMO_HITS_TARGET_TURF - icon_state = "flare" - - damage = 15 - accuracy = HIT_ACCURACY_TIER_3 - max_range = 14 - shell_speed = AMMO_SPEED_TIER_3 - - var/flare_type = /obj/item/device/flashlight/flare/on/gun - handful_type = /obj/item/device/flashlight/flare - -/datum/ammo/flare/set_bullet_traits() - . = ..() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/flare/on_hit_mob(mob/M,obj/projectile/P) - drop_flare(get_turf(M), P, P.firer) - -/datum/ammo/flare/on_hit_obj(obj/O,obj/projectile/P) - drop_flare(get_turf(P), P, P.firer) - -/datum/ammo/flare/on_hit_turf(turf/T, obj/projectile/P) - if(T.density && isturf(P.loc)) - drop_flare(P.loc, P, P.firer) - else - drop_flare(T, P, P.firer) - -/datum/ammo/flare/do_at_max_range(obj/projectile/P, mob/firer) - drop_flare(get_turf(P), P, P.firer) - -/datum/ammo/flare/proc/drop_flare(turf/T, obj/projectile/fired_projectile, mob/firer) - var/obj/item/device/flashlight/flare/G = new flare_type(T) - var/matrix/rotation = matrix() - rotation.Turn(fired_projectile.angle - 90) - G.apply_transform(rotation) - G.visible_message(SPAN_WARNING("\A [G] bursts into brilliant light nearby!")) - return G - -/datum/ammo/flare/signal - name = "signal flare" - icon_state = "flare_signal" - flare_type = /obj/item/device/flashlight/flare/signal/gun - handful_type = /obj/item/device/flashlight/flare/signal - -/datum/ammo/flare/signal/drop_flare(turf/T, obj/projectile/fired_projectile, mob/firer) - var/obj/item/device/flashlight/flare/signal/gun/signal_flare = ..() - signal_flare.activate_signal(firer) - if(istype(fired_projectile.shot_from, /obj/item/weapon/gun/flare)) - var/obj/item/weapon/gun/flare/flare_gun_fired_from = fired_projectile.shot_from - flare_gun_fired_from.last_signal_flare_name = signal_flare.name - -/datum/ammo/flare/starshell - name = "starshell ash" - icon_state = "starshell_bullet" - max_range = 5 - flare_type = /obj/item/device/flashlight/flare/on/starshell_ash - -/datum/ammo/flare/starshell/set_bullet_traits() - LAZYADD(traits_to_give, list( - BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff, /datum/element/bullet_trait_incendiary) - )) - -/datum/ammo/souto - name = "Souto Can" - ping = null //no bounce off. - damage_type = BRUTE - shrapnel_type = /obj/item/reagent_container/food/drinks/cans/souto/classic - flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_IGNORE_ARMOR|AMMO_IGNORE_RESIST|AMMO_BALLISTIC|AMMO_STOPPED_BY_COVER|AMMO_SPECIAL_EMBED - var/obj/item/reagent_container/food/drinks/cans/souto/can_type - icon_state = "souto_classic" - - max_range = 12 - shrapnel_chance = 10 - accuracy = HIT_ACCURACY_TIER_8 + HIT_ACCURACY_TIER_8 - accurate_range = 12 - shell_speed = AMMO_SPEED_TIER_1 - -/datum/ammo/souto/on_embed(mob/embedded_mob, obj/limb/target_organ) - if(ishuman(embedded_mob) && !isyautja(embedded_mob)) - if(istype(target_organ)) - target_organ.embed(new can_type) - -/datum/ammo/souto/on_hit_mob(mob/M, obj/projectile/P) - if(!M || M == P.firer) return - if(M.throw_mode && !M.get_active_hand()) //empty active hand and we're in throw mode. If so we catch the can. - if(!M.is_mob_incapacitated()) // People who are not able to catch cannot catch. - if(P.contents.len == 1) - for(var/obj/item/reagent_container/food/drinks/cans/souto/S in P.contents) - M.put_in_active_hand(S) - for(var/mob/O in viewers(world_view_size, P)) //find all people in view. - O.show_message(SPAN_DANGER("[M] catches the [S]!"), SHOW_MESSAGE_VISIBLE) //Tell them the can was caught. - return //Can was caught. - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.species.name == "Human") //no effect on synths or preds. - H.apply_effect(6, STUN) - H.apply_effect(8, WEAKEN) - H.apply_effect(15, DAZE) - H.apply_effect(15, SLOW) - shake_camera(H, 2, 1) - if(P.contents.len) - drop_can(P.loc, P) //We make a can at the location. - -/datum/ammo/souto/on_hit_obj(obj/O,obj/projectile/P) - drop_can(P.loc, P) //We make a can at the location. - -/datum/ammo/souto/on_hit_turf(turf/T, obj/projectile/P) - drop_can(P.loc, P) //We make a can at the location. - -/datum/ammo/souto/do_at_max_range(obj/projectile/P) - drop_can(P.loc, P) //We make a can at the location. - -/datum/ammo/souto/on_shield_block(mob/M, obj/projectile/P) - drop_can(P.loc, P) //We make a can at the location. - -/datum/ammo/souto/proc/drop_can(loc, obj/projectile/P) - if(P.contents.len) - for(var/obj/item/I in P.contents) - I.forceMove(loc) - randomize_projectile(P) - -/datum/ammo/souto/proc/randomize_projectile(obj/projectile/P) - shrapnel_type = pick(typesof(/obj/item/reagent_container/food/drinks/cans/souto)-/obj/item/reagent_container/food/drinks/cans/souto) - -/datum/ammo/grenade_container - name = "grenade shell" - ping = null - damage_type = BRUTE - var/nade_type = /obj/item/explosive/grenade/high_explosive - icon_state = "grenade" - flags_ammo_behavior = AMMO_IGNORE_COVER|AMMO_SKIPS_ALIENS - - damage = 15 - accuracy = HIT_ACCURACY_TIER_3 - max_range = 6 - -/datum/ammo/grenade_container/on_hit_mob(mob/M,obj/projectile/P) - drop_nade(P) - -/datum/ammo/grenade_container/on_hit_obj(obj/O,obj/projectile/P) - drop_nade(P) - -/datum/ammo/grenade_container/on_hit_turf(turf/T,obj/projectile/P) - drop_nade(P) - -/datum/ammo/grenade_container/do_at_max_range(obj/projectile/P) - drop_nade(P) - -/datum/ammo/grenade_container/proc/drop_nade(obj/projectile/P) - var/turf/T = get_turf(P) - var/obj/item/explosive/grenade/G = new nade_type(T) - G.visible_message(SPAN_WARNING("\A [G] lands on [T]!")) - G.det_time = 10 - G.cause_data = P.weapon_cause_data - G.activate() - -/datum/ammo/grenade_container/rifle - flags_ammo_behavior = NO_FLAGS - -/datum/ammo/grenade_container/smoke - name = "smoke grenade shell" - nade_type = /obj/item/explosive/grenade/smokebomb - icon_state = "smoke_shell" - -/datum/ammo/hugger_container - name = "hugger shell" - ping = null - damage_type = BRUTE - var/hugger_hive = XENO_HIVE_NORMAL - icon_state = "smoke_shell" - - damage = 15 - accuracy = HIT_ACCURACY_TIER_3 - max_range = 6 - -/datum/ammo/hugger_container/on_hit_mob(mob/M,obj/projectile/P) - spawn_hugger(get_turf(P)) - -/datum/ammo/hugger_container/on_hit_obj(obj/O,obj/projectile/P) - spawn_hugger(get_turf(P)) - -/datum/ammo/hugger_container/on_hit_turf(turf/T,obj/projectile/P) - spawn_hugger(get_turf(P)) - -/datum/ammo/hugger_container/do_at_max_range(obj/projectile/P) - spawn_hugger(get_turf(P)) - -/datum/ammo/hugger_container/proc/spawn_hugger(turf/T) - var/obj/item/clothing/mask/facehugger/child = new(T) - child.hivenumber = hugger_hive - INVOKE_ASYNC(child, TYPE_PROC_REF(/obj/item/clothing/mask/facehugger, leap_at_nearest_target)) From 143987234b1f86e43411d770a197e92b0881a336 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 13:36:00 +0300 Subject: [PATCH 18/31] rebase --- code/datums/ammo/bullet/pistol.dm | 2 +- code/datums/ammo/bullet/special_ammo.dm | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/datums/ammo/bullet/pistol.dm b/code/datums/ammo/bullet/pistol.dm index 8be63b0a15af..8280bcf5c288 100644 --- a/code/datums/ammo/bullet/pistol.dm +++ b/code/datums/ammo/bullet/pistol.dm @@ -259,7 +259,7 @@ flags_ammo_behavior = AMMO_BALLISTIC accuracy = HIT_ACCURACY_TIER_8 - damage = 30 + damage = 36 penetration = 20 shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 diff --git a/code/datums/ammo/bullet/special_ammo.dm b/code/datums/ammo/bullet/special_ammo.dm index cdf30b1af7fe..352aafade9a4 100644 --- a/code/datums/ammo/bullet/special_ammo.dm +++ b/code/datums/ammo/bullet/special_ammo.dm @@ -11,7 +11,7 @@ max_range = 12 accuracy = HIT_ACCURACY_TIER_4 - damage = 30 + damage = 36 penetration = 0 /datum/ammo/bullet/smartgun/armor_piercing @@ -20,7 +20,7 @@ accurate_range = 12 accuracy = HIT_ACCURACY_TIER_2 - damage = 20 + damage = 24 penetration = ARMOR_PENETRATION_TIER_8 damage_armor_punch = 1 @@ -98,7 +98,7 @@ icon_state = "bullet" // Keeping it bog standard with the turret but allows it to be changed accurate_range = 12 - damage = 35 + damage = 36 penetration= ARMOR_PENETRATION_TIER_10 //Bumped the penetration to serve a different role from sentries, MGs are a bit more offensive accuracy = HIT_ACCURACY_TIER_3 From 21b055771aa5f8aa6f2622674e6a2c66fd915e24 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 13:40:37 +0300 Subject: [PATCH 19/31] I don't know what to put here --- code/modules/cm_marines/smartgun_mount.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/cm_marines/smartgun_mount.dm b/code/modules/cm_marines/smartgun_mount.dm index e4c486449431..38b2e5060048 100644 --- a/code/modules/cm_marines/smartgun_mount.dm +++ b/code/modules/cm_marines/smartgun_mount.dm @@ -458,7 +458,7 @@ /// How much time should pass in between full auto shots, slightly higher than burst due to click delay and similar things that slow firing down var/fire_delay = 0.25 SECONDS /// How much time should pass in between burst fire shots - var/burst_fire_delay = 0.175 SECONDS + var/burst_fire_delay = 0.2 SECONDS /// How many rounds are fired per burst var/burst_amount = 3 /// How many rounds have been fired in the current burst/auto From cee59dfbbd130b4c43cd69f3c1875eef9f8e81ff Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 13:56:20 +0300 Subject: [PATCH 20/31] fix? --- code/datums/components/iff_fire_prevention.dm | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm index 13b3919766c9..c0c11cb974db 100644 --- a/code/datums/components/iff_fire_prevention.dm +++ b/code/datums/components/iff_fire_prevention.dm @@ -1,31 +1,21 @@ #define IFF_HALT_COOLDOWN 0.5 SECONDS /datum/component/iff_fire_prevention - var/obj/parent_gun var/iff_additional_fire_delay COOLDOWN_DECLARE(iff_halt_cooldown) /datum/component/iff_fire_prevention/Initialize(additional_fire_delay = 0) . = ..() - parent_gun = parent iff_additional_fire_delay = additional_fire_delay /datum/component/iff_fire_prevention/RegisterWithParent() . = ..() - RegisterSignal(parent_gun, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) + RegisterSignal(parent, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) /datum/component/iff_fire_prevention/UnregisterFromParent() . = ..() - UnregisterSignal(parent_gun, COMSIG_GUN_BEFORE_FIRE) - -/datum/component/iff_fire_prevention/Destroy(force, silent) - handle_qdel() - . = ..() - -/datum/component/iff_fire_prevention/proc/handle_qdel() - SIGNAL_HANDLER - parent_gun = null + UnregisterSignal(parent, COMSIG_GUN_BEFORE_FIRE) /datum/component/iff_fire_prevention/proc/check_firing_lane(obj/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) SIGNAL_HANDLER From 0450ad3cc84bff8764da7dd9eb7c477b2eeb9179 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 15:51:30 +0300 Subject: [PATCH 21/31] m46c unnerf + bugfix --- code/modules/projectiles/guns/rifles.dm | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm index a9a1d7051748..599ac6211875 100644 --- a/code/modules/projectiles/guns/rifles.dm +++ b/code/modules/projectiles/guns/rifles.dm @@ -493,6 +493,7 @@ var/mob/living/carbon/human/linked_human var/is_locked = TRUE var/iff_enabled = TRUE + start_automatic = TRUE /obj/item/weapon/gun/rifle/m46c/Initialize(mapload, ...) LAZYADD(actions_types, /datum/action/item_action/m46c/toggle_lethal_mode) @@ -502,6 +503,7 @@ LAZYADD(traits_to_give, list( BULLET_TRAIT_ENTRY_ID("iff", /datum/element/bullet_trait_iff) )) + AddComponent(/datum/component/iff_fire_prevention) recalculate_attachment_bonuses() /obj/item/weapon/gun/rifle/m46c/Destroy() @@ -635,17 +637,6 @@ remove_bullet_trait("iff") GetExactComponent(/datum/component/iff_fire_prevention).RemoveComponent() -/obj/item/weapon/gun/rifle/m46c/recalculate_attachment_bonuses() - . = ..() - if(iff_enabled) - modify_fire_delay(FIRE_DELAY_TIER_12) - remove_firemode(GUN_FIREMODE_BURSTFIRE) - remove_firemode(GUN_FIREMODE_AUTOMATIC) - - else - add_firemode(GUN_FIREMODE_BURSTFIRE) - add_firemode(GUN_FIREMODE_AUTOMATIC) - /obj/item/weapon/gun/rifle/m46c/proc/name_after_co(mob/living/carbon/human/H) linked_human = H From 83da2505af5b94063fc6fb64005abf97fc13ad2f Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 18:57:36 +0300 Subject: [PATCH 22/31] code doc --- code/_onclick/hud/fullscreen.dm | 4 ++-- code/datums/components/iff_fire_prevention.dm | 4 +++- code/modules/projectiles/gun.dm | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index c8947e206256..de9c287514e9 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -66,8 +66,8 @@ if(!client) return 7 - var/offset = client.pixel_x || client.pixel_y - return client.view + abs(offset / 32) + var/offset = max(abs(client.pixel_x), abs(client.pixel_y)) + return client.view + offset / 32 /atom/movable/screen/fullscreen icon = 'icons/mob/hud/screen1_full.dmi' diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm index c0c11cb974db..b86437cfe64c 100644 --- a/code/datums/components/iff_fire_prevention.dm +++ b/code/datums/components/iff_fire_prevention.dm @@ -1,5 +1,7 @@ #define IFF_HALT_COOLDOWN 0.5 SECONDS +/// A component that prevents gun (although you can attach it to anything else that shoot projectiles) from shooting when mob from the same faction stands in the way. +/// You can also pass number of ticks, to make gun have an additional delay if firing prevention comes into play, but it is not neccesary. /datum/component/iff_fire_prevention var/iff_additional_fire_delay COOLDOWN_DECLARE(iff_halt_cooldown) @@ -43,7 +45,7 @@ if(original_target_turf && !(original_target_turf in checked_turfs)) var/user_to_target_dist = get_dist(starting_turf, original_target_turf) - var/list/temp_checked_turfs = checked_turfs + var/list/temp_checked_turfs = checked_turfs.Copy() checked_turfs = list() for(var/turf/checked_turf as anything in temp_checked_turfs) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 297f821b5242..df43eece3aa9 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1678,6 +1678,7 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed return 1 +/// When the gun is about to shoot this is called to play the specific gun's firing sound. Requires the firing projectile and the gun's user as the first and second argument /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 From 4978be40bdcf74f27d1053ffa2cad25e608e9b23 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Thu, 19 Oct 2023 23:59:07 +0300 Subject: [PATCH 23/31] revert MD removal --- code/modules/projectiles/guns/smartgun.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index a52c54b4741b..43d98f423e57 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -31,6 +31,7 @@ /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_motion_detector, /datum/action/item_action/smartgun/toggle_recoil_compensation, ) var/datum/ammo/ammo_primary = /datum/ammo/bullet/smartgun //Toggled ammo type From 48170a1394fd48bf7dedce405335e449a98e8788 Mon Sep 17 00:00:00 2001 From: ihatethisengine <115417687+ihatethisengine@users.noreply.github.com> Date: Fri, 20 Oct 2023 03:13:23 +0300 Subject: [PATCH 24/31] Update code/_onclick/hud/fullscreen.dm Co-authored-by: fira --- code/_onclick/hud/fullscreen.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index de9c287514e9..ce41b76b8ed6 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -64,7 +64,7 @@ //Get the distance to the farthest edge of the screen /mob/proc/get_maximum_view_range() if(!client) - return 7 + return world.view var/offset = max(abs(client.pixel_x), abs(client.pixel_y)) return client.view + offset / 32 From bcbe17a2262870950cbbc35f5353d845780049a6 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Fri, 20 Oct 2023 10:47:55 +0300 Subject: [PATCH 25/31] hm --- code/__DEFINES/dcs/signals/atom/signals_gun.dm | 6 +++--- code/datums/components/iff_fire_prevention.dm | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/code/__DEFINES/dcs/signals/atom/signals_gun.dm b/code/__DEFINES/dcs/signals/atom/signals_gun.dm index 51b8c25fce7e..73209753a681 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_gun.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_gun.dm @@ -17,9 +17,9 @@ #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" +#define COMSIG_AUTO_START_SHOOTING_AT "auto_start_shooting_at" +#define COMSIG_AUTO_STOP_SHOOTING_AT "auto_stop_shooting_at" +#define COMSIG_AUTO_SHOOT "auto_shoot" //Signals for gun auto fire component #define COMSIG_GET_BURST_FIRE "get_burst_fire" diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm index b86437cfe64c..846497dcc2b7 100644 --- a/code/datums/components/iff_fire_prevention.dm +++ b/code/datums/components/iff_fire_prevention.dm @@ -28,7 +28,6 @@ var/extended_target_turf = get_angle_target_turf(user, angle, range_to_check) - var/turf/starting_turf = get_turf(user) if(!starting_turf || !extended_target_turf) @@ -65,7 +64,7 @@ continue if(checked_living.get_target_lock(user.faction_group)) - if(COOLDOWN_FINISHED(src, iff_halt_cooldown)) + if(COOLDOWN_FINISHED(src, iff_halt_cooldown) && user.client) playsound_client(user.client, 'sound/weapons/smartgun_fail.ogg', src, 25) to_chat(user, SPAN_WARNING("[firing_weapon] halts firing as an IFF marked target crosses your field of fire!")) COOLDOWN_START(src, iff_halt_cooldown, IFF_HALT_COOLDOWN) From 3fea90219a78ecc5df888a0cd85825033036fbf0 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Fri, 20 Oct 2023 11:31:11 +0300 Subject: [PATCH 26/31] more signals --- code/__DEFINES/dcs/signals/atom/signals_gun.dm | 3 +++ code/datums/components/iff_fire_prevention.dm | 14 +++++++++++++- code/modules/projectiles/guns/rifles.dm | 3 +-- code/modules/projectiles/guns/smartgun.dm | 3 +-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/code/__DEFINES/dcs/signals/atom/signals_gun.dm b/code/__DEFINES/dcs/signals/atom/signals_gun.dm index 73209753a681..76b4e5c08b70 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_gun.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_gun.dm @@ -29,3 +29,6 @@ #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 + +/// Called when IFF is toggled on or off +#define COMSIG_GUN_IFF_TOGGLED "gun_iff_toggled" diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm index 846497dcc2b7..295f1b162fdb 100644 --- a/code/datums/components/iff_fire_prevention.dm +++ b/code/datums/components/iff_fire_prevention.dm @@ -14,10 +14,14 @@ /datum/component/iff_fire_prevention/RegisterWithParent() . = ..() RegisterSignal(parent, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) + RegisterSignal(parent, COMSIG_GUN_IFF_TOGGLED, PROC_REF(handle_iff_toggle)) /datum/component/iff_fire_prevention/UnregisterFromParent() . = ..() - UnregisterSignal(parent, COMSIG_GUN_BEFORE_FIRE) + UnregisterSignal(parent, list( + COMSIG_GUN_BEFORE_FIRE, + COMSIG_GUN_IFF_TOGGLED + )) /datum/component/iff_fire_prevention/proc/check_firing_lane(obj/firing_weapon, obj/projectile/projectile_to_fire, atom/target, mob/living/user) SIGNAL_HANDLER @@ -76,4 +80,12 @@ return //if we have a target we *can* hit and find it before any IFF targets we want to fire +/// Disable fire prevention when IFF is toggled off and other way around +/datum/component/iff_fire_prevention/proc/handle_iff_toggle(obj/gun, iff_enabled) + SIGNAL_HANDLER + if(iff_enabled) + RegisterSignal(parent, COMSIG_GUN_BEFORE_FIRE, PROC_REF(check_firing_lane)) + else + UnregisterSignal(parent, COMSIG_GUN_BEFORE_FIRE) + #undef IFF_HALT_COOLDOWN diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm index 599ac6211875..4b2069a864f6 100644 --- a/code/modules/projectiles/guns/rifles.dm +++ b/code/modules/projectiles/guns/rifles.dm @@ -632,10 +632,9 @@ recalculate_attachment_bonuses() if(iff_enabled) add_bullet_trait(BULLET_TRAIT_ENTRY_ID("iff", /datum/element/bullet_trait_iff)) - AddComponent(/datum/component/iff_fire_prevention) else remove_bullet_trait("iff") - GetExactComponent(/datum/component/iff_fire_prevention).RemoveComponent() + SEND_SIGNAL(src, COMSIG_GUN_IFF_TOGGLED, iff_enabled) /obj/item/weapon/gun/rifle/m46c/proc/name_after_co(mob/living/carbon/human/H) diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index 43d98f423e57..74b04b4313a0 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -354,14 +354,13 @@ secondary_toggled = FALSE if(iff_enabled) add_bullet_trait(BULLET_TRAIT_ENTRY_ID("iff", /datum/element/bullet_trait_iff)) - AddComponent(/datum/component/iff_fire_prevention) drain += 10 MD.iff_signal = initial(MD.iff_signal) if(!iff_enabled) remove_bullet_trait("iff") - GetExactComponent(/datum/component/iff_fire_prevention).RemoveComponent() drain -= 10 MD.iff_signal = null + SEND_SIGNAL(src, COMSIG_GUN_IFF_TOGGLED, iff_enabled) /obj/item/weapon/gun/smartgun/Fire(atom/target, mob/living/user, params, reflex = 0, dual_wield) if(!requires_battery) From 84c17a27fd9280acd699933b81d3ef916ca88d63 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Fri, 20 Oct 2023 16:44:20 +0300 Subject: [PATCH 27/31] uhhhh --- code/modules/projectiles/gun.dm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index df43eece3aa9..f33195623841 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1203,6 +1203,10 @@ and you're good to go. if(before_fire_cancel & COMPONENT_HARD_CANCEL_GUN_BEFORE_FIRE) return NONE + projectile_to_fire.firer = user + if(isliving(user)) + projectile_to_fire.def_zone = user.zone_selected + play_firing_sounds(projectile_to_fire, user) if(targloc != curloc) @@ -1424,6 +1428,10 @@ 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. + projectile_to_fire.firer = user + if(isliving(user)) + projectile_to_fire.def_zone = user.zone_selected + play_firing_sounds(projectile_to_fire, user) SEND_SIGNAL(projectile_to_fire, COMSIG_BULLET_USER_EFFECTS, user) @@ -1690,10 +1698,6 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed 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 From 5a4135e33e8492ae6a15912376d81bbd347613ed Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Sat, 21 Oct 2023 16:43:53 +0300 Subject: [PATCH 28/31] IFF for PB --- code/datums/components/iff_fire_prevention.dm | 4 +++- code/modules/projectiles/gun.dm | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm index 295f1b162fdb..aa67621baaff 100644 --- a/code/datums/components/iff_fire_prevention.dm +++ b/code/datums/components/iff_fire_prevention.dm @@ -39,7 +39,9 @@ var/list/checked_turfs = getline2(starting_turf, extended_target_turf) - checked_turfs -= starting_turf + //Don't check starting turf... Unless we are shooting ourself!!! + if(target != user) + checked_turfs -= starting_turf //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index f33195623841..4b4034c8afc0 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1407,6 +1407,15 @@ and you're good to go. click_empty(user) break + //Checking if we even can PB the mob, only for the first projectile because why check the rest + if(bullets_fired == 1) + var/before_fire_cancel = SEND_SIGNAL(src, COMSIG_GUN_BEFORE_FIRE, projectile_to_fire, attacked_mob, 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 + if(SEND_SIGNAL(projectile_to_fire.ammo, COMSIG_AMMO_POINT_BLANK, attacked_mob, projectile_to_fire, user, src) & COMPONENT_CANCEL_AMMO_POINT_BLANK) flags_gun_features &= ~GUN_BURST_FIRING return TRUE From 091b8cb18bae739641945960290392d8ecd10b3f Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Sat, 21 Oct 2023 18:56:30 +0300 Subject: [PATCH 29/31] ignore scout --- code/datums/components/iff_fire_prevention.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm index aa67621baaff..b37164049ac5 100644 --- a/code/datums/components/iff_fire_prevention.dm +++ b/code/datums/components/iff_fire_prevention.dm @@ -70,6 +70,8 @@ continue if(checked_living.get_target_lock(user.faction_group)) + if(HAS_TRAIT(checked_living, TRAIT_CLOAKED)) + continue if(COOLDOWN_FINISHED(src, iff_halt_cooldown) && user.client) playsound_client(user.client, 'sound/weapons/smartgun_fail.ogg', src, 25) to_chat(user, SPAN_WARNING("[firing_weapon] halts firing as an IFF marked target crosses your field of fire!")) From 2b812cfc99047056bc35b07869181a802d3328d8 Mon Sep 17 00:00:00 2001 From: ihatethisengine Date: Sun, 22 Oct 2023 19:49:38 +0300 Subject: [PATCH 30/31] ultimate snowflake fix --- code/datums/components/iff_fire_prevention.dm | 16 ++++- code/modules/projectiles/gun.dm | 64 +++++++++++-------- 2 files changed, 50 insertions(+), 30 deletions(-) diff --git a/code/datums/components/iff_fire_prevention.dm b/code/datums/components/iff_fire_prevention.dm index b37164049ac5..3340fa36f38e 100644 --- a/code/datums/components/iff_fire_prevention.dm +++ b/code/datums/components/iff_fire_prevention.dm @@ -39,9 +39,17 @@ var/list/checked_turfs = getline2(starting_turf, extended_target_turf) - //Don't check starting turf... Unless we are shooting ourself!!! - if(target != user) - checked_turfs -= starting_turf + //Don't shoot yourself, thanks + if(target == user) + if(COOLDOWN_FINISHED(src, iff_halt_cooldown) && user.client) + playsound_client(user.client, 'sound/weapons/smartgun_fail.ogg', src, 25) + to_chat(user, SPAN_WARNING("[firing_weapon] halts firing as an IFF marked target crosses your field of fire!")) + COOLDOWN_START(src, iff_halt_cooldown, IFF_HALT_COOLDOWN) + if(iff_additional_fire_delay) + var/obj/item/weapon/gun/gun = firing_weapon + if(istype(gun)) + LAZYSET(user.fire_delay_next_fire, gun, world.time + iff_additional_fire_delay) + return COMPONENT_CANCEL_GUN_BEFORE_FIRE //At some angles (scatter or otherwise) the original target is not in checked_turfs so we put it in there in order based on distance from user //If we are literally clicking on someone with IFF then we don't want to fire, feels funny as a user otherwise @@ -66,6 +74,8 @@ return for(var/mob/living/checked_living in checked_turf) + if(checked_living == user) // sometimes it still happens + continue if(checked_living.lying && projectile_to_fire.original != checked_living) continue diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 4b4034c8afc0..8ecf0815a0f9 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1145,8 +1145,9 @@ and you're good to go. flags_gun_features &= ~GUN_BURST_FIRING return NONE - apply_bullet_effects(projectile_to_fire, user, reflex, dual_wield) //User can be passed as null. - SEND_SIGNAL(projectile_to_fire, COMSIG_BULLET_USER_EFFECTS, user) + var/original_scatter = projectile_to_fire.scatter + var/original_accuracy = projectile_to_fire.accuracy + apply_bullet_scatter(projectile_to_fire, user, reflex, dual_wield) //User can be passed as null. curloc = get_turf(user) if(QDELETED(original_target)) //If the target's destroyed, shoot at where it was last. @@ -1195,14 +1196,21 @@ and you're good to go. return NONE var/before_fire_cancel = SEND_SIGNAL(src, COMSIG_GUN_BEFORE_FIRE, projectile_to_fire, target, user) - if(before_fire_cancel) + + //yeah we revert these since we are not going to shoot anyway + projectile_to_fire.scatter = original_scatter + projectile_to_fire.accuracy = original_accuracy + if(before_fire_cancel & COMPONENT_CANCEL_GUN_BEFORE_FIRE) return TRUE if(before_fire_cancel & COMPONENT_HARD_CANCEL_GUN_BEFORE_FIRE) return NONE + apply_bullet_effects(projectile_to_fire, user, reflex, dual_wield) //User can be passed as null. + SEND_SIGNAL(projectile_to_fire, COMSIG_BULLET_USER_EFFECTS, user) + projectile_to_fire.firer = user if(isliving(user)) projectile_to_fire.def_zone = user.zone_selected @@ -1643,6 +1651,32 @@ 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) + if(wield_delay > 0 && (world.time < wield_time || world.time < pull_time)) + var/old_time = max(wield_time, pull_time) - wield_delay + var/new_time = world.time + var/pct_settled = 1 - (new_time-old_time + 1)/wield_delay + if(delay_style & WEAPON_DELAY_ACCURACY) + var/accuracy_debuff = 1 + (SETTLE_ACCURACY_MULTIPLIER - 1) * pct_settled + projectile_to_fire.accuracy /=accuracy_debuff + if(delay_style & WEAPON_DELAY_SCATTER) + var/scatter_debuff = 1 + (SETTLE_SCATTER_MULTIPLIER - 1) * pct_settled + projectile_to_fire.scatter *= scatter_debuff + + projectile_to_fire.damage = round(projectile_to_fire.damage * damage_mult) // Apply gun damage multiplier to projectile damage + + // Apply effective range and falloffs/buildups + projectile_to_fire.damage_falloff = damage_falloff_mult * projectile_to_fire.ammo.damage_falloff + projectile_to_fire.damage_buildup = damage_buildup_mult * projectile_to_fire.ammo.damage_buildup + + projectile_to_fire.effective_range_min = effective_range_min + projectile_to_fire.ammo.effective_range_min //Add on ammo-level value, if specified. + projectile_to_fire.effective_range_max = effective_range_max + projectile_to_fire.ammo.effective_range_max //Add on ammo-level value, if specified. + + projectile_to_fire.shot_from = src + + return 1 + +//This proc calculates scatter and accuracy +/obj/item/weapon/gun/proc/apply_bullet_scatter(obj/projectile/projectile_to_fire, mob/user, reflex = 0, dual_wield = 0) var/gun_accuracy_mult = accuracy_mult_unwielded var/gun_scatter = scatter_unwielded @@ -1671,30 +1705,6 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed projectile_to_fire.accuracy = round(projectile_to_fire.accuracy * gun_accuracy_mult) // Apply gun accuracy multiplier to projectile accuracy projectile_to_fire.scatter += gun_scatter - if(wield_delay > 0 && (world.time < wield_time || world.time < pull_time)) - var/old_time = max(wield_time, pull_time) - wield_delay - var/new_time = world.time - var/pct_settled = 1 - (new_time-old_time + 1)/wield_delay - if(delay_style & WEAPON_DELAY_ACCURACY) - var/accuracy_debuff = 1 + (SETTLE_ACCURACY_MULTIPLIER - 1) * pct_settled - projectile_to_fire.accuracy /=accuracy_debuff - if(delay_style & WEAPON_DELAY_SCATTER) - var/scatter_debuff = 1 + (SETTLE_SCATTER_MULTIPLIER - 1) * pct_settled - projectile_to_fire.scatter *= scatter_debuff - - projectile_to_fire.damage = round(projectile_to_fire.damage * damage_mult) // Apply gun damage multiplier to projectile damage - - // Apply effective range and falloffs/buildups - projectile_to_fire.damage_falloff = damage_falloff_mult * projectile_to_fire.ammo.damage_falloff - projectile_to_fire.damage_buildup = damage_buildup_mult * projectile_to_fire.ammo.damage_buildup - - projectile_to_fire.effective_range_min = effective_range_min + projectile_to_fire.ammo.effective_range_min //Add on ammo-level value, if specified. - projectile_to_fire.effective_range_max = effective_range_max + projectile_to_fire.ammo.effective_range_max //Add on ammo-level value, if specified. - - projectile_to_fire.shot_from = src - - return 1 - /// When the gun is about to shoot this is called to play the specific gun's firing sound. Requires the firing projectile and the gun's user as the first and second argument /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. From 2571e99509f0072a6c11fd4d94f59440f9b50737 Mon Sep 17 00:00:00 2001 From: ihatethisengine <115417687+ihatethisengine@users.noreply.github.com> Date: Sun, 12 Nov 2023 10:35:14 +0300 Subject: [PATCH 31/31] Update colonialmarines.dme --- colonialmarines.dme | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/colonialmarines.dme b/colonialmarines.dme index 4a8f259c95a4..04f44a120c28 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -125,8 +125,8 @@ #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_cell.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"