Compare commits

...
12 Commits
Author SHA1 Message Date
Tyler Blount 6b7fc0b6a3 Don't reset target restrictions during table load
Prevents an issue with load order causing target restrictions to be reset.
2020-05-20 14:45:24 -06:00
Tyler Blount 2e4bef0d09 Remove unneeded code and some style changes 2020-05-20 12:25:13 -06:00
Tyler Blount 172952cb0f Correctly implement fixes from #73 2020-05-20 12:25:13 -06:00
Tyler Blount 72c27bdbe8 CI and Lock fixes 2020-05-20 12:25:13 -06:00
Tyler Blount bd4de16007 Use correct comparison 2020-05-20 12:25:13 -06:00
Tyler Blount 2e560f2ddb Fix some CI errors 2020-05-20 12:25:12 -06:00
Tyler Blount d35d3d25f8 Finally fix no dumbfire
also some miscellaneous changes
2020-05-20 12:25:12 -06:00
Tyler Blount 2d5111f14b Perhaps this works? 2020-05-20 12:25:12 -06:00
Tyler Blount d95754d6b4 No Dumbfire fix
Another fix for MLMs associated with the No Dumbfire flag.
2020-05-20 12:25:12 -06:00
Tyler Blount 5e3d4c6cfd More fixes
Contains changes related to failed CI builds and feedback.
2020-05-20 12:25:12 -06:00
Tyler Blount deca820c9e Lost fixes
These were lost during a rebase at one point. Will leave this commit as separate to avoid issues in the future.
2020-05-20 12:25:12 -06:00
Swifty 21c298271b Initial commit of multilock missile features. 2020-05-20 12:25:11 -06:00
9 changed files with 1427 additions and 42 deletions

No files matched your search

