diff --git a/code/modules/vehicles/apc/apc.dm b/code/modules/vehicles/apc/apc.dm index 55e2cf2d11..778348b39f 100644 --- a/code/modules/vehicles/apc/apc.dm +++ b/code/modules/vehicles/apc/apc.dm @@ -112,7 +112,8 @@ GLOBAL_LIST_EMPTY(command_apc_list) /obj/vehicle/multitile/proc/activate_horn, /obj/vehicle/multitile/proc/switch_hardpoint, /obj/vehicle/multitile/proc/cycle_hardpoint, - /obj/vehicle/multitile/proc/name_vehicle + /obj/vehicle/multitile/proc/name_vehicle, + /obj/vehicle/multitile/proc/cycle_firemode )) else if(seat == VEHICLE_GUNNER) add_verb(M.client, list( diff --git a/code/modules/vehicles/hardpoints/hardpoint.dm b/code/modules/vehicles/hardpoints/hardpoint.dm index 85b7984cb7..a5e5671fe2 100644 --- a/code/modules/vehicles/hardpoints/hardpoint.dm +++ b/code/modules/vehicles/hardpoints/hardpoint.dm @@ -98,31 +98,23 @@ //maximum amount of spare mags var/max_clips = 0 + /** 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 - /**How the bullet will behave once it leaves the gun, also used for basic bullet damage and effects, etc. - Ammo will be replaced on New() for things that do not use mags.**/ - //var/datum/ammo/ammo = null - ///What is currently in the chamber. Most guns will want something in the chamber upon creation. - //var/obj/projectile/in_chamber = null - /*Ammo mags may or may not be internal, though the difference is a few additional variables. If they are not internal, don't call - on those unique vars. This is done for quicker pathing. Just keep in mind most mags aren't internal, though some are. - This is also the default magazine path loaded into a projectile weapon for reverse lookups on New(). Leave this null to do your own thing.*/ - //var/obj/item/ammo_magazine/internal/current_mag = null - - ///How much the bullet scatters when fired. - var/scatter = 0 - ///Multiplier. Increases or decreases how much bonus scatter is added with each bullet during burst fire (wielded only). - var/burst_scatter_mult = 4 - - ///What minimum range the weapon deals full damage, builds up the closer you get. 0 for no minimum. - var/effective_range_min = 0 - ///What maximum range the weapon deals full damage, tapers off using damage_falloff after hitting this value. 0 for no maximum. - var/effective_range_max = 0 + //Firemodes. + ///Current selected firemode of the gun. + var/gun_firemode = GUN_FIREMODE_SEMIAUTO + ///List of allowed firemodes. + var/list/gun_firemode_list = list() + //Semi-auto and full-auto. ///For regular shots, how long to wait before firing again. Use modify_fire_delay and set_fire_delay instead of modifying this on the fly VAR_PROTECTED/fire_delay = 0 - ///When it was last fired, related to world.time. - var/last_fired = 0 + /// 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 + ///If the gun is currently auto firing. + VAR_PROTECTED/auto_firing = FALSE //Burst fire. ///How many shots can the weapon shoot in burst? Anything less than 2 and you cannot toggle burst. Use modify_burst_amount and set_burst_amount instead of modifying this @@ -131,44 +123,20 @@ VAR_PROTECTED/burst_delay = 1 ///When burst-firing, this number is extra time before the weapon can fire again. Depends on number of rounds fired. var/extra_delay = 0 + ///If the gun is currently burst firing. + VAR_PROTECTED/burst_firing = FALSE - // Full auto - ///Whether or not the gun is firing full-auto - var/fa_firing = FALSE - ///How many full-auto shots to get to max scatter? - var/fa_scatter_peak = 4 - ///How bad does the scatter get on full auto? - var/fa_max_scatter = 6.5 - - var/flags_gun_features = GUN_AMMO_COUNTER - - /** 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 + //Firing cooldown. + ///When it was last fired, related to world.time. + var/last_fired = 0 + ///Fire delay of last firemode used. + var/last_delay = 0 - ///Current selected firemode of the gun. - var/gun_firemode = GUN_FIREMODE_SEMIAUTO - ///List of allowed firemodes. - var/list/gun_firemode_list = list() - ///How many bullets the gun fired while bursting/auto firing - var/shots_fired = 0 /// Currently selected target to fire at. Set with set_target() VAR_PRIVATE/atom/target /// Current operator (crew) of the hardpoint. VAR_PRIVATE/mob/hp_operator - /// If this gun should spawn with semi-automatic fire. Protected due to it never needing to be edited. - VAR_PROTECTED/start_semiauto = TRUE - /// If this gun should spawn with automatic fire. Protected due to it never needing to be edited. - VAR_PROTECTED/start_automatic = FALSE - /// The type of projectile that this gun should shoot - 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 - /// Semi auto cooldown - COOLDOWN_DECLARE(semiauto_fire_cooldown) - /// How long between semi-auto shots this should wait, to reduce possible spam - var/semiauto_cooldown_time = 0.2 SECONDS var/empty_alarm = 'sound/weapons/hmg_eject_mag.ogg' //----------------------------- @@ -177,12 +145,8 @@ /obj/item/hardpoint/Initialize() . = ..() - - //set_gun_config_values() set_bullet_traits() - //setup_firemodes() - //gun_firemode = gun_firemode_list[1] || GUN_FIREMODE_SEMIAUTO - AddComponent(/datum/component/automatedfire/autofire, fire_delay, burst_delay, burst_amount, gun_firemode, autofire_slow_mult, CALLBACK(src, PROC_REF(set_bursting)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(fire_wrapper)), CALLBACK(src, PROC_REF(display_ammo)), CALLBACK(src, PROC_REF(set_auto_firing))) //This should go after handle_starting_attachment() and setup_firemodes() to get the proper values set. + AddComponent(/datum/component/automatedfire/autofire, fire_delay, burst_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(continue_fire)), CALLBACK(src, PROC_REF(display_ammo)), CALLBACK(src, PROC_REF(set_auto_firing))) //This should go after handle_starting_attachment() and setup_firemodes() to get the proper values set. /obj/item/hardpoint/Destroy() if(owner) @@ -638,42 +602,14 @@ ammo.current_rounds-- -/* -/obj/item/hardpoint/proc/setup_firemodes() - var/old_firemode = gun_firemode - gun_firemode_list.len = 0 - - if(start_automatic) - gun_firemode_list |= GUN_FIREMODE_AUTOMATIC - - if(start_semiauto) - gun_firemode_list |= GUN_FIREMODE_SEMIAUTO - - if(burst_amount > BURST_AMOUNT_TIER_1) - gun_firemode_list |= GUN_FIREMODE_BURSTFIRE - - if(!length(gun_firemode_list)) - CRASH("[src] called setup_firemodes() with an empty gun_firemode_list") - - else if(old_firemode in gun_firemode_list) - gun_firemode = old_firemode - - else - gun_firemode = gun_firemode_list[1] -*/ - /// Setter proc to toggle burst firing -/obj/item/hardpoint/proc/set_bursting(bursting = FALSE) - if(bursting) - ENABLE_BITFIELD(flags_gun_features, GUN_BURST_FIRING) - else - DISABLE_BITFIELD(flags_gun_features, GUN_BURST_FIRING) +/obj/item/hardpoint/proc/set_burst_firing(burst = FALSE) + burst_firing = burst ///Clean all references /obj/item/hardpoint/proc/reset_fire() - shots_fired = 0//Let's clean everything - set_target(null) set_auto_firing(FALSE) + set_target(null) ///Set the target and take care of hard delete /obj/item/hardpoint/proc/set_target(atom/object) @@ -690,79 +626,53 @@ SIGNAL_HANDLER target = get_turf(target) -/// Setter proc for fa_firing +/// Setter proc for auto_firing /obj/item/hardpoint/proc/set_auto_firing(auto = FALSE) - fa_firing = auto + auto_firing = auto /obj/item/hardpoint/proc/display_ammo(mob/user) if(!user) user = hp_operator - if(CHECK_BITFIELD(flags_gun_features, GUN_AMMO_COUNTER) && ammo) - //var/chambered = in_chamber ? TRUE : FALSE - to_chat(user, SPAN_DANGER("[ammo.current_rounds] / [ammo.max_rounds] ROUNDS REMAINING")) - -/* -/obj/item/hardpoint/proc/try_fire() - if(!ammo?.current_rounds) - to_chat(hp_operator, SPAN_WARNING("*click*")) - playsound(src, 'sound/weapons/gun_empty.ogg', 25, 1, 5) - return - - return fire_shot() - -/obj/item/hardpoint/proc/fire_shot() //Bang Bang - var/atom/T = target - - var/turf/origin_turf = get_turf(src) - origin_turf = locate(origin_turf.x + origins[1], origin_turf.y + origins[2], origin_turf.z) - - var/obj/projectile/P = generate_bullet(hp_operator, origin_turf) - SEND_SIGNAL(P, COMSIG_BULLET_USER_EFFECTS, hp_operator) - P.fire_at(T, hp_operator, src, P.ammo.max_range, P.ammo.shell_speed) - - if(LAZYLEN(activation_sounds)) - playsound(get_turf(src), pick(activation_sounds), 60, 1) - - if(use_muzzle_flash) - muzzle_flash(Get_Angle(origin_turf, T)) - - ammo.current_rounds-- - if(!ammo.current_rounds) - handle_ammo_out() - - return AUTOFIRE_CONTINUE -*/ + if( ammo) + //to_chat(user, SPAN_DANGER("[ammo.current_rounds] / [ammo.max_rounds] ROUNDS REMAINING")) + to_chat(user, SPAN_WARNING("[name] Ammo: [SPAN_HELPFUL(ammo ? ammo.current_rounds : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds : 0)] | Mags: [SPAN_HELPFUL(LAZYLEN(backup_clips))]/[SPAN_HELPFUL(max_clips)]")) /obj/item/hardpoint/proc/handle_ammo_out(mob/user) visible_message(SPAN_NOTICE("[icon2html(src, viewers(src))] [src] beeps steadily and its ammo light blinks red.")) playsound(loc, empty_alarm, 25, 1) /obj/item/hardpoint/proc/crew_mouseup(datum/source, atom/object, turf/location, control, params) - if(!target) - return - - if(gun_firemode == GUN_FIREMODE_AUTOMATIC) - reset_fire() - display_ammo() - SEND_SIGNAL(src, COMSIG_GUN_STOP_FIRE) + if(auto_firing || burst_firing) + SEND_SIGNAL(src, COMSIG_GUN_STOP_FIRE) + //autofire component resets on burst completion, have to do it ourselves for automatic + if(auto_firing) + reset_fire() + display_ammo() ///Update the target if you draged your mouse -/obj/item/hardpoint/proc/crew_mousedrag(datum/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params) - set_target(get_turf_on_clickcatcher(over_object, hp_operator, params)) +/obj/item/hardpoint/proc/crew_mousedrag(mob/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params) + set_target(get_turf_on_clickcatcher(over_object, hp_operator, params)) //stops when dragging over UI + /* + if(istype(over_object, /atom/movable/screen)) //doesn't stop when dragging over UI, no side effects? + var/list/modifiers = params2list(params) + var/turf/turf = params2turf(modifiers["screen-loc"], get_turf(source.client.eye), source.client) + if (turf) + set_target(turf) + else + set_target(over_object) + */ + ///Check if the gun can fire and add it to bucket auto_fire system if needed, or just fire the gun if not /obj/item/hardpoint/proc/crew_mousedown(datum/source, atom/object, turf/location, control, params) - //hp_operator = owner.get_seat_mob(allowed_seat) hp_operator = source - if (CHECK_BITFIELD(flags_gun_features, GUN_BURST_FIRING)) - return - var/list/modifiers = params2list(params) if(modifiers["shift"] || modifiers["middle"] || modifiers["right"]) return + //don't click on UI if(istype(object, /atom/movable/screen)) return @@ -770,18 +680,24 @@ return set_target(get_turf_on_clickcatcher(object, hp_operator, params)) - if(gun_firemode == GUN_FIREMODE_SEMIAUTO && COOLDOWN_FINISHED(src, semiauto_fire_cooldown)) - COOLDOWN_START(src, semiauto_fire_cooldown, semiauto_cooldown_time) - //try_fire(object, hp_operator, modifiers) - fire_wrapper(object, hp_operator, modifiers) - reset_fire() - display_ammo() - return - else - SEND_SIGNAL(src, COMSIG_GUN_FIRE) + + initiate_fire(object, hp_operator, modifiers) + +/obj/item/hardpoint/proc/initiate_fire(atom/target, mob/living/user, params) + //still actively firing + if(auto_firing || burst_firing || world.time < last_fired + last_delay) + return NONE + + switch(gun_firemode) + if(GUN_FIREMODE_SEMIAUTO) + try_fire(target, user, params) + if(GUN_FIREMODE_BURSTFIRE) + SEND_SIGNAL(src, COMSIG_GUN_FIRE) + if(GUN_FIREMODE_AUTOMATIC) + SEND_SIGNAL(src, COMSIG_GUN_FIRE) /// Wrapper proc for the autofire subsystem to ensure the important args aren't null -/obj/item/hardpoint/proc/fire_wrapper(atom/target, mob/living/user, params) +/obj/item/hardpoint/proc/continue_fire(atom/target, mob/living/user, params) SHOULD_NOT_OVERRIDE(TRUE) if(!target) target = src.target @@ -789,129 +705,88 @@ user = hp_operator if(!target || !user) return NONE - return Fire(target, user, params) -/obj/item/hardpoint/proc/Fire(atom/target, mob/living/user, params) - set waitfor = FALSE + return try_fire(target, user, params) - if(!able_to_fire(user) || !target || !get_turf(user) || !get_turf(target)) +/obj/item/hardpoint/proc/try_fire(atom/target, mob/living/user, params) + if(health <= 0) + to_chat(user, SPAN_WARNING("\The [name] is broken!")) return NONE - /* - This is where burst is established for the proceeding section. Which just means the proc loops around that many times. - If burst = 1, you must null it if you ever RETURN during the for() cycle. If for whatever reason burst is left on while - the gun is not firing, it will break a lot of stuff. BREAK is fine, as it will null it. - */ - if((gun_firemode == GUN_FIREMODE_BURSTFIRE) && burst_amount > BURST_AMOUNT_TIER_1) - ENABLE_BITFIELD(flags_gun_features, GUN_BURST_FIRING) - - var/fire_return = handle_fire(target, user, params) - if(!fire_return) - return fire_return - - DISABLE_BITFIELD(flags_gun_features, GUN_BURST_FIRING) // We always want to turn off bursting when we're done, mainly for when we break early mid-burstfire. - return AUTOFIRE_CONTINUE - -/obj/item/hardpoint/proc/able_to_fire(mob/user) - if(CHECK_BITFIELD(flags_gun_features, GUN_BURST_FIRING)) - return TRUE - - // The rest is delay-related. If we're firing full-auto it doesn't matter - if(fa_firing) - return TRUE - - var/next_shot = last_fired + fire_delay - - if(world.time >= next_shot + extra_delay) //check the last time it was fired. - extra_delay = 0 - - return TRUE + if(!ammo || ammo.current_rounds <= 0) + click_empty(user) + return NONE -/obj/item/hardpoint/proc/handle_fire(atom/target, mob/living/user, params) - var/turf/curloc = get_turf(src) //In case the target or we are expired. - var/turf/targloc = get_turf(target) + if(!in_firing_arc(target)) + to_chat(user, SPAN_WARNING("The target is not within your firing arc!")) + return NONE - var/atom/original_target = target //This is for burst mode, in case the target changes per scatter chance in between fired bullets. + return fire_shot(target, user, params) - //The gun should return the bullet that it already loaded from the end cycle of the last Fire(). - //var/obj/projectile/projectile_to_fire = load_into_chamber(user) //Load a bullet in or check for existing one. - var/obj/projectile/projectile_to_fire = generate_bullet(user, curloc) - if(!projectile_to_fire) //If there is nothing to fire, click. - click_empty(user) - DISABLE_BITFIELD(flags_gun_features, GUN_BURST_FIRING) - return NONE +/obj/item/hardpoint/proc/fire_shot(atom/target, mob/living/user, params) + //offset fire origin from lower-left corner + var/turf/origin_turf = get_turf(src) + origin_turf = locate(origin_turf.x + origins[1], origin_turf.y + origins[2], origin_turf.z) - /* - apply_bullet_effects(projectile_to_fire, user) //User can be passed as null. + var/obj/projectile/projectile_to_fire = generate_bullet(user, origin_turf) SEND_SIGNAL(projectile_to_fire, COMSIG_BULLET_USER_EFFECTS, user) - */ - if(QDELETED(original_target)) //If the target's destroyed, shoot at where it was last. - target = targloc - else - target = original_target - targloc = get_turf(target) + play_firing_sounds(projectile_to_fire, user) - projectile_to_fire.original = target + INVOKE_ASYNC(projectile_to_fire, TYPE_PROC_REF(/obj/projectile, fire_at), target, user, src, projectile_to_fire.ammo.max_range, projectile_to_fire.ammo.shell_speed) + projectile_to_fire = null - /* - // turf-targeted projectiles are fired without scatter, because proc would raytrace them further away - var/ammo_flags = projectile_to_fire.ammo.flags_ammo_behavior | projectile_to_fire.projectile_override_flags - if(!CHECK_BITFIELD(ammo_flags, AMMO_HITS_TARGET_TURF)) - target = simulate_scatter(projectile_to_fire, target, curloc, targloc, user) + if(use_muzzle_flash) + muzzle_flash(Get_Angle(origin_turf, target)) - var/bullet_velocity = projectile_to_fire?.ammo?.shell_speed + velocity_add - */ + ammo.current_rounds-- + //just ran out + if(ammo.current_rounds <= 0) + playsound(get_turf(src), empty_alarm, 70, 1) + + //cooldown to respect intended ROF + last_fired = world.time + switch(gun_firemode) + if(GUN_FIREMODE_SEMIAUTO) + last_delay = fire_delay + reset_fire() + display_ammo() + if(GUN_FIREMODE_BURSTFIRE) + last_delay = burst_delay + extra_delay + if(GUN_FIREMODE_AUTOMATIC) + last_delay = fire_delay + + return AUTOFIRE_CONTINUE +/// Toggles the gun's firemode one down the list +/obj/item/hardpoint/proc/do_toggle_firemode(mob/user, new_firemode) /* - if(params) // Apply relative clicked position from the mouse info to offset projectile - if(!params["click_catcher"]) - if(params["vis-x"]) - projectile_to_fire.p_x = text2num(params["vis-x"]) - else if(params["icon-x"]) - projectile_to_fire.p_x = text2num(params["icon-x"]) - if(params["vis-y"]) - projectile_to_fire.p_y = text2num(params["vis-y"]) - else if(params["icon-y"]) - projectile_to_fire.p_y = text2num(params["icon-y"]) - var/atom/movable/clicked_target = original_target - if(istype(clicked_target)) - projectile_to_fire.p_x -= clicked_target.bound_width / 2 - projectile_to_fire.p_y -= clicked_target.bound_height / 2 - else - projectile_to_fire.p_x -= world.icon_size / 2 - projectile_to_fire.p_y -= world.icon_size / 2 - else - projectile_to_fire.p_x -= world.icon_size / 2 - projectile_to_fire.p_y -= world.icon_size / 2 + if(get_burst_firing())//can't toggle mid burst + return */ - play_firing_sounds(projectile_to_fire, user) - - if(targloc != curloc) - //This is where the projectile leaves the barrel and deals with projectile code only. - //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - //in_chamber = null // It's not in the gun anymore - INVOKE_ASYNC(projectile_to_fire, TYPE_PROC_REF(/obj/projectile, fire_at), target, user, src, projectile_to_fire?.ammo?.max_range, projectile_to_fire?.ammo?.shell_speed, original_target) - projectile_to_fire = null // Important: firing might have made projectile collide early and ALREADY have deleted it. We clear it too. - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + if(!length(gun_firemode_list)) + CRASH("[src] called do_toggle_firemode() with an empty gun_firemodes") - . = TRUE + if(length(gun_firemode_list) == 1) + to_chat(user, SPAN_NOTICE("[icon2html(src, user)] This gun only has one firemode.")) + return - shots_fired++ + if(new_firemode) + if(!(new_firemode in gun_firemode_list)) + CRASH("[src] called do_toggle_firemode() with [new_firemode] new_firemode, not on gun_firemodes") + gun_firemode = new_firemode else - return TRUE + var/mode_index = gun_firemode_list.Find(gun_firemode) + if(++mode_index <= length(gun_firemode_list)) + gun_firemode = gun_firemode_list[mode_index] + else + gun_firemode = gun_firemode_list[1] - //>>POST PROCESSING AND CLEANUP BEGIN HERE.<< - var/angle = round(Get_Angle(user, target)) //Let's do a muzzle flash. - muzzle_flash(angle,user) + playsound(user, 'sound/weapons/handling/gun_burst_toggle.ogg', 15, 1) - //This is where we load the next bullet in the chamber. - //if(!reload_into_chamber(user)) // It has to return a bullet, otherwise it's empty. - if(!ammo.current_rounds) - click_empty(user) - return TRUE //Nothing else to do here, time to cancel out. - return TRUE + to_chat(user, SPAN_NOTICE("[icon2html(src, user)] You switch to [gun_firemode].")) + SEND_SIGNAL(src, COMSIG_GUN_FIRE_MODE_TOGGLE, gun_firemode) /obj/item/hardpoint/proc/click_empty(mob/user) if(user) @@ -924,7 +799,6 @@ if(LAZYLEN(activation_sounds)) playsound(get_turf(src), pick(activation_sounds), 60, 1) - //----------------------------- //------ICON PROCS---------- //----------------------------- diff --git a/code/modules/vehicles/hardpoints/primary/dual_cannon.dm b/code/modules/vehicles/hardpoints/primary/dual_cannon.dm index 80ab1b23c4..db9c49ac56 100644 --- a/code/modules/vehicles/hardpoints/primary/dual_cannon.dm +++ b/code/modules/vehicles/hardpoints/primary/dual_cannon.dm @@ -12,8 +12,8 @@ damage_multiplier = 0.2 health = 500 - cooldown = 7 - accuracy = 0.98 + //cooldown = 7 + //accuracy = 0.98 firing_arc = 60 //var/burst_amount = 2 @@ -35,16 +35,16 @@ "8" = list(14, 9) ) - //fire_delay = 0.6 SECONDS + fire_delay = 0.5 SECONDS burst_amount = 2 burst_delay = 0.3 SECONDS - //extra_delay = 0.7 SECONDS + extra_delay = 0.4 SECONDS gun_firemode = GUN_FIREMODE_BURSTFIRE gun_firemode_list = list( + GUN_FIREMODE_SEMIAUTO, GUN_FIREMODE_BURSTFIRE, - //GUN_FIREMODE_AUTOMATIC, + GUN_FIREMODE_AUTOMATIC, ) - start_semiauto = FALSE /obj/item/hardpoint/primary/dualcannon/set_bullet_traits() ..() diff --git a/code/modules/vehicles/hardpoints/secondary/frontal_cannon.dm b/code/modules/vehicles/hardpoints/secondary/frontal_cannon.dm index b274849b20..ac4b486f9a 100644 --- a/code/modules/vehicles/hardpoints/secondary/frontal_cannon.dm +++ b/code/modules/vehicles/hardpoints/secondary/frontal_cannon.dm @@ -11,8 +11,8 @@ damage_multiplier = 0.11 health = 350 - cooldown = 16 - accuracy = 0.8 + //cooldown = 16 + //accuracy = 0.8 firing_arc = 120 //var/burst_amount = 4 @@ -34,27 +34,19 @@ "8" = list(-62, -26) ) + fire_delay = 0.5 SECONDS + burst_amount = 4 + burst_delay = 0.3 SECONDS + extra_delay = 0.4 SECONDS + gun_firemode = GUN_FIREMODE_BURSTFIRE + gun_firemode_list = list( + GUN_FIREMODE_SEMIAUTO, + GUN_FIREMODE_BURSTFIRE, + GUN_FIREMODE_AUTOMATIC, + ) + /obj/item/hardpoint/secondary/frontalcannon/set_bullet_traits() ..() LAZYADD(traits_to_give, list( BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff) )) - -/obj/item/hardpoint/secondary/frontalcannon/fire(mob/user, atom/A) - if(ammo.current_rounds <= 0) - return - - next_use = world.time + cooldown * owner.misc_multipliers["cooldown"] - - for(var/bullets_fired = 1, bullets_fired <= burst_amount, bullets_fired++) - var/atom/T = A - if(!prob((accuracy * 100) / owner.misc_multipliers["accuracy"])) - T = get_step(get_turf(A), pick(cardinal)) - if(LAZYLEN(activation_sounds)) - playsound(get_turf(src), pick(activation_sounds), 60, 1) - fire_projectile(user, T) - if(ammo.current_rounds <= 0) - break - if(bullets_fired < burst_amount) //we need to sleep only if there are more bullets to shoot in the burst - sleep(3) - to_chat(user, SPAN_WARNING("[src] Ammo: [SPAN_HELPFUL(ammo ? ammo.current_rounds : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds : 0)] | Mags: [SPAN_HELPFUL(LAZYLEN(backup_clips))]/[SPAN_HELPFUL(max_clips)]")) diff --git a/code/modules/vehicles/hardpoints/special/firing_port_weapon.dm b/code/modules/vehicles/hardpoints/special/firing_port_weapon.dm index 3695130783..f6ae86f726 100644 --- a/code/modules/vehicles/hardpoints/special/firing_port_weapon.dm +++ b/code/modules/vehicles/hardpoints/special/firing_port_weapon.dm @@ -30,6 +30,17 @@ underlayer_north_muzzleflash = TRUE + fire_delay = 0.4 SECONDS + burst_amount = 3 + burst_delay = 0.3 SECONDS + extra_delay = -0.2 SECONDS + gun_firemode = GUN_FIREMODE_BURSTFIRE + gun_firemode_list = list( + GUN_FIREMODE_SEMIAUTO, + GUN_FIREMODE_BURSTFIRE, + GUN_FIREMODE_AUTOMATIC, + ) + /obj/item/hardpoint/special/firing_port_weapon/set_bullet_traits() ..() LAZYADD(traits_to_give, list( @@ -116,8 +127,12 @@ to_chat(user, SPAN_NOTICE("\The [name] reloads automatically.")) return FALSE +/obj/item/hardpoint/special/firing_port_weapon/try_fire(atom/target, mob/living/user, params) + //FPW stop working at 50% hull + if(owner.health < initial(owner.health) * 0.5) + to_chat(user, SPAN_WARNING("\The [owner]'s hull is too damaged!")) + return FALSE -/obj/item/hardpoint/special/firing_port_weapon/fire(mob/user, atom/A) if(user.get_active_hand()) to_chat(user, SPAN_WARNING("You need a free hand to use \the [name].")) return @@ -126,17 +141,8 @@ start_auto_reload(user) return - next_use = world.time + cooldown * owner.misc_multipliers["cooldown"] - - for(var/bullets_fired = 1, bullets_fired <= burst_amount, bullets_fired++) - var/atom/T = A - if(!prob((accuracy * 100) / owner.misc_multipliers["accuracy"])) - T = get_step(get_turf(A), pick(cardinal)) - if(LAZYLEN(activation_sounds)) - playsound(get_turf(src), pick(activation_sounds), 60, 1) - fire_projectile(user, T) - if(ammo.current_rounds <= 0) - break - if(bullets_fired < burst_amount) //we need to sleep only if there are more bullets to shoot in the burst - sleep(3) - to_chat(user, SPAN_WARNING("[src] Ammo: [SPAN_HELPFUL(ammo ? ammo.current_rounds : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds : 0)]")) + if(reloading) + to_chat(user, SPAN_NOTICE("\The [name] is reloading. Wait [SPAN_HELPFUL("[((reload_time_started + reload_time - world.time) / 10)]")] seconds.")) + return FALSE + + return ..() diff --git a/code/modules/vehicles/hardpoints/support/flare.dm b/code/modules/vehicles/hardpoints/support/flare.dm index 2cee40064f..facd938aa9 100644 --- a/code/modules/vehicles/hardpoints/support/flare.dm +++ b/code/modules/vehicles/hardpoints/support/flare.dm @@ -13,8 +13,8 @@ activatable = TRUE health = 500 - cooldown = 30 - accuracy = 0.7 + //cooldown = 30 + //accuracy = 0.7 firing_arc = 120 origins = list(0, -2) @@ -35,6 +35,14 @@ "8" = list(14, -6) ) + fire_delay = 3.0 SECONDS + gun_firemode = GUN_FIREMODE_BURSTFIRE + gun_firemode_list = list( + GUN_FIREMODE_SEMIAUTO, + GUN_FIREMODE_BURSTFIRE, + GUN_FIREMODE_AUTOMATIC, + ) + /obj/item/hardpoint/support/flare_launcher/set_bullet_traits() ..() LAZYADD(traits_to_give, list( diff --git a/code/modules/vehicles/multitile/multitile_verbs.dm b/code/modules/vehicles/multitile/multitile_verbs.dm index c7dd29bbf0..fc79a6a3b7 100644 --- a/code/modules/vehicles/multitile/multitile_verbs.dm +++ b/code/modules/vehicles/multitile/multitile_verbs.dm @@ -376,3 +376,30 @@ return to_chat(user, SPAN_WARNING("Warning. No FPW for [seat] found, tell a dev!")) + +/obj/vehicle/multitile/proc/cycle_firemode() + set name = "Cycle Firemode" + set desc = "Cycles through your gun's firemodes." + set category = "Vehicle" + + var/mob/user = usr + if(!user || !istype(user)) + return + + var/obj/vehicle/multitile/vehicle = user.interactee + if(!istype(vehicle)) + return + + var/seat + for(var/vehicle_seat in vehicle.seats) + if(vehicle.seats[vehicle_seat] == user) + seat = vehicle_seat + break + if(!seat) + return + + var/obj/item/hardpoint/hardpoint = vehicle.active_hp[seat] + if(!hardpoint) + return + + hardpoint.do_toggle_firemode(usr)