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..e09b96503bc9 --- /dev/null +++ b/code/__DEFINES/dcs/signals/atom/signals_gun.dm @@ -0,0 +1,34 @@ +#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 + +/// Called when IFF is toggled on or off +#define COMSIG_GUN_IFF_TOGGLED "gun_iff_toggled" diff --git a/code/__DEFINES/dcs/signals/atom/signals_item.dm b/code/__DEFINES/dcs/signals/atom/signals_item.dm index 88f99bbff578..a70d1b8946f4 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_item.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_item.dm @@ -44,33 +44,6 @@ /// 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" - //from /datum/authority/branch/role/proc/equip_role() #define COMSIG_POST_SPAWN_UPDATE "post_spawn_update" diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index 505b1876e3af..dd3b9a2599ef 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -61,6 +61,13 @@ else client.remove_from_screen(screen) +/mob/proc/get_maximum_view_range() + if(!client) + return world.view + + + 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 new file mode 100644 index 000000000000..9a50c7878156 --- /dev/null +++ b/code/datums/components/iff_fire_prevention.dm @@ -0,0 +1,105 @@ +#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) + +/datum/component/iff_fire_prevention/Initialize(additional_fire_delay = 0) + . = ..() + iff_additional_fire_delay = additional_fire_delay + + +/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, 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 + + 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 = get_line(starting_turf, extended_target_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 + 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.Copy() + 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 == user) // sometimes it still happens + continue + if(checked_living.body_position == LYING_DOWN && projectile_to_fire.original != checked_living) + 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!")) + 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 + + 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/datums/skills/uscm.dm b/code/datums/skills/uscm.dm index 9df0ec3bb321..1bfa6d90f5fc 100644 --- a/code/datums/skills/uscm.dm +++ b/code/datums/skills/uscm.dm @@ -443,6 +443,7 @@ SOLAR DEVILS (PvE Marines) SKILL_VEHICLE = SKILL_VEHICLE_SMALL, SKILL_JTAC = SKILL_JTAC_BEGINNER, SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, ) /datum/skills/combat_medic_pve @@ -457,6 +458,7 @@ SOLAR DEVILS (PvE Marines) SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, SKILL_SURGERY = SKILL_SURGERY_NOVICE, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, ) /datum/skills/smartgunner_pve @@ -484,6 +486,7 @@ SOLAR DEVILS (PvE Marines) SKILL_LEADERSHIP = SKILL_LEAD_TRAINED, SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED, SKILL_PILOT = SKILL_PILOT_TRAINED, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, ) /datum/skills/sl_pve @@ -496,10 +499,11 @@ SOLAR DEVILS (PvE Marines) SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, SKILL_CQC = SKILL_CQC_TRAINED, SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, - SKILL_MEDICAL = SKILL_MEDICAL_TRAINED, + SKILL_MEDICAL = SKILL_MEDICAL_MEDIC, SKILL_SURGERY = SKILL_SURGERY_NOVICE, SKILL_VEHICLE = SKILL_VEHICLE_SMALL, SKILL_JTAC = SKILL_JTAC_TRAINED, SKILL_INTEL = SKILL_INTEL_TRAINED, SKILL_PILOT = SKILL_PILOT_EXPERT, + SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN, ) diff --git a/code/game/objects/items/storage/toolkit.dm b/code/game/objects/items/storage/toolkit.dm index d54201f73650..c6e95fbcae5e 100644 --- a/code/game/objects/items/storage/toolkit.dm +++ b/code/game/objects/items/storage/toolkit.dm @@ -48,8 +48,8 @@ new /obj/item/circuitboard/apc(src) new /obj/item/circuitboard/apc(src) new /obj/item/cell/high(src) - new /obj/item/cell/high(src) - new /obj/item/clothing/glasses/welding(src) + new /obj/item/explosive/plastic/breaching_charge(src) + new /obj/item/explosive/plastic/breaching_charge(src) /obj/item/storage/toolkit/empty/fill_preset_inventory() diff --git a/code/game/objects/items/tools/maintenance_tools.dm b/code/game/objects/items/tools/maintenance_tools.dm index f45953040a07..a25a8979f006 100644 --- a/code/game/objects/items/tools/maintenance_tools.dm +++ b/code/game/objects/items/tools/maintenance_tools.dm @@ -417,6 +417,11 @@ to_chat(H, SPAN_WARNING("Your eyes are really starting to hurt. This can't be good for you!")) return FALSE +/obj/item/tool/weldingtool/screen + name = "shielded blowtorch" + desc = "A blowtorch, this one has a welding screen installed to prevent eye damage." + has_welding_screen = TRUE + /obj/item/tool/weldingtool/largetank name = "industrial blowtorch" max_fuel = 60 diff --git a/code/modules/gear_presets/uscm.dm b/code/modules/gear_presets/uscm.dm index eedd0f79f4a7..baa33135368a 100644 --- a/code/modules/gear_presets/uscm.dm +++ b/code/modules/gear_presets/uscm.dm @@ -134,6 +134,7 @@ new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/smartgun(new_human), WEAR_J_STORE) new_human.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/specrag(new_human), WEAR_HEAD) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/smartgunner/full(new_human), WEAR_WAIST) + new_human.equip_to_slot_or_del(new /obj/item/storage/large_holster/machete/smartgunner/full(new_human), WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine(new_human), WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/m56_goggles(new_human), WEAR_EYES) @@ -968,7 +969,7 @@ /datum/equipment_preset/uscm/proc/spawn_marine_fluff_items(mob/living/carbon/human/new_human) var/obj/item/helmet_accessory = pick(GLOB.allowed_helmet_items) new_human.equip_to_slot_or_del(new helmet_accessory, WEAR_IN_HELMET) - if(prob(50)) + if(prob(75)) var/obj/item/helmet_accessory_two = pick(GLOB.allowed_helmet_items) new_human.equip_to_slot_or_del(new helmet_accessory_two, WEAR_IN_HELMET) var/list/possible_masks = list(/obj/item/clothing/mask/gas) + subtypesof(/obj/item/clothing/mask/rebreather) + subtypesof(/obj/item/clothing/mask/tornscarf) @@ -1013,7 +1014,7 @@ new_human.equip_to_slot_or_del(new /obj/item/tool/wirecutters/tactical(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/tool/wrench(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/device/multitool(new_human), WEAR_IN_ACCESSORY) - new_human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/largetank(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/screen(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/intel/chestrig(new_human), WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full(new_human), WEAR_R_STORE) @@ -1028,13 +1029,13 @@ new_human.equip_to_slot_or_del(new /obj/item/stack/sheet/plasteel/medium_stack(new_human), WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/patch/devils(new_human), WEAR_IN_BACK) - new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1(new_human), WEAR_J_STORE) + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1/pve(new_human), WEAR_J_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/marine(new_human), WEAR_WAIST) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap/pve(new_human.back), WEAR_IN_BELT) spawn_marine_fluff_items(new_human) //## Corpsman ##// @@ -1076,15 +1077,15 @@ new_human.equip_to_slot_or_del(new /obj/item/tool/wirecutters/tactical(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/tool/wrench(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/device/multitool(new_human), WEAR_IN_ACCESSORY) - new_human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/largetank(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/screen(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/intel/chestrig(new_human), WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full(new_human), WEAR_R_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/magazine/large(new_human), WEAR_L_STORE) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_L_STORE) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_L_STORE) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap(new_human.back), WEAR_IN_L_STORE) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap(new_human.back), WEAR_IN_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap/pve(new_human.back), WEAR_IN_L_STORE) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap/pve(new_human.back), WEAR_IN_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/insulated/black(new_human), WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) @@ -1097,7 +1098,7 @@ new_human.equip_to_slot_or_del(new /obj/item/device/healthanalyzer(new_human), WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/patch/devils(new_human), WEAR_IN_BACK) - new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1(new_human), WEAR_J_STORE) + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1/pve(new_human), WEAR_J_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/medical/lifesaver/full(new_human), WEAR_WAIST) spawn_marine_fluff_items(new_human) @@ -1134,13 +1135,14 @@ new_human.equip_to_slot_or_del(new /obj/item/tool/wirecutters/tactical(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/tool/wrench(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/device/multitool(new_human), WEAR_IN_ACCESSORY) - new_human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/simple(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/screen(new_human), WEAR_IN_ACCESSORY) - new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/smartgun(new_human), WEAR_J_STORE) + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/smartgun/pve(new_human), WEAR_J_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/smartgunner/full(new_human), WEAR_WAIST) new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/insulated/black(new_human), WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/night/m56_goggles(new_human), WEAR_EYES) + new_human.equip_to_slot_or_del(new /obj/item/storage/large_holster/machete/smartgunner/full(new_human), WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full(new_human), WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full/alternate(new_human), WEAR_R_STORE) spawn_marine_fluff_items(new_human) @@ -1182,7 +1184,7 @@ new_human.equip_to_slot_or_del(new /obj/item/tool/wirecutters/tactical(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/tool/wrench(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/device/multitool(new_human), WEAR_IN_ACCESSORY) - new_human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/largetank(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/screen(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/rto(new_human), WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full(new_human), WEAR_R_STORE) @@ -1195,13 +1197,13 @@ new_human.equip_to_slot_or_del(new /obj/item/defenses/handheld/sentry(new_human), WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/patch/devils(new_human), WEAR_IN_BACK) - new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1(new_human), WEAR_J_STORE) + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1/pve(new_human), WEAR_J_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/marine(new_human), WEAR_WAIST) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap/pve(new_human.back), WEAR_IN_BELT) spawn_marine_fluff_items(new_human) //## Squad Leader ##// @@ -1239,13 +1241,14 @@ new_human.equip_to_slot_or_del(new /obj/item/tool/wirecutters/tactical(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/tool/wrench(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/device/multitool(new_human), WEAR_IN_ACCESSORY) - new_human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/largetank(new_human), WEAR_IN_ACCESSORY) + new_human.equip_to_slot_or_del(new /obj/item/tool/weldingtool/screen(new_human), WEAR_IN_ACCESSORY) new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/marine/satchel/intel/chestrig(new_human), WEAR_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/flare/full(new_human), WEAR_R_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/firstaid/full(new_human), WEAR_L_STORE) new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine/insulated/black(new_human), WEAR_HANDS) new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET) + new_human.equip_to_slot_or_del(new /obj/item/storage/toolkit/full(new_human), WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/firstaid/regular(new_human), WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/storage/firstaid/adv(new_human), WEAR_IN_BACK) @@ -1255,11 +1258,11 @@ new_human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/large_stack(new_human), WEAR_IN_BACK) new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/patch/devils(new_human), WEAR_IN_BACK) - new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1(new_human), WEAR_J_STORE) + new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/rifle/m41aMK1/pve(new_human), WEAR_J_STORE) new_human.equip_to_slot_or_del(new /obj/item/storage/belt/marine(new_human), WEAR_WAIST) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap(new_human.back), WEAR_IN_BELT) - new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap/pve(new_human.back), WEAR_IN_BELT) + new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/rifle/m41aMK1/ap/pve(new_human.back), WEAR_IN_BELT) spawn_marine_fluff_items(new_human) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 80fce329e8cf..50e735b9181b 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -236,7 +236,6 @@ /// 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 - /** * An assoc list where the keys are fire delay group string defines * and the keys are when the guns of the group can be fired again @@ -1143,8 +1142,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. @@ -1192,6 +1192,28 @@ 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) + + //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 + + play_firing_sounds(projectile_to_fire, user) + if(targloc != curloc) simulate_recoil(dual_wield, user, target) @@ -1392,6 +1414,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 @@ -1413,6 +1444,12 @@ 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) SEND_SIGNAL(user, COMSIG_BULLET_DIRECT_HIT, attacked_mob) simulate_recoil(1, user) @@ -1621,12 +1658,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) - 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 + 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 @@ -1655,47 +1712,33 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed projectile_to_fire.accuracy = floor(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 = floor(projectile_to_fire.damage * damage_mult) // Apply gun damage multiplier to projectile damage +/// 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 - // 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 + var/actual_sound = fire_sound + if(isnull(fire_sound)) + actual_sound = pick(fire_sounds) - 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. + if(projectile_to_fire.ammo && projectile_to_fire.ammo.sound_override) + actual_sound = projectile_to_fire.ammo.sound_override - projectile_to_fire.shot_from = src + //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 - 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) + //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, 25, firing_sndfreq) - - return 1 + 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) diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm index e514a68879fb..cd0a15f5a09e 100644 --- a/code/modules/projectiles/guns/rifles.dm +++ b/code/modules/projectiles/guns/rifles.dm @@ -421,6 +421,10 @@ /obj/item/weapon/gun/rifle/m41aMK1/anchorpoint/gl desc = "A classic M41 MK1 Pulse Rifle painted in a fresh coat of the classic Humbrol 170 camoflauge. This one appears to be used by the Colonial Marine contingent aboard Anchorpoint Station, and is equipped with an underbarrel grenade launcher. Uses 10x24mm caseless ammunition." starting_attachment_types = list(/obj/item/attachable/stock/rifle/collapsible, /obj/item/attachable/attached_gun/grenade/mk1) + +/obj/item/weapon/gun/rifle/m41aMK1/pve + current_mag = /obj/item/ammo_magazine/rifle/m41aMK1/pve + //---------------------------------------------- //Special gun for the CO to replace the smartgun diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm index b2d228e27a26..c8a574adabb4 100644 --- a/code/modules/projectiles/guns/smartgun.dm +++ b/code/modules/projectiles/guns/smartgun.dm @@ -363,6 +363,7 @@ remove_bullet_trait("iff") 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) @@ -757,3 +758,17 @@ /obj/item/weapon/gun/smartgun/rmc/Initialize(mapload, ...) . = ..() MD.iff_signal = FACTION_TWE + +/obj/item/weapon/gun/smartgun/pve + name = "\improper Solar Devils M56B smartgun" + desc = "The actual firearm in the 4-piece M56B Smartgun System. This is a variant used by the Solar Devils Batallion, utilizing a unique IFF system that refuses to fire if a friendly would be hit.\nYou may toggle firing restrictions by using a special action.\nAlt-click it to open the feed cover and allow for reloading." + +/obj/item/weapon/gun/smartgun/pve/set_bullet_traits() + LAZYADD(traits_to_give, list( + BULLET_TRAIT_ENTRY_ID("iff", /datum/element/bullet_trait_iff) + )) + AddComponent(/datum/component/iff_fire_prevention) + +/obj/item/weapon/gun/smartgun/pve/set_gun_config_values() + ..() + damage_mult = BASE_BULLET_DAMAGE_MULT + BULLET_DAMAGE_MULT_TIER_5 diff --git a/code/modules/projectiles/magazines/rifles.dm b/code/modules/projectiles/magazines/rifles.dm index 60be8ed6c1ad..797dad21ed42 100644 --- a/code/modules/projectiles/magazines/rifles.dm +++ b/code/modules/projectiles/magazines/rifles.dm @@ -116,6 +116,14 @@ desc = "A long rectangular box of rounds that is only compatible with the older M41A MK1. Holds up to 95 rounds. This one contains wall-penetrating bullets." default_ammo = /datum/ammo/bullet/rifle/ap/penetrating ammo_band_color = AMMO_BAND_COLOR_PENETRATING + +/obj/item/ammo_magazine/rifle/m41aMK1/pve + desc = "A long rectangular box of rounds that is only compatible with the older M41A MK1. Holds up to 99 rounds." + max_rounds = 99 + +/obj/item/ammo_magazine/rifle/m41aMK1/ap/pve + desc = "A long rectangular box of rounds that is only compatible with the older M41A MK1. Holds up to 99 rounds. This one contains AP bullets." + max_rounds = 99 //------------------------------------------------------- //M4RA, l42 reskin, same stats as before but different, lore friendly, shell. diff --git a/colonialmarines.dme b/colonialmarines.dme index 9fff0d7db91b..e29b6ee44fdf 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -133,6 +133,7 @@ #include "code\__DEFINES\dcs\signals\signals_subsystem.dm" #include "code\__DEFINES\dcs\signals\atom\signals_atom.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" @@ -413,6 +414,7 @@ #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" diff --git a/sound/weapons/smartgun_fail.ogg b/sound/weapons/smartgun_fail.ogg new file mode 100644 index 000000000000..2d33cf7d1324 Binary files /dev/null and b/sound/weapons/smartgun_fail.ogg differ