+1050 -21
View File
File diff suppressed because it is too large. Load diff
+3
View File
@@ -18,6 +18,7 @@ void hud_init_missile_lock();
void hud_calculate_lock_position(float frametime);
void hud_calculate_lock_start_pos();
void hud_do_lock_indicator(float frametime);
void hud_do_lock_indicators(float frametime);
void hud_stop_looped_locking_sounds();
void hud_lock_reset(float lock_time_scale=1.0f);
@@ -54,7 +55,9 @@ public:
void initLoopLockedAnim(bool loop);
void render(float frametime) override;
void renderOld(float frametime);
void renderLockTriangles(int center_x, int center_y, float frametime);
void renderLockTrianglesNew(int center_x, int center_y, int start_timestamp);
void renderLockTrianglesOld(int center_x, int center_y, int radius);
void pageIn() override;
void initialize() override;
+1 -2
View File
@@ -3431,6 +3431,7 @@ void hud_show_targeting_gauges(float frametime)
vec3d target_pos;
hud_show_hostile_triangle();
hud_do_lock_indicators(frametime);
if (Player_ai->target_objnum == -1)
return;
@@ -3480,8 +3481,6 @@ void hud_show_targeting_gauges(float frametime)
// display the lock indicator
if (!Player->target_is_dying) {
hud_do_lock_indicator(frametime);
// update and render artillery
hud_artillery_update();
hud_artillery_render();
+7 -1
View File
@@ -781,10 +781,16 @@ void obj_player_fire_stuff( object *objp, control_info ci )
// single player and multiplayer masters do all of the following
if ( !MULTIPLAYER_CLIENT ) {
if ( ci.fire_secondary_count ) {
ship_fire_secondary( objp );
if ( !ship_start_secondary_fire(objp) ) {
ship_fire_secondary( objp );
}
// kill the secondary count
ci.fire_secondary_count = 0;
} else {
if ( ship_stop_secondary_fire(objp) ) {
ship_fire_secondary( objp );
}
}
}
+185 -17
View File
@@ -11844,33 +11844,34 @@ int ship_fire_secondary( object *obj, int allow_swarm )
// Ensure if this is a "require-lock" missile, that a lock actually exists
if ( wip->wi_flags[Weapon::Info_Flags::No_dumbfire] ) {
if ( aip->current_target_is_locked <= 0 ) {
if ( obj == Player_obj ) {
if ( !Weapon_energy_cheat ) {
if (!aip->current_target_is_locked && !ship_lock_present(shipp) && !(shipp->missile_locks_firing.size() > 0)) {
if (obj == Player_obj) {
if (!Weapon_energy_cheat) {
float max_dist;
max_dist = wip->lifetime * wip->max_speed;
if (wip->wi_flags[Weapon::Info_Flags::Local_ssm]){
max_dist= wip->lssm_lock_range;
if (wip->wi_flags[Weapon::Info_Flags::Local_ssm]) {
max_dist = wip->lssm_lock_range;
}
if ((aip->target_objnum != -1) && (vm_vec_dist_quick(&obj->pos, &Objects[aip->target_objnum].pos) > max_dist)) {
HUD_sourced_printf(HUD_SOURCE_HIDDEN, "%s", XSTR( "Too far from target to acquire lock", 487));
if ((aip->target_objnum != -1) &&
(vm_vec_dist_quick(&obj->pos, &Objects[aip->target_objnum].pos) > max_dist)) {
HUD_sourced_printf(HUD_SOURCE_HIDDEN, "%s", XSTR("Too far from target to acquire lock", 487));
} else {
char missile_name[NAME_LENGTH];
strcpy_s(missile_name, wip->get_display_string());
end_string_at_first_hash_symbol(missile_name);
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Cannot fire %s without a lock", 488), missile_name);
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR("Cannot fire %s without a lock", 488), missile_name);
}
snd_play( gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::OUT_OF_MISSLES)) );
swp->next_secondary_fire_stamp[bank] = timestamp(800); // to avoid repeating messages
snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::OUT_OF_MISSLES)));
swp->next_secondary_fire_stamp[bank] = timestamp(800); // to avoid repeating messages
return 0;
}
} else {
// multiplayer clients should always fire the weapon here, so return only if not
// a multiplayer client.
if ( !MULTIPLAYER_CLIENT ) {
if (!MULTIPLAYER_CLIENT) {
return 0;
}
}
@@ -11901,16 +11902,21 @@ int ship_fire_secondary( object *obj, int allow_swarm )
}
}
if ( !allow_swarm && obj == Player_obj ) {
ship_queue_missile_locks(shipp);
}
// if trying to fire a swarm missile, make sure being called from right place
if ( (wip->wi_flags[Weapon::Info_Flags::Swarm]) && !allow_swarm ) {
Assert(wip->swarm_count > 0);
if(wip->swarm_count <= 0){
if (wip->multi_lock && obj == Player_obj) {
shipp->num_swarm_missiles_to_fire = (int)shipp->missile_locks_firing.size();
} else if(wip->swarm_count <= 0){
shipp->num_swarm_missiles_to_fire = SWARM_DEFAULT_NUM_MISSILES_FIRED;
} else {
shipp->num_swarm_missiles_to_fire = wip->swarm_count;
}
shipp->swarm_missile_bank = bank;
return 1; // Note: Missiles didn't get fired, but the frame interval code will fire them.
}
@@ -11919,7 +11925,11 @@ int ship_fire_secondary( object *obj, int allow_swarm )
if ( (wip->wi_flags[Weapon::Info_Flags::Corkscrew]) && !allow_swarm ) {
//phreak 11-9-02
//changed this from 4 to custom number defined in tables
shipp->num_corkscrew_to_fire = (ubyte)(shipp->num_corkscrew_to_fire + (ubyte)wip->cs_num_fired);
if (wip->multi_lock && obj == Player_obj) {
shipp->num_corkscrew_to_fire = (ubyte)shipp->missile_locks_firing.size();
} else {
shipp->num_corkscrew_to_fire = (ubyte)(shipp->num_corkscrew_to_fire + (ubyte)wip->cs_num_fired);
}
shipp->corkscrew_missile_bank = bank;
return 1; // Note: Missiles didn't get fired, but the frame interval code will fire them.
}
@@ -11933,7 +11943,7 @@ int ship_fire_secondary( object *obj, int allow_swarm )
t = Weapon_info[weapon_idx].fire_wait; // They can fire 5 times a second
swp->burst_counter[bank_adjusted] = 0;
}
swp->next_secondary_fire_stamp[bank] = timestamp((int) (t * 1000.0f));
swp->next_secondary_fire_stamp[bank] = timestamp((int)(t * 1000.0f));
swp->last_secondary_fire_stamp[bank] = timestamp();
// Here is where we check if weapons subsystem is capable of firing the weapon.
@@ -11961,6 +11971,33 @@ int ship_fire_secondary( object *obj, int allow_swarm )
return 0; // we can make a quick out here!!!
}
int target_objnum;
ship_subsys *target_subsys;
int locked;
if ( obj == Player_obj ) {
// use missile lock slots
if ( shipp->missile_locks_firing.size() > 0 ) {
lock_info lock_data = shipp->missile_locks_firing.back();
if ( wip->multi_lock ) {
shipp->missile_locks_firing.pop_back();
}
target_objnum = OBJ_INDEX(lock_data.obj);
target_subsys = lock_data.subsys;
locked = 1;
} else {
target_objnum = -1;
target_subsys = nullptr;
locked = 0;
}
} else {
target_objnum = aip->target_objnum;
target_subsys = aip->targeted_subsys;
locked = aip->current_target_is_locked;
}
num_slots = pm->missile_banks[bank].num_slots;
// determine if there is enough ammo left to fire weapons on this bank. As with primary
@@ -12071,7 +12108,7 @@ int ship_fire_secondary( object *obj, int allow_swarm )
// create the weapon -- for multiplayer, the net_signature is assigned inside
// of weapon_create
weapon_num = weapon_create( &firing_pos, &firing_orient, weapon_idx, OBJ_INDEX(obj), -1, aip->current_target_is_locked);
weapon_num = weapon_create( &firing_pos, &firing_orient, weapon_idx, OBJ_INDEX(obj), -1, locked);
if (weapon_num == -1) {
// Weapon most likely failed to fire
@@ -12083,7 +12120,7 @@ int ship_fire_secondary( object *obj, int allow_swarm )
if (weapon_num >= 0) {
weapon_idx = Weapons[Objects[weapon_num].instance].weapon_info_index;
weapon_set_tracking_info(weapon_num, OBJ_INDEX(obj), aip->target_objnum, aip->current_target_is_locked, aip->targeted_subsys);
weapon_set_tracking_info(weapon_num, OBJ_INDEX(obj), target_objnum, locked, target_subsys);
has_fired = true;
// create the muzzle flash effect
@@ -19228,3 +19265,134 @@ bool ship::is_arriving(ship::warpstage stage, bool dock_leader_or_single)
Assertion(false, "ship::is_arriving didn't handle all possible states; get a coder!");
return false;
}
void ship_clear_lock(lock_info *slot) {
vec3d zero_vec = ZERO_VECTOR;
slot->accumulated_x_pixels = 0;
slot->accumulated_y_pixels = 0;
slot->catch_up_distance = 0.0f;
slot->catching_up = 0;
slot->current_target_sx = -1;
slot->current_target_sy = -1;
slot->dist_to_lock = 0.0f;
slot->indicator_start_x = -1;
slot->indicator_start_y = -1;
slot->indicator_visible = false;
slot->indicator_x = -1;
slot->indicator_y = -1;
slot->last_dist_to_target = 0.0f;
slot->locked_timestamp = 0;
slot->maintain_lock_count = 0;
slot->need_new_start_pos = false;
slot->target_in_lock_cone = false;
slot->world_pos = zero_vec;
slot->locked = false;
slot->obj = nullptr;
slot->subsys = nullptr;
slot->time_to_lock = -1.0f;
}
void ship_queue_missile_locks(ship *shipp)
{
shipp->missile_locks_firing.clear();
// queue up valid missile locks
std::copy_if(shipp->missile_locks.begin(), shipp->missile_locks.end(), std::back_inserter(shipp->missile_locks_firing), [](lock_info lock) { return lock.locked; });
}
bool ship_lock_present(ship *shipp)
{
return std::any_of(shipp->missile_locks.begin(), shipp->missile_locks.end(), [](lock_info lock) { return lock.locked; });
}
bool ship_start_secondary_fire(object* objp)
{
Assert( objp != nullptr);
if ( objp->type != OBJ_SHIP ) {
return false;
}
int n = objp->instance;
Assert( n >= 0 && n < MAX_SHIPS );
Assert( Ships[n].objnum == OBJ_INDEX(objp) );
ship *shipp = &Ships[n];
ship_info *sip = &Ship_info[shipp->ship_info_index];
ship_weapon* swp = &shipp->weapons;
int bank = swp->current_secondary_bank;
if ( bank < 0 || bank >= sip->num_secondary_banks ) {
return false;
}
Assert( (swp->secondary_bank_weapons[bank] >= 0) && (swp->secondary_bank_weapons[bank] < weapon_info_size()) );
weapon_info *wip = &Weapon_info[swp->secondary_bank_weapons[bank]];
if ( wip->trigger_lock ) {
swp->flags.set(Ship::Weapon_Flags::Trigger_Lock);
return true;
}
return false;
}
bool ship_stop_secondary_fire(object* objp)
{
Assert( objp != nullptr);
if ( objp->type != OBJ_SHIP ) {
return false;
}
int n = objp->instance;
if ( n < 0 || n >= MAX_SHIPS ) {
return false;
}
Assert( Ships[n].objnum == OBJ_INDEX(objp) );
ship *shipp = &Ships[n];
ship_info *sip = &Ship_info[shipp->ship_info_index];
ship_weapon *swp = &shipp->weapons;
int bank = swp->current_secondary_bank;
if ( bank < 0 || bank >= sip->num_secondary_banks ) {
return false;
}
Assert( (swp->secondary_bank_weapons[bank] >= 0) && (swp->secondary_bank_weapons[bank] < weapon_info_size()) );
weapon_info *wip = &Weapon_info[swp->secondary_bank_weapons[bank]];
if ( wip->trigger_lock && swp->flags[Ship::Weapon_Flags::Trigger_Lock]) {
swp->flags.remove(Ship::Weapon_Flags::Trigger_Lock);
return true;
}
return false;
}
+46
View File
@@ -31,6 +31,7 @@
#include "weapon/trails.h"
#include "ship/ship_flags.h"
#include "weapon/weapon_flags.h"
#include "ai/ai.h"
#include <string>
#include <particle/ParticleManager.h>
@@ -283,6 +284,36 @@ typedef struct cockpit_display_info {
int size[2];
} cockpit_display_info;
// structure to keep track of ship locks
typedef struct lock_info {
object *obj;
ship_subsys *subsys;
vec3d world_pos;
int current_target_sx;
int current_target_sy;
bool locked;
int maintain_lock_count;
int indicator_x;
int indicator_y;
int indicator_start_x;
int indicator_start_y;
bool indicator_visible;
float time_to_lock;
float dist_to_lock;
int catching_up;
float catch_up_distance;
float last_dist_to_target;
double accumulated_x_pixels;
double accumulated_y_pixels;
bool need_new_start_pos;
bool target_in_lock_cone;
int locked_timestamp;
} lock_info;
// structure definition for a linked list of subsystems for a ship. Each subsystem has a pointer
// to the static data for the subsystem. The obj_subsystem data is defined and read in the model
// code. Other dynamic data (such as current_hits) should remain in this structure.
@@ -560,6 +591,9 @@ public:
vec3d wash_rot_axis;
int wash_timestamp;
SCP_vector<lock_info> missile_locks;
SCP_vector<lock_info> missile_locks_firing;
int num_swarm_missiles_to_fire; // number of swarm missiles that need to be launched
int next_swarm_fire; // timestamp of next swarm missile to fire
int next_swarm_path; // next path number for swarm missile to take
@@ -1409,6 +1443,9 @@ 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 stream_weapons, int force = 0);
extern int ship_fire_secondary(object * objp, int allow_swarm = 0 );
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);
// for special targeting lasers
@@ -1800,4 +1837,13 @@ extern void toggle_ignore_list_flag(Ship::Ship_Flags flag);
ship_subsys* ship_get_subsys_for_submodel(ship* shipp, int submodel);
// Clears a lock_info struct with defaults
void ship_clear_lock(lock_info *slot);
// queues up locks
void ship_queue_missile_locks(ship *shipp);
// snoops missile locks to see if any are ready to fire.
bool ship_lock_present(ship *shipp);
#endif
+1
View File
@@ -9,6 +9,7 @@ namespace Ship {
Beam_Free = 0, // if this is a beam weapon, its free to fire
Turret_Lock, // is this turret is free to fire or locked
Tagged_Only, // only fire if target is tagged
Trigger_Lock, // // indicates that the trigger is held down
NUM_VALUES
};
+30 -1
View File
@@ -38,6 +38,15 @@ extern int Num_weapon_subtypes;
#define WRT_LASER 1
#define WRT_POF 2
// constants for weapon lock acquire methods
#define WLOCK_PIXEL 0
#define WLOCK_TIMER 1
// constants for weapon lock restrictions
#define LR_CURRENT_TARGET 0 // Only lock current target and subsystem
#define LR_CURRENT_TARGET_SUBSYS 1 //
#define LR_ANY_TARGETS 2
//particle names go here -nuke
#define PSPEW_NONE -1 //used to disable a spew, useful for xmts
#define PSPEW_DEFAULT 0 //std fs2 pspew
@@ -315,11 +324,24 @@ struct weapon_info
short swarm_count; // how many swarm missiles are fired for this weapon
int SwarmWait; // *Swarm firewait, default is 150 -Et1
int target_restrict;
bool multi_lock;
int max_seeking; // how many seekers can be active at a time if multilock is enabled. A value of one will lock stuff up one by one.
int max_seekers_per_target; // how many seekers can be attached to a target.
SCP_vector<int> ship_type_restrict;
SCP_vector<SCP_string> ship_type_restrict_temp;
bool trigger_lock; // Trigger must be held down and released to lock and fire.
bool launch_reset_locks; // Lock indicators reset after firing
// Specific to ASPECT homing missiles.
int acquire_method;
float min_lock_time; // minimum time (in seconds) to achieve lock
int lock_pixels_per_sec; // pixels/sec moved while locking
int catchup_pixels_per_sec; // pixels/sec moved while catching-up for a lock
int catchup_pixel_penalty; // number of extra pixels to move while locking as a penalty for catching up for a lock
int catchup_pixel_penalty; // number of extra pixels to move while locking as a penalty for catching up for a lock
float lock_fov;
// Specific to HEAT homing missiles.
float fov;
@@ -629,4 +651,11 @@ void validate_SSM_entries();
void shield_impact_explosion(vec3d *hitpos, object *objp, float radius, int idx);
// Swifty - return number of max simultaneous locks
int weapon_get_max_missile_seekers(weapon_info *wip);
// return if this weapon can lock on this ship type
bool weapon_can_lock_on_ship_type(weapon_info *wip, int ship_type);
#endif
+104
View File
@@ -1398,6 +1398,56 @@ int parse_weapon(int subtype, bool replace, const char *filename)
}
}
if (optional_string("+Target Lock Restriction:")) {
if (optional_string("current target, any subsystem")) {
wip->target_restrict = LR_CURRENT_TARGET_SUBSYS;
}
else if (optional_string("any target")) {
wip->target_restrict = LR_ANY_TARGETS;
}
else if (optional_string("current target only")) {
wip->target_restrict = LR_CURRENT_TARGET;
}
else {
wip->target_restrict = LR_CURRENT_TARGET;
}
}
if (optional_string("+Independent Seekers:")) {
stuff_boolean(&wip->multi_lock);
}
if (optional_string("+Trigger Hold:")) {
stuff_boolean(&wip->trigger_lock);
}
if (optional_string("+Reset On Launch:")) {
stuff_boolean(&wip->launch_reset_locks);
}
if (optional_string("+Max Seekers Per Target:")) {
stuff_int(&wip->max_seekers_per_target);
}
if (optional_string("+Max Active Seekers:")) {
stuff_int(&wip->max_seeking);
}
if (optional_string("+Ship Types:")) {
stuff_string_list(wip->ship_type_restrict_temp);
}
if (wip->is_locked_homing()) {
// locked homing missiles have a much longer lifespan than the AI think they do
wip->max_lifetime = wip->lifetime * LOCKED_HOMING_EXTENDED_LIFE_FACTOR;
@@ -3599,6 +3649,7 @@ void weapon_close()
void weapon_level_init()
{
int i;
extern int ships_inited;
// Reset everything between levels
Num_weapons = 0;
@@ -3610,6 +3661,19 @@ void weapon_level_init()
for (i = 0; i < weapon_info_size(); i++) {
Weapon_info[i].damage_type_idx = Weapon_info[i].damage_type_idx_sav;
Weapon_info[i].shockwave.damage_type_idx = Weapon_info[i].shockwave.damage_type_idx_sav;
if ( ships_inited ) {
// populate ship type lock restrictions
for ( int j = 0; j < (int)Weapon_info[i].ship_type_restrict_temp.size(); ++j ) {
int idx = ship_type_name_lookup((char*)Weapon_info[i].ship_type_restrict_temp[j].c_str());
if ( idx >= 0 ) {
Weapon_info[i].ship_type_restrict.push_back(idx);
}
}
Weapon_info[i].ship_type_restrict_temp.clear();
}
}
trail_level_init(); // reset all missile trails
@@ -7700,12 +7764,25 @@ void weapon_info::reset()
// *Default is 150 -Et1
this->SwarmWait = SWARM_MISSILE_DELAY;
this->target_restrict = LR_CURRENT_TARGET;
this->multi_lock = false;
this->trigger_lock = false;
this->launch_reset_locks = false;
this->max_seeking = 1;
this->max_seekers_per_target = 1;
this->ship_type_restrict.clear();
this->ship_type_restrict_temp.clear();
this->acquire_method = WLOCK_PIXEL;
this->min_lock_time = 0.0f;
this->lock_pixels_per_sec = 50;
this->catchup_pixels_per_sec = 50;
this->catchup_pixel_penalty = 50;
this->fov = 0; //should be cos(pi), not pi
this->seeker_strength = 1.0f;
this->lock_fov = 0.85f;
this->pre_launch_snd = gamesnd_id();
this->pre_launch_snd_min_interval = 0;
@@ -8094,3 +8171,30 @@ void weapon_spew_stats()
}
#endif
}
// Given a weapon, figure out how many independent locks we can have with it.
int weapon_get_max_missile_seekers(weapon_info *wip)
{
int max_target_locks;
if ( wip->multi_lock ) {
if ( wip->wi_flags[Weapon::Info_Flags::Swarm] ) {
max_target_locks = wip->swarm_count;
} else if ( wip->wi_flags[Weapon::Info_Flags::Corkscrew] ) {
max_target_locks = wip->cs_num_fired;
} else {
max_target_locks = 1;
}
} else {
max_target_locks = 1;
}
return max_target_locks;
}
bool weapon_can_lock_on_ship_type(weapon_info *wip, int ship_type)
{
// Determine if there are any restrictions, treating an empty list as true
return (wip->ship_type_restrict.size() == 0) ||
std::any_of(wip->ship_type_restrict.begin(), wip->ship_type_restrict.end(), [ship_type](int type) { return type == ship_type; });
}