Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions code/hud/hudtarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6775,10 +6775,9 @@ void HudGaugeWeapons::render(float /*frametime*/, bool config)
renderPrintfWithGauge(x + fl2i(Weapon_sunlinked_offset_x * scale), name_y, EG_NULL, scale, config, "%c", Weapon_link_icon);

// indicate if this is linked
// don't draw the link indicator if the fire can't be fired link.
// the link flag is ignored rather than cleared so the player can cycle past a no-doublefire weapon without the setting being cleared
if (!config && Player_ship->flags[Ship::Ship_Flags::Secondary_dual_fire] && !wip->wi_flags[Weapon::Info_Flags::No_doublefire] &&
!The_mission.ai_profile->flags[AI::Profile_Flags::Disable_player_secondary_doublefire] ) {
// don't draw the link indicator if this bank can't actually fire linked.
// the link flag is ignored rather than cleared so the player can cycle past an incapable bank or weapon without the setting being cleared
if (!config && Player_ship->flags[Ship::Ship_Flags::Secondary_dual_fire] && ship_secondary_bank_can_dual_fire(Player_ship, i)) {
renderPrintfWithGauge(x + fl2i(Weapon_slinked_offset_x * scale), name_y, EG_NULL, scale, config, "%c", Weapon_link_icon);
}

Expand Down Expand Up @@ -7732,10 +7731,9 @@ void HudGaugeSecondaryWeapons::render(float /*frametime*/, bool config)
renderPrintfWithGauge(position[0] + _sunlinked_offset_x, position[1] + text_y_offset, EG_NULL, 1.0f, config, "%c", Weapon_link_icon);

// indicate if this is linked
// don't draw the link indicator if the fire can't be fired link.
// the link flag is ignored rather than cleared so the player can cycle past a no-doublefire weapon without the setting being cleared
if ( Player_ship->flags[Ship::Ship_Flags::Secondary_dual_fire] && !wip->wi_flags[Weapon::Info_Flags::No_doublefire] &&
!The_mission.ai_profile->flags[AI::Profile_Flags::Disable_player_secondary_doublefire] ) {
// don't draw the link indicator if this bank can't actually fire linked.
// the link flag is ignored rather than cleared so the player can cycle past an incapable bank or weapon without the setting being cleared
if ( Player_ship->flags[Ship::Ship_Flags::Secondary_dual_fire] && ship_secondary_bank_can_dual_fire(Player_ship, i) ) {
renderPrintfWithGauge(position[0] + _slinked_offset_x, position[1] + text_y_offset, EG_NULL, 1.0f, config, "%c", Weapon_link_icon);
}

Expand Down Expand Up @@ -7945,7 +7943,7 @@ void HudGaugeHardpoints::render(float /*frametime*/, bool config)

model_render_params weapon_render_info;

if ( swp->current_secondary_bank == i && ( swp->secondary_next_slot[i] == k || ( swp->secondary_next_slot[i]+1 == k && sp->flags[Ship::Ship_Flags::Secondary_dual_fire] ) ) ) {
if ( swp->current_secondary_bank == i && ( swp->secondary_next_slot[i] == k || ( swp->secondary_next_slot[i]+1 == k && sp->flags[Ship::Ship_Flags::Secondary_dual_fire] && ship_secondary_bank_can_dual_fire(sp, i) ) ) ) {
weapon_render_info.set_color(Color_bright_blue);
} else {
weapon_render_info.set_color(Color_bright_white);
Expand Down
17 changes: 10 additions & 7 deletions code/io/keycontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1931,19 +1931,22 @@ int button_function_critical(int n, net_player *p = NULL)
break;
}

polymodel *pm = model_get(Ship_info[Ships[objp->instance].ship_info_index].model_num);

int firepoints = pm->missile_banks[Ships[objp->instance].weapons.current_secondary_bank].num_slots;

if (Ships[objp->instance].flags[Ship::Ship_Flags::Secondary_dual_fire] || firepoints < 2) {
Ships[objp->instance].flags.remove(Ship::Ship_Flags::Secondary_dual_fire);
if (!ship_secondary_bank_can_dual_fire(&Ships[objp->instance], Ships[objp->instance].weapons.current_secondary_bank)) {
// leave the dual fire preference alone; it is ignored rather than cleared for banks that can't use it
if(at_self) {
HUD_sourced_printf(HUD_SOURCE_HIDDEN, "%s", XSTR( "This secondary bank cannot fire dual missiles", 1932));
gamesnd_play_iface(InterfaceSounds::GENERAL_FAIL);
hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
}
} else if (Ships[objp->instance].flags[Ship::Ship_Flags::Secondary_dual_fire]) {
Ships[objp->instance].flags.remove(Ship::Ship_Flags::Secondary_dual_fire);
if(at_self) {
HUD_sourced_printf(HUD_SOURCE_HIDDEN, "%s", XSTR( "Secondary weapon set to normal fire mode", 34));
snd_play( gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::SECONDARY_CYCLE)) );
hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
}
} else {
Ships[objp->instance].flags.set(Ship::Ship_Flags::Secondary_dual_fire);
Ships[objp->instance].flags.set(Ship::Ship_Flags::Secondary_dual_fire);
if(at_self) {
HUD_sourced_printf(HUD_SOURCE_HIDDEN, "%s", XSTR( "Secondary weapon set to dual fire mode", 35));
snd_play( gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::SECONDARY_CYCLE)) );
Expand Down
2 changes: 1 addition & 1 deletion code/localization/localize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ bool *Lcl_unexpected_tstring_check = nullptr;
// NOTE: with map storage of XSTR strings, the indexes no longer need to be contiguous,
// but internal strings should still increment XSTR_SIZE to avoid collisions.
// retail XSTR_SIZE = 1570
// #define XSTR_SIZE 1932 // This is the next available ID
// #define XSTR_SIZE 1933 // This is the next available ID

// struct to allow for strings.tbl-determined x offset
// offset is 0 for english, by default
Expand Down
5 changes: 3 additions & 2 deletions code/playerman/playercontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1420,7 +1420,6 @@ void player_restore_target_and_weapon_link_prefs()
{
ship_info *player_sip;
player_sip = &Ship_info[Player_ship->ship_info_index];
polymodel *pm = model_get(player_sip->model_num);

// Don't restores the save flags in training, as we must ensure certain things are off, such as speed matching.
if ( !(The_mission.game_type & MISSION_TYPE_TRAINING )) {
Expand All @@ -1433,7 +1432,9 @@ void player_restore_target_and_weapon_link_prefs()
}
}

if ( Player->flags & PLAYER_FLAGS_LINK_SECONDARY && (pm->n_missiles > 0 && pm->missile_banks[0].num_slots > 1) ) {
// restore the dual fire preference regardless of whether the current bank can use it;
// the flag is ignored rather than cleared for banks that can't
if ( Player->flags & PLAYER_FLAGS_LINK_SECONDARY ) {
Player_ship->flags.set(Ship::Ship_Flags::Secondary_dual_fire);
}
}
Expand Down
57 changes: 37 additions & 20 deletions code/ship/ship.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14259,6 +14259,37 @@ static bool ship_fire_secondary_detonate(object *obj, ship_weapon *swp)

extern void ai_maybe_announce_shockwave_weapon(object *firing_objp, int weapon_index);

// Determines whether this secondary bank is currently capable of dual fire. Note that the
// Secondary_dual_fire flag can legitimately be set even when this returns false: the flag is
// ignored rather than cleared so that the player's dual fire preference isn't lost when
// cycling through banks or weapons. All code that acts on the flag should check this too.
bool ship_secondary_bank_can_dual_fire(const ship *shipp, int bank)
{
if (bank < 0 || bank >= shipp->weapons.num_secondary_banks)
return false;

int weapon_class = shipp->weapons.secondary_bank_weapons[bank];
if (weapon_class < 0)
return false;

if (Weapon_info[weapon_class].wi_flags[Weapon::Info_Flags::No_doublefire])
return false;

if (shipp->objnum == OBJ_INDEX(Player_obj))
{
if (The_mission.ai_profile->flags[AI::Profile_Flags::Disable_player_secondary_doublefire])
return false;
}
else
{
if (The_mission.ai_profile->flags[AI::Profile_Flags::Disable_ai_secondary_doublefire])
return false;
}

polymodel *pm = model_get(Ship_info[shipp->ship_info_index].model_num);
return pm->missile_banks[bank].num_slots > 1;
}

// Object *obj fires its secondary weapon, if it can.
// If its most recently fired weapon is a remotely detonatable weapon, detonate it.
// Returns number of weapons fired. Note, for swarmers, returns 1 if it is allowed
Expand Down Expand Up @@ -14621,25 +14652,14 @@ int ship_fire_secondary( object *obj, int allow_swarm, bool rollback_shot )
goto done_secondary;
}

// Handle the optional disabling of dual fire
// dual fire/doublefire can be disabled for individual weapons, for players, or for AIs
// if any of these apply to the current weapon, unset the dual fire flag on the ship
// then proceed as normal.
// This is only handled at firing time so dualfire isn't lost when cycling through weapons
if (shipp->flags[Ship_Flags::Secondary_dual_fire] &&
( wip->wi_flags[Weapon::Info_Flags::No_doublefire] ||
( The_mission.ai_profile->flags[AI::Profile_Flags::Disable_ai_secondary_doublefire] &&
shipp->objnum != OBJ_INDEX(Player_obj) ) ||
( The_mission.ai_profile->flags[AI::Profile_Flags::Disable_player_secondary_doublefire] &&
shipp->objnum == OBJ_INDEX(Player_obj) ))
) {
shipp->flags.remove(Ship_Flags::Secondary_dual_fire);
}

int start_slot, end_slot;
no_energy = shipp->weapon_energy < 2 * wip->energy_consumed; // whether there's enough energy for at least 1 shot was checked above

if ( shipp->flags[Ship_Flags::Secondary_dual_fire] && num_slots > 1) {
// Dual fire can be unavailable for this bank because it has only one firepoint, because
// the weapon disallows it, or because of an ai_profiles restriction. In any of these
// cases the flag is ignored rather than cleared so the dual fire preference isn't lost
// when cycling through banks or weapons.
if ( shipp->flags[Ship_Flags::Secondary_dual_fire] && ship_secondary_bank_can_dual_fire(shipp, bank) ) {
start_slot = swp->secondary_next_slot[bank];
// AL 11-19-97: Ensure enough ammo remains when firing linked secondary weapons
if ( check_ammo && ((swp->secondary_bank_ammo[bank] < 2 && !no_ammo_needed) || no_energy) ) {
Expand All @@ -14648,9 +14668,6 @@ int ship_fire_secondary( object *obj, int allow_swarm, bool rollback_shot )
end_slot = start_slot+1;
}
} else {
// de-set the flag just in case dual-fire was set but couldn't be used
// because there's less than two firepoints
shipp->flags.remove(Ship_Flags::Secondary_dual_fire);
start_slot = swp->secondary_next_slot[bank];
end_slot = start_slot;
}
Expand Down Expand Up @@ -14779,7 +14796,7 @@ int ship_fire_secondary( object *obj, int allow_swarm, bool rollback_shot )
swp = &Player_ship->weapons;
if (bank >= 0) {
wip = &Weapon_info[swp->secondary_bank_weapons[bank]];
if (Player_ship->flags[Ship_Flags::Secondary_dual_fire]){
if (Player_ship->flags[Ship_Flags::Secondary_dual_fire] && ship_secondary_bank_can_dual_fire(Player_ship, bank)){
joy_ff_play_secondary_shoot((int) (wip->cargo_size * 2.0f));
} else {
joy_ff_play_secondary_shoot((int) wip->cargo_size);
Expand Down
1 change: 1 addition & 0 deletions code/ship/ship.h
Original file line number Diff line number Diff line change
Expand Up @@ -1734,6 +1734,7 @@ extern bool in_autoaim_fov(ship *shipp, int bank_to_fire, object *obj);
extern int ship_stop_fire_primary(object * obj);
extern int ship_fire_primary(object * objp, int force = 0, bool rollback_shot = false);
extern int ship_fire_secondary(object * objp, int allow_swarm = 0, bool rollback_shot = false );
extern bool ship_secondary_bank_can_dual_fire(const ship *shipp, int bank);
bool ship_start_secondary_fire(object* objp);
bool ship_stop_secondary_fire(object* objp);
extern int ship_launch_countermeasure(object *objp, int rand_val = -1);
Expand Down
12 changes: 9 additions & 3 deletions code/weapon/weapons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7148,9 +7148,15 @@ int weapon_create( const vec3d *pos, const matrix *porient, int weapon_type, int
Assertion( position != NULL, "'%s' is trying to fire a weapon that is not selected", Ships[parent_objp->instance].ship_name );

size_t curr_pos = *position;
if (((Weapon_info[weapon_type].subtype == WP_LASER && parent_shipp->flags[Ship::Ship_Flags::Primary_linked]) ||
(Weapon_info[weapon_type].subtype == WP_MISSILE && parent_shipp->flags[Ship::Ship_Flags::Secondary_dual_fire])) &&
(curr_pos > 0)) {
// only advance the pattern once per linked/paired shot rather than once per projectile
bool paired_shot = false;
if (Weapon_info[weapon_type].subtype == WP_LASER) {
paired_shot = parent_shipp->flags[Ship::Ship_Flags::Primary_linked];
} else if (Weapon_info[weapon_type].subtype == WP_MISSILE && !src_turret && parent_shipp->flags[Ship::Ship_Flags::Secondary_dual_fire]) {
// for dual fire, also check whether the armed bank can actually use it, since the flag is ignored rather than cleared for banks that can't
paired_shot = ship_secondary_bank_can_dual_fire(parent_shipp, parent_shipp->weapons.current_secondary_bank);
}
if (paired_shot && (curr_pos > 0)) {
curr_pos--;
}
++(*position);
Expand Down
Loading