Compare commits

...
10 Commits
Author SHA1 Message Date
Lari Nieminen 0c1cc9e57c Merge branch 'master' of https://github.com/scp-fs2open/fs2open.github.com into newzoo 2015-04-29 11:33:37 +03:00
MageKing17 31140ab533 Make FRED use the new try-catch logic.
Missed during the recent parseExceptions merge; there was a usage of setjmp() during the background import dialogue.
2015-04-28 19:09:19 -07:00
Lari Nieminen 12a10bf676 Merge branch 'master' into newzoo
Conflicts:
	code/ai/ai_profiles.cpp
	code/bmpman/bmpman.cpp
	code/hud/hudparse.cpp
	code/mod_table/mod_table.cpp
2015-04-29 00:36:28 +03:00
Cliff Gordon 70291fe7ce Changes from the svn zookeeper branch applied to a new git branch. 2015-04-28 16:19:54 -05:00
niffiwan e3d1428e35 From Yarn: fix mantis 3157
Switch German and Polish translations of "Transport"
2015-04-28 19:36:30 +10:00
Fabian Woltermann 1d332d693d Merge pull request #38 from asarium/feature/parseExceptions
Replace longjmp with exceptions
2015-04-28 07:47:53 +02:00
niffiwan 36c656c389 bah, lrn2markdown 2015-04-27 20:46:37 +10:00
niffiwan 43b8cf2221 Resolve github issue #34 (add Coverity Badge)
Also freshen up the new README.md contents
2015-04-27 20:43:51 +10:00
Lari Nieminen 418d53f169 Removed false "returns ptr to vector" comments. 2015-04-27 11:57:39 +03:00
asarium 9aed627ce7 Replace longjmp with exceptions
Also added a EditorConfig file
2015-04-24 15:03:59 +02:00
85 changed files with 5403 additions and 4640 deletions

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
root = true
[*.{h,cpp}]
indent_style = tab
+18
View File
@@ -0,0 +1,18 @@
[![Coverity](https://scan.coverity.com/projects/870/badge.svg)](https://scan.coverity.com/projects/870)
Welcome to Freespace Open!
In 2002 Volition released the source code for Freespace2. In the years since dedicated individuals have added countless new features to create a flexible and powerful space combat simulation engine. More info can be found on our [wiki](http://www.hard-light.net/wiki/index.php/Source_Code_Project)
People interested in contributing are encouraged to read [this thread](http://www.hard-light.net/forums/index.php?topic=82688.0)
The "projects" directory contains ready projects for:
* Microsoft Visual C++ 6, 2005, 2008, 2010, 2011, 2013, 2015
* Apple Xcode
* Code::Blocks
* Eclipse
Review the commit logs to see what's new.
See the INSTALL file for instructions on how to build fs2_open, or open the relevant MSVC project
+415 -402
View File
@@ -69,445 +69,458 @@ int ai_path_type_match(char *p)
void parse_ai_profiles_tbl(const char *filename)
{
int i, rval;
int i;
char profile_name[NAME_LENGTH];
ai_profile_t dummy_profile;
char *saved_Mp = NULL;
char buf[NAME_LENGTH];
if ((rval = setjmp(parse_abort)) != 0)
try
{
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", (filename) ? filename : "<default ai_profiles.tbl>", rval));
return;
}
if (filename == NULL)
read_file_text_from_array(defaults_get_file("ai_profiles.tbl"));
else
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// start parsing
required_string("#AI Profiles");
// new default?
if (optional_string("$Default Profile:"))
stuff_string(Default_profile_name, F_NAME, NAME_LENGTH);
// begin reading data
while (required_string_either("#End","$Profile Name:"))
{
ai_profile_t *profile = &dummy_profile;
ai_profile_t *previous_profile = NULL;
bool no_create = false;
// get the name
required_string("$Profile Name:");
stuff_string(profile_name, F_NAME, NAME_LENGTH);
// see if it exists
for (i = 0; i < Num_ai_profiles; i++)
{
if (!stricmp(Ai_profiles[i].profile_name, profile_name))
{
previous_profile = &Ai_profiles[i];
break;
}
}
// modular table stuff
if (optional_string("+nocreate"))
{
no_create = true;
// use the previous one if possible,
// otherwise continue to use the dummy one
if (previous_profile != NULL)
profile = previous_profile;
}
if (filename == NULL)
read_file_text_from_array(defaults_get_file("ai_profiles.tbl"));
else
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// start parsing
required_string("#AI Profiles");
// new default?
if (optional_string("$Default Profile:"))
stuff_string(Default_profile_name, F_NAME, NAME_LENGTH);
// begin reading data
while (required_string_either("#End", "$Profile Name:"))
{
// don't create multiple profiles with the same name
if (previous_profile != NULL)
ai_profile_t *profile = &dummy_profile;
ai_profile_t *previous_profile = NULL;
bool no_create = false;
// get the name
required_string("$Profile Name:");
stuff_string(profile_name, F_NAME, NAME_LENGTH);
// see if it exists
for (i = 0; i < Num_ai_profiles; i++)
{
Warning(LOCATION, "An ai profile named '%s' already exists! The new one will not be created.\n", profile_name);
}
else
{
// make sure we're under the limit
if (Num_ai_profiles >= MAX_AI_PROFILES)
if (!stricmp(Ai_profiles[i].profile_name, profile_name))
{
Warning(LOCATION, "Too many profiles in ai_profiles.tbl! Max is %d.\n", MAX_AI_PROFILES-1); // -1 because one is built-in
skip_to_string("#End", NULL);
previous_profile = &Ai_profiles[i];
break;
}
profile = &Ai_profiles[Num_ai_profiles];
Num_ai_profiles++;
}
}
// initialize profile if we're not building from a previously parsed one
if (!no_create)
{
// base profile, so zero it out
if (profile == &Ai_profiles[0])
// modular table stuff
if (optional_string("+nocreate"))
{
memset(profile, 0, sizeof(ai_profile_t));
no_create = true;
// use the previous one if possible,
// otherwise continue to use the dummy one
if (previous_profile != NULL)
profile = previous_profile;
}
// brand new profile, so set it to the base defaults
else
{
memcpy(profile, &Ai_profiles[0], sizeof(ai_profile_t));
}
}
// set the name
strcpy_s(profile->profile_name, profile_name);
// fill in any and all settings; they're all optional and can be in any order
while (!check_for_string("$Profile Name:") && !check_for_string("#End"))
{
if (optional_string("$Player Afterburner Recharge Scale:"))
parse_float_list(profile->afterburner_recharge_scale, NUM_SKILL_LEVELS);
if (optional_string("$Max Beam Friendly Fire Damage:"))
parse_float_list(profile->beam_friendly_damage_cap, NUM_SKILL_LEVELS);
if (optional_string("$Player Countermeasure Life Scale:"))
parse_float_list(profile->cmeasure_life_scale, NUM_SKILL_LEVELS);
if (optional_string("$AI Countermeasure Firing Chance:"))
parse_float_list(profile->cmeasure_fire_chance, NUM_SKILL_LEVELS);
if (optional_string("$AI In Range Time:"))
parse_float_list(profile->in_range_time, NUM_SKILL_LEVELS);
if (optional_string("$AI Always Links Ammo Weapons:"))
parse_float_list(profile->link_ammo_levels_always, NUM_SKILL_LEVELS);
if (optional_string("$AI Maybe Links Ammo Weapons:"))
parse_float_list(profile->link_ammo_levels_maybe, NUM_SKILL_LEVELS);
if (optional_string("$Primary Ammo Burst Multiplier:"))
parse_float_list(profile->primary_ammo_burst_mult, NUM_SKILL_LEVELS);
if (optional_string("$AI Always Links Energy Weapons:"))
parse_float_list(profile->link_energy_levels_always, NUM_SKILL_LEVELS);
if (optional_string("$AI Maybe Links Energy Weapons:"))
parse_float_list(profile->link_energy_levels_maybe, NUM_SKILL_LEVELS);
if (optional_string("$Max Missles Locked on Player:") || optional_string("$Max Missiles Locked on Player:"))
parse_int_list(profile->max_allowed_player_homers, NUM_SKILL_LEVELS);
if (optional_string("$Max Player Attackers:"))
parse_int_list(profile->max_attackers, NUM_SKILL_LEVELS);
if (optional_string("$Max Incoming Asteroids:"))
parse_int_list(profile->max_incoming_asteroids, NUM_SKILL_LEVELS);
if (optional_string("$Player Damage Factor:") || optional_string("$AI Damage Reduction to Player Hull:"))
parse_float_list(profile->player_damage_scale, NUM_SKILL_LEVELS);
if (optional_string("$Player Subsys Damage Factor:") || optional_string("$AI Damage Reduction to Player Subsys:"))
parse_float_list(profile->subsys_damage_scale, NUM_SKILL_LEVELS);
// represented in fractions of F1_0
if (optional_string("$Predict Position Delay:"))
{
int iLoop;
float temp_list[NUM_SKILL_LEVELS];
parse_float_list(temp_list, NUM_SKILL_LEVELS);
for (iLoop = 0; iLoop < NUM_SKILL_LEVELS; iLoop++)
profile->predict_position_delay[iLoop] = fl2f(temp_list[iLoop]);
}
if (optional_string("$AI Shield Manage Delay:") || optional_string("$AI Shield Manage Delays:"))
parse_float_list(profile->shield_manage_delay, NUM_SKILL_LEVELS);
if (optional_string("$Friendly AI Fire Delay Scale:"))
parse_float_list(profile->ship_fire_delay_scale_friendly, NUM_SKILL_LEVELS);
if (optional_string("$Hostile AI Fire Delay Scale:"))
parse_float_list(profile->ship_fire_delay_scale_hostile, NUM_SKILL_LEVELS);
if (optional_string("$Friendly AI Secondary Fire Delay Scale:"))
parse_float_list(profile->ship_fire_secondary_delay_scale_friendly, NUM_SKILL_LEVELS);
if (optional_string("$Hostile AI Secondary Fire Delay Scale:"))
parse_float_list(profile->ship_fire_secondary_delay_scale_hostile, NUM_SKILL_LEVELS);
if (optional_string("$AI Turn Time Scale:"))
parse_float_list(profile->turn_time_scale, NUM_SKILL_LEVELS);
if (optional_string("$Glide Attack Percent:")) {
parse_float_list(profile->glide_attack_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->glide_attack_percent[i] < 0.0f || profile->glide_attack_percent[i] > 100.0f) {
Warning(LOCATION, "$Glide Attack Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->glide_attack_percent[i]);
profile->glide_attack_percent[i] = 0.0f;
}
profile->glide_attack_percent[i] /= 100.0;
}
}
if (optional_string("$Circle Strafe Percent:")) {
parse_float_list(profile->circle_strafe_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->circle_strafe_percent[i] < 0.0f || profile->circle_strafe_percent[i] > 100.0f) {
Warning(LOCATION, "$Circle Strafe Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->circle_strafe_percent[i]);
profile->circle_strafe_percent[i] = 0.0f;
}
profile->circle_strafe_percent[i] /= 100.0;
}
}
if (optional_string("$Glide Strafe Percent:")) {
parse_float_list(profile->glide_strafe_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->glide_strafe_percent[i] < 0.0f || profile->glide_strafe_percent[i] > 100.0f) {
Warning(LOCATION, "$Glide Strafe Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->glide_strafe_percent[i]);
profile->glide_strafe_percent[i] = 0.0f;
}
profile->glide_strafe_percent[i] /= 100.0;
}
}
if (optional_string("$Random Sidethrust Percent:")) {
parse_float_list(profile->random_sidethrust_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->random_sidethrust_percent[i] < 0.0f || profile->random_sidethrust_percent[i] > 100.0f) {
Warning(LOCATION, "$Random Sidethrust Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->random_sidethrust_percent[i]);
profile->random_sidethrust_percent[i] = 0.0f;
}
profile->random_sidethrust_percent[i] /= 100.0;
}
}
if (optional_string("$Stalemate Time Threshold:"))
parse_float_list(profile->stalemate_time_thresh, NUM_SKILL_LEVELS);
if (optional_string("$Stalemate Distance Threshold:"))
parse_float_list(profile->stalemate_dist_thresh, NUM_SKILL_LEVELS);
if (optional_string("$Player Shield Recharge Scale:"))
parse_float_list(profile->shield_energy_scale, NUM_SKILL_LEVELS);
if (optional_string("$Player Weapon Recharge Scale:"))
parse_float_list(profile->weapon_energy_scale, NUM_SKILL_LEVELS);
if (optional_string("$Max Turret Target Ownage:"))
parse_int_list(profile->max_turret_ownage_target, NUM_SKILL_LEVELS);
if (optional_string("$Max Turret Player Ownage:"))
parse_int_list(profile->max_turret_ownage_player, NUM_SKILL_LEVELS);
if (optional_string("$Percentage Required For Kill Scale:"))
parse_float_list(profile->kill_percentage_scale, NUM_SKILL_LEVELS);
if (optional_string("$Percentage Required For Assist Scale:"))
parse_float_list(profile->assist_percentage_scale, NUM_SKILL_LEVELS);
if (optional_string("$Percentage Awarded For Capship Assist:"))
parse_float_list(profile->assist_award_percentage_scale, NUM_SKILL_LEVELS);
if (optional_string("$Repair Penalty:"))
parse_int_list(profile->repair_penalty, NUM_SKILL_LEVELS);
if (optional_string("$Delay Before Allowing Bombs to Be Shot Down:"))
parse_float_list(profile->delay_bomb_arm_timer, NUM_SKILL_LEVELS);
if (optional_string("$Chance AI Has to Fire Missiles at Player:"))
parse_int_list(profile->chance_to_use_missiles_on_plr, NUM_SKILL_LEVELS);
if (optional_string("$Max Aim Update Delay:"))
parse_float_list(profile->max_aim_update_delay, NUM_SKILL_LEVELS);
if (optional_string("$Turret Max Aim Update Delay:"))
parse_float_list(profile->turret_max_aim_update_delay, NUM_SKILL_LEVELS);
if (optional_string("$Player Autoaim FOV:"))
{
float fov_list[NUM_SKILL_LEVELS];
parse_float_list(fov_list, NUM_SKILL_LEVELS);
for (i = 0; i < NUM_SKILL_LEVELS; i++)
// don't create multiple profiles with the same name
if (previous_profile != NULL)
{
//Enforce range
if (fov_list[i] < 0.0f || fov_list[i] >= 360.0f)
Warning(LOCATION, "An ai profile named '%s' already exists! The new one will not be created.\n", profile_name);
}
else
{
// make sure we're under the limit
if (Num_ai_profiles >= MAX_AI_PROFILES)
{
Warning(LOCATION, "$Player Autoaim FOV should be >= 0 and < 360.0 (read %f). Setting to 0.", fov_list[i]);
fov_list[i] = 0.0f;
Warning(LOCATION, "Too many profiles in ai_profiles.tbl! Max is %d.\n", MAX_AI_PROFILES - 1); // -1 because one is built-in
skip_to_string("#End", NULL);
break;
}
//Convert units
profile->player_autoaim_fov[i] = fov_list[i] * PI / 180.0f;
profile = &Ai_profiles[Num_ai_profiles];
Num_ai_profiles++;
}
}
if (optional_string("$Detail Distance Multiplier:"))
parse_float_list(profile->detail_distance_mult, NUM_SKILL_LEVELS);
set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS, AIP_FLAG);
set_flag(profile, "$smart primary weapon selection:", AIPF_SMART_PRIMARY_WEAPON_SELECTION, AIP_FLAG);
set_flag(profile, "$smart secondary weapon selection:", AIPF_SMART_SECONDARY_WEAPON_SELECTION, AIP_FLAG);
set_flag(profile, "$smart shield management:", AIPF_SMART_SHIELD_MANAGEMENT, AIP_FLAG);
set_flag(profile, "$smart afterburner management:", AIPF_SMART_AFTERBURNER_MANAGEMENT, AIP_FLAG);
set_flag(profile, "$allow rapid secondary dumbfire:", AIPF_ALLOW_RAPID_SECONDARY_DUMBFIRE, AIP_FLAG);
set_flag(profile, "$huge turret weapons ignore bombs:", AIPF_HUGE_TURRET_WEAPONS_IGNORE_BOMBS, AIP_FLAG);
set_flag(profile, "$don't insert random turret fire delay:", AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY, AIP_FLAG);
set_flag(profile, "$hack improve non-homing swarm turret fire accuracy:", AIPF_HACK_IMPROVE_NON_HOMING_SWARM_TURRET_FIRE_ACCURACY, AIP_FLAG);
set_flag(profile, "$shockwaves damage small ship subsystems:", AIPF_SHOCKWAVES_DAMAGE_SMALL_SHIP_SUBSYSTEMS, AIP_FLAG);
set_flag(profile, "$navigation subsystem governs warpout capability:", AIPF_NAVIGATION_SUBSYS_GOVERNS_WARP, AIP_FLAG);
set_flag(profile, "$ignore lower bound for minimum speed of docked ship:", AIPF_NO_MIN_DOCK_SPEED_CAP, AIP_FLAG);
set_flag(profile, "$disable linked fire penalty:", AIPF_DISABLE_LINKED_FIRE_PENALTY, AIP_FLAG);
set_flag(profile, "$disable weapon damage scaling:", AIPF_DISABLE_WEAPON_DAMAGE_SCALING, AIP_FLAG);
set_flag(profile, "$use additive weapon velocity:", AIPF_USE_ADDITIVE_WEAPON_VELOCITY, AIP_FLAG);
set_flag(profile, "$use newtonian dampening:", AIPF_USE_NEWTONIAN_DAMPENING, AIP_FLAG);
set_flag(profile, "$include beams for kills and assists:", AIPF_INCLUDE_BEAMS_IN_STAT_CALCS, AIP_FLAG);
set_flag(profile, "$score kills based on damage caused:", AIPF_KILL_SCORING_SCALES_WITH_DAMAGE, AIP_FLAG);
set_flag(profile, "$score assists based on damage caused:", AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE, AIP_FLAG);
set_flag(profile, "$allow event and goal scoring in multiplayer:", AIPF_ALLOW_MULTI_EVENT_SCORING, AIP_FLAG);
set_flag(profile, "$fix linked primary weapon decision bug:", AIPF_FIX_LINKED_PRIMARY_BUG, AIP_FLAG);
set_flag(profile, "$prevent turrets targeting too distant bombs:", AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE, AIP_FLAG);
set_flag(profile, "$smart subsystem targeting for turrets:", AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS, AIP_FLAG);
set_flag(profile, "$fix heat seekers homing on stealth ships bug:", AIPF_FIX_HEAT_SEEKER_STEALTH_BUG, AIP_FLAG);
set_flag(profile, "$multi allow empty primaries:", AIPF_MULTI_ALLOW_EMPTY_PRIMARIES, AIP_FLAG);
set_flag(profile, "$multi allow empty secondaries:", AIPF_MULTI_ALLOW_EMPTY_SECONDARIES, AIP_FLAG);
set_flag(profile, "$allow turrets target weapons freely:", AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY, AIP_FLAG);
set_flag(profile, "$use only single fov for turrets:", AIPF_USE_ONLY_SINGLE_FOV_FOR_TURRETS, AIP_FLAG);
set_flag(profile, "$allow vertical dodge:", AIPF_ALLOW_VERTICAL_DODGE, AIP_FLAG);
set_flag(profile, "$force beam turrets to use normal fov:", AIPF_FORCE_BEAM_TURRET_FOV, AIP_FLAG);
set_flag(profile, "$fix ai class bug:", AIPF_FIX_AI_CLASS_BUG, AIP_FLAG);
set_flag(profile, "$turrets ignore targets radius in range checks:", AIPF2_TURRETS_IGNORE_TARGET_RADIUS, AIP_FLAG2);
set_flag(profile, "$no extra collision avoidance vs player:", AIPF2_NO_SPECIAL_PLAYER_AVOID, AIP_FLAG2);
set_flag(profile, "$perform fewer checks for death screams:", AIPF2_PERFORM_FEWER_SCREAM_CHECKS, AIP_FLAG2);
set_flag(profile, "$advanced turret fov edge checks:", AIPF2_ADVANCED_TURRET_FOV_EDGE_CHECKS, AIP_FLAG2);
set_flag(profile, "$require turrets to have target in fov:", AIPF2_REQUIRE_TURRET_TO_HAVE_TARGET_IN_FOV, AIP_FLAG2);
set_flag(profile, "$all ships manage shields:", AIPF2_ALL_SHIPS_MANAGE_SHIELDS, AIP_FLAG2);
set_flag(profile, "$ai aims from ship center:", AIPF2_AI_AIMS_FROM_SHIP_CENTER, AIP_FLAG2);
set_flag(profile, "$allow primary link at mission start:", AIPF2_ALLOW_PRIMARY_LINK_AT_START, AIP_FLAG2);
set_flag(profile, "$allow beams to damage bombs:", AIPF2_BEAMS_DAMAGE_WEAPONS, AIP_FLAG2);
set_flag(profile, "$disable weapon damage scaling for player:", AIPF2_PLAYER_WEAPON_SCALE_FIX, AIP_FLAG2);
set_flag(profile, "$countermeasures affect aspect seekers:", AIPF2_ASPECT_LOCK_COUNTERMEASURE, AIP_FLAG2);
set_flag(profile, "$ai guards specific ship in wing:", AIPF2_AI_GUARDS_SPECIFIC_SHIP_IN_WING, AIP_FLAG2);
profile->ai_path_mode = AI_PATH_MODE_NORMAL;
if(optional_string("$ai path mode:"))
// initialize profile if we're not building from a previously parsed one
if (!no_create)
{
stuff_string(buf, F_NAME, NAME_LENGTH);
int j = ai_path_type_match(buf);
if(j >= 0) {
profile->ai_path_mode = j;
} else {
Warning(LOCATION, "Invalid ai path mode '%s' specified", buf);
// base profile, so zero it out
if (profile == &Ai_profiles[0])
{
memset(profile, 0, sizeof(ai_profile_t));
}
// brand new profile, so set it to the base defaults
else
{
memcpy(profile, &Ai_profiles[0], sizeof(ai_profile_t));
}
}
set_flag(profile, "$no warp camera:", AIPF2_NO_WARP_CAMERA, AIP_FLAG2);
// set the name
strcpy_s(profile->profile_name, profile_name);
set_flag(profile, "$fix ai path order bug:", AIPF2_FIX_AI_PATH_ORDER_BUG, AIP_FLAG2);
set_flag(profile, "$strict turret-tagged-only targeting:", AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING, AIP_FLAG2);
// fill in any and all settings; they're all optional and can be in any order
while (!check_for_string("$Profile Name:") && !check_for_string("#End"))
{
if (optional_string("$Player Afterburner Recharge Scale:"))
parse_float_list(profile->afterburner_recharge_scale, NUM_SKILL_LEVELS);
if (optional_string("$Max Beam Friendly Fire Damage:"))
parse_float_list(profile->beam_friendly_damage_cap, NUM_SKILL_LEVELS);
if (optional_string("$Player Countermeasure Life Scale:"))
parse_float_list(profile->cmeasure_life_scale, NUM_SKILL_LEVELS);
if (optional_string("$AI Countermeasure Firing Chance:"))
parse_float_list(profile->cmeasure_fire_chance, NUM_SKILL_LEVELS);
if (optional_string("$AI In Range Time:"))
parse_float_list(profile->in_range_time, NUM_SKILL_LEVELS);
if (optional_string("$AI Always Links Ammo Weapons:"))
parse_float_list(profile->link_ammo_levels_always, NUM_SKILL_LEVELS);
if (optional_string("$AI Maybe Links Ammo Weapons:"))
parse_float_list(profile->link_ammo_levels_maybe, NUM_SKILL_LEVELS);
if (optional_string("$Primary Ammo Burst Multiplier:"))
parse_float_list(profile->primary_ammo_burst_mult, NUM_SKILL_LEVELS);
if (optional_string("$AI Always Links Energy Weapons:"))
parse_float_list(profile->link_energy_levels_always, NUM_SKILL_LEVELS);
if (optional_string("$AI Maybe Links Energy Weapons:"))
parse_float_list(profile->link_energy_levels_maybe, NUM_SKILL_LEVELS);
if (optional_string("$Max Missles Locked on Player:") || optional_string("$Max Missiles Locked on Player:"))
parse_int_list(profile->max_allowed_player_homers, NUM_SKILL_LEVELS);
if (optional_string("$Max Player Attackers:"))
parse_int_list(profile->max_attackers, NUM_SKILL_LEVELS);
if (optional_string("$Max Incoming Asteroids:"))
parse_int_list(profile->max_incoming_asteroids, NUM_SKILL_LEVELS);
if (optional_string("$Player Damage Factor:") || optional_string("$AI Damage Reduction to Player Hull:"))
parse_float_list(profile->player_damage_scale, NUM_SKILL_LEVELS);
if (optional_string("$Player Subsys Damage Factor:") || optional_string("$AI Damage Reduction to Player Subsys:"))
parse_float_list(profile->subsys_damage_scale, NUM_SKILL_LEVELS);
// represented in fractions of F1_0
if (optional_string("$Predict Position Delay:"))
{
int iLoop;
float temp_list[NUM_SKILL_LEVELS];
parse_float_list(temp_list, NUM_SKILL_LEVELS);
for (iLoop = 0; iLoop < NUM_SKILL_LEVELS; iLoop++)
profile->predict_position_delay[iLoop] = fl2f(temp_list[iLoop]);
}
if (optional_string("$AI Shield Manage Delay:") || optional_string("$AI Shield Manage Delays:"))
parse_float_list(profile->shield_manage_delay, NUM_SKILL_LEVELS);
if (optional_string("$Friendly AI Fire Delay Scale:"))
parse_float_list(profile->ship_fire_delay_scale_friendly, NUM_SKILL_LEVELS);
if (optional_string("$Hostile AI Fire Delay Scale:"))
parse_float_list(profile->ship_fire_delay_scale_hostile, NUM_SKILL_LEVELS);
if (optional_string("$Friendly AI Secondary Fire Delay Scale:"))
parse_float_list(profile->ship_fire_secondary_delay_scale_friendly, NUM_SKILL_LEVELS);
if (optional_string("$Hostile AI Secondary Fire Delay Scale:"))
parse_float_list(profile->ship_fire_secondary_delay_scale_hostile, NUM_SKILL_LEVELS);
if (optional_string("$AI Turn Time Scale:"))
parse_float_list(profile->turn_time_scale, NUM_SKILL_LEVELS);
if (optional_string("$Glide Attack Percent:")) {
parse_float_list(profile->glide_attack_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->glide_attack_percent[i] < 0.0f || profile->glide_attack_percent[i] > 100.0f) {
Warning(LOCATION, "$Glide Attack Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->glide_attack_percent[i]);
profile->glide_attack_percent[i] = 0.0f;
}
profile->glide_attack_percent[i] /= 100.0;
}
}
if (optional_string("$Circle Strafe Percent:")) {
parse_float_list(profile->circle_strafe_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->circle_strafe_percent[i] < 0.0f || profile->circle_strafe_percent[i] > 100.0f) {
Warning(LOCATION, "$Circle Strafe Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->circle_strafe_percent[i]);
profile->circle_strafe_percent[i] = 0.0f;
}
profile->circle_strafe_percent[i] /= 100.0;
}
}
if (optional_string("$Glide Strafe Percent:")) {
parse_float_list(profile->glide_strafe_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->glide_strafe_percent[i] < 0.0f || profile->glide_strafe_percent[i] > 100.0f) {
Warning(LOCATION, "$Glide Strafe Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->glide_strafe_percent[i]);
profile->glide_strafe_percent[i] = 0.0f;
}
profile->glide_strafe_percent[i] /= 100.0;
}
}
if (optional_string("$Random Sidethrust Percent:")) {
parse_float_list(profile->random_sidethrust_percent, NUM_SKILL_LEVELS);
//Percent is nice for modders, but here in the code we want it betwwen 0 and 1.0
//While we're at it, verify the range
for (i = 0; i < NUM_SKILL_LEVELS; i++) {
if (profile->random_sidethrust_percent[i] < 0.0f || profile->random_sidethrust_percent[i] > 100.0f) {
Warning(LOCATION, "$Random Sidethrust Percent should be between 0 and 100.0 (read %f). Setting to 0.", profile->random_sidethrust_percent[i]);
profile->random_sidethrust_percent[i] = 0.0f;
}
profile->random_sidethrust_percent[i] /= 100.0;
}
}
if (optional_string("$Stalemate Time Threshold:"))
parse_float_list(profile->stalemate_time_thresh, NUM_SKILL_LEVELS);
if (optional_string("$Stalemate Distance Threshold:"))
parse_float_list(profile->stalemate_dist_thresh, NUM_SKILL_LEVELS);
if (optional_string("$Player Shield Recharge Scale:"))
parse_float_list(profile->shield_energy_scale, NUM_SKILL_LEVELS);
if (optional_string("$Player Weapon Recharge Scale:"))
parse_float_list(profile->weapon_energy_scale, NUM_SKILL_LEVELS);
if (optional_string("$Max Turret Target Ownage:"))
parse_int_list(profile->max_turret_ownage_target, NUM_SKILL_LEVELS);
if (optional_string("$Max Turret Player Ownage:"))
parse_int_list(profile->max_turret_ownage_player, NUM_SKILL_LEVELS);
if (optional_string("$Percentage Required For Kill Scale:"))
parse_float_list(profile->kill_percentage_scale, NUM_SKILL_LEVELS);
if (optional_string("$Percentage Required For Assist Scale:"))
parse_float_list(profile->assist_percentage_scale, NUM_SKILL_LEVELS);
if (optional_string("$Percentage Awarded For Capship Assist:"))
parse_float_list(profile->assist_award_percentage_scale, NUM_SKILL_LEVELS);
if (optional_string("$Repair Penalty:"))
parse_int_list(profile->repair_penalty, NUM_SKILL_LEVELS);
if (optional_string("$Delay Before Allowing Bombs to Be Shot Down:"))
parse_float_list(profile->delay_bomb_arm_timer, NUM_SKILL_LEVELS);
if (optional_string("$Chance AI Has to Fire Missiles at Player:"))
parse_int_list(profile->chance_to_use_missiles_on_plr, NUM_SKILL_LEVELS);
if (optional_string("$Max Aim Update Delay:"))
parse_float_list(profile->max_aim_update_delay, NUM_SKILL_LEVELS);
if (optional_string("$Turret Max Aim Update Delay:"))
parse_float_list(profile->turret_max_aim_update_delay, NUM_SKILL_LEVELS);
if (optional_string("$Player Autoaim FOV:"))
{
float fov_list[NUM_SKILL_LEVELS];
parse_float_list(fov_list, NUM_SKILL_LEVELS);
for (i = 0; i < NUM_SKILL_LEVELS; i++)
{
//Enforce range
if (fov_list[i] < 0.0f || fov_list[i] >= 360.0f)
{
Warning(LOCATION, "$Player Autoaim FOV should be >= 0 and < 360.0 (read %f). Setting to 0.", fov_list[i]);
fov_list[i] = 0.0f;
}
//Convert units
profile->player_autoaim_fov[i] = fov_list[i] * PI / 180.0f;
}
}
if (optional_string("$Detail Distance Multiplier:"))
parse_float_list(profile->detail_distance_mult, NUM_SKILL_LEVELS);
set_flag(profile, "$big ships can attack beam turrets on untargeted ships:", AIPF_BIG_SHIPS_CAN_ATTACK_BEAM_TURRETS_ON_UNTARGETED_SHIPS, AIP_FLAG);
set_flag(profile, "$smart primary weapon selection:", AIPF_SMART_PRIMARY_WEAPON_SELECTION, AIP_FLAG);
set_flag(profile, "$smart secondary weapon selection:", AIPF_SMART_SECONDARY_WEAPON_SELECTION, AIP_FLAG);
set_flag(profile, "$smart shield management:", AIPF_SMART_SHIELD_MANAGEMENT, AIP_FLAG);
set_flag(profile, "$smart afterburner management:", AIPF_SMART_AFTERBURNER_MANAGEMENT, AIP_FLAG);
set_flag(profile, "$allow rapid secondary dumbfire:", AIPF_ALLOW_RAPID_SECONDARY_DUMBFIRE, AIP_FLAG);
set_flag(profile, "$huge turret weapons ignore bombs:", AIPF_HUGE_TURRET_WEAPONS_IGNORE_BOMBS, AIP_FLAG);
set_flag(profile, "$don't insert random turret fire delay:", AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY, AIP_FLAG);
set_flag(profile, "$hack improve non-homing swarm turret fire accuracy:", AIPF_HACK_IMPROVE_NON_HOMING_SWARM_TURRET_FIRE_ACCURACY, AIP_FLAG);
set_flag(profile, "$shockwaves damage small ship subsystems:", AIPF_SHOCKWAVES_DAMAGE_SMALL_SHIP_SUBSYSTEMS, AIP_FLAG);
set_flag(profile, "$navigation subsystem governs warpout capability:", AIPF_NAVIGATION_SUBSYS_GOVERNS_WARP, AIP_FLAG);
set_flag(profile, "$ignore lower bound for minimum speed of docked ship:", AIPF_NO_MIN_DOCK_SPEED_CAP, AIP_FLAG);
set_flag(profile, "$disable linked fire penalty:", AIPF_DISABLE_LINKED_FIRE_PENALTY, AIP_FLAG);
set_flag(profile, "$disable weapon damage scaling:", AIPF_DISABLE_WEAPON_DAMAGE_SCALING, AIP_FLAG);
set_flag(profile, "$use additive weapon velocity:", AIPF_USE_ADDITIVE_WEAPON_VELOCITY, AIP_FLAG);
set_flag(profile, "$use newtonian dampening:", AIPF_USE_NEWTONIAN_DAMPENING, AIP_FLAG);
set_flag(profile, "$include beams for kills and assists:", AIPF_INCLUDE_BEAMS_IN_STAT_CALCS, AIP_FLAG);
set_flag(profile, "$score kills based on damage caused:", AIPF_KILL_SCORING_SCALES_WITH_DAMAGE, AIP_FLAG);
set_flag(profile, "$score assists based on damage caused:", AIPF_ASSIST_SCORING_SCALES_WITH_DAMAGE, AIP_FLAG);
set_flag(profile, "$allow event and goal scoring in multiplayer:", AIPF_ALLOW_MULTI_EVENT_SCORING, AIP_FLAG);
set_flag(profile, "$fix linked primary weapon decision bug:", AIPF_FIX_LINKED_PRIMARY_BUG, AIP_FLAG);
set_flag(profile, "$prevent turrets targeting too distant bombs:", AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE, AIP_FLAG);
set_flag(profile, "$smart subsystem targeting for turrets:", AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS, AIP_FLAG);
set_flag(profile, "$fix heat seekers homing on stealth ships bug:", AIPF_FIX_HEAT_SEEKER_STEALTH_BUG, AIP_FLAG);
set_flag(profile, "$multi allow empty primaries:", AIPF_MULTI_ALLOW_EMPTY_PRIMARIES, AIP_FLAG);
set_flag(profile, "$multi allow empty secondaries:", AIPF_MULTI_ALLOW_EMPTY_SECONDARIES, AIP_FLAG);
set_flag(profile, "$allow turrets target weapons freely:", AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY, AIP_FLAG);
set_flag(profile, "$use only single fov for turrets:", AIPF_USE_ONLY_SINGLE_FOV_FOR_TURRETS, AIP_FLAG);
set_flag(profile, "$allow vertical dodge:", AIPF_ALLOW_VERTICAL_DODGE, AIP_FLAG);
set_flag(profile, "$force beam turrets to use normal fov:", AIPF_FORCE_BEAM_TURRET_FOV, AIP_FLAG);
set_flag(profile, "$fix ai class bug:", AIPF_FIX_AI_CLASS_BUG, AIP_FLAG);
set_flag(profile, "$turrets ignore targets radius in range checks:", AIPF2_TURRETS_IGNORE_TARGET_RADIUS, AIP_FLAG2);
set_flag(profile, "$no extra collision avoidance vs player:", AIPF2_NO_SPECIAL_PLAYER_AVOID, AIP_FLAG2);
set_flag(profile, "$perform fewer checks for death screams:", AIPF2_PERFORM_FEWER_SCREAM_CHECKS, AIP_FLAG2);
set_flag(profile, "$advanced turret fov edge checks:", AIPF2_ADVANCED_TURRET_FOV_EDGE_CHECKS, AIP_FLAG2);
set_flag(profile, "$require turrets to have target in fov:", AIPF2_REQUIRE_TURRET_TO_HAVE_TARGET_IN_FOV, AIP_FLAG2);
set_flag(profile, "$all ships manage shields:", AIPF2_ALL_SHIPS_MANAGE_SHIELDS, AIP_FLAG2);
set_flag(profile, "$ai aims from ship center:", AIPF2_AI_AIMS_FROM_SHIP_CENTER, AIP_FLAG2);
set_flag(profile, "$allow primary link at mission start:", AIPF2_ALLOW_PRIMARY_LINK_AT_START, AIP_FLAG2);
set_flag(profile, "$allow beams to damage bombs:", AIPF2_BEAMS_DAMAGE_WEAPONS, AIP_FLAG2);
set_flag(profile, "$disable weapon damage scaling for player:", AIPF2_PLAYER_WEAPON_SCALE_FIX, AIP_FLAG2);
set_flag(profile, "$countermeasures affect aspect seekers:", AIPF2_ASPECT_LOCK_COUNTERMEASURE, AIP_FLAG2);
set_flag(profile, "$ai guards specific ship in wing:", AIPF2_AI_GUARDS_SPECIFIC_SHIP_IN_WING, AIP_FLAG2);
profile->ai_path_mode = AI_PATH_MODE_NORMAL;
if (optional_string("$ai path mode:"))
{
stuff_string(buf, F_NAME, NAME_LENGTH);
int j = ai_path_type_match(buf);
if (j >= 0) {
profile->ai_path_mode = j;
}
else {
Warning(LOCATION, "Invalid ai path mode '%s' specified", buf);
}
}
set_flag(profile, "$no warp camera:", AIPF2_NO_WARP_CAMERA, AIP_FLAG2);
set_flag(profile, "$fix ai path order bug:", AIPF2_FIX_AI_PATH_ORDER_BUG, AIP_FLAG2);
set_flag(profile, "$strict turret-tagged-only targeting:", AIPF2_STRICT_TURRET_TAGGED_ONLY_TARGETING, AIP_FLAG2);
// ----------
profile->bay_arrive_speed_mult = 1.0f;
profile->bay_depart_speed_mult = 1.0f;
if (optional_string("$bay arrive start speed multiplier:")) {
stuff_float(&profile->bay_arrive_speed_mult);
}
if (optional_string("$bay depart end speed multiplier:")) {
stuff_float(&profile->bay_depart_speed_mult);
}
// ----------
// compatibility
if (optional_string("$perform less checks for death screams:"))
{
mprintf(("Warning: \"$perform less checks for death screams\" flag is deprecated in favor of \"$perform fewer checks for death screams\"\n"));
bool temp;
stuff_boolean(&temp);
if (temp)
profile->flags2 |= AIPF2_PERFORM_FEWER_SCREAM_CHECKS;
else
profile->flags2 &= ~AIPF2_PERFORM_FEWER_SCREAM_CHECKS;
// compatibility
if (optional_string("$perform less checks for death screams:"))
{
mprintf(("Warning: \"$perform less checks for death screams\" flag is deprecated in favor of \"$perform fewer checks for death screams\"\n"));
bool temp;
stuff_boolean(&temp);
if (temp)
profile->flags2 |= AIPF2_PERFORM_FEWER_SCREAM_CHECKS;
else
profile->flags2 &= ~AIPF2_PERFORM_FEWER_SCREAM_CHECKS;
}
if (optional_string("$allow primary link delay:"))
{
mprintf(("Warning: \"$allow primary link delay\" flag is deprecated in favor of \"$allow primary link at mission start\"\n"));
bool temp;
stuff_boolean(&temp);
if (temp)
profile->flags2 &= ~AIPF2_ALLOW_PRIMARY_LINK_AT_START;
else
profile->flags2 |= AIPF2_ALLOW_PRIMARY_LINK_AT_START;
}
// if we've been through once already and are at the same place, force a move
if (saved_Mp && (saved_Mp == Mp))
{
char tmp[60];
memset(tmp, 0, 60);
strncpy(tmp, Mp, 59);
mprintf(("WARNING: Unrecognized parameter in ai_profiles: %s\n", tmp));
Mp++;
}
// find next valid option
skip_to_start_of_string_either("$", "#");
saved_Mp = Mp;
}
if (optional_string("$allow primary link delay:"))
{
mprintf(("Warning: \"$allow primary link delay\" flag is deprecated in favor of \"$allow primary link at mission start\"\n"));
bool temp;
stuff_boolean(&temp);
if (temp)
profile->flags2 &= ~AIPF2_ALLOW_PRIMARY_LINK_AT_START;
else
profile->flags2 |= AIPF2_ALLOW_PRIMARY_LINK_AT_START;
}
// if we've been through once already and are at the same place, force a move
if ( saved_Mp && (saved_Mp == Mp) )
{
char tmp[60];
memset(tmp, 0, 60);
strncpy(tmp, Mp, 59);
mprintf(("WARNING: Unrecognized parameter in ai_profiles: %s\n", tmp));
Mp++;
}
// find next valid option
skip_to_start_of_string_either("$", "#");
saved_Mp = Mp;
}
required_string("#End");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", (filename) ? filename : "<default ai_profiles.tbl>", e.what()));
return;
}
required_string("#End");
// add tbl/tbm to multiplayer validation list
extern void fs2netd_add_table_validation(const char *tblname);
+5
View File
@@ -151,6 +151,11 @@ typedef struct ai_profile_t {
int ai_path_mode;
// Ships flying bay paths will gradually accelerate/decelerate instead of
// flying the whole path at max speed
float bay_arrive_speed_mult;
float bay_depart_speed_mult;
} ai_profile_t;
+56 -9
View File
@@ -826,13 +826,14 @@ LOCAL int ai_inited = 0;
void ai_init()
{
if ( !ai_inited ) {
// Do the first time initialization stuff here
int rval;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "ai.tbl", rval));
} else {
parse_aitbl();
// Do the first time initialization stuff here
try
{
parse_aitbl();
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "ai.tbl", e.what()));
}
ai_inited = 1;
@@ -4010,11 +4011,57 @@ float ai_path_1()
dot_to_next = vm_vec_dot_to_point(&nvel_vec, &Pl_objp->pos, &gnvp);
// This path mode respects the "cap-waypoint-speed" SEXP
float max_allowed_speed = 0;
float max_allowed_speed = 0.0f;
if ( aip->waypoint_speed_cap > 0) {
max_allowed_speed = (float) aip->waypoint_speed_cap;
}
// Maybe gradually ramp up/down the speed of a ship flying a fighterbay path
if (aip->mode == AIM_BAY_EMERGE || (aip->mode == AIM_BAY_DEPART && aip->path_cur != aip->path_start)) {
SCP_string pathName(pm->paths[Path_points[aip->path_start].path_num].name);
ship_info *gsip = &Ship_info[gshipp->ship_info_index];
float speed_mult = 1.0f;
if (aip->mode == AIM_BAY_EMERGE) { // Arriving
if (gsip->pathMetadata.find(pathName) != gsip->pathMetadata.end()) {
speed_mult = gsip->pathMetadata[pathName].arrive_speed_mult;
}
if (speed_mult == FLT_MIN) {
speed_mult = The_mission.ai_profile->bay_arrive_speed_mult;
}
} else { // Departing
if (gsip->pathMetadata.find(pathName) != gsip->pathMetadata.end()) {
speed_mult = gsip->pathMetadata[pathName].depart_speed_mult;
}
if (speed_mult == FLT_MIN) {
speed_mult = The_mission.ai_profile->bay_depart_speed_mult;
}
}
if (speed_mult != 1.0f) {
// We use the distance between the first and last point on the path here; it's not accurate
// if the path is not straight, but should be good enough usually; can be changed if necessary.
float total_path_length = vm_vec_dist_quick(&Path_points[aip->path_start].pos, &Path_points[aip->path_start + num_points - 1].pos);
float dist_to_end;
if (aip->mode == AIM_BAY_EMERGE) { // Arriving
dist_to_end = vm_vec_dist_quick(&Pl_objp->pos, &Path_points[aip->path_start].pos);
} else { // Departing
dist_to_end = vm_vec_dist_quick(&Pl_objp->pos, &Path_points[aip->path_start + num_points - 1].pos);
}
// Calculate max speed, but respect the waypoint speed cap if it's lower
float max_bay_speed = sip->max_speed * (speed_mult + (1.0f - speed_mult) * (dist_to_end / total_path_length));
if (max_allowed_speed == 0.0f) {
max_allowed_speed = max_bay_speed;
} else {
max_allowed_speed = MIN(max_allowed_speed, max_bay_speed);
}
}
}
set_accel_for_docking(Pl_objp, aip, dot, dot_to_next, dist_to_next, dist_to_goal, sip, max_allowed_speed);
aip->prev_dot_to_goal = dot;
@@ -7582,7 +7629,7 @@ void update_aspect_lock_information(ai_info *aip, vec3d *vec_to_enemy, float dis
wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];
if (num_weapon_types && (wip->wi_flags & WIF_LOCKED_HOMING)) {
if (num_weapon_types && (wip->wi_flags & WIF_LOCKED_HOMING) && !(shipp->flags2 & SF2_NO_SECONDARY_LOCKON)) {
if (dist_to_enemy > 300.0f - MIN(enemy_radius, 100.0f))
aip->ai_flags |= AIF_SEEK_LOCK;
else
+124 -119
View File
@@ -1887,143 +1887,148 @@ that is being protected.
void asteroid_parse_tbl()
{
char impact_ani_file[MAX_FILENAME_LEN];
int rval;
// How did we get here without having any species defined?
Assertion(Species_info.size() > 0,
"Cannot parse asteroids/debris if there "
"are no species for them to belong to."
);
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "asteroid.tbl", rval));
return;
}
read_file_text("asteroid.tbl", CF_TYPE_TABLES);
reset_parse();
required_string("#Asteroid Types");
int tally = 0;
int max_asteroids =
NUM_DEBRIS_SIZES + Species_info.size() * NUM_DEBRIS_SIZES;
#ifndef NDEBUG
SCP_vector<SCP_string> parsed_asteroids;
#endif
// parse and tally each asteroid
while (required_string_either("#End","$Name:"))
try
{
asteroid_info new_asteroid;
read_file_text("asteroid.tbl", CF_TYPE_TABLES);
reset_parse();
asteroid_parse_section( &new_asteroid );
required_string("#Asteroid Types");
int tally = 0;
int max_asteroids =
NUM_DEBRIS_SIZES + Species_info.size() * NUM_DEBRIS_SIZES;
int species = tally / NUM_DEBRIS_SIZES;
if (tally >= max_asteroids)
{
#ifdef NDEBUG
// Bump the warning count in release so they get something
// even if the message never gets displayed.
Warning(LOCATION, "Ignoring extra asteroid/debris");
#else
SCP_string msg("Ignoring extra asteroid/debris '");
msg.append(new_asteroid.name);
msg.append("'\n");
Warning(LOCATION,msg.c_str());
parsed_asteroids.push_back(msg);
#endif
}
else
{
#ifndef NDEBUG
SCP_string msg;
msg.append("Parsing asteroid: '");
msg.append(new_asteroid.name);
msg.append("' as a '");
msg.append((species == 0)?"generic":Species_info[species-1].species_name);
msg.append("'");
switch(tally % NUM_DEBRIS_SIZES) {
case ASTEROID_TYPE_SMALL:
msg.append(" small\n");
break;
case ASTEROID_TYPE_MEDIUM:
msg.append(" medium\n");
break;
case ASTEROID_TYPE_LARGE:
msg.append(" large\n");
break;
default:
Error(LOCATION, "Get a coder! Math has broken!\n"
"Important numbers:\n"
"\ttally: %d\n"
"\tNUM_DEBRIS_SIZES: %d\n",
tally, NUM_DEBRIS_SIZES
);
msg.append(" unknown\n");
SCP_vector<SCP_string> parsed_asteroids;
#endif
// parse and tally each asteroid
while (required_string_either("#End", "$Name:"))
{
asteroid_info new_asteroid;
asteroid_parse_section(&new_asteroid);
int species = tally / NUM_DEBRIS_SIZES;
if (tally >= max_asteroids)
{
#ifdef NDEBUG
// Bump the warning count in release so they get something
// even if the message never gets displayed.
Warning(LOCATION, "Ignoring extra asteroid/debris");
#else
SCP_string msg("Ignoring extra asteroid/debris '");
msg.append(new_asteroid.name);
msg.append("'\n");
Warning(LOCATION, msg.c_str());
parsed_asteroids.push_back(msg);
#endif
}
parsed_asteroids.push_back(msg);
#endif
Asteroid_info.push_back(new_asteroid);
}
tally++;
}
required_string("#End");
if (tally != max_asteroids)
{
else
{
#ifndef NDEBUG
for(SCP_vector<SCP_string>::iterator iter = parsed_asteroids.begin();
iter != parsed_asteroids.end(); ++iter)
{
mprintf(("Asteroid.tbl as parsed:\n"));
mprintf((iter->c_str()));
SCP_string msg;
msg.append("Parsing asteroid: '");
msg.append(new_asteroid.name);
msg.append("' as a '");
msg.append((species == 0) ? "generic" : Species_info[species - 1].species_name);
msg.append("'");
switch (tally % NUM_DEBRIS_SIZES) {
case ASTEROID_TYPE_SMALL:
msg.append(" small\n");
break;
case ASTEROID_TYPE_MEDIUM:
msg.append(" medium\n");
break;
case ASTEROID_TYPE_LARGE:
msg.append(" large\n");
break;
default:
Error(LOCATION, "Get a coder! Math has broken!\n"
"Important numbers:\n"
"\ttally: %d\n"
"\tNUM_DEBRIS_SIZES: %d\n",
tally, NUM_DEBRIS_SIZES
);
msg.append(" unknown\n");
}
parsed_asteroids.push_back(msg);
#endif
Asteroid_info.push_back(new_asteroid);
}
tally++;
}
required_string("#End");
if (tally != max_asteroids)
{
#ifndef NDEBUG
for (SCP_vector<SCP_string>::iterator iter = parsed_asteroids.begin();
iter != parsed_asteroids.end(); ++iter)
{
mprintf(("Asteroid.tbl as parsed:\n"));
mprintf((iter->c_str()));
}
#endif
Error(LOCATION,
"Found %d asteroids/debris when %d expected\n\n"
"<Number expected> = <Number of species> * %d + %d generic asteroids\n"
"%d = %d*%d + %d\n\n"
Error(LOCATION,
"Found %d asteroids/debris when %d expected\n\n"
"<Number expected> = <Number of species> * %d + %d generic asteroids\n"
"%d = %d*%d + %d\n\n"
#ifdef NDEBUG
"Run a debug build to see a list of all parsed asteroids\n",
"Run a debug build to see a list of all parsed asteroids\n",
#else
"See the debug.log for a listing of all parsed asteroids\n",
"See the debug.log for a listing of all parsed asteroids\n",
#endif
tally, max_asteroids,
NUM_DEBRIS_SIZES, NUM_DEBRIS_SIZES,
max_asteroids, Species_info.size(), NUM_DEBRIS_SIZES, NUM_DEBRIS_SIZES
);
tally, max_asteroids,
NUM_DEBRIS_SIZES, NUM_DEBRIS_SIZES,
max_asteroids, Species_info.size(), NUM_DEBRIS_SIZES, NUM_DEBRIS_SIZES
);
}
Asteroid_impact_explosion_ani = -1;
required_string("$Impact Explosion:");
stuff_string(impact_ani_file, F_NAME, MAX_FILENAME_LEN);
if (VALID_FNAME(impact_ani_file)) {
int num_frames;
Asteroid_impact_explosion_ani = bm_load_animation(impact_ani_file, &num_frames, NULL, NULL, 1);
}
required_string("$Impact Explosion Radius:");
stuff_float(&Asteroid_impact_explosion_radius);
if (optional_string("$Briefing Icon Closeup Model:")) {
stuff_string(Asteroid_icon_closeup_model, F_NAME, NAME_LENGTH);
}
else {
strcpy_s(Asteroid_icon_closeup_model, Asteroid_info[ASTEROID_TYPE_LARGE].pof_files[0]); // magic file from retail
}
if (optional_string("$Briefing Icon Closeup Position:")) {
stuff_vec3d(&Asteroid_icon_closeup_position);
}
else {
vm_vec_make(&Asteroid_icon_closeup_position, 0.0f, 0.0f, -334.0f); // magic numbers from retail
}
if (optional_string("$Briefing Icon Closeup Zoom:")) {
stuff_float(&Asteroid_icon_closeup_zoom);
}
else {
Asteroid_icon_closeup_zoom = 0.5f; // magic number from retail
}
}
Asteroid_impact_explosion_ani = -1;
required_string("$Impact Explosion:");
stuff_string(impact_ani_file, F_NAME, MAX_FILENAME_LEN);
if ( VALID_FNAME(impact_ani_file) ) {
int num_frames;
Asteroid_impact_explosion_ani = bm_load_animation( impact_ani_file, &num_frames, NULL, NULL, 1);
}
required_string("$Impact Explosion Radius:");
stuff_float(&Asteroid_impact_explosion_radius);
if (optional_string("$Briefing Icon Closeup Model:")) {
stuff_string(Asteroid_icon_closeup_model, F_NAME, NAME_LENGTH);
} else {
strcpy_s(Asteroid_icon_closeup_model, Asteroid_info[ASTEROID_TYPE_LARGE].pof_files[0]); // magic file from retail
}
if (optional_string("$Briefing Icon Closeup Position:")) {
stuff_vec3d(&Asteroid_icon_closeup_position);
} else {
vm_vec_make(&Asteroid_icon_closeup_position, 0.0f, 0.0f, -334.0f); // magic numbers from retail
}
if (optional_string("$Briefing Icon Closeup Zoom:")) {
stuff_float(&Asteroid_icon_closeup_zoom);
} else {
Asteroid_icon_closeup_zoom = 0.5f; // magic number from retail
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "asteroid.tbl", e.what()));
return;
}
}
+58 -57
View File
@@ -1271,68 +1271,69 @@ void NavSystem_Init()
void parse_autopilot_table(char *filename)
{
int rval;
SCP_vector<SCP_string> lines;
if ((rval = setjmp(parse_abort)) != 0)
try
{
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", (filename) ? filename : "<default autopilot.tbl>", rval));
if (filename == NULL)
read_file_text_from_array(defaults_get_file("autopilot.tbl"));
else
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
required_string("#Autopilot");
// autopilot link distance
required_string("$Link Distance:");
stuff_int(&NavLinkDistance);
if (optional_string("$Interrupt autopilot if enemy within distance:"))
stuff_int(&AutopilotMinEnemyDistance);
else
AutopilotMinEnemyDistance = 5000;
if (optional_string("$Interrupt autopilot if asteroid within distance:"))
stuff_int(&AutopilotMinAsteroidDistance);
else
AutopilotMinAsteroidDistance = 1000;
if (optional_string("$Lock Weapons During Autopilot:"))
stuff_boolean(&LockWeaponsDuringAutopilot);
else
LockWeaponsDuringAutopilot = false;
// optional no cutscene bars
if (optional_string("+No_Cutscene_Bars"))
UseCutsceneBars = false;
// optional no cutscene bars
if (optional_string("+No_Autopilot_Interrupt"))
Cmdline_autopilot_interruptable = 0;
// No Nav selected message
char *msg_tags[] = { "$No Nav Selected:", "$Gliding:",
"$Too Close:", "$Hostiles:", "$Linked:", "$Hazard:",
"$Support Present:", "$Support Working:" };
for (int i = 0; i < NP_NUM_MESSAGES; i++)
{
required_string(msg_tags[i]);
required_string("+Msg:");
stuff_string(NavMsgs[i].message, F_MESSAGE, 256);
required_string("+Snd File:");
stuff_string(NavMsgs[i].filename, F_NAME, 256);
}
required_string("#END");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", (filename) ? filename : "<default autopilot.tbl>", e.what()));
return;
}
if (filename == NULL)
read_file_text_from_array(defaults_get_file("autopilot.tbl"));
else
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
required_string("#Autopilot");
// autopilot link distance
required_string("$Link Distance:");
stuff_int(&NavLinkDistance);
if (optional_string("$Interrupt autopilot if enemy within distance:"))
stuff_int(&AutopilotMinEnemyDistance);
else
AutopilotMinEnemyDistance = 5000;
if (optional_string("$Interrupt autopilot if asteroid within distance:"))
stuff_int(&AutopilotMinAsteroidDistance);
else
AutopilotMinAsteroidDistance = 1000;
if (optional_string("$Lock Weapons During Autopilot:"))
stuff_boolean(&LockWeaponsDuringAutopilot);
else
LockWeaponsDuringAutopilot = false;
// optional no cutscene bars
if (optional_string("+No_Cutscene_Bars"))
UseCutsceneBars = false;
// optional no cutscene bars
if (optional_string("+No_Autopilot_Interrupt"))
Cmdline_autopilot_interruptable = 0;
// No Nav selected message
char *msg_tags[] = { "$No Nav Selected:", "$Gliding:",
"$Too Close:", "$Hostiles:", "$Linked:", "$Hazard:",
"$Support Present:", "$Support Working:" };
for (int i = 0; i < NP_NUM_MESSAGES; i++)
{
required_string(msg_tags[i]);
required_string("+Msg:");
stuff_string(NavMsgs[i].message, F_MESSAGE, 256);
required_string("+Snd File:");
stuff_string(NavMsgs[i].filename, F_NAME, 256);
}
required_string("#END");
}
+1
View File
@@ -63,6 +63,7 @@ union bm_extra_info {
// stuff for static animations
ubyte type; //!< type for individual images
char filename[MAX_FILENAME_LEN]; //!< filename for individual images
bool in_subdir; // Whether frames are in their own subdirectory
} eff;
} ani;
+22 -19
View File
@@ -1027,7 +1027,7 @@ int bm_load(const SCP_string& filename) {
}
int bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, ubyte *type) {
int frames = 0, fps = 30, keyframe = 0, rval;
int frames = 0, fps = 30, keyframe = 0;
char ext[8];
ubyte c_type = BM_TYPE_NONE;
char file_text[1024];
@@ -1040,28 +1040,31 @@ int bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
// pause anything that may happen to be parsing right now
pause_parse();
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("BMPMAN: Unable to parse '%s'! Error code = %i.\n", filename, rval));
try
{
// now start parsing the EFF
read_file_text(filename, dir_type, file_text, file_text_raw);
reset_parse(file_text);
required_string("$Type:");
stuff_string(ext, F_NAME, sizeof(ext));
required_string("$Frames:");
stuff_int(&frames);
if (optional_string("$FPS:"))
stuff_int(&fps);
if (optional_string("$Keyframe:"))
stuff_int(&keyframe);
}
catch (const parse::ParseException& e)
{
mprintf(("BMPMAN: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
unpause_parse();
return -1;
}
// now start parsing the EFF
read_file_text(filename, dir_type, file_text, file_text_raw);
reset_parse(file_text);
required_string("$Type:");
stuff_string(ext, F_NAME, sizeof(ext));
required_string("$Frames:");
stuff_int(&frames);
if (optional_string("$FPS:"))
stuff_int(&fps);
if (optional_string("$Keyframe:"))
stuff_int(&keyframe);
// done with EFF so unpause parsing so whatever can continue
unpause_parse();
+11 -5
View File
@@ -415,6 +415,11 @@ void bm_get_frame_usage(int *ntotal, int *nnew);
*/
int bm_reload(int bitmap_handle, const char* filename);
/**
* @brief Stuffs Pathtypes with an additional path leading to a subdir of the same name as the given file (minus file extension)
*/
bool set_temp_subdir_pathtype(const char *filename);
/**
* @brief Tells bmpman to start keeping track of what bitmaps are used where
*/
@@ -622,16 +627,17 @@ int bm_set_render_target(int handle, int face = -1);
*
* @param[in] filename The filename of the .EFF
* @param[in] dir_type
* @param[out] nframes (optional) If given, is set to the number of frames this .EFF has
* @param[out] nfps (optional) If given, is set to the fps of this .EFF
* @param[out] key (optional) If given, is set to the keyframe index of this .EFF
* @param[out] type (optional) If given, is set to the BM_TYPE of the .EFF
* @param[out] nframes (optional) If given, is set to the number of frames this .EFF has
* @param[out] nfps (optional) If given, is set to the fps of this .EFF
* @param[out] key (optional) If given, is set to the keyframe index of this .EFF
* @param[out] type (optional) If given, is set to the BM_TYPE of the .EFF
* @param[out] in_subdir (optional) If given, is set to true if the frames of this .EFF are in a subdir
*
* @returns 0 If successful,
* @returns -1 if not successful
*
* @todo retval should be a bool
*/
int bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, ubyte *type);
int bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, ubyte *type, bool *in_subdir);
#endif
+1
View File
@@ -86,6 +86,7 @@ cf_pathtype Pathtypes[CF_MAX_PATH_TYPES] = {
{ CF_TYPE_INTEL_ANIMS, "data" DIR_SEPARATOR_STR "intelanims", ".pcx .ani .eff .tga .jpg .png .dds", CF_TYPE_DATA },
{ CF_TYPE_SCRIPTS, "data" DIR_SEPARATOR_STR "scripts", ".lua .lc", CF_TYPE_DATA },
{ CF_TYPE_FICTION, "data" DIR_SEPARATOR_STR "fiction", ".txt", CF_TYPE_DATA },
{ CF_TYPE_TEMP_SUBDIR_LOOKUP, "", ".eff", CF_TYPE_DATA },
};
+2 -1
View File
@@ -78,8 +78,9 @@ typedef struct {
#define CF_TYPE_INTEL_ANIMS 34
#define CF_TYPE_SCRIPTS 35
#define CF_TYPE_FICTION 36
#define CF_TYPE_TEMP_SUBDIR_LOOKUP 37
#define CF_MAX_PATH_TYPES 37 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
#define CF_MAX_PATH_TYPES 38 // Can be as high as you'd like //DTP; yeah but beware alot of things uses CF_MAX_PATH_TYPES
// TRUE if type is specified and valid
+1
View File
@@ -901,6 +901,7 @@ int cf_find_file_location( const char *filespec, int pathtype, int max_out, char
case CF_TYPE_MULTI_CACHE:
case CF_TYPE_MISSIONS:
case CF_TYPE_CACHE:
case CF_TYPE_TEMP_SUBDIR_LOOKUP:
cfs_slow_search = 1;
break;
+45 -6
View File
@@ -956,9 +956,9 @@ void control_config_reset_defaults(int presetnum)
// Reset keyboard defaults
for (i=0; i<CCFG_MAX; i++) {
// Note that key_default and joy_default are NOT overwritten here;
// they should retain the values of the first preset because
// for example the key-pressed SEXP works off the defaults of the first preset
// Note that key_default, joy_default and text_default are NOT
// overwritten here; they should retain the values of the first preset
Control_config[i].text = preset[i].text;
Control_config[i].key_id = preset[i].key_default;
Control_config[i].joy_id = preset[i].joy_default;
Control_config[i].tab = preset[i].tab;
@@ -2107,6 +2107,45 @@ void control_config_do_frame(float frametime)
List_buttons[i++].disable();
}
// If multiple controls presets are provided, display which one is in use
if (Control_config_presets.size() > 1) {
SCP_string preset_str;
int matching_preset = -1;
for (i=0; i<(int)Control_config_presets.size(); i++) {
bool this_preset_matches = true;
config_item *this_preset = Control_config_presets[i];
for (int j=0; j<CCFG_MAX; j++) {
if (!Control_config[j].disabled && Control_config[j].key_id != this_preset[j].key_default) {
this_preset_matches = false;
break;
}
}
if (this_preset_matches) {
matching_preset = i;
break;
}
}
if (matching_preset >= 0) {
sprintf(preset_str, "Controls: %s", Control_config_preset_names[matching_preset].c_str());
} else {
sprintf(preset_str, "Controls: custom");
}
gr_get_string_size(&w, NULL, preset_str.c_str());
gr_set_color_fast(&Color_text_normal);
if (gr_screen.res == GR_640) {
gr_string(16, (24 - font_height) / 2, preset_str.c_str(), GR_RESIZE_MENU);
} else {
gr_string(24, (40 - font_height) / 2, preset_str.c_str(), GR_RESIZE_MENU);
}
}
// blit help overlay if active
help_overlay_maybe_blit(Control_config_overlay_id, gr_screen.res);
@@ -2207,11 +2246,11 @@ int check_control_used(int id, int key)
// check what current modifiers are pressed
mask = 0;
if (keyd_pressed[KEY_LSHIFT] || key_down_count(KEY_LSHIFT) || keyd_pressed[KEY_RSHIFT] || key_down_count(KEY_RSHIFT)) {
if (keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT]) {
mask |= KEY_SHIFTED;
}
if (keyd_pressed[KEY_LALT] || key_down_count(KEY_LALT) || keyd_pressed[KEY_RALT] || key_down_count(KEY_RALT)) {
if (keyd_pressed[KEY_LALT] || keyd_pressed[KEY_RALT]) {
mask |= KEY_ALTED;
}
@@ -2226,7 +2265,7 @@ int check_control_used(int id, int key)
z &= KEY_MASK;
if (keyd_pressed[z] || key_down_count(z)) {
if (keyd_pressed[z]) {
control_used(id);
return 1;
}
+3 -1
View File
@@ -63,13 +63,14 @@ typedef struct config_item {
short joy_default; //!< default joystick button bound to action
char tab; //!< what tab (category) it belongs in
bool hasXSTR; //!< whether we should translate this with an XSTR
char *text; //!< describes the action in the config screen
char *default_text; //!< default description of the action
char type; //!< manner control should be checked in
short key_id; //!< actual key bound to action
short joy_id; //!< joystick button bound to action
int used; //!< has control been used yet in mission? If so, this is the timestamp
bool disabled; //!< whether this action should be available at all
bool continuous_ongoing;//!< whether this action is a continuous one and is currently ongoing
char *text; //!< overridable description of the action
} config_item;
/*!
@@ -292,6 +293,7 @@ extern int Control_config_overlay_id;
extern config_item Control_config[]; //!< Stores the keyboard configuration
extern SCP_vector<config_item*> Control_config_presets; // tabled control presets; pointers to config_item arrays
extern SCP_vector<SCP_string> Control_config_preset_names; // names for Control_config_presets (identical order of items)
extern char **Scan_code_text;
extern char **Joy_button_text;
+137 -120
View File
@@ -45,153 +45,153 @@ int Invert_axis_defaults[JOY_NUM_AXES] = { 0, 0, 0, 0, 0, 0 };
//XSTR:OFF
config_item Control_config[CCFG_MAX + 1] = {
// targeting a ship
{ KEY_T, -1, TARGET_TAB, true, "Target Next Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_T, -1, TARGET_TAB, true, "Target Previous Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_H, 2, TARGET_TAB, true, "Target Next Closest Hostile Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_H, -1, TARGET_TAB, true, "Target Previous Closest Hostile Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_H, -1, TARGET_TAB, true, "Toggle Auto Targeting", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_F, -1, TARGET_TAB, true, "Target Next Closest Friendly Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_F, -1, TARGET_TAB, true, "Target Previous Closest Friendly Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_Y, 4, TARGET_TAB, true, "Target Ship in Reticle", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_G, -1, TARGET_TAB, true, "Target Target's Nearest Attacker", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_Y, -1, TARGET_TAB, true, "Target Last Ship to Send Transmission", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_T, -1, TARGET_TAB, true, "Turn Off Targeting", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_T, -1, TARGET_TAB, true, "Target Next Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_T, -1, TARGET_TAB, true, "Target Previous Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_H, 2, TARGET_TAB, true, "Target Next Closest Hostile Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_H, -1, TARGET_TAB, true, "Target Previous Closest Hostile Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_H, -1, TARGET_TAB, true, "Toggle Auto Targeting", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_F, -1, TARGET_TAB, true, "Target Next Closest Friendly Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_F, -1, TARGET_TAB, true, "Target Previous Closest Friendly Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_Y, 4, TARGET_TAB, true, "Target Ship in Reticle", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_G, -1, TARGET_TAB, true, "Target Target's Nearest Attacker", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_Y, -1, TARGET_TAB, true, "Target Last Ship to Send Transmission", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_T, -1, TARGET_TAB, true, "Turn Off Targeting", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
// targeting a ship's subsystem
{ KEY_V, -1, TARGET_TAB, true, "Target Subsystem in Reticle", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_S, -1, TARGET_TAB, true, "Target Next Subsystem", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_S, -1, TARGET_TAB, true, "Target Previous Subsystem", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_S, -1, TARGET_TAB, true, "Turn Off Targeting of Subsystems", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_V, -1, TARGET_TAB, true, "Target Subsystem in Reticle", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_S, -1, TARGET_TAB, true, "Target Next Subsystem", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_S, -1, TARGET_TAB, true, "Target Previous Subsystem", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_S, -1, TARGET_TAB, true, "Turn Off Targeting of Subsystems", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
// matching speed
{ KEY_M, -1, COMPUTER_TAB, true, "Match Target Speed", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_M, -1, COMPUTER_TAB, true, "Toggle Auto Speed Matching", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_M, -1, COMPUTER_TAB, true, "Match Target Speed", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_M, -1, COMPUTER_TAB, true, "Toggle Auto Speed Matching", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
// weapons
{ KEY_LCTRL, 0, WEAPON_TAB, true, "Fire Primary Weapon", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_SPACEBAR, 1, WEAPON_TAB, true, "Fire Secondary Weapon", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_PERIOD, -1, WEAPON_TAB, true, "Cycle Forward Primary Weapon", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_COMMA, -1, WEAPON_TAB, true, "Cycle Backward Primary Weapon", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_DIVIDE, -1, WEAPON_TAB, true, "Cycle Secondary Weapon Bank", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_DIVIDE, -1, WEAPON_TAB, true, "Cycle Secondary Weapon Firing Rate", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_X, 3, WEAPON_TAB, true, "Launch Countermeasure", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_LCTRL, 0, WEAPON_TAB, true, "Fire Primary Weapon", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_SPACEBAR, 1, WEAPON_TAB, true, "Fire Secondary Weapon", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_PERIOD, -1, WEAPON_TAB, true, "Cycle Forward Primary Weapon", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_COMMA, -1, WEAPON_TAB, true, "Cycle Backward Primary Weapon", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_DIVIDE, -1, WEAPON_TAB, true, "Cycle Secondary Weapon Bank", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_DIVIDE, -1, WEAPON_TAB, true, "Cycle Secondary Weapon Firing Rate", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_X, 3, WEAPON_TAB, true, "Launch Countermeasure", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
// controls
{ KEY_A, -1, SHIP_TAB, true, "Forward Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_Z, -1, SHIP_TAB, true, "Reverse Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_PAD7, -1, SHIP_TAB, true, "Bank Left", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_PAD9, -1, SHIP_TAB, true, "Bank Right", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_PAD8, -1, SHIP_TAB, true, "Pitch Forward", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_PAD2, -1, SHIP_TAB, true, "Pitch Backward", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_PAD4, -1, SHIP_TAB, true, "Turn Left", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_PAD6, -1, SHIP_TAB, true, "Turn Right", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_A, -1, SHIP_TAB, true, "Forward Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_Z, -1, SHIP_TAB, true, "Reverse Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_PAD7, -1, SHIP_TAB, true, "Bank Left", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_PAD9, -1, SHIP_TAB, true, "Bank Right", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_PAD8, -1, SHIP_TAB, true, "Pitch Forward", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_PAD2, -1, SHIP_TAB, true, "Pitch Backward", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_PAD4, -1, SHIP_TAB, true, "Turn Left", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_PAD6, -1, SHIP_TAB, true, "Turn Right", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
// throttle controls
{ KEY_BACKSP, -1, SHIP_TAB, true, "Set Throttle to Zero", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SLASH, -1, SHIP_TAB, true, "Set Throttle to Max", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_LBRACKET, -1, SHIP_TAB, true, "Set Throttle to One-Third", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_RBRACKET, -1, SHIP_TAB, true, "Set Throttle to Two-Thirds", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_EQUAL, -1, SHIP_TAB, true, "Increase Throttle 5 Percent", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_MINUS, -1, SHIP_TAB, true, "Decrease Throttle 5 Percent", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_BACKSP, -1, SHIP_TAB, true, "Set Throttle to Zero", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SLASH, -1, SHIP_TAB, true, "Set Throttle to Max", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_LBRACKET, -1, SHIP_TAB, true, "Set Throttle to One-Third", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_RBRACKET, -1, SHIP_TAB, true, "Set Throttle to Two-Thirds", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_EQUAL, -1, SHIP_TAB, true, "Increase Throttle 5 Percent", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_MINUS, -1, SHIP_TAB, true, "Decrease Throttle 5 Percent", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
// squadmate messaging
{ KEY_SHIFTED | KEY_A, -1, COMPUTER_TAB, true, "Attack My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_Z, -1, COMPUTER_TAB, true, "Disarm My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_D, -1, COMPUTER_TAB, true, "Disable My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_V, -1, COMPUTER_TAB, true, "Attack My Subsystem", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_X, -1, COMPUTER_TAB, true, "Capture My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_E, -1, COMPUTER_TAB, true, "Engage Enemy", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_W, -1, COMPUTER_TAB, true, "Form on My Wing", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_I, -1, COMPUTER_TAB, true, "Ignore My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_P, -1, COMPUTER_TAB, true, "Protect My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_C, -1, COMPUTER_TAB, true, "Cover Me", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_J, -1, COMPUTER_TAB, true, "Return to Base", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_R, -1, COMPUTER_TAB, true, "Rearm Me", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_A, -1, COMPUTER_TAB, true, "Attack My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_Z, -1, COMPUTER_TAB, true, "Disarm My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_D, -1, COMPUTER_TAB, true, "Disable My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_V, -1, COMPUTER_TAB, true, "Attack My Subsystem", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_X, -1, COMPUTER_TAB, true, "Capture My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_E, -1, COMPUTER_TAB, true, "Engage Enemy", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_W, -1, COMPUTER_TAB, true, "Form on My Wing", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_I, -1, COMPUTER_TAB, true, "Ignore My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_P, -1, COMPUTER_TAB, true, "Protect My Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_C, -1, COMPUTER_TAB, true, "Cover Me", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_J, -1, COMPUTER_TAB, true, "Return to Base", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_R, -1, COMPUTER_TAB, true, "Rearm Me", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_R, 6, TARGET_TAB, true, "Target Closest Attacking Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_R, 6, TARGET_TAB, true, "Target Closest Attacking Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
// Views
{ KEY_PADMULTIPLY, -1, COMPUTER_TAB, true, "Chase View", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_PADPERIOD, -1, COMPUTER_TAB, true, "External View", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_PADENTER, -1, COMPUTER_TAB, true, "Toggle External Camera Lock", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_PAD0, -1, COMPUTER_TAB, true, "Free Look View", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false }, // Not in use anymore (Swifty)
{ KEY_PADDIVIDE, -1, COMPUTER_TAB, true, "Current Target View", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_PADPLUS, -1, COMPUTER_TAB, true, "Increase View Distance", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_PADMINUS, -1, COMPUTER_TAB, true, "Decrease View Distance", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_PAD5, -1, COMPUTER_TAB, true, "Center View", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ -1, 33, COMPUTER_TAB, true, "View Up", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ -1, 32, COMPUTER_TAB, true, "View Rear", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ -1, 34, COMPUTER_TAB, true, "View Left", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ -1, 35, COMPUTER_TAB, true, "View Right", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_PADMULTIPLY, -1, COMPUTER_TAB, true, "Chase View", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_PADPERIOD, -1, COMPUTER_TAB, true, "External View", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_PADENTER, -1, COMPUTER_TAB, true, "Toggle External Camera Lock", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_PAD0, -1, COMPUTER_TAB, true, "Free Look View", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL }, // Not in use anymore (Swifty)
{ KEY_PADDIVIDE, -1, COMPUTER_TAB, true, "Current Target View", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_PADPLUS, -1, COMPUTER_TAB, true, "Increase View Distance", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_PADMINUS, -1, COMPUTER_TAB, true, "Decrease View Distance", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_PAD5, -1, COMPUTER_TAB, true, "Center View", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ -1, 33, COMPUTER_TAB, true, "View Up", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ -1, 32, COMPUTER_TAB, true, "View Rear", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ -1, 34, COMPUTER_TAB, true, "View Left", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ -1, 35, COMPUTER_TAB, true, "View Right", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_RAPOSTRO, -1, COMPUTER_TAB, true, "Cycle Radar Range", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_C, -1, COMPUTER_TAB, true, "Communications Menu", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ -1, -1, -1, true, "Show Objectives", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_J, -1, COMPUTER_TAB, true, "Enter Subspace (End Mission)", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_J, -1, TARGET_TAB, true, "Target Target's Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_TAB, 5, SHIP_TAB, true, "Afterburner", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_RAPOSTRO, -1, COMPUTER_TAB, true, "Cycle Radar Range", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_C, -1, COMPUTER_TAB, true, "Communications Menu", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ -1, -1, -1, true, "Show Objectives", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_J, -1, COMPUTER_TAB, true, "Enter Subspace (End Mission)", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_J, -1, TARGET_TAB, true, "Target Target's Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_TAB, 5, SHIP_TAB, true, "Afterburner", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_INSERT, -1, COMPUTER_TAB, true, "Increase Weapon Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_DELETE, -1, COMPUTER_TAB, true, "Decrease Weapon Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_HOME, -1, COMPUTER_TAB, true, "Increase Shield Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_END, -1, COMPUTER_TAB, true, "Decrease Shield Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_PAGEUP, -1, COMPUTER_TAB, true, "Increase Engine Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_PAGEDOWN, -1, COMPUTER_TAB, true, "Decrease Engine Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_D, -1, COMPUTER_TAB, true, "Equalize Energy Settings", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_INSERT, -1, COMPUTER_TAB, true, "Increase Weapon Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_DELETE, -1, COMPUTER_TAB, true, "Decrease Weapon Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_HOME, -1, COMPUTER_TAB, true, "Increase Shield Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_END, -1, COMPUTER_TAB, true, "Decrease Shield Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_PAGEUP, -1, COMPUTER_TAB, true, "Increase Engine Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_PAGEDOWN, -1, COMPUTER_TAB, true, "Decrease Engine Energy", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_D, -1, COMPUTER_TAB, true, "Equalize Energy Settings", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_Q, 7, COMPUTER_TAB, true, "Equalize Shields", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_UP, -1, COMPUTER_TAB, true, "Augment Forward Shield", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_DOWN, -1, COMPUTER_TAB, true, "Augment Rear Shield", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_LEFT, -1, COMPUTER_TAB, true, "Augment Left Shield", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_RIGHT, -1, COMPUTER_TAB, true, "Augment Right Shield", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SCROLLOCK, -1, COMPUTER_TAB, true, "Transfer Energy Laser->Shield", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_SCROLLOCK, -1, COMPUTER_TAB, true, "Transfer Energy Shield->Laser", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_Q, 7, COMPUTER_TAB, true, "Equalize Shields", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_UP, -1, COMPUTER_TAB, true, "Augment Forward Shield", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_DOWN, -1, COMPUTER_TAB, true, "Augment Rear Shield", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_LEFT, -1, COMPUTER_TAB, true, "Augment Left Shield", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_RIGHT, -1, COMPUTER_TAB, true, "Augment Right Shield", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SCROLLOCK, -1, COMPUTER_TAB, true, "Transfer Energy Laser->Shield", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_SCROLLOCK, -1, COMPUTER_TAB, true, "Transfer Energy Shield->Laser", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
// { -1, -1, -1, true, "Show Damage Popup Window" },
{ -1, -1, SHIP_TAB, false, "Glide When Pressed", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ -1, -1, SHIP_TAB, false, "Glide When Pressed", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
//Backslash -- this was a convenient place for Glide When Pressed, as Show Damage Popup isn't used
{ -1, -1, SHIP_TAB, true, "Bank When Pressed", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ -1, -1, -1, true, "Show Nav Map", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_E, -1, COMPUTER_TAB, true, "Add or Remove Escort", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_SHIFTED | KEY_E, -1, COMPUTER_TAB, true, "Clear Escort List", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_E, -1, TARGET_TAB, true, "Target Next Escort Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_R, -1, TARGET_TAB, true, "Target Closest Repair Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ -1, -1, SHIP_TAB, true, "Bank When Pressed", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ -1, -1, -1, true, "Show Nav Map", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_E, -1, COMPUTER_TAB, true, "Add or Remove Escort", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_SHIFTED | KEY_E, -1, COMPUTER_TAB, true, "Clear Escort List", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_E, -1, TARGET_TAB, true, "Target Next Escort Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_R, -1, TARGET_TAB, true, "Target Closest Repair Ship", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_U, -1, TARGET_TAB, true, "Target Next Uninspected Cargo", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_U, -1, TARGET_TAB, true, "Target Previous Uninspected Cargo", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_N, -1, TARGET_TAB, true, "Target Newest Ship in Area", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_K, -1, TARGET_TAB, true, "Target Next Live Turret", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_K, -1, TARGET_TAB, true, "Target Previous Live Turret", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_U, -1, TARGET_TAB, true, "Target Next Uninspected Cargo", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_U, -1, TARGET_TAB, true, "Target Previous Uninspected Cargo", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_N, -1, TARGET_TAB, true, "Target Newest Ship in Area", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_K, -1, TARGET_TAB, true, "Target Next Live Turret", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_K, -1, TARGET_TAB, true, "Target Previous Live Turret", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_B, -1, TARGET_TAB, true, "Target Next Hostile Bomb or Bomber", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_B, -1, TARGET_TAB, true, "Target Previous Hostile Bomb or Bomber", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_B, -1, TARGET_TAB, true, "Target Next Hostile Bomb or Bomber", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_B, -1, TARGET_TAB, true, "Target Previous Hostile Bomb or Bomber", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
// multiplayer messaging keys
{ KEY_1, -1, COMPUTER_TAB, true, "(Multiplayer) Message All", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_2, -1, COMPUTER_TAB, true, "(Multiplayer) Message Friendly", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_3, -1, COMPUTER_TAB, true, "(Multiplayer) Message Hostile", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_4, -1, COMPUTER_TAB, true, "(Multiplayer) Message Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_X, -1, COMPUTER_TAB, true, "(Multiplayer) Observer Zoom to Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_PERIOD, -1, COMPUTER_TAB, true, "Increase Time Compression", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_COMMA, -1, COMPUTER_TAB, true, "Decrease Time Compression", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_L, -1, COMPUTER_TAB, true, "Toggle High HUD Contrast", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_N, -1, COMPUTER_TAB, true, "(Multiplayer) Toggle Network Info", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_END, -1, COMPUTER_TAB, true, "(Multiplayer) Self Destruct", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_1, -1, COMPUTER_TAB, true, "(Multiplayer) Message All", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_2, -1, COMPUTER_TAB, true, "(Multiplayer) Message Friendly", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_3, -1, COMPUTER_TAB, true, "(Multiplayer) Message Hostile", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_4, -1, COMPUTER_TAB, true, "(Multiplayer) Message Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_X, -1, COMPUTER_TAB, true, "(Multiplayer) Observer Zoom to Target", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_PERIOD, -1, COMPUTER_TAB, true, "Increase Time Compression", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_COMMA, -1, COMPUTER_TAB, true, "Decrease Time Compression", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_L, -1, COMPUTER_TAB, true, "Toggle High HUD Contrast", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_N, -1, COMPUTER_TAB, true, "(Multiplayer) Toggle Network Info", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_END, -1, COMPUTER_TAB, true, "(Multiplayer) Self Destruct", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
// Misc
{ KEY_SHIFTED | KEY_O, -1, COMPUTER_TAB, true, "Toggle HUD", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_3, -1, SHIP_TAB, true, "Right Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_1, -1, SHIP_TAB, true, "Left Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_PADPLUS, -1, SHIP_TAB, true, "Up Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_SHIFTED | KEY_PADENTER, -1, SHIP_TAB, true, "Down Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_SHIFTED | KEY_Q, -1, COMPUTER_TAB, true, "Toggle HUD Wireframe Target View", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ -1, -1, COMPUTER_TAB, false, "Top-Down View", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ -1, -1, COMPUTER_TAB, false, "Target Padlock View", CC_TYPE_TRIGGER, -1, -1, 0, false, false }, // (Swifty) Toggle for VM_TRACK
{ KEY_SHIFTED | KEY_O, -1, COMPUTER_TAB, true, "Toggle HUD", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_3, -1, SHIP_TAB, true, "Right Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_1, -1, SHIP_TAB, true, "Left Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_PADPLUS, -1, SHIP_TAB, true, "Up Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_SHIFTED | KEY_PADENTER, -1, SHIP_TAB, true, "Down Thrust", CC_TYPE_CONTINUOUS, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_SHIFTED | KEY_Q, -1, COMPUTER_TAB, true, "Toggle HUD Wireframe Target View", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ -1, -1, COMPUTER_TAB, false, "Top-Down View", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ -1, -1, COMPUTER_TAB, false, "Target Padlock View", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL }, // (Swifty) Toggle for VM_TRACK
// Auto Navigation Systen
{ KEY_ALTED | KEY_A, -1, COMPUTER_TAB, false, "Toggle Auto Pilot", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_N, -1, COMPUTER_TAB, false, "Cycle Nav Points", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_G, -1, SHIP_TAB, false, "Toggle Gliding", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_O, -1, WEAPON_TAB, false, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER, -1, -1, 0, false, false },
{ KEY_ALTED | KEY_A, -1, COMPUTER_TAB, false, "Toggle Auto Pilot", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_N, -1, COMPUTER_TAB, false, "Cycle Nav Points", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_ALTED | KEY_G, -1, SHIP_TAB, false, "Toggle Gliding", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ KEY_O, -1, WEAPON_TAB, false, "Cycle Primary Weapon Firing Rate", CC_TYPE_TRIGGER, -1, -1, 0, false, false, NULL },
{ -1, -1, -1, false, "", CC_TYPE_TRIGGER, -1, -1, 0, false, false }
};
@@ -404,6 +404,7 @@ char **Scan_code_text = Scan_code_text_english;
char **Joy_button_text = Joy_button_text_english;
SCP_vector<config_item*> Control_config_presets;
SCP_vector<SCP_string> Control_config_preset_names;
void set_modifier_status()
{
@@ -591,6 +592,9 @@ void control_config_common_init()
for (int i=0; i<CCFG_MAX; i++) {
Control_config[i].disabled = false;
Control_config[i].continuous_ongoing = false;
// init the overridable description with a copy of the default
Control_config[i].text = strdup(Control_config[i].default_text);
}
control_config_common_load_overrides();
@@ -811,6 +815,14 @@ void control_config_common_load_overrides()
std::copy(Control_config, Control_config + CCFG_MAX + 1, cfg_preset);
Control_config_presets.push_back(cfg_preset);
SCP_string preset_name;
if (optional_string("$Name:")) {
stuff_string_line(preset_name);
} else {
preset_name = "<unnamed preset>";
}
Control_config_preset_names.push_back(preset_name);
while (required_string_either("#End","$Bind Name:")) {
const int iBufferLength = 64;
char szTempBuffer[iBufferLength];
@@ -822,7 +834,7 @@ void control_config_common_load_overrides()
for (size_t i = 0; i < cCntrlAryLength; ++i) {
config_item& r_ccConfig = cfg_preset[i];
if (!strcmp(szTempBuffer, r_ccConfig.text)) {
if (!strcmp(szTempBuffer, r_ccConfig.default_text)) {
/**
* short key_default;
* short joy_default;
@@ -833,6 +845,11 @@ void control_config_common_load_overrides()
int iTemp;
if (optional_string("$New Name:")) {
stuff_string(szTempBuffer, F_NAME, iBufferLength);
r_ccConfig.text = strdup(szTempBuffer);
}
if (optional_string("$Key Default:")) {
if (optional_string("NONE")) {
r_ccConfig.key_default = (short)-1;
+52 -50
View File
@@ -52,59 +52,61 @@ void cutscene_init()
{
atexit(cutscene_close);
char buf[MULTITEXT_LENGTH];
int rval;
cutscene_info cutinfo;
cutscene_info cutinfo;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "cutscenes.tbl", rval));
try
{
read_file_text("cutscenes.tbl", CF_TYPE_TABLES);
reset_parse();
// parse in all the cutscenes
Cutscenes.clear();
skip_to_string("#Cutscenes");
ignore_white_space();
bool isFirstCutscene = true;
while (required_string_either("#End", "$Filename:"))
{
required_string("$Filename:");
stuff_string(cutinfo.filename, F_PATHNAME, MAX_FILENAME_LEN);
required_string("$Name:");
stuff_string(cutinfo.name, F_NAME, NAME_LENGTH);
required_string("$Description:");
stuff_string(buf, F_MULTITEXT, sizeof(buf));
drop_white_space(buf);
compact_multitext_string(buf);
cutinfo.description = vm_strdup(buf);
if (optional_string("$cd:"))
stuff_int(&cutinfo.cd);
else
cutinfo.cd = 0;
cutinfo.viewable = false;
if (isFirstCutscene) {
isFirstCutscene = false;
// The original code assumes the first movie is the intro, so always viewable
cutinfo.viewable = true;
}
if (optional_string("$Always Viewable:")) {
stuff_boolean(&cutinfo.viewable);
}
Cutscenes.push_back(cutinfo);
}
required_string("#End");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "cutscenes.tbl", e.what()));
return;
}
read_file_text("cutscenes.tbl", CF_TYPE_TABLES);
reset_parse();
// parse in all the cutscenes
Cutscenes.clear();
skip_to_string("#Cutscenes");
ignore_white_space();
bool isFirstCutscene = true;
while ( required_string_either("#End", "$Filename:") )
{
required_string("$Filename:");
stuff_string( cutinfo.filename, F_PATHNAME, MAX_FILENAME_LEN );
required_string("$Name:");
stuff_string( cutinfo.name, F_NAME, NAME_LENGTH );
required_string("$Description:");
stuff_string(buf, F_MULTITEXT, sizeof(buf));
drop_white_space(buf);
compact_multitext_string(buf);
cutinfo.description = vm_strdup(buf);
if (optional_string("$cd:"))
stuff_int( &cutinfo.cd );
else
cutinfo.cd = 0;
cutinfo.viewable = false;
if (isFirstCutscene) {
isFirstCutscene = false;
// The original code assumes the first movie is the intro, so always viewable
cutinfo.viewable = true;
}
if (optional_string("$Always Viewable:")) {
stuff_boolean(&cutinfo.viewable);
}
Cutscenes.push_back(cutinfo);
}
required_string("#End");
}
// function to return 0 based index of which CD a particular movie is on
+4
View File
@@ -926,6 +926,10 @@ int debris_check_collision(object *pdebris, object *other_obj, vec3d *hitpos, co
// reset flags to check MC_CHECK_MODEL | MC_CHECK_SPHERELINE and maybe MC_CHECK_INVISIBLE_FACES and MC_SUBMODEL_INSTANCE
mc.flags = copy_flags | MC_SUBMODEL_INSTANCE;
if (Ship_info[Ships[ship_obj->instance].ship_info_index].collision_lod > -1) {
mc.lod = Ship_info[Ships[ship_obj->instance].ship_info_index].collision_lod;
}
// check each submodel in turn
for (smv = submodel_vector.begin(); smv != submodel_vector.end(); ++smv) {
// turn on submodel for collision test
+82 -73
View File
@@ -159,84 +159,93 @@ static void fireball_set_default_color(int idx)
*/
void parse_fireball_tbl(const char *filename)
{
int rval;
lod_checker lod_check;
color fb_color;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
try
{
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
required_string("#Start");
while (required_string_either("#End", "$Name:")) {
memset(&lod_check, 0, sizeof(lod_checker));
// base filename
required_string("$Name:");
stuff_string(lod_check.filename, F_NAME, MAX_FILENAME_LEN);
lod_check.override = -1;
// these entries should only be in TBMs, and it has to include at least one
if (Parsing_modular_table) {
if (optional_string("+Explosion_Medium")) {
lod_check.override = FIREBALL_EXPLOSION_MEDIUM;
}
else if (optional_string("+Warp_Effect")) {
lod_check.override = FIREBALL_WARP;
}
else if (optional_string("+Knossos_Effect")) {
lod_check.override = FIREBALL_KNOSSOS;
}
else if (optional_string("+Asteroid")) {
lod_check.override = FIREBALL_ASTEROID;
}
else if (optional_string("+Explosion_Large1")) {
lod_check.override = FIREBALL_EXPLOSION_LARGE1;
}
else if (optional_string("+Explosion_Large2")){
lod_check.override = FIREBALL_EXPLOSION_LARGE2;
}
else {
required_string("+Custom_Fireball");
stuff_int(&lod_check.override);
}
}
lod_check.num_lods = 1;
// Do we have an LOD num
if (optional_string("$LOD:")) {
stuff_int(&lod_check.num_lods);
}
if (lod_check.num_lods > MAX_FIREBALL_LOD) {
lod_check.num_lods = MAX_FIREBALL_LOD;
}
// check for particular lighting color
if (optional_string("$Light color:")) {
int r, g, b;
stuff_int(&r);
stuff_int(&g);
stuff_int(&b);
CLAMP(r, 0, 255);
CLAMP(g, 0, 255);
CLAMP(b, 0, 255);
gr_init_color(&fb_color, r, g, b);
}
else {
// to keep things simple, we just use 0 alpha to indicate that a default value should be used
memset(&fb_color, 0, sizeof(color));
}
// we may use one filename for multiple entries so we'll have to handle dupes post parse
LOD_checker.push_back(lod_check);
LOD_color.push_back(fb_color);
}
required_string("#End");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
required_string("#Start");
while (required_string_either("#End", "$Name:")) {
memset( &lod_check, 0, sizeof(lod_checker) );
// base filename
required_string("$Name:");
stuff_string(lod_check.filename, F_NAME, MAX_FILENAME_LEN);
lod_check.override = -1;
// these entries should only be in TBMs, and it has to include at least one
if ( Parsing_modular_table ) {
if (optional_string("+Explosion_Medium")) {
lod_check.override = FIREBALL_EXPLOSION_MEDIUM;
} else if (optional_string("+Warp_Effect")) {
lod_check.override = FIREBALL_WARP;
} else if (optional_string("+Knossos_Effect")) {
lod_check.override = FIREBALL_KNOSSOS;
} else if (optional_string("+Asteroid")) {
lod_check.override = FIREBALL_ASTEROID;
} else if (optional_string("+Explosion_Large1")) {
lod_check.override = FIREBALL_EXPLOSION_LARGE1;
} else if (optional_string("+Explosion_Large2")){
lod_check.override = FIREBALL_EXPLOSION_LARGE2;
} else {
required_string("+Custom_Fireball");
stuff_int(&lod_check.override);
}
}
lod_check.num_lods = 1;
// Do we have an LOD num
if (optional_string("$LOD:")) {
stuff_int(&lod_check.num_lods);
}
if (lod_check.num_lods > MAX_FIREBALL_LOD) {
lod_check.num_lods = MAX_FIREBALL_LOD;
}
// check for particular lighting color
if ( optional_string("$Light color:") ) {
int r, g, b;
stuff_int(&r);
stuff_int(&g);
stuff_int(&b);
CLAMP(r, 0, 255);
CLAMP(g, 0, 255);
CLAMP(b, 0, 255);
gr_init_color(&fb_color, r, g, b);
} else {
// to keep things simple, we just use 0 alpha to indicate that a default value should be used
memset( &fb_color, 0, sizeof(color) );
}
// we may use one filename for multiple entries so we'll have to handle dupes post parse
LOD_checker.push_back(lod_check);
LOD_color.push_back(fb_color);
}
required_string("#End");
}
void fireball_parse_tbl()
+49 -46
View File
@@ -1267,7 +1267,7 @@ void bg_bitmap_dlg::OnImportBackground()
{
CFileDialog cfd(TRUE, ".fs2", NULL, 0, "FreeSpace2 Missions (*.fs2)|*.fs2||\0");
char filename[256], error_str[1024];
int rval, temp, count;
int temp, count;
char *saved_mp;
//warn on pressing the button
@@ -1280,59 +1280,62 @@ void bg_bitmap_dlg::OnImportBackground()
strcpy_s(filename, cfd.GetPathName());
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("BGBITMAPDLG: Unable to parse '%s'! Error code = %i.\n", filename, rval));
sprintf(error_str, "Could not parse file: %s", filename);
MessageBox((LPCTSTR) error_str, (LPCTSTR) "Unable to import mission background!", MB_ICONERROR | MB_OK);
return;
}
// parse in the new file
read_file_text(filename);
reset_parse();
if (!skip_to_start_of_string("#Background bitmaps"))
return;
// skip beginning stuff
required_string("#Background bitmaps");
required_string("$Num stars:");
stuff_int(&temp);
required_string("$Ambient light level:");
stuff_int(&temp);
saved_mp = Mp;
// see if we have more than one background in this mission
count = 0;
while(skip_to_string("$Bitmap List:"))
count++;
Mp = saved_mp;
// pick one (if count is 0, it's retail with just one background)
if (count > 0)
try
{
int i, which = 0;
// parse in the new file
read_file_text(filename);
reset_parse();
if (count > 1)
if (!skip_to_start_of_string("#Background bitmaps"))
return;
// skip beginning stuff
required_string("#Background bitmaps");
required_string("$Num stars:");
stuff_int(&temp);
required_string("$Ambient light level:");
stuff_int(&temp);
saved_mp = Mp;
// see if we have more than one background in this mission
count = 0;
while (skip_to_string("$Bitmap List:"))
count++;
Mp = saved_mp;
// pick one (if count is 0, it's retail with just one background)
if (count > 0)
{
BackgroundChooser dlg(count);
if (dlg.DoModal() == IDCANCEL)
return;
int i, which = 0;
which = dlg.GetChosenBackground();
if (count > 1)
{
BackgroundChooser dlg(count);
if (dlg.DoModal() == IDCANCEL)
return;
which = dlg.GetChosenBackground();
}
for (i = 0; i < which + 1; i++)
skip_to_string("$Bitmap List:");
}
for (i = 0; i < which + 1; i++)
skip_to_string("$Bitmap List:");
// now parse the background we've selected
parse_one_background(&Backgrounds[get_active_background()]);
reinitialize_lists();
}
catch (const parse::ParseException& e)
{
mprintf(("BGBITMAPDLG: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
sprintf(error_str, "Could not parse file: %s\n\nError message: %s", filename, e.what());
// now parse the background we've selected
parse_one_background(&Backgrounds[get_active_background()]);
reinitialize_lists();
MessageBox((LPCTSTR)error_str, (LPCTSTR) "Unable to import mission background!", MB_ICONERROR | MB_OK);
return;
}
}
void bg_bitmap_dlg::reinitialize_lists()
+151 -145
View File
@@ -323,7 +323,7 @@ void parse_helptbl(const char *filename)
int overlay_id, currcount, vtxcount;
char name[HELP_MAX_NAME_LENGTH];
char buf[HELP_MAX_STRING_LENGTH + 1];
int i, j, rval;
int i, j;
SCP_vector<help_pline> pline_temp;
help_pline pline_temp2;
@@ -335,160 +335,166 @@ void parse_helptbl(const char *filename)
help_left_bracket lbracket_temp2;
vec3d vec3d_temp;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
return;
}
try
{
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// for each overlay...
while (optional_string("$")) {
// for each overlay...
while (optional_string("$")) {
stuff_string(name, F_NAME, HELP_MAX_NAME_LENGTH);
stuff_string(name, F_NAME, HELP_MAX_NAME_LENGTH);
overlay_id = help_overlay_get_index(name);
overlay_id = help_overlay_get_index(name);
if (overlay_id < 0) {
if (num_help_overlays >= MAX_HELP_OVERLAYS) {
Warning(LOCATION, "Could not load help overlay after '%s' as maximum number of help overlays was reached (Max is %d)", help_overlaylist[overlay_id - 1].name, MAX_HELP_OVERLAYS);
if (overlay_id < 0) {
if (num_help_overlays >= MAX_HELP_OVERLAYS) {
Warning(LOCATION, "Could not load help overlay after '%s' as maximum number of help overlays was reached (Max is %d)", help_overlaylist[overlay_id - 1].name, MAX_HELP_OVERLAYS);
if (!skip_to_string("$end")) {
Error(LOCATION, "Couldn't find $end. Help.tbl or -hlp.tbm is invalid.\n");
}
continue;
} else {
overlay_id = num_help_overlays;
strcpy_s(help_overlaylist[overlay_id].name, name);
num_help_overlays++;
}
}
// clear out counters in the overlay struct
help_overlaylist[overlay_id].plinecount = 0;
help_overlaylist[overlay_id].textcount = 0;
help_overlaylist[overlay_id].rbracketcount = 0;
help_overlaylist[overlay_id].lbracketcount = 0;
help_overlaylist[overlay_id].fontlist.clear();
help_overlaylist[overlay_id].plinelist.clear();
help_overlaylist[overlay_id].textlist.clear();
help_overlaylist[overlay_id].rbracketlist.clear();
help_overlaylist[overlay_id].lbracketlist.clear();
if (optional_string("+resolutions")) {
stuff_int(&help_overlaylist[overlay_id].num_resolutions);
} else {
help_overlaylist[overlay_id].num_resolutions = 2;
}
if (help_overlaylist[overlay_id].num_resolutions < 1) {
Error(LOCATION, "+resolutions in %s is %d. (Must be 1 or greater)", filename, help_overlaylist[overlay_id].num_resolutions);
}
if (optional_string("+font")) {
int font;
for (i=0; i<help_overlaylist[overlay_id].num_resolutions; i++) {
stuff_int(&font);
help_overlaylist[overlay_id].fontlist.push_back(font);
}
} else {
for (i=0; i<help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].fontlist.push_back(FONT1);
}
}
for (i=0; i<help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].plinelist.push_back(pline_temp);
help_overlaylist[overlay_id].textlist.push_back(text_temp);
help_overlaylist[overlay_id].rbracketlist.push_back(rbracket_temp);
help_overlaylist[overlay_id].lbracketlist.push_back(lbracket_temp);
}
int type;
// read in all elements for this overlay
while ((type = required_string_one_of(5, "+pline", "+text", "+right_bracket", "+left_bracket", "$end")) != 4) { // Doing it this way means an error lists "$end" at the end, which seems appropriate. -MageKing17
switch (type) {
case 0: // +pline
required_string("+pline");
currcount = help_overlaylist[overlay_id].plinecount;
int a, b; // temp vars to read in int before cast to float;
// read number of pline vertices
stuff_int(&vtxcount);
// get vertex coordinates for each resolution
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].plinelist.at(i).push_back(pline_temp2);
for (j = 0; j < vtxcount; j++) {
help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.push_back(vec3d_temp);
help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtxcount = vtxcount;
stuff_int(&a);
stuff_int(&b);
help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.at(j).xyz.x = (float)a;
help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.at(j).xyz.y = (float)b;
help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.at(j).xyz.z = 0.0f;
if (!skip_to_string("$end")) {
Error(LOCATION, "Couldn't find $end. Help.tbl or -hlp.tbm is invalid.\n");
}
continue;
}
help_overlaylist[overlay_id].plinecount++;
break;
case 1: // +text
required_string("+text");
currcount = help_overlaylist[overlay_id].textcount;
// get coordinates for each resolution
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].textlist.at(i).push_back(text_temp2);
stuff_int(&(help_overlaylist[overlay_id].textlist.at(i).at(currcount).x_coord));
stuff_int(&(help_overlaylist[overlay_id].textlist.at(i).at(currcount).y_coord));
else {
overlay_id = num_help_overlays;
strcpy_s(help_overlaylist[overlay_id].name, name);
num_help_overlays++;
}
// get string (always use the first resolution)
stuff_string(buf, F_MESSAGE, sizeof(buf));
help_overlaylist[overlay_id].textlist.at(0).at(currcount).string = vm_strdup(buf);
help_overlaylist[overlay_id].textcount++;
break;
case 2: // +right_bracket
required_string("+right_bracket");
currcount = help_overlaylist[overlay_id].rbracketcount;
// get coordinates for each resolution
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].rbracketlist.at(i).push_back(rbracket_temp2);
stuff_int(&(help_overlaylist[overlay_id].rbracketlist.at(i).at(currcount).x_coord));
stuff_int(&(help_overlaylist[overlay_id].rbracketlist.at(i).at(currcount).y_coord));
}
help_overlaylist[overlay_id].rbracketcount++;
break;
case 3: // +left_bracket
required_string("+left_bracket");
currcount = help_overlaylist[overlay_id].lbracketcount;
// get coordinates for each resolution
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].lbracketlist.at(i).push_back(lbracket_temp2);
stuff_int(&(help_overlaylist[overlay_id].lbracketlist.at(i).at(currcount).x_coord));
stuff_int(&(help_overlaylist[overlay_id].lbracketlist.at(i).at(currcount).y_coord));
}
help_overlaylist[overlay_id].lbracketcount++;
break;
case -1:
// -noparseerrors is set
break;
case 4: // $end
default:
Assertion(false, "This should never happen.\n");
break;
}
// clear out counters in the overlay struct
help_overlaylist[overlay_id].plinecount = 0;
help_overlaylist[overlay_id].textcount = 0;
help_overlaylist[overlay_id].rbracketcount = 0;
help_overlaylist[overlay_id].lbracketcount = 0;
help_overlaylist[overlay_id].fontlist.clear();
help_overlaylist[overlay_id].plinelist.clear();
help_overlaylist[overlay_id].textlist.clear();
help_overlaylist[overlay_id].rbracketlist.clear();
help_overlaylist[overlay_id].lbracketlist.clear();
if (optional_string("+resolutions")) {
stuff_int(&help_overlaylist[overlay_id].num_resolutions);
}
else {
help_overlaylist[overlay_id].num_resolutions = 2;
}
if (help_overlaylist[overlay_id].num_resolutions < 1) {
Error(LOCATION, "+resolutions in %s is %d. (Must be 1 or greater)", filename, help_overlaylist[overlay_id].num_resolutions);
}
if (optional_string("+font")) {
int font;
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
stuff_int(&font);
help_overlaylist[overlay_id].fontlist.push_back(font);
}
}
else {
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].fontlist.push_back(FONT1);
}
}
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].plinelist.push_back(pline_temp);
help_overlaylist[overlay_id].textlist.push_back(text_temp);
help_overlaylist[overlay_id].rbracketlist.push_back(rbracket_temp);
help_overlaylist[overlay_id].lbracketlist.push_back(lbracket_temp);
}
int type;
// read in all elements for this overlay
while ((type = required_string_one_of(5, "+pline", "+text", "+right_bracket", "+left_bracket", "$end")) != 4) { // Doing it this way means an error lists "$end" at the end, which seems appropriate. -MageKing17
switch (type) {
case 0: // +pline
required_string("+pline");
currcount = help_overlaylist[overlay_id].plinecount;
int a, b; // temp vars to read in int before cast to float;
// read number of pline vertices
stuff_int(&vtxcount);
// get vertex coordinates for each resolution
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].plinelist.at(i).push_back(pline_temp2);
for (j = 0; j < vtxcount; j++) {
help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.push_back(vec3d_temp);
help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtxcount = vtxcount;
stuff_int(&a);
stuff_int(&b);
help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.at(j).xyz.x = (float)a;
help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.at(j).xyz.y = (float)b;
help_overlaylist[overlay_id].plinelist.at(i).at(currcount).vtx.at(j).xyz.z = 0.0f;
}
}
help_overlaylist[overlay_id].plinecount++;
break;
case 1: // +text
required_string("+text");
currcount = help_overlaylist[overlay_id].textcount;
// get coordinates for each resolution
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].textlist.at(i).push_back(text_temp2);
stuff_int(&(help_overlaylist[overlay_id].textlist.at(i).at(currcount).x_coord));
stuff_int(&(help_overlaylist[overlay_id].textlist.at(i).at(currcount).y_coord));
}
// get string (always use the first resolution)
stuff_string(buf, F_MESSAGE, sizeof(buf));
help_overlaylist[overlay_id].textlist.at(0).at(currcount).string = vm_strdup(buf);
help_overlaylist[overlay_id].textcount++;
break;
case 2: // +right_bracket
required_string("+right_bracket");
currcount = help_overlaylist[overlay_id].rbracketcount;
// get coordinates for each resolution
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].rbracketlist.at(i).push_back(rbracket_temp2);
stuff_int(&(help_overlaylist[overlay_id].rbracketlist.at(i).at(currcount).x_coord));
stuff_int(&(help_overlaylist[overlay_id].rbracketlist.at(i).at(currcount).y_coord));
}
help_overlaylist[overlay_id].rbracketcount++;
break;
case 3: // +left_bracket
required_string("+left_bracket");
currcount = help_overlaylist[overlay_id].lbracketcount;
// get coordinates for each resolution
for (i = 0; i < help_overlaylist[overlay_id].num_resolutions; i++) {
help_overlaylist[overlay_id].lbracketlist.at(i).push_back(lbracket_temp2);
stuff_int(&(help_overlaylist[overlay_id].lbracketlist.at(i).at(currcount).x_coord));
stuff_int(&(help_overlaylist[overlay_id].lbracketlist.at(i).at(currcount).y_coord));
}
help_overlaylist[overlay_id].lbracketcount++;
break;
case -1:
// -noparseerrors is set
break;
case 4: // $end
default:
Assertion(false, "This should never happen.\n");
break;
}
} // end while
required_string("$end");
} // end while
required_string("$end");
} // end while
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
}
+8 -9
View File
@@ -28,15 +28,14 @@
#pragma optimize("", off)
#define DEFAULT_MASTER_EVENT_MUSIC_VOLUME 0.5f
#define HULL_VALUE_TO_PLAY_INTENSE_BATTLE_MUSIC 0.75f
////////////////////////////
// Globals
////////////////////////////
int Event_Music_battle_started = 0;
float Master_event_music_volume = DEFAULT_MASTER_EVENT_MUSIC_VOLUME; // range is 0->1
float Default_music_volume = 0.5f; // range is 0->1
float Master_event_music_volume = Default_music_volume;
typedef struct tagSNDPATTERN {
int default_next_pattern; // Needed so the next_pattern member can be reset
@@ -1374,12 +1373,8 @@ void parse_menumusic()
//
void event_music_parse_musictbl(const char *filename)
{
int rval;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
} else {
try
{
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
@@ -1399,6 +1394,10 @@ void event_music_parse_musictbl(const char *filename)
}
}
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
}
}
// -------------------------------------------------------------------------------------------------
+2 -1
View File
@@ -41,7 +41,8 @@
extern int Event_Music_battle_started; // flag that will tell us if we've started a battle in the current mission
extern int Event_music_enabled;
extern float Master_event_music_volume; // range is 0->1
extern float Default_music_volume; // range is 0->1
extern float Master_event_music_volume; // range is 0->1
/////////////////////////////////////////////////////////////////////////////
+74 -74
View File
@@ -693,83 +693,83 @@ static SCP_vector<species_info> missingFlybySounds;
void parse_sound_table(const char* filename)
{
int rval;
if ((rval = setjmp(parse_abort)) != 0)
try
{
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// Parse the gameplay sounds section
if (optional_string("#Game Sounds Start"))
{
while (!check_for_string("#Game Sounds End"))
{
game_snd tempSound;
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds))
{
Snds.push_back(game_snd(tempSound));
}
}
required_string("#Game Sounds End");
}
// Parse the interface sounds section
if (optional_string("#Interface Sounds Start"))
{
while (!check_for_string("#Interface Sounds End"))
{
game_snd tempSound;
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds_iface))
{
Snds_iface.push_back(game_snd(tempSound));
Snds_iface_handle.push_back(-1);
}
}
required_string("#Interface Sounds End");
}
// parse flyby sound section
if (optional_string("#Flyby Sounds Start"))
{
char species_name_tag[NAME_LENGTH + 2];
int sanity_check = 0;
size_t i;
while (!check_for_string("#Flyby Sounds End") && (sanity_check <= (int)Species_info.size()))
{
for (i = 0; i < Species_info.size(); i++)
{
species_info *species = &Species_info[i];
sprintf(species_name_tag, "$%s:", species->species_name);
if (check_for_string(species_name_tag))
{
gamesnd_parse_line(&species->snd_flyby_fighter, species_name_tag);
gamesnd_parse_line(&species->snd_flyby_bomber, species_name_tag);
sanity_check--;
}
else
{
sanity_check++;
}
}
}
required_string("#Flyby Sounds End");
}
if (optional_string("#Sound Environments Start"))
{
parse_sound_environments();
}
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// Parse the gameplay sounds section
if (optional_string("#Game Sounds Start"))
{
while (!check_for_string("#Game Sounds End"))
{
game_snd tempSound;
if (gamesnd_parse_line(&tempSound, "$Name:", &Snds))
{
Snds.push_back(game_snd(tempSound));
}
}
required_string("#Game Sounds End");
}
// Parse the interface sounds section
if (optional_string("#Interface Sounds Start"))
{
while (!check_for_string("#Interface Sounds End"))
{
game_snd tempSound;
if (gamesnd_parse_line( &tempSound, "$Name:", &Snds_iface))
{
Snds_iface.push_back(game_snd(tempSound));
Snds_iface_handle.push_back(-1);
}
}
required_string("#Interface Sounds End");
}
// parse flyby sound section
if (optional_string("#Flyby Sounds Start"))
{
char species_name_tag[NAME_LENGTH + 2];
int sanity_check = 0;
size_t i;
while (!check_for_string("#Flyby Sounds End") && (sanity_check <= (int)Species_info.size()))
{
for (i = 0; i < Species_info.size(); i++)
{
species_info *species = &Species_info[i];
sprintf(species_name_tag, "$%s:", species->species_name);
if (check_for_string(species_name_tag))
{
gamesnd_parse_line(&species->snd_flyby_fighter, species_name_tag);
gamesnd_parse_line(&species->snd_flyby_bomber, species_name_tag);
sanity_check--;
}
else
{
sanity_check++;
}
}
}
required_string("#Flyby Sounds End");
}
if (optional_string("#Sound Environments Start"))
{
parse_sound_environments();
}
}
/**
+320 -308
View File
@@ -273,71 +273,74 @@ void parse_colors(const char *filename)
{
Assertion(filename != NULL, "parse_colors() called on NULL; get a coder!\n");
read_file_text(filename, CF_TYPE_TABLES);
int err_code;
if ((err_code = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %d.\n", filename, err_code));
return;
}
reset_parse();
// we search for the colors based on their order of definition above
// if the color isn't found, we just use default values
if (optional_string("#Start Colors"))
try
{
// vars for holding rgba values
int rgba[4] = {0,0,0,0};
int i, j;
reset_parse();
char* color_names[TOTAL_COLORS] = {
"$Blue:",
"$Bright Blue:",
"$Green:",
"$Bright Green:",
"$Black:",
"$Grey:",
"$Silver:",
"$White:",
"$Bright White:",
"$Violet Gray:",
"$Violet:",
"$Dim Red:",
"$Red:",
"$Bright Red:",
"$Pink:",
"$Light Pink:",
"$Yellow:",
"$Bright Yellow:",
"$UI Light Green:",
"$UI Green:",
"$UI Light Pink:",
"$UI Pink:"
};
// we search for the colors based on their order of definition above
// if the color isn't found, we just use default values
if (optional_string("#Start Colors"))
{
// vars for holding rgba values
int rgba[4] = { 0, 0, 0, 0 };
int i, j;
// now for each color, check if it's corresponding string is there
for (i = 0; i < TOTAL_COLORS; i++) {
if (optional_string(color_names[i])) {
// if so, get its rgba values and initialise it using them
mprintf(("'%s' has been redefined.\n", color_names[i]));
//if (check_for_string("(")) {
char* color_names[TOTAL_COLORS] = {
"$Blue:",
"$Bright Blue:",
"$Green:",
"$Bright Green:",
"$Black:",
"$Grey:",
"$Silver:",
"$White:",
"$Bright White:",
"$Violet Gray:",
"$Violet:",
"$Dim Red:",
"$Red:",
"$Bright Red:",
"$Pink:",
"$Light Pink:",
"$Yellow:",
"$Bright Yellow:",
"$UI Light Green:",
"$UI Green:",
"$UI Light Pink:",
"$UI Pink:"
};
// now for each color, check if it's corresponding string is there
for (i = 0; i < TOTAL_COLORS; i++) {
if (optional_string(color_names[i])) {
// if so, get its rgba values and initialise it using them
mprintf(("'%s' has been redefined.\n", color_names[i]));
//if (check_for_string("(")) {
stuff_int_list(rgba, 4, RAW_INTEGER_TYPE);
for (j = 0; j < 4; j++) {
if (rgba[j] < 0) {
Warning(LOCATION, "RGBA value for '%s' in %s too low (%d), capping to 0.\n", color_names[i], filename, rgba[j]);
rgba[j] = 0;
} else if (rgba[j] > 255) {
}
else if (rgba[j] > 255) {
Warning(LOCATION, "RGBA value for '%s' in %s too high (%d), capping to 255.\n", color_names[i], filename, rgba[j]);
rgba[j] = 255;
}
}
//} else {
// stuff_hex_list(rgba, 4);
//}
gr_init_alphacolor(COLOR_LIST[i], rgba[0], rgba[1], rgba[2], rgba[3]);
//} else {
// stuff_hex_list(rgba, 4);
//}
gr_init_alphacolor(COLOR_LIST[i], rgba[0], rgba[1], rgba[2], rgba[3]);
}
}
required_string("#End");
}
required_string("#End");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
}
@@ -346,281 +349,290 @@ void parse_everything_else(const char *filename)
Assertion(filename != NULL, "parse_everything_else() called on NULL; get a coder!\n");
read_file_text(filename, CF_TYPE_TABLES);
int err_code;
if ((err_code = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %d.\n", filename, err_code));
return;
}
try
{
reset_parse();
reset_parse();
int rgba[4] = { 0, 0, 0, 0 };
int rgba[4] = {0,0,0,0};
// reusable temp vars
int i, j;
SCP_string temp;
// reusable temp vars
int i, j;
SCP_string temp;
if (optional_string("#Start Colors")) {
// Skip this section; we already parsed it in every file.
skip_to_string("#End", NULL);
}
//Team coloring
if (optional_string("#Team Colors")) {
while (required_string_either("#End", "$Team Name:")) {
required_string("$Team Name:"); // required to move the parse pointer forward
team_color temp_color;
char temp2[NAME_LENGTH];
stuff_string(temp2, F_NAME, NAME_LENGTH);
temp = temp2;
if (!stricmp(temp2, "none")) {
Warning(LOCATION, "Team color in '%s' defined with a name of '%s'; this won't be usable due to 'None' being used for a lack of a team color by the engine.\n", filename, temp2);
}
if (required_string("$Team Stripe Color:")) {
int rgb[3];
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i = 0; i < 3; i++) {
CLAMP(rgb[i], 0, 255);
}
temp_color.stripe.r = rgb[0] / 255.0f;
temp_color.stripe.g = rgb[1] / 255.0f;
temp_color.stripe.b = rgb[2] / 255.0f;
}
if (required_string("$Team Base Color:")) {
int rgb[3];
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i = 0; i < 3; i++) {
CLAMP(rgb[i], 0, 255);
}
temp_color.base.r = rgb[0] / 255.0f;
temp_color.base.g = rgb[1] / 255.0f;
temp_color.base.b = rgb[2] / 255.0f;
}
if (Team_Colors.find(temp) == Team_Colors.end()) { // Only push to the vector if the team isn't already defined.
Team_Names.push_back(temp);
}
Team_Colors[temp] = temp_color;
}
required_string("#End");
}
// Previously-hardcoded interface colors
if (optional_string("#Interface Colors")) {
char *color_names[INTERFACE_COLORS] = {
"$Text Normal:",
"$Text Subselected:",
"$Text Selected:",
"$Text Error:",
"$Text Error Highlighted:",
"$Text Active:",
"$Text Active Highlighted:",
"$Text Heading:",
"$More Indicator:",
"$Bright More Indicator:",
"$Bright:",
"$Normal:",
"$Briefing Grid:",
};
// now for each color, check if its corresponding string is there
for (i = 0; i < INTERFACE_COLORS; i++) {
if (optional_string(color_names[i])) {
// if so, get its rgba values and initialise it using them
mprintf(("'%s' has been redefined.\n", color_names[i]));
if ( check_for_string("(") ) {
// If we have a list of integers, use them.
stuff_int_list(rgba, 4, RAW_INTEGER_TYPE);
for (j = 0; j < 4; j++) {
if (rgba[j] < 0)
{
Warning(LOCATION, "RGBA value for '%s' in %s too low (%d), capping to 0.\n", color_names[i], filename, rgba[j]);
rgba[j] = 0;
}
else if (rgba[j] > 255)
{
Warning(LOCATION, "RGBA value for '%s' in %s too high (%d), capping to 255.\n", color_names[i], filename, rgba[j]);
rgba[j] = 255;
}
}
gr_init_alphacolor(interface_colors[i], rgba[0], rgba[1], rgba[2], rgba[3]);
//} else if (check_for_string("#")) {
// stuff_hex_list(rgba, 4);
// gr_init_alphacolor(interface_colors[i], rgba[0], rgba[1], rgba[2], rgba[3]);
} else {
// We have a string; it should be the name of a color to use.
stuff_string(temp, F_NAME);
for (j = 0; j < TOTAL_COLORS; j++) {
if ( !temp.compare(COLOR_NAMES[j]) ) {
break;
}
}
if ( j == TOTAL_COLORS ) {
Warning(LOCATION, "Unknown color '%s' in %s, for definition of '%s'; using default ('%s').\n", temp.c_str(), filename, color_names[i], COLOR_NAMES[interface_defaults[i]]);
} else {
Assertion(j >= 0 && j < TOTAL_COLORS, "Attempting to copy nonexistant color (%d out of 0-%d)!\n", j, TOTAL_COLORS-1);
memcpy(interface_colors[i], COLOR_LIST[j], sizeof(color));
}
}
}
}
required_string("#End");
}
// Text color tags; for briefings, command briefings, debriefings, and the fiction viewer
if (optional_string("#Color Tags")) {
while (required_string_either("$Tag:", "#End") < 1) {
required_string("$Tag:");
color temp_color;
char tag;
stuff_string(temp, F_RAW);
if (temp[0] == '$') {
if (temp[1] == '\0') {
Error(LOCATION, "%s - found a '$Tag:' entry with a solitary '$'.\n", filename);
}
tag = temp[1];
if (temp[2] != '\0') {
Warning(LOCATION, "%s - tag '$%c' has extra text in its definition.\n", filename, tag);
}
} else if (temp[0] == '\0') {
Error(LOCATION, "%s - found a '$Tag:' entry with no tag.\n", filename);
} else {
tag = temp[0];
if (temp[1] != '\0') {
Warning(LOCATION, "%s - tag '$%c' has extra text in its definition.\n", filename, tag);
}
}
if (Tagged_Colors.find(tag) == Tagged_Colors.end()) { // Only push the tag to our list of tags if it's actually new, not just a redefinition.
Color_Tags.push_back(tag);
}
switch(required_string_one_of(4, "+Color:", "+Friendly", "+Hostile", "+Neutral")) {
case 0: // +Color
required_string("+Color:");
rgba[0] = rgba[1] = rgba[2] = 0;
rgba[3] = 255; // Odds are pretty high you want it to have full alpha...
if ( check_for_string("(") ) {
stuff_int_list(rgba, 4, RAW_INTEGER_TYPE);
for (j = 0; j < 4; j++) {
if (rgba[j] < 0)
{
Warning(LOCATION, "RGBA value for '$%c' in %s too low (%d), capping to 0.\n", tag, filename, rgba[j]);
rgba[j] = 0;
}
else if (rgba[j] > 255)
{
Warning(LOCATION, "RGBA value for '$%c' in %s too high (%d), capping to 255.\n", tag, filename, rgba[j]);
rgba[j] = 255;
}
}
gr_init_alphacolor(&temp_color, rgba[0], rgba[1], rgba[2], rgba[3]);
Custom_Colors[tag] = temp_color;
Tagged_Colors[tag] = &Custom_Colors[tag];
//} else if ( check_for_string ("#") ) {
// stuff_hex_list(rgba, 4);
// gr_init_alphacolor(&temp_color, rgba[0], rgba[1], rgba[2], rgba[3]);
// Custom_Colors[tag] = temp_color;
// Tagged_Colors[tag] = &Custom_Colors[tag];
} else {
// We have a string; it should be the name of a color to use.
stuff_string(temp, F_NAME);
for (j = 0; j < TOTAL_COLORS; j++) {
if ( !temp.compare(COLOR_NAMES[j]) ) {
break;
}
}
if ( j == TOTAL_COLORS ) {
Error(LOCATION, "Unknown color '%s' in %s, for definition of tag '$%c'.\n", temp.c_str(), filename, tag);
}
Tagged_Colors[tag] = COLOR_LIST[j];
}
break;
case 1: // +Friendly
required_string("+Friendly");
Tagged_Colors[tag] = &Brief_color_green;
break;
case 2: // +Hostile
required_string("+Hostile");
Tagged_Colors[tag] = &Brief_color_red;
break;
case 3: // +Neutral
required_string("+Neutral");
Tagged_Colors[tag] = &Brief_color_legacy_neutral;
break;
case -1:
// -noparseerrors is set
if (Tagged_Colors.find(tag) == Tagged_Colors.end()) { // It was a new color, but since we haven't actually defined it...
Color_Tags.pop_back();
}
break;
default:
Assertion(false, "MageKing17 made a coding error somewhere, and you should laugh at him (and report this error).\n");
break;
}
if (optional_string("#Start Colors")) {
// Skip this section; we already parsed it in every file.
skip_to_string("#End", NULL);
}
required_string("#End");
}
Assertion(Color_Tags.size() == Tagged_Colors.size(), "Color_Tags and Tagged_Colors size mismatch; get a coder!\n");
//Team coloring
if (optional_string("#Team Colors")) {
if (optional_string("#Default Text Colors")) {
while (required_string_either("#End", "$Team Name:")) {
required_string("$Team Name:"); // required to move the parse pointer forward
team_color temp_color;
char* color_names[MAX_DEFAULT_TEXT_COLORS] = {
"$Fiction Viewer:",
"$Command Briefing:",
"$Briefing:",
"$Redalert Briefing:",
"$Debriefing:",
"$Recommendation:",
"$Loop Briefing:",
};
char temp2[NAME_LENGTH];
stuff_string(temp2, F_NAME, NAME_LENGTH);
temp = temp2;
char *color_value[MAX_DEFAULT_TEXT_COLORS] = {
&default_fiction_viewer_color,
&default_command_briefing_color,
&default_briefing_color,
&default_redalert_briefing_color,
&default_debriefing_color,
&default_recommendation_color,
&default_loop_briefing_color,
};
if (!stricmp(temp2, "none")) {
Warning(LOCATION, "Team color in '%s' defined with a name of '%s'; this won't be usable due to 'None' being used for a lack of a team color by the engine.\n", filename, temp2);
}
if (required_string("$Team Stripe Color:")) {
int rgb[3];
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i = 0; i < 3; i++) {
CLAMP(rgb[i], 0, 255);
}
temp_color.stripe.r = rgb[0] / 255.0f;
temp_color.stripe.g = rgb[1] / 255.0f;
temp_color.stripe.b = rgb[2] / 255.0f;
}
if (required_string("$Team Base Color:")) {
int rgb[3];
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i = 0; i < 3; i++) {
CLAMP(rgb[i], 0, 255);
}
temp_color.base.r = rgb[0] / 255.0f;
temp_color.base.g = rgb[1] / 255.0f;
temp_color.base.b = rgb[2] / 255.0f;
}
if (Team_Colors.find(temp) == Team_Colors.end()) { // Only push to the vector if the team isn't already defined.
Team_Names.push_back(temp);
}
Team_Colors[temp] = temp_color;
}
required_string("#End");
}
// Previously-hardcoded interface colors
if (optional_string("#Interface Colors")) {
char *color_names[INTERFACE_COLORS] = {
"$Text Normal:",
"$Text Subselected:",
"$Text Selected:",
"$Text Error:",
"$Text Error Highlighted:",
"$Text Active:",
"$Text Active Highlighted:",
"$Text Heading:",
"$More Indicator:",
"$Bright More Indicator:",
"$Bright:",
"$Normal:",
"$Briefing Grid:",
};
// now for each color, check if its corresponding string is there
for (i = 0; i < INTERFACE_COLORS; i++) {
if (optional_string(color_names[i])) {
// if so, get its rgba values and initialise it using them
mprintf(("'%s' has been redefined.\n", color_names[i]));
if (check_for_string("(")) {
// If we have a list of integers, use them.
stuff_int_list(rgba, 4, RAW_INTEGER_TYPE);
for (j = 0; j < 4; j++) {
if (rgba[j] < 0)
{
Warning(LOCATION, "RGBA value for '%s' in %s too low (%d), capping to 0.\n", color_names[i], filename, rgba[j]);
rgba[j] = 0;
}
else if (rgba[j] > 255)
{
Warning(LOCATION, "RGBA value for '%s' in %s too high (%d), capping to 255.\n", color_names[i], filename, rgba[j]);
rgba[j] = 255;
}
}
gr_init_alphacolor(interface_colors[i], rgba[0], rgba[1], rgba[2], rgba[3]);
//} else if (check_for_string("#")) {
// stuff_hex_list(rgba, 4);
// gr_init_alphacolor(interface_colors[i], rgba[0], rgba[1], rgba[2], rgba[3]);
}
else {
// We have a string; it should be the name of a color to use.
stuff_string(temp, F_NAME);
for (j = 0; j < TOTAL_COLORS; j++) {
if (!temp.compare(COLOR_NAMES[j])) {
break;
}
}
if (j == TOTAL_COLORS) {
Warning(LOCATION, "Unknown color '%s' in %s, for definition of '%s'; using default ('%s').\n", temp.c_str(), filename, color_names[i], COLOR_NAMES[interface_defaults[i]]);
}
else {
Assertion(j >= 0 && j < TOTAL_COLORS, "Attempting to copy nonexistant color (%d out of 0-%d)!\n", j, TOTAL_COLORS - 1);
memcpy(interface_colors[i], COLOR_LIST[j], sizeof(color));
}
}
}
}
required_string("#End");
}
// Text color tags; for briefings, command briefings, debriefings, and the fiction viewer
if (optional_string("#Color Tags")) {
while (required_string_either("$Tag:", "#End") < 1) {
required_string("$Tag:");
color temp_color;
char tag;
for (i = 0; i < MAX_DEFAULT_TEXT_COLORS; i++) {
if ( optional_string(color_names[i]) ) {
stuff_string(temp, F_RAW);
if (temp[0] == '$') {
if (temp[1] == '\0') {
Error(LOCATION, "%s - default text color '%s' entry with a solitary '$'.\n", filename, color_names[i]);
Error(LOCATION, "%s - found a '$Tag:' entry with a solitary '$'.\n", filename);
}
*color_value[i] = temp[1];
tag = temp[1];
if (temp[2] != '\0') {
Warning(LOCATION, "%s - default text color '%s' has extra text after the tag '$%c'.\n", filename, color_names[i], *color_value[i]);
}
} else if (temp[0] == '\0') {
Error(LOCATION, "%s - default text color '%s' entry with no tag.\n", filename, color_names[i]);
} else {
*color_value[i] = temp[0];
if (temp[1] != '\0') {
Warning(LOCATION, "%s - default text color '%s' has extra text after the tag '$%c'.\n", filename, color_names[i], *color_value[i]);
Warning(LOCATION, "%s - tag '$%c' has extra text in its definition.\n", filename, tag);
}
}
if (Tagged_Colors.find(*color_value[i]) == Tagged_Colors.end()) {
// Just mprintf() this information instead of complaining with a Warning(); the tag might be defined in a later-loading TBM, and if it isn't, nothing too terrible will happen.
mprintf(("%s - default text color '%s' set to non-existant tag '$%c'.\n", filename, color_names[i], *color_value[i]));
else if (temp[0] == '\0') {
Error(LOCATION, "%s - found a '$Tag:' entry with no tag.\n", filename);
}
else {
tag = temp[0];
if (temp[1] != '\0') {
Warning(LOCATION, "%s - tag '$%c' has extra text in its definition.\n", filename, tag);
}
}
if (Tagged_Colors.find(tag) == Tagged_Colors.end()) { // Only push the tag to our list of tags if it's actually new, not just a redefinition.
Color_Tags.push_back(tag);
}
switch (required_string_one_of(4, "+Color:", "+Friendly", "+Hostile", "+Neutral")) {
case 0: // +Color
required_string("+Color:");
rgba[0] = rgba[1] = rgba[2] = 0;
rgba[3] = 255; // Odds are pretty high you want it to have full alpha...
if (check_for_string("(")) {
stuff_int_list(rgba, 4, RAW_INTEGER_TYPE);
for (j = 0; j < 4; j++) {
if (rgba[j] < 0)
{
Warning(LOCATION, "RGBA value for '$%c' in %s too low (%d), capping to 0.\n", tag, filename, rgba[j]);
rgba[j] = 0;
}
else if (rgba[j] > 255)
{
Warning(LOCATION, "RGBA value for '$%c' in %s too high (%d), capping to 255.\n", tag, filename, rgba[j]);
rgba[j] = 255;
}
}
gr_init_alphacolor(&temp_color, rgba[0], rgba[1], rgba[2], rgba[3]);
Custom_Colors[tag] = temp_color;
Tagged_Colors[tag] = &Custom_Colors[tag];
//} else if ( check_for_string ("#") ) {
// stuff_hex_list(rgba, 4);
// gr_init_alphacolor(&temp_color, rgba[0], rgba[1], rgba[2], rgba[3]);
// Custom_Colors[tag] = temp_color;
// Tagged_Colors[tag] = &Custom_Colors[tag];
}
else {
// We have a string; it should be the name of a color to use.
stuff_string(temp, F_NAME);
for (j = 0; j < TOTAL_COLORS; j++) {
if (!temp.compare(COLOR_NAMES[j])) {
break;
}
}
if (j == TOTAL_COLORS) {
Error(LOCATION, "Unknown color '%s' in %s, for definition of tag '$%c'.\n", temp.c_str(), filename, tag);
}
Tagged_Colors[tag] = COLOR_LIST[j];
}
break;
case 1: // +Friendly
required_string("+Friendly");
Tagged_Colors[tag] = &Brief_color_green;
break;
case 2: // +Hostile
required_string("+Hostile");
Tagged_Colors[tag] = &Brief_color_red;
break;
case 3: // +Neutral
required_string("+Neutral");
Tagged_Colors[tag] = &Brief_color_legacy_neutral;
break;
case -1:
// -noparseerrors is set
if (Tagged_Colors.find(tag) == Tagged_Colors.end()) { // It was a new color, but since we haven't actually defined it...
Color_Tags.pop_back();
}
break;
default:
Assertion(false, "MageKing17 made a coding error somewhere, and you should laugh at him (and report this error).\n");
break;
}
}
required_string("#End");
}
required_string("#End");
Assertion(Color_Tags.size() == Tagged_Colors.size(), "Color_Tags and Tagged_Colors size mismatch; get a coder!\n");
if (optional_string("#Default Text Colors")) {
char* color_names[MAX_DEFAULT_TEXT_COLORS] = {
"$Fiction Viewer:",
"$Command Briefing:",
"$Briefing:",
"$Redalert Briefing:",
"$Debriefing:",
"$Recommendation:",
"$Loop Briefing:",
};
char *color_value[MAX_DEFAULT_TEXT_COLORS] = {
&default_fiction_viewer_color,
&default_command_briefing_color,
&default_briefing_color,
&default_redalert_briefing_color,
&default_debriefing_color,
&default_recommendation_color,
&default_loop_briefing_color,
};
for (i = 0; i < MAX_DEFAULT_TEXT_COLORS; i++) {
if (optional_string(color_names[i])) {
stuff_string(temp, F_RAW);
if (temp[0] == '$') {
if (temp[1] == '\0') {
Error(LOCATION, "%s - default text color '%s' entry with a solitary '$'.\n", filename, color_names[i]);
}
*color_value[i] = temp[1];
if (temp[2] != '\0') {
Warning(LOCATION, "%s - default text color '%s' has extra text after the tag '$%c'.\n", filename, color_names[i], *color_value[i]);
}
}
else if (temp[0] == '\0') {
Error(LOCATION, "%s - default text color '%s' entry with no tag.\n", filename, color_names[i]);
}
else {
*color_value[i] = temp[0];
if (temp[1] != '\0') {
Warning(LOCATION, "%s - default text color '%s' has extra text after the tag '$%c'.\n", filename, color_names[i], *color_value[i]);
}
}
if (Tagged_Colors.find(*color_value[i]) == Tagged_Colors.end()) {
// Just mprintf() this information instead of complaining with a Warning(); the tag might be defined in a later-loading TBM, and if it isn't, nothing too terrible will happen.
mprintf(("%s - default text color '%s' set to non-existant tag '$%c'.\n", filename, color_names[i], *color_value[i]));
}
}
}
required_string("#End");
}
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
}
+3 -2
View File
@@ -33,6 +33,7 @@
#include "io/keycontrol.h" // m!m
#include "debugconsole/console.h"
#include "debugconsole/console.h"
#include "popup/popup.h"
#if defined(SCP_UNIX) && !defined(__APPLE__)
@@ -83,7 +84,7 @@ int gr_alpha_test = 0;
// Default clipping distances
const float Default_min_draw_distance = 1.0f;
const float Default_max_draw_distance = 1e10;
const float Default_max_draw_distance = 10000000.0f;
float Min_draw_distance = Default_min_draw_distance;
float Max_draw_distance = Default_max_draw_distance;
@@ -1771,7 +1772,7 @@ void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float a
void gr_flip()
{
// m!m avoid running CHA_ONFRAME when the "Quit mission" popup is shown. See mantis 2446 for reference
if (!quit_mission_popup_shown)
if (!quit_mission_popup_shown && !popup_active())
{
//WMC - Evaluate global hook if not override.
Script_system.RunBytecode(Script_globalhook);
+97 -92
View File
@@ -579,7 +579,7 @@ void gr_set_font(int fontnum)
void parse_fonts_tbl(char *only_parse_first_font, size_t only_parse_first_font_size)
{
int rval, i;
int i;
char *filename;
// choose file name
@@ -591,99 +591,104 @@ void parse_fonts_tbl(char *only_parse_first_font, size_t only_parse_first_font_s
filename = NULL;
}
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", (filename) ? filename : NOX("<default fonts.tbl>"), rval));
try
{
if (filename != NULL) {
read_file_text(filename, CF_TYPE_TABLES);
}
else {
read_file_text_from_array(defaults_get_file("fonts.tbl"));
}
reset_parse();
// start parsing
required_string("#Fonts");
// read fonts
while (required_string_either("#End", "$Font:")) {
char font_filename[MAX_FILENAME_LEN];
// grab font
required_string("$Font:");
stuff_string(font_filename, F_NAME, MAX_FILENAME_LEN);
// if we only need the first font, copy it and bail
if (only_parse_first_font != NULL) {
strcpy_s(only_parse_first_font, only_parse_first_font_size, font_filename);
return;
}
// create font
int font_id = gr_create_font(font_filename);
if (font_id < 0) {
Warning(LOCATION, "Could not create font from typeface '%s'!", font_filename);
skip_to_start_of_string_either("#End", "$Font:");
}
else {
// max allowed special char index; i.e. 7 special chars in retail fonts 1 & 3
static const int MAX_SPECIAL_CHAR_IDX = UCHAR_MAX - 6;
// 'default' special char index for all languages using this font
int default_special_char_index = 0;
if (optional_string("+Default Special Character Index:")) {
stuff_int(&default_special_char_index);
if (default_special_char_index < 0 || default_special_char_index >= MAX_SPECIAL_CHAR_IDX) {
Error(LOCATION, "Default special character index (%d) for font (%s), must be 0 - %u", default_special_char_index, font_filename, MAX_SPECIAL_CHAR_IDX);
}
for (i = 0; i < (int)Lcl_languages.size(); ++i) {
Lcl_languages[i].special_char_indexes[font_id] = (ubyte)default_special_char_index;
}
}
while (optional_string("+Language:")) {
char lang_name[LCL_LANG_NAME_LEN + 1];
int special_char_index, lang_idx = -1;
stuff_string(lang_name, F_NAME, LCL_LANG_NAME_LEN + 1);
// find language and set the index, or if not found move to the next one
for (i = 0; i < (int)Lcl_languages.size(); ++i) {
if (!strcmp(Lcl_languages[i].lang_name, lang_name)) {
lang_idx = i;
break;
}
}
if (lang_idx == -1) {
Warning(LOCATION, "Ignoring invalid language (%s) specified by font (%s); not built-in or in strings.tbl", lang_name, font_filename);
skip_to_start_of_string_either("+Language:", "$Font:", "#End");
continue;
}
if (optional_string("+Special Character Index:")) {
stuff_int(&special_char_index);
if (special_char_index < 0 || special_char_index >= MAX_SPECIAL_CHAR_IDX) {
Error(LOCATION, "Special character index (%d) for font (%s), language (%s) is invalid, must be 0 - %u", special_char_index, font_filename, lang_name, MAX_SPECIAL_CHAR_IDX);
}
Lcl_languages[lang_idx].special_char_indexes[font_id] = (ubyte)special_char_index;
}
}
}
}
// done parsing
required_string("#End");
// double check
if (Num_fonts < 3) {
Error(LOCATION, "There must be at least three fonts in %s!", (filename) ? filename : NOX("<default fonts.tbl>"));
}
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", (filename) ? filename : NOX("<default fonts.tbl>"), e.what()));
return;
}
if (filename != NULL) {
read_file_text(filename, CF_TYPE_TABLES);
} else {
read_file_text_from_array(defaults_get_file("fonts.tbl"));
}
reset_parse();
// start parsing
required_string("#Fonts");
// read fonts
while (required_string_either("#End","$Font:")) {
char font_filename[MAX_FILENAME_LEN];
// grab font
required_string("$Font:");
stuff_string(font_filename, F_NAME, MAX_FILENAME_LEN);
// if we only need the first font, copy it and bail
if (only_parse_first_font != NULL) {
strcpy_s(only_parse_first_font, only_parse_first_font_size, font_filename);
return;
}
// create font
int font_id = gr_create_font(font_filename);
if (font_id < 0) {
Warning(LOCATION, "Could not create font from typeface '%s'!", font_filename);
skip_to_start_of_string_either("#End","$Font:");
} else {
// max allowed special char index; i.e. 7 special chars in retail fonts 1 & 3
static const int MAX_SPECIAL_CHAR_IDX = UCHAR_MAX-6;
// 'default' special char index for all languages using this font
int default_special_char_index = 0;
if (optional_string("+Default Special Character Index:")) {
stuff_int(&default_special_char_index);
if (default_special_char_index < 0 || default_special_char_index >= MAX_SPECIAL_CHAR_IDX) {
Error(LOCATION, "Default special character index (%d) for font (%s), must be 0 - %u", default_special_char_index, font_filename, MAX_SPECIAL_CHAR_IDX);
}
for (i = 0; i < (int)Lcl_languages.size(); ++i) {
Lcl_languages[i].special_char_indexes[font_id] = (ubyte)default_special_char_index;
}
}
while (optional_string("+Language:")) {
char lang_name[LCL_LANG_NAME_LEN + 1];
int special_char_index, lang_idx = -1;
stuff_string(lang_name, F_NAME, LCL_LANG_NAME_LEN + 1);
// find language and set the index, or if not found move to the next one
for (i = 0; i < (int)Lcl_languages.size(); ++i) {
if (!strcmp(Lcl_languages[i].lang_name, lang_name)) {
lang_idx = i;
break;
}
}
if (lang_idx == -1) {
Warning(LOCATION, "Ignoring invalid language (%s) specified by font (%s); not built-in or in strings.tbl", lang_name, font_filename );
skip_to_start_of_string_either("+Language:","$Font:","#End");
continue;
}
if (optional_string("+Special Character Index:")) {
stuff_int(&special_char_index);
if (special_char_index < 0 || special_char_index >= MAX_SPECIAL_CHAR_IDX) {
Error(LOCATION, "Special character index (%d) for font (%s), language (%s) is invalid, must be 0 - %u", special_char_index, font_filename, lang_name, MAX_SPECIAL_CHAR_IDX);
}
Lcl_languages[lang_idx].special_char_indexes[font_id] = (ubyte)special_char_index;
}
}
}
}
// done parsing
required_string("#End");
// double check
if (Num_fonts < 3) {
Error(LOCATION, "There must be at least three fonts in %s!", (filename) ? filename : NOX("<default fonts.tbl>"));
}
}
void gr_stuff_first_font(char *first_font, size_t first_font_size )
+7 -1
View File
@@ -220,13 +220,19 @@ int generic_anim_stream(generic_anim *ga)
ga->previous_frame = -1;
}
else {
bool in_subdir;
bpp = 32;
if(ga->use_hud_color)
bpp = 8;
bm_load_and_parse_eff(ga->filename, CF_TYPE_ANY, &ga->num_frames, &anim_fps, &ga->keyframe, 0);
bm_load_and_parse_eff(ga->filename, CF_TYPE_ANY, &ga->num_frames, &anim_fps, &ga->keyframe, 0, &in_subdir);
char *p = strrchr( ga->filename, '.' );
if ( p )
*p = 0;
if (in_subdir) {
set_temp_subdir_pathtype(ga->filename);
}
char frame_name[32];
snprintf(frame_name, 32, "%s_0000", ga->filename);
ga->bitmap_id = bm_load(frame_name);
+87 -84
View File
@@ -687,115 +687,118 @@ void gr_opengl_post_process_save_zbuffer()
static bool opengl_post_init_table()
{
int rval;
bool warned = false;
if ( (rval = setjmp(parse_abort)) != 0 ) {
mprintf(("Unable to parse 'post_processing.tbl'! Error code = %d.\n", rval));
return false;
}
try
{
if (cf_exists_full("post_processing.tbl", CF_TYPE_TABLES))
read_file_text("post_processing.tbl", CF_TYPE_TABLES);
else
read_file_text_from_array(defaults_get_file("post_processing.tbl"));
if (cf_exists_full("post_processing.tbl", CF_TYPE_TABLES))
read_file_text("post_processing.tbl", CF_TYPE_TABLES);
else
read_file_text_from_array(defaults_get_file("post_processing.tbl"));
reset_parse();
reset_parse();
if (optional_string("#Effects")) {
while ( !required_string_one_of(3, "$Name:", "#Ship Effects", "#End") ) {
char tbuf[NAME_LENGTH+1] = { 0 };
post_effect_t eff;
if (optional_string("#Effects")) {
while (!required_string_one_of(3, "$Name:", "#Ship Effects", "#End")) {
char tbuf[NAME_LENGTH + 1] = { 0 };
post_effect_t eff;
required_string("$Name:");
stuff_string(tbuf, F_NAME, NAME_LENGTH);
eff.name = tbuf;
required_string("$Name:");
stuff_string(tbuf, F_NAME, NAME_LENGTH);
eff.name = tbuf;
required_string("$Uniform:");
stuff_string(tbuf, F_NAME, NAME_LENGTH);
eff.uniform_name = tbuf;
required_string("$Uniform:");
stuff_string(tbuf, F_NAME, NAME_LENGTH);
eff.uniform_name = tbuf;
required_string("$Define:");
stuff_string(tbuf, F_NAME, NAME_LENGTH);
eff.define_name = tbuf;
required_string("$Define:");
stuff_string(tbuf, F_NAME, NAME_LENGTH);
eff.define_name = tbuf;
required_string("$AlwaysOn:");
stuff_boolean(&eff.always_on);
required_string("$AlwaysOn:");
stuff_boolean(&eff.always_on);
required_string("$Default:");
stuff_float(&eff.default_intensity);
eff.intensity = eff.default_intensity;
required_string("$Default:");
stuff_float(&eff.default_intensity);
eff.intensity = eff.default_intensity;
required_string("$Div:");
stuff_float(&eff.div);
required_string("$Div:");
stuff_float(&eff.div);
required_string("$Add:");
stuff_float(&eff.add);
required_string("$Add:");
stuff_float(&eff.add);
// Post_effects index is used for flag checks, so we can't have more than 32
if (Post_effects.size() < 32) {
Post_effects.push_back( eff );
} else if ( !warned ) {
mprintf(("WARNING: post_processing.tbl can only have a max of 32 effects! Ignoring extra...\n"));
warned = true;
// Post_effects index is used for flag checks, so we can't have more than 32
if (Post_effects.size() < 32) {
Post_effects.push_back(eff);
}
else if (!warned) {
mprintf(("WARNING: post_processing.tbl can only have a max of 32 effects! Ignoring extra...\n"));
warned = true;
}
}
}
}
//Built-in per-ship effects
ship_effect se1;
strcpy_s(se1.name, "FS1 Ship select");
se1.shader_effect = 0;
se1.disables_rendering = false;
se1.invert_timer = false;
Ship_effects.push_back(se1);
//Built-in per-ship effects
ship_effect se1;
strcpy_s(se1.name, "FS1 Ship select");
se1.shader_effect = 0;
se1.disables_rendering = false;
se1.invert_timer = false;
Ship_effects.push_back(se1);
if (optional_string("#Ship Effects")) {
while ( !required_string_one_of(3, "$Name:", "#Light Shafts", "#End") ) {
ship_effect se;
char tbuf[NAME_LENGTH] = { 0 };
if (optional_string("#Ship Effects")) {
while (!required_string_one_of(3, "$Name:", "#Light Shafts", "#End")) {
ship_effect se;
char tbuf[NAME_LENGTH] = { 0 };
required_string("$Name:");
stuff_string(tbuf, F_NAME, NAME_LENGTH);
strcpy_s(se.name, tbuf);
required_string("$Name:");
stuff_string(tbuf, F_NAME, NAME_LENGTH);
strcpy_s(se.name, tbuf);
required_string("$Shader Effect:");
stuff_int(&se.shader_effect);
required_string("$Shader Effect:");
stuff_int(&se.shader_effect);
required_string("$Disables Rendering:");
stuff_boolean(&se.disables_rendering);
required_string("$Disables Rendering:");
stuff_boolean(&se.disables_rendering);
required_string("$Invert timer:");
stuff_boolean(&se.invert_timer);
required_string("$Invert timer:");
stuff_boolean(&se.invert_timer);
Ship_effects.push_back(se);
Ship_effects.push_back(se);
}
}
if (optional_string("#Light Shafts")) {
required_string("$AlwaysOn:");
stuff_boolean(&ls_on);
required_string("$Density:");
stuff_float(&ls_density);
required_string("$Falloff:");
stuff_float(&ls_falloff);
required_string("$Weight:");
stuff_float(&ls_weight);
required_string("$Intensity:");
stuff_float(&ls_intensity);
required_string("$Sample Number:");
stuff_int(&ls_samplenum);
ls_cpintensity = ls_weight;
for (int i = 1; i < ls_samplenum; i++)
ls_cpintensity += ls_weight * pow(ls_falloff, i);
ls_cpintensity *= ls_intensity;
}
required_string("#End");
return true;
}
if (optional_string("#Light Shafts")) {
required_string("$AlwaysOn:");
stuff_boolean(&ls_on);
required_string("$Density:");
stuff_float(&ls_density);
required_string("$Falloff:");
stuff_float(&ls_falloff);
required_string("$Weight:");
stuff_float(&ls_weight);
required_string("$Intensity:");
stuff_float(&ls_intensity);
required_string("$Sample Number:");
stuff_int(&ls_samplenum);
ls_cpintensity = ls_weight;
for(int i = 1; i < ls_samplenum; i++)
ls_cpintensity += ls_weight * pow(ls_falloff, i);
ls_cpintensity *= ls_intensity;
catch (const parse::ParseException& e)
{
mprintf(("Unable to parse 'post_processing.tbl'! Error message = %s.\n", e.what()));
return false;
}
required_string("#End");
return true;
}
static char *opengl_post_load_shader(char *filename, int flags, int flags2)
+1 -1
View File
@@ -1090,7 +1090,7 @@ bool HudGauge::canRender()
}
if (gauge_config == HUD_ETS_GAUGE) {
if (Ships[Player_obj->instance].flags2 & SF2_NO_ETS) {
if (Ships[Player_obj->instance].flags2 & SF2_NO_ETS && !Show_disabled_ets_gauges) {
return false;
}
}
+59 -56
View File
@@ -62,72 +62,75 @@ int ssm_info_lookup(char *name)
// game init
void ssm_init()
{
int rval;
ssm_info bogus, *s;
char weapon_name[NAME_LENGTH];
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "ssm.tbl", rval));
return;
}
try
{
read_file_text("ssm.tbl", CF_TYPE_TABLES);
reset_parse();
read_file_text("ssm.tbl", CF_TYPE_TABLES);
reset_parse();
// parse the table
Ssm_info_count = 0;
while (!optional_string("#end")){
// another ssm definition
if (optional_string("$SSM:")){
// pointer to info struct
if (Ssm_info_count >= MAX_SSM_TYPES){
s = &bogus;
}
else {
s = &Ssm_info[Ssm_info_count];
}
// parse the table
Ssm_info_count = 0;
while(!optional_string("#end")){
// another ssm definition
if(optional_string("$SSM:")){
// pointer to info struct
if(Ssm_info_count >= MAX_SSM_TYPES){
s = &bogus;
} else {
s = &Ssm_info[Ssm_info_count];
}
// name
stuff_string(s->name, F_NAME, NAME_LENGTH);
// name
stuff_string(s->name, F_NAME, NAME_LENGTH);
// stuff data
required_string("+Weapon:");
stuff_string(weapon_name, F_NAME, NAME_LENGTH);
required_string("+Count:");
stuff_int(&s->count);
required_string("+WarpRadius:");
stuff_float(&s->warp_radius);
required_string("+WarpTime:");
stuff_float(&s->warp_time);
// According to fireballs.cpp, "Warp lifetime must be at least 4 seconds!"
if ((s->warp_time) < 4.0f) {
// So let's warn them before they try to use it, shall we?
Warning(LOCATION, "Expected a '+WarpTime:' value equal or greater than 4.0, found '%f' in weapon '%s'.\n Setting to 4.0, please check and set to a number 4.0 or greater!\n", s->warp_time, weapon_name);
// And then make the Assert obsolete -- Zacam
s->warp_time = 4.0f;
}
required_string("+Radius:");
stuff_float(&s->radius);
required_string("+Offset:");
stuff_float(&s->offset);
if (optional_string("+HUD Message:"))
stuff_boolean(&s->send_message);
else
s->send_message = true;
if (optional_string("+Custom Message:")) {
stuff_string(s->message, F_NAME, NAME_LENGTH);
s->use_custom_message = true;
}
parse_sound("+Alarm Sound:", &s->sound_index, s->name);
// stuff data
required_string("+Weapon:");
stuff_string(weapon_name, F_NAME, NAME_LENGTH);
required_string("+Count:");
stuff_int(&s->count);
required_string("+WarpRadius:");
stuff_float(&s->warp_radius);
required_string("+WarpTime:");
stuff_float(&s->warp_time);
// According to fireballs.cpp, "Warp lifetime must be at least 4 seconds!"
if ( (s->warp_time) < 4.0f) {
// So let's warn them before they try to use it, shall we?
Warning(LOCATION, "Expected a '+WarpTime:' value equal or greater than 4.0, found '%f' in weapon '%s'.\n Setting to 4.0, please check and set to a number 4.0 or greater!\n", s->warp_time, weapon_name);
// And then make the Assert obsolete -- Zacam
s->warp_time = 4.0f;
}
required_string("+Radius:");
stuff_float(&s->radius);
required_string("+Offset:");
stuff_float(&s->offset);
if (optional_string("+HUD Message:"))
stuff_boolean(&s->send_message);
else
s->send_message = true;
if (optional_string("+Custom Message:")) {
stuff_string(s->message, F_NAME, NAME_LENGTH);
s->use_custom_message = true;
}
parse_sound("+Alarm Sound:", &s->sound_index, s->name);
// see if we have a valid weapon
s->weapon_info_index = -1;
s->weapon_info_index = weapon_info_lookup(weapon_name);
if(s->weapon_info_index >= 0){
// valid
Ssm_info_count++;
// see if we have a valid weapon
s->weapon_info_index = -1;
s->weapon_info_index = weapon_info_lookup(weapon_name);
if (s->weapon_info_index >= 0){
// valid
Ssm_info_count++;
}
}
}
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "ssm.tbl", e.what()));
return;
}
}
void ssm_get_random_start_pos(vec3d *out, vec3d *start, matrix *orient, int ssm_index)
+26 -23
View File
@@ -1641,40 +1641,43 @@ void hud_config_color_save(char *name)
void hud_config_color_load(char *name)
{
int idx, rval;
int idx;
char str[1024];
char *fname;
fname = cf_add_ext(name, ".hcf");
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("HUDCONFIG: Unable to parse '%s'! Error code = %i.\n", fname, rval));
return;
}
try
{
read_file_text(fname);
reset_parse();
read_file_text(fname);
reset_parse();
// First, set all gauges to the current main color
for (idx = 0; idx < NUM_HUD_GAUGES; idx++){
gr_init_alphacolor(&HUD_config.clr[idx], HUD_color_red, HUD_color_green, HUD_color_blue, (HUD_color_alpha + 1) * 16);
}
// First, set all gauges to the current main color
for (idx=0; idx<NUM_HUD_GAUGES; idx++){
gr_init_alphacolor(&HUD_config.clr[idx], HUD_color_red, HUD_color_green, HUD_color_blue, (HUD_color_alpha+1)*16);
}
// Now read in the color values for the gauges
while (optional_string("+Gauge:")) {
stuff_string(str, F_NAME, sizeof(str));
// Now read in the color values for the gauges
while (optional_string("+Gauge:")) {
stuff_string(str, F_NAME, sizeof(str));
for (idx=0; idx<NUM_HUD_GAUGES; idx++) {
if (!stricmp(str, Hud_Gauge_Names[idx])) {
required_string("+RGBA:");
stuff_ubyte(&HUD_config.clr[idx].red);
stuff_ubyte(&HUD_config.clr[idx].green);
stuff_ubyte(&HUD_config.clr[idx].blue);
stuff_ubyte(&HUD_config.clr[idx].alpha);
break;
for (idx = 0; idx < NUM_HUD_GAUGES; idx++) {
if (!stricmp(str, Hud_Gauge_Names[idx])) {
required_string("+RGBA:");
stuff_ubyte(&HUD_config.clr[idx].red);
stuff_ubyte(&HUD_config.clr[idx].green);
stuff_ubyte(&HUD_config.clr[idx].blue);
stuff_ubyte(&HUD_config.clr[idx].alpha);
break;
}
}
}
}
catch (const parse::ParseException& e)
{
mprintf(("HUDCONFIG: Unable to parse '%s'! Error message = %s.\n", fname, e.what()));
return;
}
}
void hud_config_alpha_slider_up()
+4
View File
@@ -420,6 +420,10 @@ int hud_abort_lock()
return 1;
}
if ( Player_ship->flags2 & SF2_NO_SECONDARY_LOCKON ) {
return 1;
}
// if we're on the same team and the team doesn't attack itself, then don't lock!
if ((Player_ship->team == target_team) && (!iff_x_attacks_y(Player_ship->team, target_team)))
{
+204 -183
View File
@@ -46,6 +46,7 @@ int Hud_reticle_style = HUD_RETICLE_STYLE_FS2;
bool Hud_retail = true;
bool Scale_retail_gauges = true;
bool Show_disabled_ets_gauges = false;
int Hud_font = -1;
@@ -164,7 +165,7 @@ int parse_ship_start()
void parse_hud_gauges_tbl(const char *filename)
{
int i, rval;
int i;
char *saved_Mp = NULL;
int colors[3] = {255, 255, 255};
@@ -174,110 +175,112 @@ void parse_hud_gauges_tbl(const char *filename)
color *ship_clr_p = NULL;
bool scale_gauge = true;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
return;
}
try
{
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
if(optional_string("$Load Retail Configuration:")) {
stuff_boolean(&Hud_retail);
}
if ( optional_string("$Color:") ) {
stuff_int_list(colors, 3);
check_color(colors);
gr_init_alphacolor(&hud_color, colors[0], colors[1], colors[2], 255);
hud_clr_p = &hud_color;
}
if(optional_string("$Font:")) {
stuff_int(&Hud_font);
}
if(optional_string("$Max Directives:")) {
stuff_int(&Max_directives);
}
if(optional_string("$Max Escort Ships:")) {
stuff_int(&Max_escort_ships);
}
if(optional_string("$Length Unit Multiplier:")) {
stuff_float(&Hud_unit_multiplier);
if (Hud_unit_multiplier <= 0.0f) {
Warning(LOCATION, "\"$Length Unit Multiplier:\" value of \"%f\" is invalid! Resetting to default.", Hud_unit_multiplier);
Hud_unit_multiplier = 1.0f;
if (optional_string("$Load Retail Configuration:")) {
stuff_boolean(&Hud_retail);
}
}
if(optional_string("$Speed Unit Multiplier:")) {
stuff_float(&Hud_speed_multiplier);
if (optional_string("$Color:")) {
stuff_int_list(colors, 3);
if (Hud_speed_multiplier <= 0.0f) {
Warning(LOCATION, "\"$Speed Unit Multiplier:\" value of \"%f\" is invalid! Resetting to default.", Hud_speed_multiplier);
Hud_speed_multiplier = 1.0f;
check_color(colors);
gr_init_alphacolor(&hud_color, colors[0], colors[1], colors[2], 255);
hud_clr_p = &hud_color;
}
} else {
Hud_speed_multiplier = Hud_unit_multiplier;
}
if (optional_string("$Wireframe Targetbox:")) {
stuff_int(&Targetbox_wire);
if ((Targetbox_wire < 0) || (Targetbox_wire > 3)) {
Targetbox_wire = 0;
if (optional_string("$Font:")) {
stuff_int(&Hud_font);
}
}
if (optional_string("$Targetbox Shader Effect:")) {
stuff_int(&Targetbox_shader_effect);
if (Targetbox_shader_effect < 0) {
Targetbox_shader_effect = 0;
if (optional_string("$Max Directives:")) {
stuff_int(&Max_directives);
}
}
if (optional_string("$Lock Wireframe Mode:")) {
stuff_boolean(&Lock_targetbox_mode);
}
if (optional_string("$Max Escort Ships:")) {
stuff_int(&Max_escort_ships);
}
if (optional_string("$Scale Gauges:")) {
stuff_boolean(&scale_gauge);
Scale_retail_gauges = scale_gauge;
}
if (optional_string("$Length Unit Multiplier:")) {
stuff_float(&Hud_unit_multiplier);
if(optional_string("$Reticle Style:")) {
int temp = required_string_either("FS1", "FS2");
if (Hud_unit_multiplier <= 0.0f) {
Warning(LOCATION, "\"$Length Unit Multiplier:\" value of \"%f\" is invalid! Resetting to default.", Hud_unit_multiplier);
Hud_unit_multiplier = 1.0f;
}
}
// using require_string_either won't advance the Mp pointer to the next token so force it instead
skip_to_start_of_string("#Gauge Config");
if (optional_string("$Speed Unit Multiplier:")) {
stuff_float(&Hud_speed_multiplier);
if (temp < 0)
Warning(LOCATION, "Undefined reticle style in hud_gauges.tbl!");
else
Hud_reticle_style = temp;
}
if (Hud_speed_multiplier <= 0.0f) {
Warning(LOCATION, "\"$Speed Unit Multiplier:\" value of \"%f\" is invalid! Resetting to default.", Hud_speed_multiplier);
Hud_speed_multiplier = 1.0f;
}
}
else {
Hud_speed_multiplier = Hud_unit_multiplier;
}
int base_res[2];
int ship_idx = -1;
int ship_font = -1;
int gauge_type = -1;
int use_font = -1;
color *use_clr_p = NULL;
SCP_vector<int> ship_classes;
bool retail_config = false;
int n_ships = 0;
if (optional_string("$Wireframe Targetbox:")) {
stuff_int(&Targetbox_wire);
if ((Targetbox_wire < 0) || (Targetbox_wire > 3)) {
Targetbox_wire = 0;
}
}
while(optional_string("#Gauge Config")) {
ship_classes.clear();
switch (optional_string_either("$Ship:", "$Ships:")) {
if (optional_string("$Targetbox Shader Effect:")) {
stuff_int(&Targetbox_shader_effect);
if (Targetbox_shader_effect < 0) {
Targetbox_shader_effect = 0;
}
}
if (optional_string("$Lock Wireframe Mode:")) {
stuff_boolean(&Lock_targetbox_mode);
}
if (optional_string("$Scale Gauges:")) {
stuff_boolean(&scale_gauge);
Scale_retail_gauges = scale_gauge;
}
if (optional_string("$Reticle Style:")) {
int temp = required_string_either("FS1", "FS2");
// using require_string_either won't advance the Mp pointer to the next token so force it instead
skip_to_start_of_string("#Gauge Config");
if (temp < 0)
Warning(LOCATION, "Undefined reticle style in hud_gauges.tbl!");
else
Hud_reticle_style = temp;
}
if (optional_string("$Show disabled ETS gauges:")) {
stuff_boolean(&Show_disabled_ets_gauges);
}
int base_res[2];
int ship_idx = -1;
int ship_font = -1;
int gauge_type = -1;
int use_font = -1;
color *use_clr_p = NULL;
SCP_vector<int> ship_classes;
bool retail_config = false;
int n_ships = 0;
while (optional_string("#Gauge Config")) {
ship_classes.clear();
switch (optional_string_either("$Ship:", "$Ships:")) {
case 0:
mprintf(("$Ship in hud_gauges.tbl and -hdg.tbms is deprecated. Use \"$Ships: (\"Some ship class\") instead.\n"));
if(!ships_inited) {
if (!ships_inited) {
// just in case ship info has not been initialized.
skip_to_start_of_string("#Gauge Config");
continue;
@@ -287,15 +290,15 @@ void parse_hud_gauges_tbl(const char *filename)
ship_idx = parse_ship_start();
ship_classes.push_back(ship_idx);
if(ship_idx >= 0) {
if (ship_idx >= 0) {
Ship_info[ship_idx].hud_enabled = true;
// see if we need to load defaults for this configuration
if(optional_string("$Load Retail Configuration:")) {
if (optional_string("$Load Retail Configuration:")) {
stuff_boolean(&Ship_info[ship_idx].hud_retail);
}
if ( optional_string("$Color:") ) {
if (optional_string("$Color:")) {
stuff_int_list(colors, 3);
check_color(colors);
@@ -303,10 +306,11 @@ void parse_hud_gauges_tbl(const char *filename)
ship_clr_p = &ship_color;
}
if(optional_string("$Font:")) {
if (optional_string("$Font:")) {
stuff_int(&ship_font);
}
} else {
}
else {
// can't find ship class. move on.
ship_classes.push_back(-1);
skip_to_start_of_string("#Gauge Config");
@@ -319,7 +323,7 @@ void parse_hud_gauges_tbl(const char *filename)
n_ships = stuff_int_list(shiparray, 256, SHIP_INFO_TYPE);
if(optional_string("$Load Retail Configuration:")) {
if (optional_string("$Load Retail Configuration:")) {
stuff_boolean(&retail_config);
}
@@ -329,7 +333,7 @@ void parse_hud_gauges_tbl(const char *filename)
Ship_info[shiparray[i]].hud_retail = retail_config;
}
if ( optional_string("$Color:") ) {
if (optional_string("$Color:")) {
stuff_int_list(colors, 3);
check_color(colors);
@@ -337,119 +341,131 @@ void parse_hud_gauges_tbl(const char *filename)
ship_clr_p = &ship_color;
}
if(optional_string("$Font:")) {
if (optional_string("$Font:")) {
stuff_int(&ship_font);
}
break;
default:
// No particular ship. -1 for default HUD configuration.
ship_classes.push_back(-1);
ship_font = -1;
ship_clr_p = NULL;
break;
}
// No particular ship. -1 for default HUD configuration.
ship_classes.push_back(-1);
ship_font = -1;
ship_clr_p = NULL;
break;
}
if ( ship_clr_p != NULL ) {
use_clr_p = ship_clr_p;
} else {
use_clr_p = hud_clr_p;
}
if (ship_clr_p != NULL) {
use_clr_p = ship_clr_p;
}
else {
use_clr_p = hud_clr_p;
}
if(ship_font >= 0) {
use_font = ship_font;
} else {
use_font = Hud_font;
}
if (ship_font >= 0) {
use_font = ship_font;
}
else {
use_font = Hud_font;
}
// Now start going through resolution info for this HUD layout
required_string("$Base:");
// Now start going through resolution info for this HUD layout
required_string("$Base:");
// get the base width and height describing this HUD
stuff_int_list(base_res, 2, RAW_INTEGER_TYPE);
// get the base width and height describing this HUD
stuff_int_list(base_res, 2, RAW_INTEGER_TYPE);
// gauge scaling for this base res?
if (optional_string("$Scale Gauges:")) {
stuff_boolean(&scale_gauge);
}
// gauge scaling for this base res?
if (optional_string("$Scale Gauges:")) {
stuff_boolean(&scale_gauge);
}
// Pruning time. Let's see if the current resolution defined by the user matches the conditions set by this entry
if(optional_string("$Required Aspect:")) {
// filter aspect ratio.
if(optional_string("Full Screen")) {
if( (float)gr_screen.max_w / (float)gr_screen.max_h > 1.5) {
skip_to_start_of_string("#Gauge Config");
//skip_to_start_of_string_either("#Gauge Config", "#End");
continue;
// Pruning time. Let's see if the current resolution defined by the user matches the conditions set by this entry
if (optional_string("$Required Aspect:")) {
// filter aspect ratio.
if (optional_string("Full Screen")) {
if ((float)gr_screen.max_w / (float)gr_screen.max_h > 1.5) {
skip_to_start_of_string("#Gauge Config");
//skip_to_start_of_string_either("#Gauge Config", "#End");
continue;
}
}
} else if(optional_string("Wide Screen")) {
if( (float)gr_screen.max_w / (float)gr_screen.max_h <= 1.5) {
skip_to_start_of_string("#Gauge Config");
//skip_to_start_of_string_either("#Gauge Config", "#End");
continue;
else if (optional_string("Wide Screen")) {
if ((float)gr_screen.max_w / (float)gr_screen.max_h <= 1.5) {
skip_to_start_of_string("#Gauge Config");
//skip_to_start_of_string_either("#Gauge Config", "#End");
continue;
}
}
}
}
// check minimum resolution
if(optional_string("$Min:")) {
int min_res[2];
stuff_int_list(min_res, 2, RAW_INTEGER_TYPE);
if(min_res[0] > gr_screen.max_w) {
skip_to_start_of_string("#Gauge Config");
continue;
} else if (min_res[0] == gr_screen.max_w) {
if(min_res[1] > gr_screen.max_h) {
}
// check minimum resolution
if (optional_string("$Min:")) {
int min_res[2];
stuff_int_list(min_res, 2, RAW_INTEGER_TYPE);
if (min_res[0] > gr_screen.max_w) {
skip_to_start_of_string("#Gauge Config");
continue;
}
else if (min_res[0] == gr_screen.max_w) {
if (min_res[1] > gr_screen.max_h) {
skip_to_start_of_string("#Gauge Config");
continue;
}
}
}
}
// check maximum resolution
if(optional_string("$Max:")) {
int max_res[2];
stuff_int_list(max_res, 2, RAW_INTEGER_TYPE);
// check maximum resolution
if (optional_string("$Max:")) {
int max_res[2];
stuff_int_list(max_res, 2, RAW_INTEGER_TYPE);
if(max_res[0] < gr_screen.max_w) {
skip_to_start_of_string("#Gauge Config");
continue;
} else if (max_res[0] == gr_screen.max_w) {
if(max_res[1] < gr_screen.max_h) {
if (max_res[0] < gr_screen.max_w) {
skip_to_start_of_string("#Gauge Config");
continue;
}
else if (max_res[0] == gr_screen.max_w) {
if (max_res[1] < gr_screen.max_h) {
skip_to_start_of_string("#Gauge Config");
continue;
}
}
}
// let's start parsing for gauges.
required_string("$Gauges:");
while (!check_for_string("$Gauges:") && !check_for_string("$End Gauges")) {
// find out what type of gauge we're parsing.
gauge_type = parse_gauge_type();
// then call the specific gauge load handler function for this gauge type.
if (optional_string("default")) {
// sending -1 base width and height will indicate GR_640 or GR_1024 to the handlers
load_gauge(gauge_type, -1, -1, use_font, scale_gauge, &ship_classes, use_clr_p);
}
else {
load_gauge(gauge_type, base_res[0], base_res[1], use_font, scale_gauge, &ship_classes, use_clr_p);
}
if (saved_Mp && (saved_Mp == Mp)) {
Mp++;
}
skip_to_start_of_string_either("$", "+");
// stolened from AI_profiles
// if we've been through once already and are at the same place, force a move
saved_Mp = Mp;
}
required_string("$End Gauges");
required_string("#End");
}
// let's start parsing for gauges.
required_string("$Gauges:");
while (!check_for_string("$Gauges:") && !check_for_string("$End Gauges")) {
// find out what type of gauge we're parsing.
gauge_type = parse_gauge_type();
// then call the specific gauge load handler function for this gauge type.
if(optional_string("default")) {
// sending -1 base width and height will indicate GR_640 or GR_1024 to the handlers
load_gauge(gauge_type, -1, -1, use_font, scale_gauge, &ship_classes, use_clr_p);
} else {
load_gauge(gauge_type, base_res[0], base_res[1], use_font, scale_gauge, &ship_classes, use_clr_p);
}
if ( saved_Mp && (saved_Mp == Mp) ) {
Mp++;
}
skip_to_start_of_string_either("$", "+");
// stolened from AI_profiles
// if we've been through once already and are at the same place, force a move
saved_Mp = Mp;
}
required_string("$End Gauges");
required_string("#End");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
}
@@ -2006,6 +2022,7 @@ void load_gauge_center_reticle(int base_w, int base_h, int hud_font, bool scale_
int scaleX = 15;
int scaleY = 10;
int size = 5;
int autoaim_frame = -1;
if(Hud_reticle_style == HUD_RETICLE_STYLE_FS1) {
if(gr_screen.res == GR_640) {
@@ -2055,8 +2072,12 @@ void load_gauge_center_reticle(int base_w, int base_h, int hud_font, bool scale_
if (optional_string("Firepoint Y coordinate multiplier:"))
stuff_int(&scaleY);
if(optional_string("Autoaim Frame:"))
stuff_int(&autoaim_frame);
hud_gauge->initBitmaps(fname);
hud_gauge->initFirepointDisplay(firepoints, scaleX, scaleY, size);
hud_gauge->setAutoaimFrame(autoaim_frame);
if(ship_idx->at(0) >= 0) {
for (SCP_vector<int>::iterator ship_index = ship_idx->begin(); ship_index != ship_idx->end(); ++ship_index) {
+1
View File
@@ -20,6 +20,7 @@ extern float Hud_speed_multiplier;
#define HUD_RETICLE_STYLE_FS2 1
extern int Hud_reticle_style;
extern bool Show_disabled_ets_gauges;
//Functions
int hud_get_gauge_index(char* name);
+66 -12
View File
@@ -20,6 +20,7 @@
#include "weapon/emp.h"
#include "localization/localize.h"
#include "network/multi.h"
#include "weapon/weapon.h"
#define NUM_RETICLE_ANIS 11 // keep up to date when modifying the number of reticle ani files
@@ -228,6 +229,7 @@ static int Threat_lock_frame; // frame offset of current lock flashing warnin
HudGaugeReticle::HudGaugeReticle():
HudGauge(HUD_OBJECT_CENTER_RETICLE, HUD_CENTER_RETICLE, true, false, (VM_EXTERNAL | VM_DEAD_VIEW | VM_WARP_CHASE | VM_PADLOCK_ANY | VM_TOPDOWN | VM_OTHER_SHIP), 255, 255, 255)
{
has_autoaim_lock = false;
}
void HudGaugeReticle::initBitmaps(char *fname)
@@ -247,9 +249,39 @@ void HudGaugeReticle::initFirepointDisplay(bool firepoint, int scaleX, int scale
void HudGaugeReticle::render(float frametime)
{
ship_info *sip = &Ship_info[Player_ship->ship_info_index];
if (autoaim_frame_offset > 0 || sip->autoaim_lock_snd > -1 || sip->autoaim_lost_snd > -1) {
ship *shipp = &Ships[Objects[Player->objnum].instance];
ship_weapon *swp = &shipp->weapons;
ai_info *aip = &Ai_info[shipp->ai_index];
if (aip->target_objnum != -1) {
bool autoaiming = false;
autoaiming = in_autoaim_fov(shipp, swp->current_primary_bank, &Objects[aip->target_objnum]);
if (autoaiming) {
if (!has_autoaim_lock && sip->autoaim_lock_snd > -1) {
snd_play( &Snds[sip->autoaim_lock_snd]);
}
has_autoaim_lock = true;
}
else {
if (has_autoaim_lock && sip->autoaim_lost_snd > -1) {
snd_play( &Snds[sip->autoaim_lost_snd]);
}
has_autoaim_lock = false;
}
}
}
setGaugeColor(HUD_C_BRIGHT);
renderBitmap(crosshair.first_frame, position[0], position[1]);
if (has_autoaim_lock)
renderBitmap(crosshair.first_frame + autoaim_frame_offset, position[0], position[1]);
else
renderBitmap(crosshair.first_frame, position[0], position[1]);
if (firepoint_display) {
fp.clear();
@@ -277,7 +309,7 @@ void HudGaugeReticle::render(float frametime)
void HudGaugeReticle::getFirepointStatus() {
//First, get the player ship
ship_info* pship;
ship_info* sip;
ship* shipp;
polymodel* pm;
@@ -285,30 +317,45 @@ void HudGaugeReticle::getFirepointStatus() {
if (Objects[Player->objnum].type == OBJ_SHIP) {
shipp = &Ships[Objects[Player->objnum].instance];
pship = &Ship_info[shipp->ship_info_index];
sip = &Ship_info[shipp->ship_info_index];
//Get the player eyepoint
pm = model_get(pship->model_num);
pm = model_get(sip->model_num);
if (pm->n_view_positions == 0) {
mprintf(("Model %s does not have a defined eyepoint. Firepoint display could not be generated\n", pm->filename));
} else {
if (pm->n_guns > 0) {
if (pm->n_guns > 0) {
eye eyepoint = pm->view_positions[shipp->current_viewpoint];
vec2d ep = { eyepoint.pnt.xyz.x, eyepoint.pnt.xyz.y };
for (int i = 0; i < pm->n_guns; i++) {
int isactive = 0;
int bankactive = 0;
ship_weapon *swp = &shipp->weapons;
if (!timestamp_elapsed(shipp->weapons.next_primary_fire_stamp[i]))
isactive = 1;
bankactive = 1;
else if (timestamp_elapsed(shipp->weapons.primary_animation_done_time[i]))
isactive = 1;
bankactive = 1;
else if (i == shipp->weapons.current_primary_bank || shipp->flags & SF_PRIMARY_LINKED)
isactive = 2;
bankactive = 2;
int num_slots = pm->gun_banks[i].num_slots;
for (int j = 0; j < num_slots; j++) {
int fpactive = bankactive;
if (sip->flags2 & SIF2_DYN_PRIMARY_LINKING) {
// If this firepoint is not among the next shot(s) to be fired, dim it one step
if ( !( (j >= (shipp->last_fired_point[i]+1) % num_slots) && (j <= (shipp->last_fired_point[i]+swp->primary_bank_slot_count[i]) % num_slots) ) ) {
fpactive--;
}
} else if (Weapon_info[swp->primary_bank_weapons[i]].wi_flags2 & WIF2_CYCLE) {
// If this firepoint is not the next one to be fired, dim it one step
if (j != (shipp->last_fired_point[i]+1) % num_slots) {
fpactive--;
}
}
for (int j = 0; j < pm->gun_banks[i].num_slots; j++) {
vec3d fpfromeye;
matrix eye_orient, player_transpose;
@@ -317,7 +364,7 @@ void HudGaugeReticle::getFirepointStatus() {
vm_matrix_x_matrix(&eye_orient, &player_transpose, &Eye_matrix);
vm_vec_rotate(&fpfromeye, &pm->gun_banks[i].pnt[j], &eye_orient);
firepoint tmp = { { fpfromeye.xyz.x - ep.x, ep.y - fpfromeye.xyz.y }, isactive };
firepoint tmp = { { fpfromeye.xyz.x - ep.x, ep.y - fpfromeye.xyz.y }, fpactive };
fp.push_back(tmp);
}
}
@@ -326,6 +373,13 @@ void HudGaugeReticle::getFirepointStatus() {
}
}
void HudGaugeReticle::setAutoaimFrame(int framenum) {
if (framenum < 0 || framenum > crosshair.num_frames - 1)
autoaim_frame_offset = 0;
else
autoaim_frame_offset = framenum;
}
void HudGaugeReticle::pageIn()
{
bm_page_in_aabitmap( crosshair.first_frame, crosshair.num_frames);
+3
View File
@@ -43,6 +43,8 @@ protected:
int firepoint_size;
int firepoint_scale_x;
int firepoint_scale_y;
int autoaim_frame_offset;
bool has_autoaim_lock;
public:
HudGaugeReticle();
void render(float frametime);
@@ -50,6 +52,7 @@ public:
void pageIn();
void initFirepointDisplay(bool firepoint, int scaleX, int scaleY, int size);
void getFirepointStatus();
void setAutoaimFrame(int framenum);
};
class HudGaugeThrottle: public HudGauge
+1 -1
View File
@@ -1095,7 +1095,7 @@ void hud_target_subobject_common(int next_flag)
target_shipp = &Ships[Objects[Player_ai->target_objnum].instance];
if (!Player_ai->targeted_subsys) {
start = GET_FIRST(&target_shipp->subsys_list);
start = END_OF_LIST(&target_shipp->subsys_list);
} else {
start = Player_ai->targeted_subsys;
}
+398 -397
View File
@@ -128,406 +128,407 @@ void iff_init()
int i, j, k;
int string_idx;
int rval;
if ((rval = setjmp(parse_abort)) != 0)
try
{
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "iff_defs.tbl", rval));
// Goober5000 - if table doesn't exist, use the default table
if (cf_exists_full("iff_defs.tbl", CF_TYPE_TABLES))
read_file_text("iff_defs.tbl", CF_TYPE_TABLES);
else
read_file_text_from_array(defaults_get_file("iff_defs.tbl"));
reset_parse();
// parse the table --------------------------------------------------------
required_string("#IFFs");
// get the traitor
required_string("$Traitor IFF:");
stuff_string(traitor_name, F_NAME, NAME_LENGTH);
int rgb[3];
// check if alternate colours are wanted to be used for these
// Marks various stuff... like asteroids
if ((optional_string("$Selection Color:")) || (optional_string("$Selection Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
iff_init_color(rgb[0], rgb[1], rgb[2]);
}
else
iff_init_color(0xff, 0xff, 0xff);
// Marks the ship currently saying something
if ((optional_string("$Message Color:")) || (optional_string("$Message Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
iff_init_color(rgb[0], rgb[1], rgb[2]);
}
else
iff_init_color(0x7f, 0x7f, 0x7f);
// Marks the tagged ships
if ((optional_string("$Tagged Color:")) || (optional_string("$Tagged Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
iff_init_color(rgb[0], rgb[1], rgb[2]);
}
else
iff_init_color(0xff, 0xff, 0x00);
// init radar blips colour table
int a_bright, a_dim;
bool alternate_blip_color = false;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 2; j++)
{
for (k = 0; k < 3; k++)
{
radar_iff_color[i][j][k] = -1;
}
}
}
// if the bright/dim scaling is wanted to be changed
if (optional_string("$Dimmed IFF brightness:"))
{
int dim_iff_brightness;
stuff_int(&dim_iff_brightness);
Assert(dim_iff_brightness >= 0 && dim_iff_brightness <= HUD_COLOR_ALPHA_MAX);
*iff_color_brightness = dim_iff_brightness;
}
else
*iff_color_brightness = 4;
// alternate = use same method as with ship blips
// retail = use 1/2 intensities
if (optional_string("$Use Alternate Blip Coloring:") || optional_string("$Use Alternate Blip Colouring:"))
{
stuff_boolean(&alternate_blip_color);
}
// Parse blip colours, their order is hardcoded.
if ((optional_string("$Missile Blip Color:")) || (optional_string("$Missile Blip Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i = 0; i < 3; i++)
{
Assert(rgb[i] >= 0 && rgb[i] <= 255);
radar_iff_color[0][1][i] = rgb[i];
radar_iff_color[0][0][i] = rgb[i] / 2;
}
}
if ((optional_string("$Navbuoy Blip Color:")) || (optional_string("$Navbuoy Blip Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i = 0; i < 3; i++)
{
Assert(rgb[i] >= 0 && rgb[i] <= 255);
radar_iff_color[1][1][i] = rgb[i];
radar_iff_color[1][0][i] = rgb[i] / 2;
}
}
if ((optional_string("$Warping Blip Color:")) || (optional_string("$Warping Blip Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i = 0; i < 3; i++)
{
Assert(rgb[i] >= 0 && rgb[i] <= 255);
radar_iff_color[2][1][i] = rgb[i];
radar_iff_color[2][0][i] = rgb[i] / 2;
}
}
if ((optional_string("$Node Blip Color:")) || (optional_string("$Node Blip Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i = 0; i < 3; i++)
{
Assert(rgb[i] >= 0 && rgb[i] <= 255);
radar_iff_color[3][1][i] = rgb[i];
radar_iff_color[3][0][i] = rgb[i] / 2;
}
}
if ((optional_string("$Tagged Blip Color:")) || (optional_string("$Tagged Blip Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i = 0; i < 3; i++)
{
Assert(rgb[i] >= 0 && rgb[i] <= 255);
radar_iff_color[4][1][i] = rgb[i];
radar_iff_color[4][0][i] = rgb[i] / 2;
}
}
if (alternate_blip_color == true)
{
a_bright = iff_get_alpha_value(true);
a_dim = iff_get_alpha_value(false);
for (i = 0; i < 5; i++)
{
if (radar_iff_color[i][0][0] >= 0)
{
for (j = 0; j < 3; j++)
{
radar_iff_color[i][0][j] = radar_iff_color[i][1][j];
}
radar_iff_color[i][1][3] = a_bright;
radar_iff_color[i][0][3] = a_dim;
}
}
}
else
{
for (i = 0; i < 5; i++)
{
if (radar_iff_color[i][0][0] >= 0)
{
radar_iff_color[i][0][3] = 255;
radar_iff_color[i][1][3] = 255;
}
}
}
if (optional_string("$Radar Target ID Flags:")) {
parse_string_flag_list((int*)&radar_target_id_flags, rti_flags, Num_rti_flags);
if (optional_string("+reset"))
radar_target_id_flags = 0;
}
// begin reading data
Num_iffs = 0;
while (required_string_either("#End", "$IFF Name:"))
{
iff_info *iff;
int cur_iff;
// make sure we're under the limit
if (Num_iffs >= MAX_IFFS)
{
Warning(LOCATION, "Too many iffs in iffs_defs.tbl! Max is %d.\n", MAX_IFFS);
skip_to_start_of_string("#End", NULL);
break;
}
// add new IFF
iff = &Iff_info[Num_iffs];
cur_iff = Num_iffs;
Num_iffs++;
// get required IFF info ----------------------------------------------
// get the iff name
required_string("$IFF Name:");
stuff_string(iff->iff_name, F_NAME, NAME_LENGTH);
// get the iff color
if (check_for_string("$Colour:"))
required_string("$Colour:");
else
required_string("$Color:");
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
iff->color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
// get relationships between IFFs -------------------------------------
// get the list of iffs attacked
if (optional_string("$Attacks:"))
num_attack_names[cur_iff] = stuff_string_list(attack_names[cur_iff], MAX_IFFS);
else
num_attack_names[cur_iff] = 0;
// get the list of observed colors
num_observed_colors[cur_iff] = 0;
while (optional_string("+Sees"))
{
// get iff observed
stuff_string_until(observed_color_table[cur_iff][num_observed_colors[cur_iff]].iff_name, "As:", NAME_LENGTH);
required_string("As:");
// get color observed
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
observed_color_table[cur_iff][num_observed_colors[cur_iff]].color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
// increment
num_observed_colors[cur_iff]++;
}
// get flags ----------------------------------------------------------
// get iff flags
iff->flags = 0;
if (optional_string("$Flags:"))
{
char flag_strings[MAX_IFF_FLAGS][NAME_LENGTH];
int num_strings = stuff_string_list(flag_strings, MAX_IFF_FLAGS);
for (string_idx = 0; string_idx < num_strings; string_idx++)
{
if (!stricmp(NOX("support allowed"), flag_strings[string_idx]))
iff->flags |= IFFF_SUPPORT_ALLOWED;
else if (!stricmp(NOX("exempt from all teams at war"), flag_strings[string_idx]))
iff->flags |= IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR;
else if (!stricmp(NOX("orders hidden"), flag_strings[string_idx]))
iff->flags |= IFFF_ORDERS_HIDDEN;
else if (!stricmp(NOX("orders shown"), flag_strings[string_idx]))
iff->flags |= IFFF_ORDERS_SHOWN;
else if (!stricmp(NOX("wing name hidden"), flag_strings[string_idx]))
iff->flags |= IFFF_WING_NAME_HIDDEN;
else
Warning(LOCATION, "Bogus string in iff flags: %s\n", flag_strings[string_idx]);
}
}
// get default ship flags
iff->default_parse_flags = 0;
if (optional_string("$Default Ship Flags:"))
{
i = 0;
j = 0;
char flag_strings[MAX_PARSE_OBJECT_FLAGS][NAME_LENGTH];
int num_strings = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS);
for (i = 0; i < num_strings; i++)
{
for (j = 0; j < MAX_PARSE_OBJECT_FLAGS; j++)
{
if (!stricmp(flag_strings[i], Parse_object_flags[j]))
{
iff->default_parse_flags |= (1 << j);
break;
}
}
}
if (j == MAX_PARSE_OBJECT_FLAGS)
Warning(LOCATION, "Bogus string in iff default ship flags: %s\n", flag_strings[i]);
}
// again
iff->default_parse_flags2 = 0;
if (optional_string("$Default Ship Flags2:"))
{
i = 0;
j = 0;
char flag_strings[MAX_PARSE_OBJECT_FLAGS_2][NAME_LENGTH];
int num_strings = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS_2);
for (i = 0; i < num_strings; i++)
{
for (j = 0; j < MAX_PARSE_OBJECT_FLAGS_2; j++)
{
if (!stricmp(flag_strings[i], Parse_object_flags_2[j]))
{
iff->default_parse_flags2 |= (1 << j);
break;
}
}
}
if (j == MAX_PARSE_OBJECT_FLAGS_2)
Warning(LOCATION, "Bogus string in iff default ship flags2: %s\n", flag_strings[i]);
}
// this is cleared between each level but let's just set it here for thoroughness
iff->ai_rearm_timestamp = timestamp(-1);
}
required_string("#End");
// now resolve the relationships ------------------------------------------
// first get the traitor
Iff_traitor = iff_lookup(traitor_name);
if (Iff_traitor < 0)
{
Iff_traitor = 0;
Warning(LOCATION, "Traitor IFF %s not found in iff_defs.tbl! Defaulting to %s.\n", traitor_name, Iff_info[Iff_traitor].iff_name);
}
// next get the attackees and colors
for (int cur_iff = 0; cur_iff < Num_iffs; cur_iff++)
{
iff_info *iff = &Iff_info[cur_iff];
// clear the iffs to be attacked
iff->attackee_bitmask = 0;
iff->attackee_bitmask_all_teams_at_war = 0;
// clear the observed colors
for (j = 0; j < MAX_IFFS; j++)
iff->observed_color_index[j] = -1;
// resolve the list names
for (int list_index = 0; list_index < MAX_IFFS; list_index++)
{
// are we within the number of attackees listed?
if (list_index < num_attack_names[cur_iff])
{
// find out who
int target_iff = iff_lookup(attack_names[cur_iff][list_index]);
// valid?
if (target_iff >= 0)
iff->attackee_bitmask |= iff_get_mask(target_iff);
else
Warning(LOCATION, "Attack target IFF %s not found for IFF %s in iff_defs.tbl!\n", attack_names[cur_iff][list_index], iff->iff_name);
}
// are we within the number of colors listed?
if (list_index < num_observed_colors[cur_iff])
{
// find out who
int target_iff = iff_lookup(observed_color_table[cur_iff][list_index].iff_name);
// valid?
if (target_iff >= 0)
iff->observed_color_index[target_iff] = observed_color_table[cur_iff][list_index].color_index;
else
Warning(LOCATION, "Observed color IFF %s not found for IFF %s in iff_defs.tbl!\n", observed_color_table[cur_iff][list_index].iff_name, iff->iff_name);
}
}
// resolve the all teams at war relationships
if (iff->flags & IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR)
{
// exempt, so use standard attacks
iff->attackee_bitmask_all_teams_at_war = iff->attackee_bitmask;
}
else
{
// nonexempt, so build bitmask of all other nonexempt teams
for (int other_iff = 0; other_iff < Num_iffs; other_iff++)
{
// skip myself (unless I attack myself normally)
if ((other_iff == cur_iff) && !iff_x_attacks_y(cur_iff, cur_iff))
continue;
// skip anyone exempt
if (Iff_info[other_iff].flags & IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR)
continue;
// add everyone else
iff->attackee_bitmask_all_teams_at_war |= iff_get_mask(other_iff);
}
}
}
// add tbl/tbm to multiplayer validation list
extern void fs2netd_add_table_validation(const char *tblname);
fs2netd_add_table_validation("iff_defs.tbl");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "iff_defs.tbl", e.what()));
return;
}
// Goober5000 - if table doesn't exist, use the default table
if (cf_exists_full("iff_defs.tbl", CF_TYPE_TABLES))
read_file_text("iff_defs.tbl", CF_TYPE_TABLES);
else
read_file_text_from_array(defaults_get_file("iff_defs.tbl"));
reset_parse();
// parse the table --------------------------------------------------------
required_string("#IFFs");
// get the traitor
required_string("$Traitor IFF:");
stuff_string(traitor_name, F_NAME, NAME_LENGTH);
int rgb[3];
// check if alternate colours are wanted to be used for these
// Marks various stuff... like asteroids
if ((optional_string("$Selection Color:")) || (optional_string("$Selection Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
iff_init_color(rgb[0], rgb[1], rgb[2]);
}
else
iff_init_color(0xff, 0xff, 0xff);
// Marks the ship currently saying something
if ((optional_string("$Message Color:")) || (optional_string("$Message Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
iff_init_color(rgb[0], rgb[1], rgb[2]);
}
else
iff_init_color(0x7f, 0x7f, 0x7f);
// Marks the tagged ships
if ((optional_string("$Tagged Color:")) || (optional_string("$Tagged Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
iff_init_color(rgb[0], rgb[1], rgb[2]);
}
else
iff_init_color(0xff, 0xff, 0x00);
// init radar blips colour table
int a_bright,a_dim;
bool alternate_blip_color = false;
for (i=0;i<5;i++)
{
for (j=0;j<2;j++)
{
for (k=0;k<3;k++)
{
radar_iff_color[i][j][k] = -1;
}
}
}
// if the bright/dim scaling is wanted to be changed
if (optional_string("$Dimmed IFF brightness:"))
{
int dim_iff_brightness;
stuff_int(&dim_iff_brightness);
Assert(dim_iff_brightness >= 0 && dim_iff_brightness <= HUD_COLOR_ALPHA_MAX);
*iff_color_brightness = dim_iff_brightness;
}
else
*iff_color_brightness = 4;
// alternate = use same method as with ship blips
// retail = use 1/2 intensities
if (optional_string("$Use Alternate Blip Coloring:") || optional_string("$Use Alternate Blip Colouring:"))
{
stuff_boolean(&alternate_blip_color);
}
// Parse blip colours, their order is hardcoded.
if ((optional_string("$Missile Blip Color:")) || (optional_string("$Missile Blip Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i=0;i<3;i++)
{
Assert(rgb[i] >= 0 && rgb[i] <= 255);
radar_iff_color[0][1][i] = rgb[i];
radar_iff_color[0][0][i] = rgb[i]/2;
}
}
if ((optional_string("$Navbuoy Blip Color:")) || (optional_string("$Navbuoy Blip Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i=0;i<3;i++)
{
Assert(rgb[i] >= 0 && rgb[i] <= 255);
radar_iff_color[1][1][i] = rgb[i];
radar_iff_color[1][0][i] = rgb[i]/2;
}
}
if ((optional_string("$Warping Blip Color:")) || (optional_string("$Warping Blip Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i=0;i<3;i++)
{
Assert(rgb[i] >= 0 && rgb[i] <= 255);
radar_iff_color[2][1][i] = rgb[i];
radar_iff_color[2][0][i] = rgb[i]/2;
}
}
if ((optional_string("$Node Blip Color:")) || (optional_string("$Node Blip Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i=0;i<3;i++)
{
Assert(rgb[i] >= 0 && rgb[i] <= 255);
radar_iff_color[3][1][i] = rgb[i];
radar_iff_color[3][0][i] = rgb[i]/2;
}
}
if ((optional_string("$Tagged Blip Color:")) || (optional_string("$Tagged Blip Colour:")))
{
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
for (i=0;i<3;i++)
{
Assert(rgb[i] >= 0 && rgb[i] <= 255);
radar_iff_color[4][1][i] = rgb[i];
radar_iff_color[4][0][i] = rgb[i]/2;
}
}
if (alternate_blip_color == true)
{
a_bright = iff_get_alpha_value(true);
a_dim = iff_get_alpha_value(false);
for (i=0;i<5;i++)
{
if (radar_iff_color[i][0][0] >= 0)
{
for (j=0;j<3;j++)
{
radar_iff_color[i][0][j] = radar_iff_color[i][1][j];
}
radar_iff_color[i][1][3] = a_bright;
radar_iff_color[i][0][3] = a_dim;
}
}
}
else
{
for (i=0;i<5;i++)
{
if (radar_iff_color[i][0][0] >= 0)
{
radar_iff_color[i][0][3] = 255;
radar_iff_color[i][1][3] = 255;
}
}
}
if (optional_string("$Radar Target ID Flags:")) {
parse_string_flag_list((int*)&radar_target_id_flags, rti_flags, Num_rti_flags);
if (optional_string("+reset"))
radar_target_id_flags = 0;
}
// begin reading data
Num_iffs = 0;
while (required_string_either("#End", "$IFF Name:"))
{
iff_info *iff;
int cur_iff;
// make sure we're under the limit
if (Num_iffs >= MAX_IFFS)
{
Warning(LOCATION, "Too many iffs in iffs_defs.tbl! Max is %d.\n", MAX_IFFS);
skip_to_start_of_string("#End", NULL);
break;
}
// add new IFF
iff = &Iff_info[Num_iffs];
cur_iff = Num_iffs;
Num_iffs++;
// get required IFF info ----------------------------------------------
// get the iff name
required_string("$IFF Name:");
stuff_string(iff->iff_name, F_NAME, NAME_LENGTH);
// get the iff color
if (check_for_string("$Colour:"))
required_string("$Colour:");
else
required_string("$Color:");
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
iff->color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
// get relationships between IFFs -------------------------------------
// get the list of iffs attacked
if (optional_string("$Attacks:"))
num_attack_names[cur_iff] = stuff_string_list(attack_names[cur_iff], MAX_IFFS);
else
num_attack_names[cur_iff] = 0;
// get the list of observed colors
num_observed_colors[cur_iff] = 0;
while (optional_string("+Sees"))
{
// get iff observed
stuff_string_until(observed_color_table[cur_iff][num_observed_colors[cur_iff]].iff_name, "As:", NAME_LENGTH);
required_string("As:");
// get color observed
stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
observed_color_table[cur_iff][num_observed_colors[cur_iff]].color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
// increment
num_observed_colors[cur_iff]++;
}
// get flags ----------------------------------------------------------
// get iff flags
iff->flags = 0;
if (optional_string("$Flags:"))
{
char flag_strings[MAX_IFF_FLAGS][NAME_LENGTH];
int num_strings = stuff_string_list(flag_strings, MAX_IFF_FLAGS);
for (string_idx = 0; string_idx < num_strings; string_idx++)
{
if (!stricmp(NOX("support allowed"), flag_strings[string_idx]))
iff->flags |= IFFF_SUPPORT_ALLOWED;
else if (!stricmp(NOX("exempt from all teams at war"), flag_strings[string_idx]))
iff->flags |= IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR;
else if (!stricmp(NOX("orders hidden"), flag_strings[string_idx]))
iff->flags |= IFFF_ORDERS_HIDDEN;
else if (!stricmp(NOX("orders shown"), flag_strings[string_idx]))
iff->flags |= IFFF_ORDERS_SHOWN;
else if (!stricmp(NOX("wing name hidden"), flag_strings[string_idx]))
iff->flags |= IFFF_WING_NAME_HIDDEN;
else
Warning(LOCATION, "Bogus string in iff flags: %s\n", flag_strings[string_idx]);
}
}
// get default ship flags
iff->default_parse_flags = 0;
if (optional_string("$Default Ship Flags:"))
{
i = 0;
j = 0;
char flag_strings[MAX_PARSE_OBJECT_FLAGS][NAME_LENGTH];
int num_strings = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS);
for (i = 0; i < num_strings; i++)
{
for (j = 0; j < MAX_PARSE_OBJECT_FLAGS; j++)
{
if (!stricmp(flag_strings[i], Parse_object_flags[j]))
{
iff->default_parse_flags |= (1 << j);
break;
}
}
}
if (j == MAX_PARSE_OBJECT_FLAGS)
Warning(LOCATION, "Bogus string in iff default ship flags: %s\n", flag_strings[i]);
}
// again
iff->default_parse_flags2 = 0;
if (optional_string("$Default Ship Flags2:"))
{
i = 0;
j = 0;
char flag_strings[MAX_PARSE_OBJECT_FLAGS_2][NAME_LENGTH];
int num_strings = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS_2);
for (i = 0; i < num_strings; i++)
{
for (j = 0; j < MAX_PARSE_OBJECT_FLAGS_2; j++)
{
if (!stricmp(flag_strings[i], Parse_object_flags_2[j]))
{
iff->default_parse_flags2 |= (1 << j);
break;
}
}
}
if (j == MAX_PARSE_OBJECT_FLAGS_2)
Warning(LOCATION, "Bogus string in iff default ship flags2: %s\n", flag_strings[i]);
}
// this is cleared between each level but let's just set it here for thoroughness
iff->ai_rearm_timestamp = timestamp(-1);
}
required_string("#End");
// now resolve the relationships ------------------------------------------
// first get the traitor
Iff_traitor = iff_lookup(traitor_name);
if (Iff_traitor < 0)
{
Iff_traitor = 0;
Warning(LOCATION, "Traitor IFF %s not found in iff_defs.tbl! Defaulting to %s.\n", traitor_name, Iff_info[Iff_traitor].iff_name);
}
// next get the attackees and colors
for (int cur_iff = 0; cur_iff < Num_iffs; cur_iff++)
{
iff_info *iff = &Iff_info[cur_iff];
// clear the iffs to be attacked
iff->attackee_bitmask = 0;
iff->attackee_bitmask_all_teams_at_war = 0;
// clear the observed colors
for (j = 0; j < MAX_IFFS; j++)
iff->observed_color_index[j] = -1;
// resolve the list names
for (int list_index = 0; list_index < MAX_IFFS; list_index++)
{
// are we within the number of attackees listed?
if (list_index < num_attack_names[cur_iff])
{
// find out who
int target_iff = iff_lookup(attack_names[cur_iff][list_index]);
// valid?
if (target_iff >= 0)
iff->attackee_bitmask |= iff_get_mask(target_iff);
else
Warning(LOCATION, "Attack target IFF %s not found for IFF %s in iff_defs.tbl!\n", attack_names[cur_iff][list_index], iff->iff_name);
}
// are we within the number of colors listed?
if (list_index < num_observed_colors[cur_iff])
{
// find out who
int target_iff = iff_lookup(observed_color_table[cur_iff][list_index].iff_name);
// valid?
if (target_iff >= 0)
iff->observed_color_index[target_iff] = observed_color_table[cur_iff][list_index].color_index;
else
Warning(LOCATION, "Observed color IFF %s not found for IFF %s in iff_defs.tbl!\n", observed_color_table[cur_iff][list_index].iff_name, iff->iff_name);
}
}
// resolve the all teams at war relationships
if (iff->flags & IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR)
{
// exempt, so use standard attacks
iff->attackee_bitmask_all_teams_at_war = iff->attackee_bitmask;
}
else
{
// nonexempt, so build bitmask of all other nonexempt teams
for (int other_iff = 0; other_iff < Num_iffs; other_iff++)
{
// skip myself (unless I attack myself normally)
if ((other_iff == cur_iff) && !iff_x_attacks_y(cur_iff, cur_iff))
continue;
// skip anyone exempt
if (Iff_info[other_iff].flags & IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR)
continue;
// add everyone else
iff->attackee_bitmask_all_teams_at_war |= iff_get_mask(other_iff);
}
}
}
// add tbl/tbm to multiplayer validation list
extern void fs2netd_add_table_validation(const char *tblname);
fs2netd_add_table_validation("iff_defs.tbl");
}
/**
+10 -1
View File
@@ -41,6 +41,7 @@
#define LAB_FLAG_FULLY_LOAD (1<<5) // use create_ship() to test the ships
#define LAB_FLAG_SHOW_WEAPONS (1<<6) // determines if external weapons models are displayed
#define LAB_FLAG_INITIAL_ROTATION (1<<7) // initial rotation setting
#define LAB_FLAG_DESTROYED_SUBSYSTEMS (1<<8) // render model as if all subsystems are destroyed
// modes
#define LAB_MODE_NONE 0 // not showing anything
@@ -684,7 +685,7 @@ void labviewer_add_model_thrusters(ship_info *sip)
mst.distortion_bitmap = thruster_distortion_bitmap;
mst.use_ab = Lab_thrust_afterburn;
mst.glow_noise = thruster_glow_noise;
mst.glow_noise = thruster_glow_noise * sip->thruster_glow_noise_mult;
mst.rotvel = &vmd_zero_vector;
if (Lab_mode == LAB_MODE_SHIP) {
@@ -904,6 +905,13 @@ void labviewer_render_model(float frametime)
}
}
}
if (sip != NULL) {
if (Lab_viewer_flags & LAB_FLAG_DESTROYED_SUBSYSTEMS) {
model_show_damaged(Lab_model_num, 1);
}
}
opengl_shader_set_animated_effect(ANIMATED_SHADER_LOADOUTSELECT_FS1);
opengl_shader_set_animated_timer(MIN((timer_get_milliseconds()-anim_timer_start)/1500.0f,2.0f));
@@ -1855,6 +1863,7 @@ void labviewer_make_render_options_window(Button *caller)
ADD_RENDER_FLAG("Animated Shader", Lab_model_flags, MR_ANIMATED_SHADER);
ADD_RENDER_FLAG("Show Ship Weapons", Lab_viewer_flags, LAB_FLAG_SHOW_WEAPONS);
ADD_RENDER_FLAG("Initial Rotation", Lab_viewer_flags, LAB_FLAG_INITIAL_ROTATION);
ADD_RENDER_FLAG("Show Destroyed Subsystems", Lab_viewer_flags, LAB_FLAG_DESTROYED_SUBSYSTEMS);
// start tree
+20 -19
View File
@@ -142,32 +142,33 @@ bool ScreenClassInfoEntry::Parse()
void GUISystem::ParseClassInfo(char* filename)
{
int rval;
if (ClassInfoParsed) {
Warning(LOCATION, "Class info is being parsed twice");
DestroyClassInfo();
}
try
{
read_file_text(filename);
reset_parse();
ScreenClassInfo.Parse();
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("WMCGUI: Unable to parse '%s'! Error code = %i.\n", filename, rval));
bool flag;
do {
ScreenClassInfoEntry* sciep = new ScreenClassInfoEntry;
flag = sciep->Parse();
if (flag) {
list_append(&ScreenClassInfo, sciep);
}
} while (flag);
ClassInfoParsed = true;
}
catch (const parse::ParseException& e)
{
mprintf(("WMCGUI: Unable to parse '%s'! Error code = %s.\n", filename, e.what()));
return;
}
read_file_text(filename);
reset_parse();
ScreenClassInfo.Parse();
bool flag;
do {
ScreenClassInfoEntry* sciep = new ScreenClassInfoEntry;
flag = sciep->Parse();
if (flag) {
list_append(&ScreenClassInfo, sciep);
}
} while(flag);
ClassInfoParsed = true;
}
void ClassInfoEntry::Parse(char* tag, int in_type)
+23 -14
View File
@@ -112,7 +112,6 @@ void lcl_init(int lang_init)
char lang_string[128];
const char *ret;
int lang, idx, i;
int rval;
// initialize encryption
encrypt_init();
@@ -121,12 +120,14 @@ void lcl_init(int lang_init)
Lcl_languages.push_back(Lcl_builtin_languages[FS2_OPEN_DEFAULT_LANGUAGE]);
// check string.tbl to see which languages we support
if ( (rval = setjmp(parse_abort)) != 0 ) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "strings.tbl", rval));
}
else {
try
{
parse_stringstbl_quick("strings.tbl");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "strings.tbl", e.what()));
}
parse_modular_table(NOX("*-lcl.tbm"), parse_stringstbl_quick);
@@ -407,7 +408,7 @@ void parse_tstringstbl(const char *filename)
// initialize the xstr table
void lcl_xstr_init()
{
int i, rval;
int i;
for (i = 0; i < XSTR_SIZE; i++)
@@ -417,18 +418,26 @@ void lcl_xstr_init()
Lcl_ext_str[i] = NULL;
if ( (rval = setjmp(parse_abort)) != 0 )
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "strings.tbl", rval));
else
try
{
parse_stringstbl("strings.tbl");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "strings.tbl", e.what()));
}
parse_modular_table(NOX("*-lcl.tbm"), parse_stringstbl);
if ( (rval = setjmp(parse_abort)) != 0 )
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "tstrings.tbl", rval));
else
try
{
parse_tstringstbl("tstrings.tbl");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "tstrings.tbl", e.what()));
}
parse_modular_table(NOX("*-tlc.tbm"), parse_tstringstbl);
@@ -1209,7 +1218,7 @@ void lcl_translate_brief_icon_name_gr(char *name)
} else if ((pos = strstr(name, "Transport")) != NULL) {
pos += 9; // strlen of "transport"
strcpy_s(buf, "Transportowiec");
strcpy_s(buf, "Transporter");
strcat_s(buf, pos);
strcpy(name, buf);
@@ -1356,7 +1365,7 @@ char buf[128];
} else if ((pos = strstr(name, "Transport")) != NULL) {
pos += 9; // strlen of "transport"
strcpy_s(buf, "Transporter");
strcpy_s(buf, "Transportowiec");
strcat_s(buf, pos);
strcpy(name, buf);
+3 -3
View File
@@ -225,7 +225,7 @@ vec3d *vm_vec_avg4(vec3d *dest,vec3d *src0,vec3d *src1,vec3d *src2,vec3d *src3)
}
//scales a vector in place. returns ptr to vector
//scales a vector in place.
#ifndef _INLINE_VECMAT
void vm_vec_scale(vec3d *dest,float s)
{
@@ -236,7 +236,7 @@ void vm_vec_scale(vec3d *dest,float s)
#endif
//scales and copies a vector. returns ptr to dest
//scales and copies a vector.
#ifndef _INLINE_VECMAT
void vm_vec_copy_scale(vec3d *dest,vec3d *src,float s)
{
@@ -288,7 +288,7 @@ void vm_vec_scale_sub2(vec3d *dest,vec3d *src,float k)
}
#endif
//scales a vector in place, taking n/d for scale. returns ptr to vector
//scales a vector in place, taking n/d for scale.
//dest *= n/d
#ifndef _INLINE_VECMAT
void vm_vec_scale2(vec3d *dest,float n,float d)
+116 -116
View File
@@ -279,133 +279,133 @@ int credits_screen_button_pressed(int n)
}
void credits_parse_table(const char* filename)
{
int rval;
{
try
{
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
if ((rval = setjmp(parse_abort)) != 0)
{
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
return;
}
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// any metadata?
if (optional_string("$Music:"))
{
stuff_string(Credits_music_name, F_NAME, NAME_LENGTH);
}
if (optional_string("$Number of Images:"))
{
int temp;
stuff_int(&temp);
if (temp > 0)
Credits_num_images = temp;
}
if (optional_string("$Start Image Index:"))
{
stuff_int(&Credits_artwork_index);
// bounds check
if (Credits_artwork_index < 0)
// any metadata?
if (optional_string("$Music:"))
{
Credits_artwork_index = 0;
stuff_string(Credits_music_name, F_NAME, NAME_LENGTH);
}
else if (Credits_artwork_index >= Credits_num_images)
if (optional_string("$Number of Images:"))
{
Credits_artwork_index = Credits_num_images - 1;
int temp;
stuff_int(&temp);
if (temp > 0)
Credits_num_images = temp;
}
}
if (optional_string("$Text scroll rate:"))
{
stuff_float(&Credits_scroll_rate);
if (Credits_scroll_rate < 0.01f)
Credits_scroll_rate = 0.01f;
}
if (optional_string("$Artworks display time:"))
{
stuff_float(&Credits_artwork_display_time);
if (Credits_artwork_display_time < 0.01f)
Credits_artwork_display_time = 0.01f;
}
if (optional_string("$Artworks fade time:"))
{
stuff_float(&Credits_artwork_fade_time);
if (Credits_artwork_fade_time < 0.01f)
Credits_artwork_fade_time = 0.01f;
}
if (optional_string("$SCP Credits position:"))
{
char mode[NAME_LENGTH];
stuff_string(mode, F_NAME, NAME_LENGTH);
if (!stricmp(mode, "Start"))
SCP_credits_position = START;
else if (!stricmp(mode, "End"))
SCP_credits_position = END;
else
Warning(LOCATION, "Unknown credits position mode \"%s\".", mode);
}
ignore_white_space();
SCP_string credits_text;
SCP_string line;
SCP_vector<int> charNum;
SCP_vector<const char*> lines;
int numLines = -1;
bool first_run = true;
while(!check_for_string_raw("#end"))
{
// Read in a line of text
stuff_string_line(line);
// This is a bit odd but it means if a total conversion uses different credits the
// Volition credit won't happen
// Also don't append the default credits anymore when there was already a parsed table
if(first_run && !Credits_parsed && !line.compare(mod_check))
if (optional_string("$Start Image Index:"))
{
credits_text.append(unmodified_credits);
}
stuff_int(&Credits_artwork_index);
first_run = false;
if (line.empty())
{
// If the line is empty then just append a newline, don't bother with splitting it first
credits_text.append("\n");
}
else
{
// split_str doesn't take care of this.
charNum.clear();
// Split the string into multiple lines if it's too long
numLines = split_str(line.c_str(), Credits_text_coords[gr_screen.res][2], charNum, lines, -1);
// Make sure that we have valid data
Assertion(lines.size() == (size_t) numLines, "split_str reported %d lines but vector contains %d entries!", numLines, lines.size());
Assertion(lines.size() <= charNum.size(),
"Something has gone wrong while splitting strings. Got %d lines but only %d chacter lengths.",
lines.size(), charNum.size());
// Now add all splitted lines to the credit text and append a newline to the end
for (int i = 0; i < numLines; i++)
// bounds check
if (Credits_artwork_index < 0)
{
credits_text.append(SCP_string(lines[i], charNum[i]));
credits_text.append("\n");
Credits_artwork_index = 0;
}
else if (Credits_artwork_index >= Credits_num_images)
{
Credits_artwork_index = Credits_num_images - 1;
}
}
if (optional_string("$Text scroll rate:"))
{
stuff_float(&Credits_scroll_rate);
if (Credits_scroll_rate < 0.01f)
Credits_scroll_rate = 0.01f;
}
if (optional_string("$Artworks display time:"))
{
stuff_float(&Credits_artwork_display_time);
if (Credits_artwork_display_time < 0.01f)
Credits_artwork_display_time = 0.01f;
}
if (optional_string("$Artworks fade time:"))
{
stuff_float(&Credits_artwork_fade_time);
if (Credits_artwork_fade_time < 0.01f)
Credits_artwork_fade_time = 0.01f;
}
if (optional_string("$SCP Credits position:"))
{
char mode[NAME_LENGTH];
stuff_string(mode, F_NAME, NAME_LENGTH);
if (!stricmp(mode, "Start"))
SCP_credits_position = START;
else if (!stricmp(mode, "End"))
SCP_credits_position = END;
else
Warning(LOCATION, "Unknown credits position mode \"%s\".", mode);
}
ignore_white_space();
SCP_string credits_text;
SCP_string line;
SCP_vector<int> charNum;
SCP_vector<const char*> lines;
int numLines = -1;
bool first_run = true;
while (!check_for_string_raw("#end"))
{
// Read in a line of text
stuff_string_line(line);
// This is a bit odd but it means if a total conversion uses different credits the
// Volition credit won't happen
// Also don't append the default credits anymore when there was already a parsed table
if (first_run && !Credits_parsed && !line.compare(mod_check))
{
credits_text.append(unmodified_credits);
}
first_run = false;
if (line.empty())
{
// If the line is empty then just append a newline, don't bother with splitting it first
credits_text.append("\n");
}
else
{
// split_str doesn't take care of this.
charNum.clear();
// Split the string into multiple lines if it's too long
numLines = split_str(line.c_str(), Credits_text_coords[gr_screen.res][2], charNum, lines, -1);
// Make sure that we have valid data
Assertion(lines.size() == (size_t)numLines, "split_str reported %d lines but vector contains %d entries!", numLines, lines.size());
Assertion(lines.size() <= charNum.size(),
"Something has gone wrong while splitting strings. Got %d lines but only %d chacter lengths.",
lines.size(), charNum.size());
// Now add all splitted lines to the credit text and append a newline to the end
for (int i = 0; i < numLines; i++)
{
credits_text.append(SCP_string(lines[i], charNum[i]));
credits_text.append("\n");
}
}
}
Credit_text_parts.push_back(credits_text);
Credits_parsed = true;
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
Credit_text_parts.push_back(credits_text);
Credits_parsed = true;
}
void credits_parse()
+416 -399
View File
@@ -2079,415 +2079,432 @@ void parse_main_hall_table(const char* filename)
{
SCP_vector<main_hall_defines> temp_vector;
main_hall_defines *m, temp;
int idx, s_idx, m_idx, rval;
int idx, s_idx, m_idx;
int num_resolutions = 2;
unsigned int count;
char temp_string[MAX_FILENAME_LEN];
SCP_string temp_scp_string;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
return;
}
try
{
read_file_text(filename, CF_TYPE_TABLES);
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
reset_parse();
if (optional_string("$Num Resolutions:")) {
stuff_int(&num_resolutions);
}
if (num_resolutions < 1) {
Error(LOCATION, "$Num Resolutions in %s is %d. (Must be 1 or greater)", filename, num_resolutions);
}
// go for it
count = Main_hall_defines.size();
while (!optional_string("#end")) {
Main_hall_defines.push_back(temp_vector);
// read in all resolutions
for (m_idx = 0; m_idx < num_resolutions; m_idx++) {
Main_hall_defines.at(count).push_back(temp);
m = &Main_hall_defines.at(count).at(m_idx);
// ready
required_string("$Main Hall");
// Parse the entry name for the first resolution, checking for duplicates and erroring if necessary
if (m_idx == 0) {
if (optional_string("+Name:")) {
stuff_string(temp_string, F_RAW, MAX_FILENAME_LEN);
// we can't have two mainhalls with the same name
if (main_hall_get_pointer(temp_string) == NULL) {
m->name = temp_string;
} else {
Error(LOCATION, "A mainhall with the name '%s' already exists. All mainhalls must have unique names.", temp_string);
}
} else {
snprintf(temp_string, MAX_FILENAME_LEN, "%d", count);
m->name = temp_string;
}
} else {
if (optional_string("+Name:")) {
stuff_string(temp_string, F_RAW, MAX_FILENAME_LEN);
/**
* the reason that this is an error is that even if we were to change the names to match
* it is very likely the user would get the wrong mainhall loaded since their campaign files
* may still refer to the entry with the incorrect name
*/
if (strcmp(temp_string, Main_hall_defines.at(count).at(0).name.c_str()) != 0) {
Error(LOCATION, "The mainhall '%s' has different names for different resolutions. All resolutions must have the same name. Either remove the hi-res entries' names entirely or set them to match the first resolution entry's name.", Main_hall_defines.at(0).at(count).name.c_str());
}
}
m->name = Main_hall_defines.at(count).at(0).name;
}
// add cheats
while (optional_string("+Cheat String:")) {
stuff_string(temp_scp_string, F_RAW);
m->cheat.push_back(temp_scp_string);
if(temp_scp_string.size() > MAIN_HALL_MAX_CHEAT_LEN) {
// Since the value is longer than the cheat buffer it will never match.
Warning(LOCATION, "The value '%s' for '+Cheat String:' is too long! It can be at most %d characters long.", temp_scp_string.size(), MAIN_HALL_MAX_CHEAT_LEN);
}
required_string("+Anim To Change:");
stuff_string(temp_scp_string, F_NAME);
m->cheat_anim_from.push_back(temp_scp_string);
required_string("+Anim To Change To:");
stuff_string(temp_scp_string, F_NAME);
m->cheat_anim_to.push_back(temp_scp_string);
}
// minimum resolution
if (optional_string("+Min Resolution:")) {
stuff_int(&m->min_width);
stuff_int(&m->min_height);
} else if (m_idx == 0) {
m->min_width = 0;
m->min_height = 0;
} else {
m->min_width = GR_1024_THRESHOLD_WIDTH;
m->min_height = GR_1024_THRESHOLD_HEIGHT;
}
// minimum aspect ratio
if (optional_string("+Min Aspect Ratio:")) {
stuff_float(&m->min_aspect_ratio);
} else {
m->min_aspect_ratio = 0.0f;
}
// bitmap and mask
required_string("+Bitmap:");
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->bitmap = temp_string;
required_string("+Mask:");
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->mask = temp_string;
required_string("+Music:");
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->music_name = temp_string;
// Goober5000
if (optional_string("+Substitute Music:")) {
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->substitute_music_name = temp_string;
}
if (optional_string("+Help Overlay:")) {
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->help_overlay_name = temp_string;
}
if (optional_string("+Help Overlay Resolution Index:")) {
stuff_int(&m->help_overlay_resolution_index);
} else {
m->help_overlay_resolution_index = m_idx;
}
// zoom area
if (optional_string("+Zoom To:")) {
stuff_int(&m->zoom_area_width);
stuff_int(&m->zoom_area_height);
} else {
m->zoom_area_width = -1;
m->zoom_area_height = -1;
}
// intercom sounds
required_string("+Num Intercom Sounds:");
stuff_int(&m->num_random_intercom_sounds);
// initialise intercom sounds vectors
intercom_sounds_init(*m);
for (idx = 0; idx < m->num_random_intercom_sounds; idx++) {
// intercom delay
required_string("+Intercom delay:");
stuff_int(&m->intercom_delay.at(idx).at(0));
stuff_int(&m->intercom_delay.at(idx).at(1));
}
for (idx = 0; idx < m->num_random_intercom_sounds; idx++) {
// intercom sound id
parse_sound("+Intercom sound:", &m->intercom_sounds.at(idx), "+Intercom sound:", PARSE_SOUND_INTERFACE_SOUND);
}
for (idx = 0; idx < m->num_random_intercom_sounds; idx++) {
// intercom pan
required_string("+Intercom pan:");
stuff_float(&m->intercom_sound_pan.at(idx));
}
// misc animations
required_string("+Num Misc Animations:");
stuff_int(&m->num_misc_animations);
// initialise the misc anim vectors
misc_anim_init(*m);
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim names
required_string("+Misc anim:");
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->misc_anim_name.at(idx) = (SCP_string)temp_string;
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim groups, optionally
if (optional_string("+Misc anim group:")) {
stuff_int(&m->misc_anim_group.at(idx));
} else {
m->misc_anim_group.at(idx) = -1;
}
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim delay
required_string("+Misc anim delay:");
stuff_int(&m->misc_anim_delay.at(idx).at(0));
stuff_int(&m->misc_anim_delay.at(idx).at(1));
stuff_int(&m->misc_anim_delay.at(idx).at(2));
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim coords
required_string("+Misc anim coords:");
stuff_int(&m->misc_anim_coords.at(idx).at(0));
stuff_int(&m->misc_anim_coords.at(idx).at(1));
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim mode
required_string("+Misc anim mode:");
stuff_int(&m->misc_anim_modes.at(idx));
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim pan
required_string("+Misc anim pan:");
stuff_float(&m->misc_anim_sound_pan.at(idx));
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim sound id
parse_sound_list("+Misc anim sounds:", m->misc_anim_special_sounds.at(idx), "+Misc anim sounds:", PARSE_SOUND_INTERFACE_SOUND);
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim sound triggers
required_string("+Misc anim trigger:");
int temp_int = 0;
stuff_int(&temp_int);
for (s_idx = 0; s_idx < temp_int; s_idx++) {
m->misc_anim_special_trigger.at(idx).push_back(0);
stuff_int(&m->misc_anim_special_trigger.at(idx).at(s_idx));
}
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim sound handles - deprecated, but deal with it just in case
if (optional_string("+Misc anim handles:")) {
advance_to_eoln(NULL);
}
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim sound flags - table flag deprecated, so ignore user input
if (optional_string("+Misc anim flags:")) {
advance_to_eoln(NULL);
}
// we need one flag for each sound
Assert(m->misc_anim_special_sounds.at(idx).size() < INT_MAX);
for (s_idx = 0; s_idx < (int)m->misc_anim_special_sounds.at(idx).size(); s_idx++) {
m->misc_anim_sound_flag.at(idx).push_back(0);
}
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// render over doors - default to false
if (optional_string("+Misc anim over doors:")) {
bool temp_b;
stuff_boolean(&temp_b);
m->misc_anim_over_doors.push_back(temp_b);
} else {
m->misc_anim_over_doors.push_back(0);
}
}
region_info_init(*m);
// door animations
required_string("+Num Door Animations:");
stuff_int(&m->num_door_animations);
// initialise the door anim vectors
door_anim_init(*m);
for (idx = 0; idx < m->num_door_animations; idx++) {
// door name
required_string("+Door anim:");
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->door_anim_name.at(idx) = (SCP_string)temp_string;
}
for (idx = 0; idx < m->num_door_animations; idx++) {
// door coords
required_string("+Door coords:");
stuff_int(&m->door_anim_coords.at(idx).at(0));
stuff_int(&m->door_anim_coords.at(idx).at(1));
stuff_int(&m->door_anim_coords.at(idx).at(2));
stuff_int(&m->door_anim_coords.at(idx).at(3));
}
for (idx = 0; idx < m->num_door_animations; idx++) {
// door open and close sounds
parse_sound_list("+Door sounds:", m->door_sounds.at(idx), "+Door sounds:", (parse_sound_flags)(PARSE_SOUND_INTERFACE_SOUND | PARSE_SOUND_SCP_SOUND_LIST));
}
for (idx = 0; idx < m->num_door_animations; idx++) {
// door pan value
required_string("+Door pan:");
stuff_float(&m->door_sound_pan[idx]);
}
int mask;
for (idx = 0; optional_string("+Door mask value:"); idx++) {
// door mask
stuff_string(temp_string, F_RAW, MAX_FILENAME_LEN);
mask = (int) strtol(temp_string, NULL, 0);
mask = 255 - mask;
if(idx >= (int) m->regions.size()) {
m->regions.resize(idx + 1);
}
m->regions[idx].mask = mask;
}
for (idx = 0; optional_string("+Door action:"); idx++) {
// door action
if(idx >= (int) m->regions.size()) {
m->regions.resize(idx + 1);
}
if (optional_string("Script")) {
m->regions[idx].action = SCRIPT_REGION;
stuff_string(m->regions[idx].lua_action, F_RAW);
} else {
stuff_string(temp_scp_string, F_RAW);
int action = -1;
for (int i = 0; Main_hall_region_map[i].name != NULL; i++) {
if (temp_scp_string == Main_hall_region_map[i].name) {
action = Main_hall_region_map[i].mask;
break;
}
}
if (action == -1) {
SCP_string err_msg = "";
for (int i = 0; Main_hall_region_map[i].name != NULL; i++) {
if (i != 0) {
err_msg += ", ";
}
err_msg += Main_hall_region_map[i].name;
}
Error(LOCATION, "Unkown Door Region '%s'! Expected one of: %s", temp_scp_string.c_str(), err_msg.c_str());
}
m->regions[idx].action = action;
}
}
for (idx = 0; optional_string("+Door key:"); idx++) {
// door key
stuff_string(temp_string, F_RAW, MAX_FILENAME_LEN);
if ((int) m->regions.size() <= idx) {
m->regions.resize(idx + 1);
}
m->regions[idx].key = temp_string[0];
}
for (idx = 0; optional_string("+Door description:"); idx++) {
// region description (tooltip)
stuff_string(temp_scp_string, F_MESSAGE);
if (temp_scp_string != "default") {
if(idx >= (int) m->regions.size()) {
m->regions.resize(idx + 1);
}
m->regions[idx].description = temp_scp_string;
if (idx == 2) {
m->default_readyroom = false;
}
}
}
// font for tooltips and other text
if (optional_string("+Font:")) {
stuff_int(&m->font);
} else {
m->font = FONT1;
}
// tooltip padding
if (optional_string("+Tooltip Padding:")) {
stuff_int(&m->tooltip_padding);
} else {
m->tooltip_padding = -1; // we'll get the default value later
}
// tooltip y location
if (optional_string("+Tooltip Y:")) {
stuff_int(&m->region_yval);
} else {
m->region_yval = -1;
}
if (optional_string("$Num Resolutions:")) {
stuff_int(&num_resolutions);
}
count++;
}
if (num_resolutions < 1) {
Error(LOCATION, "$Num Resolutions in %s is %d. (Must be 1 or greater)", filename, num_resolutions);
}
// free up memory from parsing the mainhall tbl
stop_parse();
// go for it
count = Main_hall_defines.size();
while (!optional_string("#end")) {
Main_hall_defines.push_back(temp_vector);
// read in all resolutions
for (m_idx = 0; m_idx < num_resolutions; m_idx++) {
Main_hall_defines.at(count).push_back(temp);
m = &Main_hall_defines.at(count).at(m_idx);
// ready
required_string("$Main Hall");
// Parse the entry name for the first resolution, checking for duplicates and erroring if necessary
if (m_idx == 0) {
if (optional_string("+Name:")) {
stuff_string(temp_string, F_RAW, MAX_FILENAME_LEN);
// we can't have two mainhalls with the same name
if (main_hall_get_pointer(temp_string) == NULL) {
m->name = temp_string;
}
else {
Error(LOCATION, "A mainhall with the name '%s' already exists. All mainhalls must have unique names.", temp_string);
}
}
else {
snprintf(temp_string, MAX_FILENAME_LEN, "%d", count);
m->name = temp_string;
}
}
else {
if (optional_string("+Name:")) {
stuff_string(temp_string, F_RAW, MAX_FILENAME_LEN);
/**
* the reason that this is an error is that even if we were to change the names to match
* it is very likely the user would get the wrong mainhall loaded since their campaign files
* may still refer to the entry with the incorrect name
*/
if (strcmp(temp_string, Main_hall_defines.at(count).at(0).name.c_str()) != 0) {
Error(LOCATION, "The mainhall '%s' has different names for different resolutions. All resolutions must have the same name. Either remove the hi-res entries' names entirely or set them to match the first resolution entry's name.", Main_hall_defines.at(0).at(count).name.c_str());
}
}
m->name = Main_hall_defines.at(count).at(0).name;
}
// add cheats
while (optional_string("+Cheat String:")) {
stuff_string(temp_scp_string, F_RAW);
m->cheat.push_back(temp_scp_string);
if (temp_scp_string.size() > MAIN_HALL_MAX_CHEAT_LEN) {
// Since the value is longer than the cheat buffer it will never match.
Warning(LOCATION, "The value '%s' for '+Cheat String:' is too long! It can be at most %d characters long.", temp_scp_string.size(), MAIN_HALL_MAX_CHEAT_LEN);
}
required_string("+Anim To Change:");
stuff_string(temp_scp_string, F_NAME);
m->cheat_anim_from.push_back(temp_scp_string);
required_string("+Anim To Change To:");
stuff_string(temp_scp_string, F_NAME);
m->cheat_anim_to.push_back(temp_scp_string);
}
// minimum resolution
if (optional_string("+Min Resolution:")) {
stuff_int(&m->min_width);
stuff_int(&m->min_height);
}
else if (m_idx == 0) {
m->min_width = 0;
m->min_height = 0;
}
else {
m->min_width = GR_1024_THRESHOLD_WIDTH;
m->min_height = GR_1024_THRESHOLD_HEIGHT;
}
// minimum aspect ratio
if (optional_string("+Min Aspect Ratio:")) {
stuff_float(&m->min_aspect_ratio);
}
else {
m->min_aspect_ratio = 0.0f;
}
// bitmap and mask
required_string("+Bitmap:");
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->bitmap = temp_string;
required_string("+Mask:");
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->mask = temp_string;
required_string("+Music:");
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->music_name = temp_string;
// Goober5000
if (optional_string("+Substitute Music:")) {
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->substitute_music_name = temp_string;
}
if (optional_string("+Help Overlay:")) {
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->help_overlay_name = temp_string;
}
if (optional_string("+Help Overlay Resolution Index:")) {
stuff_int(&m->help_overlay_resolution_index);
}
else {
m->help_overlay_resolution_index = m_idx;
}
// zoom area
if (optional_string("+Zoom To:")) {
stuff_int(&m->zoom_area_width);
stuff_int(&m->zoom_area_height);
}
else {
m->zoom_area_width = -1;
m->zoom_area_height = -1;
}
// intercom sounds
required_string("+Num Intercom Sounds:");
stuff_int(&m->num_random_intercom_sounds);
// initialise intercom sounds vectors
intercom_sounds_init(*m);
for (idx = 0; idx < m->num_random_intercom_sounds; idx++) {
// intercom delay
required_string("+Intercom delay:");
stuff_int(&m->intercom_delay.at(idx).at(0));
stuff_int(&m->intercom_delay.at(idx).at(1));
}
for (idx = 0; idx < m->num_random_intercom_sounds; idx++) {
// intercom sound id
parse_sound("+Intercom sound:", &m->intercom_sounds.at(idx), "+Intercom sound:", PARSE_SOUND_INTERFACE_SOUND);
}
for (idx = 0; idx < m->num_random_intercom_sounds; idx++) {
// intercom pan
required_string("+Intercom pan:");
stuff_float(&m->intercom_sound_pan.at(idx));
}
// misc animations
required_string("+Num Misc Animations:");
stuff_int(&m->num_misc_animations);
// initialise the misc anim vectors
misc_anim_init(*m);
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim names
required_string("+Misc anim:");
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->misc_anim_name.at(idx) = (SCP_string)temp_string;
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim groups, optionally
if (optional_string("+Misc anim group:")) {
stuff_int(&m->misc_anim_group.at(idx));
}
else {
m->misc_anim_group.at(idx) = -1;
}
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim delay
required_string("+Misc anim delay:");
stuff_int(&m->misc_anim_delay.at(idx).at(0));
stuff_int(&m->misc_anim_delay.at(idx).at(1));
stuff_int(&m->misc_anim_delay.at(idx).at(2));
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim coords
required_string("+Misc anim coords:");
stuff_int(&m->misc_anim_coords.at(idx).at(0));
stuff_int(&m->misc_anim_coords.at(idx).at(1));
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim mode
required_string("+Misc anim mode:");
stuff_int(&m->misc_anim_modes.at(idx));
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim pan
required_string("+Misc anim pan:");
stuff_float(&m->misc_anim_sound_pan.at(idx));
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim sound id
parse_sound_list("+Misc anim sounds:", m->misc_anim_special_sounds.at(idx), "+Misc anim sounds:", PARSE_SOUND_INTERFACE_SOUND);
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim sound triggers
required_string("+Misc anim trigger:");
int temp_int = 0;
stuff_int(&temp_int);
for (s_idx = 0; s_idx < temp_int; s_idx++) {
m->misc_anim_special_trigger.at(idx).push_back(0);
stuff_int(&m->misc_anim_special_trigger.at(idx).at(s_idx));
}
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim sound handles - deprecated, but deal with it just in case
if (optional_string("+Misc anim handles:")) {
advance_to_eoln(NULL);
}
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// anim sound flags - table flag deprecated, so ignore user input
if (optional_string("+Misc anim flags:")) {
advance_to_eoln(NULL);
}
// we need one flag for each sound
Assert(m->misc_anim_special_sounds.at(idx).size() < INT_MAX);
for (s_idx = 0; s_idx < (int)m->misc_anim_special_sounds.at(idx).size(); s_idx++) {
m->misc_anim_sound_flag.at(idx).push_back(0);
}
}
for (idx = 0; idx < m->num_misc_animations; idx++) {
// render over doors - default to false
if (optional_string("+Misc anim over doors:")) {
bool temp_b;
stuff_boolean(&temp_b);
m->misc_anim_over_doors.push_back(temp_b);
}
else {
m->misc_anim_over_doors.push_back(0);
}
}
region_info_init(*m);
// door animations
required_string("+Num Door Animations:");
stuff_int(&m->num_door_animations);
// initialise the door anim vectors
door_anim_init(*m);
for (idx = 0; idx < m->num_door_animations; idx++) {
// door name
required_string("+Door anim:");
stuff_string(temp_string, F_NAME, MAX_FILENAME_LEN);
m->door_anim_name.at(idx) = (SCP_string)temp_string;
}
for (idx = 0; idx < m->num_door_animations; idx++) {
// door coords
required_string("+Door coords:");
stuff_int(&m->door_anim_coords.at(idx).at(0));
stuff_int(&m->door_anim_coords.at(idx).at(1));
stuff_int(&m->door_anim_coords.at(idx).at(2));
stuff_int(&m->door_anim_coords.at(idx).at(3));
}
for (idx = 0; idx < m->num_door_animations; idx++) {
// door open and close sounds
parse_sound_list("+Door sounds:", m->door_sounds.at(idx), "+Door sounds:", (parse_sound_flags)(PARSE_SOUND_INTERFACE_SOUND | PARSE_SOUND_SCP_SOUND_LIST));
}
for (idx = 0; idx < m->num_door_animations; idx++) {
// door pan value
required_string("+Door pan:");
stuff_float(&m->door_sound_pan[idx]);
}
int mask;
for (idx = 0; optional_string("+Door mask value:"); idx++) {
// door mask
stuff_string(temp_string, F_RAW, MAX_FILENAME_LEN);
mask = (int)strtol(temp_string, NULL, 0);
mask = 255 - mask;
if (idx >= (int)m->regions.size()) {
m->regions.resize(idx + 1);
}
m->regions[idx].mask = mask;
}
for (idx = 0; optional_string("+Door action:"); idx++) {
// door action
if (idx >= (int)m->regions.size()) {
m->regions.resize(idx + 1);
}
if (optional_string("Script")) {
m->regions[idx].action = SCRIPT_REGION;
stuff_string(m->regions[idx].lua_action, F_RAW);
}
else {
stuff_string(temp_scp_string, F_RAW);
int action = -1;
for (int i = 0; Main_hall_region_map[i].name != NULL; i++) {
if (temp_scp_string == Main_hall_region_map[i].name) {
action = Main_hall_region_map[i].mask;
break;
}
}
if (action == -1) {
SCP_string err_msg = "";
for (int i = 0; Main_hall_region_map[i].name != NULL; i++) {
if (i != 0) {
err_msg += ", ";
}
err_msg += Main_hall_region_map[i].name;
}
Error(LOCATION, "Unkown Door Region '%s'! Expected one of: %s", temp_scp_string.c_str(), err_msg.c_str());
}
m->regions[idx].action = action;
}
}
for (idx = 0; optional_string("+Door key:"); idx++) {
// door key
stuff_string(temp_string, F_RAW, MAX_FILENAME_LEN);
if ((int)m->regions.size() <= idx) {
m->regions.resize(idx + 1);
}
m->regions[idx].key = temp_string[0];
}
for (idx = 0; optional_string("+Door description:"); idx++) {
// region description (tooltip)
stuff_string(temp_scp_string, F_MESSAGE);
if (temp_scp_string != "default") {
if (idx >= (int)m->regions.size()) {
m->regions.resize(idx + 1);
}
m->regions[idx].description = temp_scp_string;
if (idx == 2) {
m->default_readyroom = false;
}
}
}
// font for tooltips and other text
if (optional_string("+Font:")) {
stuff_int(&m->font);
}
else {
m->font = FONT1;
}
// tooltip padding
if (optional_string("+Tooltip Padding:")) {
stuff_int(&m->tooltip_padding);
}
else {
m->tooltip_padding = -1; // we'll get the default value later
}
// tooltip y location
if (optional_string("+Tooltip Y:")) {
stuff_int(&m->region_yval);
}
else {
m->region_yval = -1;
}
}
count++;
}
// free up memory from parsing the mainhall tbl
stop_parse();
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
}
/**
+16 -15
View File
@@ -1292,25 +1292,26 @@ int Player_tips_shown = 0;
// tooltips
void player_tips_init()
{
int rval;
Num_player_tips = 0;
try
{
read_file_text("tips.tbl", CF_TYPE_TABLES);
reset_parse();
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "tips.tbl", rval));
return;
}
while (!optional_string("#end")) {
required_string("+Tip:");
read_file_text("tips.tbl", CF_TYPE_TABLES);
reset_parse();
while(!optional_string("#end")) {
required_string("+Tip:");
if(Num_player_tips >= MAX_PLAYER_TIPS) {
break;
if (Num_player_tips >= MAX_PLAYER_TIPS) {
break;
}
Player_tips[Num_player_tips++] = stuff_and_malloc_string(F_NAME, NULL);
}
Player_tips[Num_player_tips++] = stuff_and_malloc_string(F_NAME, NULL);
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "tips.tbl", e.what()));
return;
}
}
+41 -38
View File
@@ -1026,51 +1026,54 @@ int techroom_load_ani(anim **animpp, char *name)
void techroom_intel_init()
{
int rval, temp;
int temp;
static int inited = 0;
if (inited)
return;
try
{
read_file_text("species.tbl", CF_TYPE_TABLES);
reset_parse();
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "species.tbl", rval));
Intel_info_size = 0;
while (optional_string("$Entry:")) {
Assert(Intel_info_size < MAX_INTEL_ENTRIES);
if (Intel_info_size >= MAX_INTEL_ENTRIES) {
mprintf(("TECHMENU: Too many intel entries!\n"));
break;
}
Intel_info[Intel_info_size].flags = IIF_DEFAULT_VALUE;
required_string("$Name:");
stuff_string(Intel_info[Intel_info_size].name, F_NAME, NAME_LENGTH);
required_string("$Anim:");
stuff_string(Intel_info[Intel_info_size].anim_filename, F_NAME, NAME_LENGTH);
required_string("$AlwaysInTechRoom:");
stuff_int(&temp);
if (temp) {
// set default to align with what we read - Goober5000
Intel_info[Intel_info_size].flags |= IIF_IN_TECH_DATABASE;
Intel_info[Intel_info_size].flags |= IIF_DEFAULT_IN_TECH_DATABASE;
}
required_string("$Description:");
stuff_string(Intel_info[Intel_info_size].desc, F_MULTITEXT, TECH_INTEL_DESC_LEN);
Intel_info_size++;
}
inited = 1;
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "species.tbl", e.what()));
return;
}
read_file_text("species.tbl", CF_TYPE_TABLES);
reset_parse();
Intel_info_size = 0;
while (optional_string("$Entry:")) {
Assert(Intel_info_size < MAX_INTEL_ENTRIES);
if (Intel_info_size >= MAX_INTEL_ENTRIES) {
mprintf(("TECHMENU: Too many intel entries!\n"));
break;
}
Intel_info[Intel_info_size].flags = IIF_DEFAULT_VALUE;
required_string("$Name:");
stuff_string(Intel_info[Intel_info_size].name, F_NAME, NAME_LENGTH);
required_string("$Anim:");
stuff_string(Intel_info[Intel_info_size].anim_filename, F_NAME, NAME_LENGTH);
required_string("$AlwaysInTechRoom:");
stuff_int(&temp);
if (temp) {
// set default to align with what we read - Goober5000
Intel_info[Intel_info_size].flags |= IIF_IN_TECH_DATABASE;
Intel_info[Intel_info_size].flags |= IIF_DEFAULT_IN_TECH_DATABASE;
}
required_string("$Description:");
stuff_string(Intel_info[Intel_info_size].desc, F_MULTITEXT, TECH_INTEL_DESC_LEN);
Intel_info_size++;
}
inited = 1;
}
void techroom_init()
+60 -59
View File
@@ -274,77 +274,78 @@ int brief_text_wipe_finished();
//
void brief_parse_icon_tbl()
{
int rval, icon;
int icon;
size_t species;
char name[MAX_FILENAME_LEN];
Assert(!Species_info.empty());
const size_t max_icons = Species_info.size() * MIN_BRIEF_ICONS;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "icons.tbl", rval));
return;
}
read_file_text("icons.tbl", CF_TYPE_TABLES);
reset_parse();
required_string("#Start");
Briefing_icon_info.clear();
while (required_string_either("#End","$Name:"))
try
{
if(Briefing_icon_info.size() >= max_icons) {
Warning(LOCATION, "Too many icons in icons.tbl; only the first %d will be used", max_icons);
skip_to_start_of_string("#End");
break;
}
read_file_text("icons.tbl", CF_TYPE_TABLES);
reset_parse();
briefing_icon_info bii;
required_string("#Start");
// parse regular frames
required_string("$Name:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
generic_anim_init(&bii.regular, name);
// parse fade frames
required_string("$Name:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
hud_anim_init(&bii.fade, 0, 0, name);
// parse highlighting frames
required_string("$Name:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
hud_anim_init(&bii.highlight, 0, 0, name);
// add it to the collection
Briefing_icon_info.push_back(bii);
}
required_string("#End");
// now assign the icons to their species
const size_t num_species_covered = Briefing_icon_info.size() / MIN_BRIEF_ICONS;
size_t bii_index = 0;
for (icon = 0; icon < MIN_BRIEF_ICONS; icon++)
{
for (species = 0; species < num_species_covered; species++)
Species_info[species].bii_index[icon] = bii_index++;
}
// error check
if (num_species_covered < Species_info.size())
{
SCP_string errormsg = "The following species are missing icon info in icons.tbl:\n";
for (species = num_species_covered; species < Species_info.size(); species++)
Briefing_icon_info.clear();
while (required_string_either("#End", "$Name:"))
{
errormsg += Species_info[species].species_name;
errormsg += "\n";
if (Briefing_icon_info.size() >= max_icons) {
Warning(LOCATION, "Too many icons in icons.tbl; only the first %d will be used", max_icons);
skip_to_start_of_string("#End");
break;
}
briefing_icon_info bii;
// parse regular frames
required_string("$Name:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
generic_anim_init(&bii.regular, name);
// parse fade frames
required_string("$Name:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
hud_anim_init(&bii.fade, 0, 0, name);
// parse highlighting frames
required_string("$Name:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
hud_anim_init(&bii.highlight, 0, 0, name);
// add it to the collection
Briefing_icon_info.push_back(bii);
}
required_string("#End");
// now assign the icons to their species
const size_t num_species_covered = Briefing_icon_info.size() / MIN_BRIEF_ICONS;
size_t bii_index = 0;
for (icon = 0; icon < MIN_BRIEF_ICONS; icon++)
{
for (species = 0; species < num_species_covered; species++)
Species_info[species].bii_index[icon] = bii_index++;
}
Error(LOCATION, errormsg.c_str());
// error check
if (num_species_covered < Species_info.size())
{
SCP_string errormsg = "The following species are missing icon info in icons.tbl:\n";
for (species = num_species_covered; species < Species_info.size(); species++)
{
errormsg += Species_info[species].species_name;
errormsg += "\n";
}
Error(LOCATION, errormsg.c_str());
}
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "icons.tbl", e.what()));
}
}
+211 -195
View File
@@ -100,7 +100,7 @@ bool campaign_is_ignored(const char *filename);
*/
int mission_campaign_get_info(const char *filename, char *name, int *type, int *max_players, char **desc)
{
int rval, i, success = 0;
int i, success = 0;
char campaign_type[NAME_LENGTH], fname[MAX_FILENAME_LEN];
Assert( name != NULL );
@@ -116,53 +116,57 @@ int mission_campaign_get_info(const char *filename, char *name, int *type, int *
*type = -1;
do {
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("MISSIONCAMPAIGN: Unable to parse '%s'! Error code = %i.\n", fname, rval));
break;
}
try
{
read_file_text(fname);
reset_parse();
read_file_text(fname);
reset_parse();
required_string("$Name:");
stuff_string(name, F_NAME, NAME_LENGTH);
if (name == NULL) {
nprintf(("Warning", "No name found for campaign file %s\n", filename));
break;
}
required_string("$Name:");
stuff_string( name, F_NAME, NAME_LENGTH );
if (name == NULL) {
nprintf(("Warning", "No name found for campaign file %s\n", filename));
break;
}
required_string("$Type:");
stuff_string(campaign_type, F_NAME, NAME_LENGTH);
required_string("$Type:");
stuff_string( campaign_type, F_NAME, NAME_LENGTH );
for (i = 0; i < MAX_CAMPAIGN_TYPES; i++) {
if (!stricmp(campaign_type, campaign_types[i])) {
*type = i;
}
}
for (i=0; i<MAX_CAMPAIGN_TYPES; i++) {
if ( !stricmp(campaign_type, campaign_types[i]) ) {
*type = i;
if (name == NULL) {
Warning(LOCATION, "Invalid campaign type \"%s\"\n", campaign_type);
break;
}
if (desc) {
if (optional_string("+Description:")) {
*desc = stuff_and_malloc_string(F_MULTITEXT, NULL);
}
else {
*desc = NULL;
}
}
// if this is a multiplayer campaign, get the max players
if ((*type) != CAMPAIGN_TYPE_SINGLE) {
skip_to_string("+Num Players:");
stuff_int(max_players);
}
// if we found a valid campaign type
if ((*type) >= 0) {
success = 1;
}
}
if (name == NULL) {
Warning(LOCATION, "Invalid campaign type \"%s\"\n", campaign_type);
catch (const parse::ParseException& e)
{
mprintf(("MISSIONCAMPAIGN: Unable to parse '%s'! Error message = %s.\n", fname, e.what()));
break;
}
if (desc) {
if (optional_string("+Description:")) {
*desc = stuff_and_malloc_string(F_MULTITEXT, NULL);
} else {
*desc = NULL;
}
}
// if this is a multiplayer campaign, get the max players
if ((*type) != CAMPAIGN_TYPE_SINGLE) {
skip_to_string("+Num Players:");
stuff_int(max_players);
}
// if we found a valid campaign type
if ((*type) >= 0) {
success = 1;
}
} while (0);
Assert(success);
@@ -176,22 +180,14 @@ int mission_campaign_get_info(const char *filename, char *name, int *type, int *
*/
int mission_campaign_get_mission_list(const char *filename, char **list, int max)
{
int rval, i, num = 0;
int i, num = 0;
char name[MAX_FILENAME_LEN];
filename = cf_add_ext(filename, FS_CAMPAIGN_FILE_EXT);
// read the campaign file and get the list of mission filenames
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("MISSIONCAMPAIGN: Unable to parse '%s'! Error code = %i.\n", filename, rval));
// since we can't return count of allocated elements, free them instead
for (i=0; i<num; i++)
vm_free(list[i]);
num = -1;
} else {
try
{
read_file_text(filename);
reset_parse();
@@ -203,6 +199,16 @@ int mission_campaign_get_mission_list(const char *filename, char **list, int max
Warning(LOCATION, "Maximum number of missions exceeded (%d)!", max);
}
}
catch (const parse::ParseException& e)
{
mprintf(("MISSIONCAMPAIGN: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
// since we can't return count of allocated elements, free them instead
for (i = 0; i<num; i++)
vm_free(list[i]);
num = -1;
}
return num;
}
@@ -410,7 +416,7 @@ void mission_campaign_get_sw_info()
*/
int mission_campaign_load( char *filename, player *pl, int load_savefile, bool reset_stats )
{
int len, rval, i;
int len, i;
char name[NAME_LENGTH], type[NAME_LENGTH], temp[NAME_LENGTH];
if (campaign_is_ignored(filename)) {
@@ -429,21 +435,8 @@ int mission_campaign_load( char *filename, player *pl, int load_savefile, bool r
}
// read the mission file and get the list of mission filenames
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("Error parsing '%s'\r\nError code = %i.\r\n", filename, rval));
Campaign.filename[0] = 0;
Campaign.num_missions = 0;
if ( !Fred_running && !(Game_mode & GM_MULTIPLAYER) ) {
Campaign_file_missing = 1;
Campaign_load_failure = CAMPAIGN_ERROR_MISSING;
return CAMPAIGN_ERROR_MISSING;
}
return CAMPAIGN_ERROR_CORRUPT;
} else {
try
{
// be sure to remove all old malloced strings of Mission_names
// we must also free any goal stuff that was from a previous campaign
// this also frees sexpressions so the next call to init_sexp will be able to reclaim
@@ -643,6 +636,21 @@ int mission_campaign_load( char *filename, player *pl, int load_savefile, bool r
Campaign.num_missions++;
}
}
catch (const parse::ParseException& e)
{
mprintf(("Error parsing '%s'\r\nError message = %s.\r\n", filename, e.what()));
Campaign.filename[0] = 0;
Campaign.num_missions = 0;
if (!Fred_running && !(Game_mode & GM_MULTIPLAYER)) {
Campaign_file_missing = 1;
Campaign_load_failure = CAMPAIGN_ERROR_MISSING;
return CAMPAIGN_ERROR_MISSING;
}
return CAMPAIGN_ERROR_CORRUPT;
}
// set up the other variables for the campaign stuff. After initializing, we must try and load
// the campaign save file for this player. Since all campaign loads go through this routine, I
@@ -1406,14 +1414,9 @@ void mission_campaign_clear()
*/
int mission_campaign_get_filenames(char *filename, char dest[][NAME_LENGTH], int *num)
{
int rval;
// read the mission file and get the list of mission filenames
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("MISSIONCAMPAIGN: Unable to parse '%s'! Error code = %i.\n", filename, rval));
return rval;
} else {
try
{
Assert( strlen(filename) < MAX_FILENAME_LEN ); // make sure no overflow
read_file_text(filename);
reset_parse();
@@ -1431,6 +1434,11 @@ int mission_campaign_get_filenames(char *filename, char dest[][NAME_LENGTH], int
(*num)++;
}
}
catch (const parse::ParseException& e)
{
mprintf(("MISSIONCAMPAIGN: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return 1;
}
return 0;
}
@@ -1443,110 +1451,115 @@ void read_mission_goal_list(int num)
{
char *filename, notes[NOTES_LENGTH], goals[MAX_GOALS][NAME_LENGTH];
char events[MAX_MISSION_EVENTS][NAME_LENGTH];
int i, z, rval, event_count, count = 0;
int i, z, event_count, count = 0;
filename = Campaign.missions[num].name;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("MISSIONCAMPAIGN: Unable to parse '%s'! Error code = %i.\n", filename, rval));
try
{
read_file_text(filename);
reset_parse();
init_sexp();
// first, read the mission notes for this mission. Used in campaign editor
if (skip_to_string("#Mission Info")) {
if (skip_to_string("$Notes:")) {
stuff_string(notes, F_NOTES, NOTES_LENGTH);
if (Campaign.missions[num].notes){
vm_free(Campaign.missions[num].notes);
}
Campaign.missions[num].notes = (char *)vm_malloc(strlen(notes) + 1);
strcpy(Campaign.missions[num].notes, notes);
}
}
event_count = 0;
// skip to events section in the mission file. Events come before goals, so we process them first
if (skip_to_string("#Events")) {
while (1) {
if (skip_to_string("$Formula:", "#Goals") != 1){
break;
}
z = skip_to_string("+Name:", "$Formula:");
if (!z){
break;
}
if (z == 1){
stuff_string(events[event_count], F_NAME, NAME_LENGTH);
}
else {
sprintf(events[event_count], NOX("Event #%d"), event_count + 1);
}
event_count++;
if (event_count > MAX_MISSION_EVENTS) {
Warning(LOCATION, "Maximum number of events exceeded (%d)!", MAX_MISSION_EVENTS);
event_count = MAX_MISSION_EVENTS;
break;
}
}
}
count = 0;
if (skip_to_string("#Goals")) {
while (1) {
if (skip_to_string("$Type:", "#End") != 1){
break;
}
z = skip_to_string("+Name:", "$Type:");
if (!z){
break;
}
if (z == 1){
stuff_string(goals[count], F_NAME, NAME_LENGTH);
}
else {
sprintf(goals[count], NOX("Goal #%d"), count + 1);
}
count++;
if (count > MAX_GOALS) {
Warning(LOCATION, "Maximum number of goals exceeded (%d)!", MAX_GOALS);
count = MAX_GOALS;
break;
}
}
}
Campaign.missions[num].num_goals = count;
if (count) {
Campaign.missions[num].goals = (mgoal *)vm_malloc(count * sizeof(mgoal));
Assert(Campaign.missions[num].goals); // make sure we got the memory
memset(Campaign.missions[num].goals, 0, count * sizeof(mgoal));
for (i = 0; i < count; i++){
strcpy_s(Campaign.missions[num].goals[i].name, goals[i]);
}
}
// copy the events
Campaign.missions[num].num_events = event_count;
if (event_count) {
Campaign.missions[num].events = (mevent *)vm_malloc(event_count * sizeof(mevent));
Assert(Campaign.missions[num].events);
memset(Campaign.missions[num].events, 0, event_count * sizeof(mevent));
for (i = 0; i < event_count; i++){
strcpy_s(Campaign.missions[num].events[i].name, events[i]);
}
}
// Goober5000 - variables do not need to be read here
}
catch (const parse::ParseException& e)
{
mprintf(("MISSIONCAMPAIGN: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
read_file_text(filename);
reset_parse();
init_sexp();
// first, read the mission notes for this mission. Used in campaign editor
if (skip_to_string("#Mission Info")) {
if (skip_to_string("$Notes:")) {
stuff_string(notes, F_NOTES, NOTES_LENGTH);
if (Campaign.missions[num].notes){
vm_free(Campaign.missions[num].notes);
}
Campaign.missions[num].notes = (char *) vm_malloc(strlen(notes) + 1);
strcpy(Campaign.missions[num].notes, notes);
}
}
event_count = 0;
// skip to events section in the mission file. Events come before goals, so we process them first
if ( skip_to_string("#Events") ) {
while (1) {
if (skip_to_string("$Formula:", "#Goals") != 1){
break;
}
z = skip_to_string("+Name:", "$Formula:");
if (!z){
break;
}
if (z == 1){
stuff_string(events[event_count], F_NAME, NAME_LENGTH);
} else {
sprintf(events[event_count], NOX("Event #%d"), event_count + 1);
}
event_count++;
if (event_count > MAX_MISSION_EVENTS) {
Warning(LOCATION, "Maximum number of events exceeded (%d)!", MAX_MISSION_EVENTS);
event_count = MAX_MISSION_EVENTS;
break;
}
}
}
count = 0;
if (skip_to_string("#Goals")) {
while (1) {
if (skip_to_string("$Type:", "#End") != 1){
break;
}
z = skip_to_string("+Name:", "$Type:");
if (!z){
break;
}
if (z == 1){
stuff_string(goals[count], F_NAME, NAME_LENGTH);
} else {
sprintf(goals[count], NOX("Goal #%d"), count + 1);
}
count++;
if (count > MAX_GOALS) {
Warning(LOCATION, "Maximum number of goals exceeded (%d)!", MAX_GOALS);
count = MAX_GOALS;
break;
}
}
}
Campaign.missions[num].num_goals = count;
if (count) {
Campaign.missions[num].goals = (mgoal *) vm_malloc(count * sizeof(mgoal));
Assert(Campaign.missions[num].goals); // make sure we got the memory
memset(Campaign.missions[num].goals, 0, count * sizeof(mgoal));
for (i=0; i<count; i++){
strcpy_s(Campaign.missions[num].goals[i].name, goals[i]);
}
}
// copy the events
Campaign.missions[num].num_events = event_count;
if (event_count) {
Campaign.missions[num].events = (mevent *)vm_malloc(event_count * sizeof(mevent));
Assert ( Campaign.missions[num].events );
memset(Campaign.missions[num].events, 0, event_count * sizeof(mevent));
for (i = 0; i < event_count; i++ ){
strcpy_s(Campaign.missions[num].events[i].name, events[i]);
}
}
// Goober5000 - variables do not need to be read here
}
/**
@@ -1622,33 +1635,36 @@ void mission_campaign_maybe_play_movie(int type)
*/
int mission_campaign_parse_is_multi(char *filename, char *name)
{
int i, rval;
int i;
char temp[NAME_LENGTH];
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("MISSIONCAMPAIGN: Unable to parse '%s'! Error code = %i.\n", filename, rval));
try
{
read_file_text(filename);
reset_parse();
required_string("$Name:");
stuff_string(temp, F_NAME, NAME_LENGTH);
if (name)
strcpy(name, temp);
required_string("$Type:");
stuff_string(temp, F_NAME, NAME_LENGTH);
for (i = 0; i < MAX_CAMPAIGN_TYPES; i++) {
if (!stricmp(temp, campaign_types[i])) {
return i;
}
}
Error(LOCATION, "Unknown campaign type %s", temp);
return -1;
}
read_file_text( filename );
reset_parse();
required_string("$Name:");
stuff_string( temp, F_NAME, NAME_LENGTH );
if ( name )
strcpy( name, temp );
required_string( "$Type:" );
stuff_string( temp, F_NAME, NAME_LENGTH );
for (i = 0; i < MAX_CAMPAIGN_TYPES; i++ ) {
if ( !stricmp(temp, campaign_types[i]) ) {
return i;
}
catch (const parse::ParseException& e)
{
mprintf(("MISSIONCAMPAIGN: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return -1;
}
Error(LOCATION, "Unknown campaign type %s", temp );
return -1;
}
/**
+10 -7
View File
@@ -648,19 +648,22 @@ void parse_msgtbl()
// this is called at the start of each level
void messages_init()
{
int rval, i;
int i;
static int table_read = 0;
if ( !table_read ) {
Default_command_persona = -1;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "messages.tbl", rval));
try
{
parse_msgtbl();
table_read = 1;
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "messages.tbl", e.what()));
return;
}
parse_msgtbl();
table_read = 1;
}
Current_mission_mood = 0;
+57 -45
View File
@@ -1838,6 +1838,7 @@ int parse_create_object_sub(p_object *p_objp)
shipp->ship_max_shield_strength = p_objp->ship_max_shield_strength;
shipp->ship_max_hull_strength = p_objp->ship_max_hull_strength;
shipp->max_shield_recharge = p_objp->max_shield_recharge;
// Goober5000 - ugh, this is really stupid having to do this here; if the
// ship creation code was better organized this wouldn't be necessary
@@ -2250,7 +2251,7 @@ int parse_create_object_sub(p_object *p_objp)
Objects[objnum].hull_strength = p_objp->initial_hull * shipp->ship_max_hull_strength / 100.0f;
for (iLoop = 0; iLoop<Objects[objnum].n_quadrants; iLoop++)
{
Objects[objnum].shield_quadrant[iLoop] = (float) (p_objp->initial_shields * get_max_shield_quad(&Objects[objnum]) / 100.0f);
Objects[objnum].shield_quadrant[iLoop] = (float) (shipp->max_shield_recharge * p_objp->initial_shields * get_max_shield_quad(&Objects[objnum]) / 100.0f);
}
// initial velocities now do not apply to ships which warp in after mission starts
@@ -3110,6 +3111,7 @@ int parse_object(mission *pm, int flag, p_object *p_objp)
}
Assert(p_objp->ship_max_hull_strength > 0.0f); // Goober5000: div-0 check (not shield because we might not have one)
p_objp->max_shield_recharge = Ship_info[p_objp->ship_class].max_shield_recharge;
// if the kamikaze flag is set, we should have the next flag
@@ -4603,8 +4605,9 @@ void resolve_path_masks(int anchor, int *path_mask)
Assert(!(anchor & SPECIAL_ARRIVAL_ANCHOR_FLAG));
parent_pobjp = mission_parse_get_parse_object(Parse_names[anchor]);
// load model for checking paths
modelnum = model_load(Ship_info[parent_pobjp->ship_class].pof_file, 0, NULL);
// Load the anchor ship model with subsystems and all; it'll need to be done for this mission anyway
ship_info *sip = &Ship_info[parent_pobjp->ship_class];
modelnum = model_load(sip->pof_file, sip->n_subsystems, &sip->subsystems[0]);
// resolve names to indexes
*path_mask = 0;
@@ -4617,9 +4620,6 @@ void resolve_path_masks(int anchor, int *path_mask)
*path_mask |= (1 << bay_path);
}
// unload model
model_unload(modelnum);
// cache the result
prp->cached_mask = *path_mask;
}
@@ -5853,15 +5853,18 @@ int get_mission_info(const char *filename, mission *mission_p, bool basic)
break;
}
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("MISSIONS: Unable to parse '%s'! Error code = %i.\n", real_fname, rval));
try
{
read_file_text(real_fname, CF_TYPE_MISSIONS);
mission_p->Reset();
parse_init(basic);
parse_mission_info(mission_p, basic);
}
catch (const parse::ParseException& e)
{
mprintf(("MISSIONS: Unable to parse '%s'! Error message = %s.\n", real_fname, e.what()));
break;
}
read_file_text(real_fname, CF_TYPE_MISSIONS);
mission_p->Reset( );
parse_init(basic);
parse_mission_info(mission_p, basic);
} while (0);
return rval;
@@ -5926,22 +5929,27 @@ int parse_main(const char *mission_name, int flags)
cfclose(ftemp);
}
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("MISSIONS: Unable to parse '%s'! Error code = %i.\n", mission_name, rval));
try
{
// import?
if (flags & MPF_IMPORT_FSM) {
read_file_text(mission_name, CF_TYPE_ANY);
convertFSMtoFS2();
}
else {
read_file_text(mission_name, CF_TYPE_MISSIONS);
}
The_mission.Reset();
rval = parse_mission(&The_mission, flags);
display_parse_diagnostics();
}
catch (const parse::ParseException& e)
{
mprintf(("MISSIONS: Unable to parse '%s'! Error message = %s.\n", mission_name, e.what()));
rval = 1;
break;
}
// import?
if (flags & MPF_IMPORT_FSM) {
read_file_text(mission_name, CF_TYPE_ANY);
convertFSMtoFS2();
} else {
read_file_text(mission_name, CF_TYPE_MISSIONS);
}
The_mission.Reset( );
rval = parse_mission(&The_mission, flags);
display_parse_diagnostics();
} while (0);
if (!Fred_running)
@@ -6283,7 +6291,7 @@ void mission_parse_set_up_initial_docks()
*/
int mission_parse_is_multi(const char *filename, char *mission_name)
{
int rval, game_type;
int game_type;
int filelength;
CFILE *ftemp;
@@ -6302,25 +6310,28 @@ int mission_parse_is_multi(const char *filename, char *mission_name)
game_type = 0;
do {
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("MISSIONS: Unable to parse '%s'! Error code = %i.\n", filename, rval));
try
{
read_file_text(filename, CF_TYPE_MISSIONS);
reset_parse();
if (skip_to_string("$Name:") != 1) {
nprintf(("Network", "Unable to process %s because we couldn't find $Name:", filename));
break;
}
stuff_string(mission_name, F_NAME, NAME_LENGTH);
if (skip_to_string("+Game Type Flags:") != 1) {
nprintf(("Network", "Unable to process %s because we couldn't find +Game Type Flags:\n", filename));
break;
}
stuff_int(&game_type);
}
catch (const parse::ParseException& e)
{
mprintf(("MISSIONS: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
break;
}
read_file_text(filename, CF_TYPE_MISSIONS);
reset_parse();
if ( skip_to_string("$Name:") != 1 ) {
nprintf(("Network", "Unable to process %s because we couldn't find $Name:", filename));
break;
}
stuff_string( mission_name, F_NAME, NAME_LENGTH );
if ( skip_to_string("+Game Type Flags:") != 1 ) {
nprintf(("Network", "Unable to process %s because we couldn't find +Game Type Flags:\n", filename));
break;
}
stuff_int(&game_type);
} while (0);
return (game_type & MISSION_TYPE_MULTI) ? game_type : 0;
@@ -7555,6 +7566,7 @@ void mission_bring_in_support_ship( object *requester_objp )
// set support ship hitpoints
pobj->ship_max_hull_strength = Ship_info[i].max_hull_strength;
pobj->ship_max_shield_strength = Ship_info[i].max_shield_strength;
pobj->max_shield_recharge = Ship_info[i].max_shield_recharge;
pobj->team = requester_shipp->team;
+2
View File
@@ -424,6 +424,8 @@ public:
float ship_max_hull_strength; // Needed to deal with special hitpoints
float ship_max_shield_strength;
float max_shield_recharge;
// Goober5000
SCP_vector<texture_replace> replacement_textures;
+41 -39
View File
@@ -1058,49 +1058,51 @@ void debrief_traitor_init()
if ( !inited ) {
debriefing *debrief;
debrief_stage *stagep;
int rval;
int stage_num;
try
{
read_file_text("traitor.tbl", CF_TYPE_TABLES);
reset_parse();
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "traitor.tbl", rval));
// simplied form of the debriefing stuff.
debrief = &Traitor_debriefing;
required_string("#Debriefing_info");
required_string("$Num stages:");
stuff_int(&debrief->num_stages);
Assert(debrief->num_stages == 1);
stage_num = 0;
stagep = &debrief->stages[stage_num++];
required_string("$Formula:");
stagep->formula = get_sexp_main();
required_string("$multi text");
stuff_string(stagep->text, F_MULTITEXT, NULL);
required_string("$Voice:");
char traitor_voice_file[MAX_FILENAME_LEN];
stuff_string(traitor_voice_file, F_FILESPEC, MAX_FILENAME_LEN);
// DKA 9/13/99 Only 1 traitor msg for FS2
// if ( Player->main_hall ) {
// strcpy_s(stagep->voice, NOX("3_"));
// } else {
// strcpy_s(stagep->voice, NOX("1_"));
// }
// Goober5000
debrief_choose_voice(stagep->voice, traitor_voice_file, debrief_find_persona_index(), 1);
required_string("$Recommendation text:");
stuff_string(stagep->recommendation_text, F_MULTITEXT, NULL);
inited = 1;
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "traitor.tbl", e.what()));
return;
}
read_file_text("traitor.tbl", CF_TYPE_TABLES);
reset_parse();
// simplied form of the debriefing stuff.
debrief = &Traitor_debriefing;
required_string("#Debriefing_info");
required_string("$Num stages:");
stuff_int(&debrief->num_stages);
Assert(debrief->num_stages == 1);
stage_num = 0;
stagep = &debrief->stages[stage_num++];
required_string("$Formula:");
stagep->formula = get_sexp_main();
required_string("$multi text");
stuff_string( stagep->text, F_MULTITEXT, NULL);
required_string("$Voice:");
char traitor_voice_file[MAX_FILENAME_LEN];
stuff_string(traitor_voice_file, F_FILESPEC, MAX_FILENAME_LEN);
// DKA 9/13/99 Only 1 traitor msg for FS2
// if ( Player->main_hall ) {
// strcpy_s(stagep->voice, NOX("3_"));
// } else {
// strcpy_s(stagep->voice, NOX("1_"));
// }
// Goober5000
debrief_choose_voice(stagep->voice, traitor_voice_file, debrief_find_persona_index(), 1);
required_string("$Recommendation text:");
stuff_string( stagep->recommendation_text, F_MULTITEXT, NULL);
inited = 1;
}
// disable the accept button if in single player and I am a traitor
+5
View File
@@ -1513,6 +1513,11 @@ void draw_model_icon(int model_id, int flags, float closeup_zoom, int x, int y,
//Assume it's a weapon
rot_angles.h = -(PI_2);
}
else if(sip->model_icon_angles.p != 0.0f || sip->model_icon_angles.b != 0.0f || sip->model_icon_angles.h != 0.0f)
{
// If non-zero model_icon_angles exists, always use that
rot_angles = sip->model_icon_angles;
}
else if(sip->flags & SIF_SMALL_SHIP)
{
rot_angles.p = -(PI_2);
+218 -211
View File
@@ -36,240 +36,247 @@ bool Beams_use_damage_factors = false;
void parse_mod_table(const char *filename)
{
int rval;
// SCP_vector<SCP_string> lines;
if ((rval = setjmp(parse_abort)) != 0)
try
{
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", (filename) ? filename : "<default game_settings.tbl>", rval));
return;
}
if (filename == NULL)
read_file_text_from_array(defaults_get_file("game_settings.tbl"));
else
read_file_text(filename, CF_TYPE_TABLES);
if (filename == NULL)
read_file_text_from_array(defaults_get_file("game_settings.tbl"));
else
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
reset_parse();
// start parsing
optional_string("#CAMPAIGN SETTINGS");
// start parsing
optional_string("#CAMPAIGN SETTINGS");
if (optional_string("$Default Campaign File Name:")) {
char temp[MAX_FILENAME_LEN];
stuff_string(temp, F_NAME, MAX_FILENAME_LEN);
// remove extension?
if (drop_extension(temp)) {
mprintf(("Game Settings Table: Removed extension on default campaign file name %s\n", temp));
}
// check length
int maxlen = (MAX_FILENAME_LEN - 4);
int len = strlen(temp);
if (len > maxlen) {
Warning(LOCATION, "Token too long: [%s]. Length = %i. Max is %i.\n", temp, len, maxlen);
temp[maxlen] = 0;
}
strcpy_s(Default_campaign_file_name, temp);
}
if (optional_string("#Ignored Campaign File Names")) {
SCP_string campaign_name;
while (optional_string("$Campaign File Name:")) {
stuff_string(campaign_name, F_NAME);
if (optional_string("$Default Campaign File Name:")) {
char temp[MAX_FILENAME_LEN];
stuff_string(temp, F_NAME, MAX_FILENAME_LEN);
// remove extension?
if (drop_extension(campaign_name)) {
mprintf(("Game Settings Table: Removed extension on ignored campaign file name %s\n", campaign_name.c_str()));
if (drop_extension(temp)) {
mprintf(("Game Settings Table: Removed extension on default campaign file name %s\n", temp));
}
Ignored_campaigns.push_back(campaign_name);
// check length
int maxlen = (MAX_FILENAME_LEN - 4);
int len = strlen(temp);
if (len > maxlen) {
Warning(LOCATION, "Token too long: [%s]. Length = %i. Max is %i.\n", temp, len, maxlen);
temp[maxlen] = 0;
}
strcpy_s(Default_campaign_file_name, temp);
}
}
if (optional_string("$Red-alert applies to delayed ships:")) {
stuff_boolean(&Red_alert_applies_to_delayed_ships);
if (Red_alert_applies_to_delayed_ships) {
mprintf(("Game Settings Table: Red-alert stats will be loaded for ships that arrive later in missions\n"));
} else {
mprintf(("Game Settings Table: Red-alert stats will NOT be loaded for ships that arrive later in missions (this is retail behavior)\n"));
if (optional_string("#Ignored Campaign File Names")) {
SCP_string campaign_name;
while (optional_string("$Campaign File Name:")) {
stuff_string(campaign_name, F_NAME);
// remove extension?
if (drop_extension(campaign_name)) {
mprintf(("Game Settings Table: Removed extension on ignored campaign file name %s\n", campaign_name.c_str()));
}
Ignored_campaigns.push_back(campaign_name);
}
}
}
optional_string("#HUD SETTINGS");
// how long should the game wait before displaying a directive?
if (optional_string("$Directive Wait Time:")) {
stuff_int(&Directive_wait_time);
}
if (optional_string("$Cutscene camera displays HUD:")) {
stuff_boolean(&Cutscene_camera_displays_hud);
}
// compatibility
if (optional_string("$Cutscene camera disables HUD:")) {
mprintf(("Game Settings Table: \"$$Cutscene camera disables HUD\" is deprecated in favor of \"$Cutscene camera displays HUD\"\n"));
bool temp;
stuff_boolean(&temp);
Cutscene_camera_displays_hud = !temp;
}
if (optional_string("$Full color head animations:")) {
stuff_boolean(&Full_color_head_anis);
}
// compatibility
if (optional_string("$Color head animations with hud colors:")) {
mprintf(("Game Settings Table: \"$Color head animations with hud colors\" is deprecated in favor of \"$Full color head animations\"\n"));
bool temp;
stuff_boolean(&temp);
Full_color_head_anis = !temp;
}
optional_string("#SEXP SETTINGS");
if (optional_string("$Loop SEXPs Then Arguments:")) {
stuff_boolean(&True_loop_argument_sexps);
if (True_loop_argument_sexps) {
mprintf(("Game Settings Table: Using Reversed Loops For SEXP Arguments\n"));
} else {
mprintf(("Game Settings Table: Using Standard Loops For SEXP Arguments\n"));
if (optional_string("$Red-alert applies to delayed ships:")) {
stuff_boolean(&Red_alert_applies_to_delayed_ships);
if (Red_alert_applies_to_delayed_ships) {
mprintf(("Game Settings Table: Red-alert stats will be loaded for ships that arrive later in missions\n"));
}
else {
mprintf(("Game Settings Table: Red-alert stats will NOT be loaded for ships that arrive later in missions (this is retail behavior)\n"));
}
}
}
if (optional_string("$Use Alternate Chaining Behavior:")) {
stuff_boolean(&Alternate_chaining_behavior);
if (Alternate_chaining_behavior) {
mprintf(("Game Settings Table: Using alternate event chaining behavior\n"));
} else {
mprintf(("Game Settings Table: Using standard event chaining behavior\n"));
optional_string("#HUD SETTINGS");
// how long should the game wait before displaying a directive?
if (optional_string("$Directive Wait Time:")) {
stuff_int(&Directive_wait_time);
}
}
optional_string("#GRAPHICS SETTINGS");
if (optional_string("$Enable External Shaders:")) {
stuff_boolean(&Enable_external_shaders);
if (Enable_external_shaders)
mprintf(("Game Settings Table: External shaders are enabled\n"));
else
mprintf(("Game Settings Table: External shaders are DISABLED\n"));
}
if (optional_string("$Default Detail Level:")) {
int detail_level;
stuff_int(&detail_level);
mprintf(("Game Settings Table: Setting default detail level to %i of %i-%i\n", detail_level, 0, NUM_DEFAULT_DETAIL_LEVELS-1));
if (detail_level < 0 || detail_level > NUM_DEFAULT_DETAIL_LEVELS-1) {
Warning(LOCATION, "Invalid detail level: %i, setting to %i\n", detail_level, Default_detail_level);
} else {
Default_detail_level = detail_level;
if (optional_string("$Cutscene camera displays HUD:")) {
stuff_boolean(&Cutscene_camera_displays_hud);
}
}
if (optional_string("$Briefing Window FOV:")) {
float fov;
stuff_float(&fov);
mprintf(("Game Settings Table: Setting briefing window FOV from %f to %f\n", Briefing_window_FOV, fov));
Briefing_window_FOV = fov;
}
optional_string("#NETWORK SETTINGS");
if (optional_string("$FS2NetD port:")) {
stuff_int(&FS2NetD_port);
if (FS2NetD_port)
mprintf(("Game Settings Table: FS2NetD connecting to port %i\n", FS2NetD_port));
}
optional_string("#SOUND SETTINGS");
if (optional_string("$Default Sound Volume:")) {
stuff_float(&Master_sound_volume);
}
if (optional_string("$Default Music Volume:")) {
stuff_float(&Master_event_music_volume);
}
if (optional_string("$Default Voice Volume:")) {
stuff_float(&Master_voice_volume);
}
optional_string("#FRED SETTINGS");
if (optional_string("$Disable Hard Coded Message Head Ani Files:")) {
stuff_boolean(&Disable_hc_message_ani);
if (Disable_hc_message_ani) {
mprintf(("Game Settings Table: FRED - Disabling Hard Coded Message Ani Files\n"));
} else {
mprintf(("Game Settings Table: FRED - Using Hard Coded Message Ani Files\n"));
// compatibility
if (optional_string("$Cutscene camera disables HUD:")) {
mprintf(("Game Settings Table: \"$$Cutscene camera disables HUD\" is deprecated in favor of \"$Cutscene camera displays HUD\"\n"));
bool temp;
stuff_boolean(&temp);
Cutscene_camera_displays_hud = !temp;
}
}
optional_string("#OTHER SETTINGS");
if (optional_string("$Fixed Turret Collisions:")) {
stuff_boolean(&Fixed_turret_collisions);
}
if (optional_string("$Damage Impacted Subsystem First:")) {
stuff_boolean(&Damage_impacted_subsystem_first);
}
if (optional_string("$Default ship select effect:")) {
char effect[NAME_LENGTH];
stuff_string(effect, F_NAME, NAME_LENGTH);
if (!stricmp(effect, "FS2"))
Default_ship_select_effect = 2;
else if (!stricmp(effect, "FS1"))
Default_ship_select_effect = 1;
else if (!stricmp(effect, "off"))
Default_ship_select_effect = 0;
}
if (optional_string("$Default weapon select effect:")) {
char effect[NAME_LENGTH];
stuff_string(effect, F_NAME, NAME_LENGTH);
if (!stricmp(effect, "FS2"))
Default_weapon_select_effect = 2;
else if (!stricmp(effect, "FS1"))
Default_weapon_select_effect = 1;
else if (!stricmp(effect, "off"))
Default_weapon_select_effect = 0;
}
if (optional_string("$Weapons inherit parent collision group:")) {
stuff_boolean(&Weapons_inherit_parent_collision_group);
if (Weapons_inherit_parent_collision_group)
mprintf(("Game Settings Table: Weapons inherit parent collision group\n"));
}
if (optional_string("$Flight controls follow eyepoint orientation:")) {
stuff_boolean(&Flight_controls_follow_eyepoint_orientation);
if (Flight_controls_follow_eyepoint_orientation)
mprintf(("Game Settings Table: Flight controls follow eyepoint orientation\n"));
}
if (optional_string("$Beams Use Damage Factors:")) {
stuff_boolean(&Beams_use_damage_factors);
if (Beams_use_damage_factors) {
mprintf(("Game Settings Table: Beams will use Damage Factors\n"));
} else {
mprintf(("Game Settings Table: Beams will ignore Damage Factors (retail behavior)\n"));
if (optional_string("$Full color head animations:")) {
stuff_boolean(&Full_color_head_anis);
}
// compatibility
if (optional_string("$Color head animations with hud colors:")) {
mprintf(("Game Settings Table: \"$Color head animations with hud colors\" is deprecated in favor of \"$Full color head animations\"\n"));
bool temp;
stuff_boolean(&temp);
Full_color_head_anis = !temp;
}
}
required_string("#END");
optional_string("#SEXP SETTINGS");
if (optional_string("$Loop SEXPs Then Arguments:")) {
stuff_boolean(&True_loop_argument_sexps);
if (True_loop_argument_sexps) {
mprintf(("Game Settings Table: Using Reversed Loops For SEXP Arguments\n"));
}
else {
mprintf(("Game Settings Table: Using Standard Loops For SEXP Arguments\n"));
}
}
if (optional_string("$Use Alternate Chaining Behavior:")) {
stuff_boolean(&Alternate_chaining_behavior);
if (Alternate_chaining_behavior) {
mprintf(("Game Settings Table: Using alternate event chaining behavior\n"));
}
else {
mprintf(("Game Settings Table: Using standard event chaining behavior\n"));
}
}
optional_string("#GRAPHICS SETTINGS");
if (optional_string("$Enable External Shaders:")) {
stuff_boolean(&Enable_external_shaders);
if (Enable_external_shaders)
mprintf(("Game Settings Table: External shaders are enabled\n"));
else
mprintf(("Game Settings Table: External shaders are DISABLED\n"));
}
if (optional_string("$Default Detail Level:")) {
int detail_level;
stuff_int(&detail_level);
mprintf(("Game Settings Table: Setting default detail level to %i of %i-%i\n", detail_level, 0, NUM_DEFAULT_DETAIL_LEVELS - 1));
if (detail_level < 0 || detail_level > NUM_DEFAULT_DETAIL_LEVELS - 1) {
Warning(LOCATION, "Invalid detail level: %i, setting to %i\n", detail_level, Default_detail_level);
}
else {
Default_detail_level = detail_level;
}
}
if (optional_string("$Briefing Window FOV:")) {
float fov;
stuff_float(&fov);
mprintf(("Game Settings Table: Setting briefing window FOV from %f to %f\n", Briefing_window_FOV, fov));
Briefing_window_FOV = fov;
}
optional_string("#NETWORK SETTINGS");
if (optional_string("$FS2NetD port:")) {
stuff_int(&FS2NetD_port);
if (FS2NetD_port)
mprintf(("Game Settings Table: FS2NetD connecting to port %i\n", FS2NetD_port));
}
optional_string("#SOUND SETTINGS");
if (optional_string("$Default Sound Volume:")) {
stuff_float(&Master_sound_volume);
}
if (optional_string("$Default Music Volume:")) {
stuff_float(&Master_event_music_volume);
}
if (optional_string("$Default Voice Volume:")) {
stuff_float(&Master_voice_volume);
}
optional_string("#FRED SETTINGS");
if (optional_string("$Disable Hard Coded Message Head Ani Files:")) {
stuff_boolean(&Disable_hc_message_ani);
if (Disable_hc_message_ani) {
mprintf(("Game Settings Table: FRED - Disabling Hard Coded Message Ani Files\n"));
}
else {
mprintf(("Game Settings Table: FRED - Using Hard Coded Message Ani Files\n"));
}
}
optional_string("#OTHER SETTINGS");
if (optional_string("$Fixed Turret Collisions:")) {
stuff_boolean(&Fixed_turret_collisions);
}
if (optional_string("$Damage Impacted Subsystem First:")) {
stuff_boolean(&Damage_impacted_subsystem_first);
}
if (optional_string("$Default ship select effect:")) {
char effect[NAME_LENGTH];
stuff_string(effect, F_NAME, NAME_LENGTH);
if (!stricmp(effect, "FS2"))
Default_ship_select_effect = 2;
else if (!stricmp(effect, "FS1"))
Default_ship_select_effect = 1;
else if (!stricmp(effect, "off"))
Default_ship_select_effect = 0;
}
if (optional_string("$Default weapon select effect:")) {
char effect[NAME_LENGTH];
stuff_string(effect, F_NAME, NAME_LENGTH);
if (!stricmp(effect, "FS2"))
Default_weapon_select_effect = 2;
else if (!stricmp(effect, "FS1"))
Default_weapon_select_effect = 1;
else if (!stricmp(effect, "off"))
Default_weapon_select_effect = 0;
}
if (optional_string("$Weapons inherit parent collision group:")) {
stuff_boolean(&Weapons_inherit_parent_collision_group);
if (Weapons_inherit_parent_collision_group)
mprintf(("Game Settings Table: Weapons inherit parent collision group\n"));
}
if (optional_string("$Flight controls follow eyepoint orientation:")) {
stuff_boolean(&Flight_controls_follow_eyepoint_orientation);
if (Flight_controls_follow_eyepoint_orientation)
mprintf(("Game Settings Table: Flight controls follow eyepoint orientation\n"));
}
if (optional_string("$Beams Use Damage Factors:")) {
stuff_boolean(&Beams_use_damage_factors);
if (Beams_use_damage_factors) {
mprintf(("Game Settings Table: Beams will use Damage Factors\n"));
}
else {
mprintf(("Game Settings Table: Beams will ignore Damage Factors (retail behavior)\n"));
}
}
required_string("#END");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", (filename) ? filename : "<default game_settings.tbl>", e.what()));
return;
}
}
void mod_table_init()
+2 -1
View File
@@ -1022,7 +1022,8 @@ typedef struct mc_info {
vec3d *p0; // The starting point of the ray (sphere) to check
vec3d *p1; // The ending point of the ray (sphere) to check
int flags; // Flags that the model_collide code looks at. See MC_??? defines
float radius; // If MC_CHECK_THICK is set, checks a sphere moving with the radius.
float radius; // If MC_CHECK_THICK is set, checks a sphere moving with the radius.
int lod; // Which detail level of the submodel to check instead
// Return values
int num_hits; // How many collisions were found
+16 -1
View File
@@ -1130,7 +1130,22 @@ void mc_check_subobj( int mn )
if ( Cmdline_old_collision_sys ) {
model_collide_sub(sm->bsp_data);
} else {
model_collide_bsp(model_get_bsp_collision_tree(sm->collision_tree_index), 0);
if (Mc->lod > 0 && sm->num_details > 0) {
bsp_info *lod_sm = sm;
for (int i = Mc->lod - 1; i >= 0; i--) {
if (sm->details[i] != -1) {
lod_sm = &Mc_pm->submodel[sm->details[i]];
//mprintf(("Checking %s collision for %s using %s instead\n", Mc_pm->filename, sm->name, lod_sm->name));
break;
}
}
model_collide_bsp(model_get_bsp_collision_tree(lod_sm->collision_tree_index), 0);
} else {
model_collide_bsp(model_get_bsp_collision_tree(sm->collision_tree_index), 0);
}
}
}
}
+51 -31
View File
@@ -83,7 +83,6 @@ static float Interp_box_scale = 1.0f; // this is used to scale both detail boxes
static vec3d Interp_render_box_min = ZERO_VECTOR;
static vec3d Interp_render_box_max = ZERO_VECTOR;
static float Interp_render_sphere_radius = 0.0f;
static vec3d Interp_render_sphere_offset = ZERO_VECTOR;
// -------------------------------------------------------------------
// lighting save stuff
@@ -369,7 +368,6 @@ void interp_clear_instance()
Interp_render_box_min = vmd_zero_vector;
Interp_render_box_max = vmd_zero_vector;
Interp_render_sphere_radius = 0.0f;
Interp_render_sphere_offset = vmd_zero_vector;
}
/**
@@ -2728,6 +2726,7 @@ void model_really_render(int model_num, matrix *orient, vec3d * pos, uint flags,
uint save_gr_zbuffering_mode;
int zbuf_mode;
ship *shipp = NULL;
ship_info *sip = NULL;
object *objp = NULL;
bool set_autocen = false;
bool draw_thrusters = false;
@@ -2742,6 +2741,7 @@ void model_really_render(int model_num, matrix *orient, vec3d * pos, uint flags,
if (objp->type == OBJ_SHIP) {
shipp = &Ships[objp->instance];
sip = &Ship_info[shipp->ship_info_index];
if (shipp->flags2 & SF2_GLOWMAPS_DISABLED)
flags |= MR_NO_GLOWMAPS;
@@ -2905,33 +2905,37 @@ void model_really_render(int model_num, matrix *orient, vec3d * pos, uint flags,
}
#endif
// scale the render box settings based on the "Model Detail" slider
switch (Detail.detail_distance)
{
// 1st dot is 20%
case 0:
Interp_box_scale = 0.2f;
break;
if (shipp != NULL && (sip->flags2 & SIF2_LOCK_DETAIL_BOXES)) {
Interp_box_scale = 1.0f;
} else {
// scale the render box settings based on the "Model Detail" slider
switch (Detail.detail_distance)
{
// 1st dot is 20%
case 0:
Interp_box_scale = 0.2f;
break;
// 2nd dot is 50%
case 1:
Interp_box_scale = 0.5f;
break;
// 2nd dot is 50%
case 1:
Interp_box_scale = 0.5f;
break;
// 3rd dot is 80%
case 2:
Interp_box_scale = 0.8f;
break;
// 3rd dot is 80%
case 2:
Interp_box_scale = 0.8f;
break;
// 4th dot is 100% (this is the default setting for "High" and "Very High" settings)
case 3:
Interp_box_scale = 1.0f;
break;
// 4th dot is 100% (this is the default setting for "High" and "Very High" settings)
case 3:
Interp_box_scale = 1.0f;
break;
// 5th dot (max) is 120%
case 4:
Interp_box_scale = 1.2f;
break;
// 5th dot (max) is 120%
case 4:
Interp_box_scale = 1.2f;
break;
}
}
vec3d auto_back = ZERO_VECTOR;
@@ -4468,7 +4472,13 @@ void model_render_children_buffers(polymodel *pm, int mn, int detail_level)
vm_vec_copy_scale(&Interp_render_box_min, &model->render_box_min, Interp_box_scale);
vm_vec_copy_scale(&Interp_render_box_max, &model->render_box_max, Interp_box_scale);
if ( (-model->use_render_box + in_box(&Interp_render_box_min, &Interp_render_box_max, &model->offset)) )
vec3d offset;
if (model->use_render_box_offset)
offset = model->render_box_offset;
else
model_find_submodel_offset(&offset, pm->id, mn);
if ( (-model->use_render_box + in_box(&Interp_render_box_min, &Interp_render_box_max, &offset)) )
return;
}
if ( !(Interp_flags & MR_FULL_DETAIL) && model->use_render_sphere ) {
@@ -4476,8 +4486,10 @@ void model_render_children_buffers(polymodel *pm, int mn, int detail_level)
// TODO: doesn't consider submodel rotations yet -zookeeper
vec3d offset;
model_find_submodel_offset(&offset, pm->id, mn);
vm_vec_add2(&offset, &model->render_sphere_offset);
if (model->use_render_sphere_offset)
offset = model->render_sphere_offset;
else
model_find_submodel_offset(&offset, pm->id, mn);
if ( (-model->use_render_sphere + in_sphere(&offset, Interp_render_sphere_radius)) )
return;
@@ -4591,7 +4603,13 @@ void model_render_buffers(polymodel *pm, int mn, bool is_child)
vm_vec_copy_scale(&Interp_render_box_min, &model->render_box_min, Interp_box_scale);
vm_vec_copy_scale(&Interp_render_box_max, &model->render_box_max, Interp_box_scale);
if ( (-model->use_render_box + in_box(&Interp_render_box_min, &Interp_render_box_max, &model->offset)) )
vec3d offset;
if (model->use_render_box_offset)
offset = model->render_box_offset;
else
model_find_submodel_offset(&offset, pm->id, mn);
if ( (-model->use_render_box + in_box(&Interp_render_box_min, &Interp_render_box_max, &offset)) )
return;
}
if ( !is_child && !(Interp_flags & MR_FULL_DETAIL) && model->use_render_sphere ) {
@@ -4599,8 +4617,10 @@ void model_render_buffers(polymodel *pm, int mn, bool is_child)
// TODO: doesn't consider submodel rotations yet -zookeeper
vec3d offset;
model_find_submodel_offset(&offset, pm->id, mn);
vm_vec_add2(&offset, &model->render_sphere_offset);
if (model->use_render_sphere_offset)
offset = model->render_sphere_offset;
else
model_find_submodel_offset(&offset, pm->id, mn);
if ( (-model->use_render_sphere + in_sphere(&offset, Interp_render_sphere_radius)) )
return;
+26 -5
View File
@@ -1354,6 +1354,18 @@ int read_model_file(polymodel * pm, char *filename, int n_subsystems, model_subs
while (*p == ' ') p++;
pm->submodel[n].use_render_box = atoi(p);
if ( (p = strstr(props, "$box_offset:")) != NULL ) {
p += 12;
while (*p == ' ') p++;
pm->submodel[n].render_box_offset.xyz.x = (float)strtod(p, (char **)NULL);
while (*p != ',') p++;
pm->submodel[n].render_box_offset.xyz.y = (float)strtod(++p, (char **)NULL);
while (*p != ',') p++;
pm->submodel[n].render_box_offset.xyz.z = (float)strtod(++p, (char **)NULL);
pm->submodel[n].use_render_box_offset = true;
}
if ( (p = strstr(props, "$box_min:")) != NULL ) {
p += 9;
while (*p == ' ') p++;
@@ -1400,6 +1412,8 @@ int read_model_file(polymodel * pm, char *filename, int n_subsystems, model_subs
pm->submodel[n].render_sphere_offset.xyz.y = (float)strtod(++p, (char **)NULL);
while (*p != ',') p++;
pm->submodel[n].render_sphere_offset.xyz.z = (float)strtod(++p, (char **)NULL);
pm->submodel[n].use_render_sphere_offset = true;
} else {
pm->submodel[n].render_sphere_offset = vmd_zero_vector;
}
@@ -2466,7 +2480,7 @@ int model_load(char *filename, int n_subsystems, model_subsystem *subsystems, in
pm = new polymodel;
Polygon_models[num] = pm;
pm->n_paths = 0;
pm->paths = NULL;
@@ -2639,6 +2653,12 @@ int model_load(char *filename, int n_subsystems, model_subsystem *subsystems, in
}
dl2 = tolower(sm2->name[first_diff]) - 'a';
// Handle LODs named "detail0/1/2/etc" too (as opposed to "detaila/b/c/etc")
if (sm1->parent == -1 && sm2->parent == -1 && !sm1->is_damaged && !sm2->is_damaged && !sm1->is_live_debris && !sm2->is_live_debris) {
dl2 = dl2 - dl1;
dl1 = 0;
}
if ( (dl1<0) || (dl2<0) || (dl1>=MAX_MODEL_DETAIL_LEVELS) || (dl2>=MAX_MODEL_DETAIL_LEVELS) ) continue; // invalid detail levels
if ( dl1 == 0 ) {
@@ -2663,10 +2683,11 @@ int model_load(char *filename, int n_subsystems, model_subsystem *subsystems, in
if ( !Cmdline_old_collision_sys ) {
for ( i = 0; i < pm->n_models; ++i ) {
pm->submodel[i].collision_tree_index = model_create_bsp_collision_tree();
bsp_collision_tree *tree = model_get_bsp_collision_tree(pm->submodel[i].collision_tree_index);
model_collide_parse_bsp(tree, pm->submodel[i].bsp_data, pm->version);
if ( !(pm->submodel[i].nocollide_this_only || pm->submodel[i].no_collisions) ) {
pm->submodel[i].collision_tree_index = model_create_bsp_collision_tree();
bsp_collision_tree *tree = model_get_bsp_collision_tree(pm->submodel[i].collision_tree_index);
model_collide_parse_bsp(tree, pm->submodel[i].bsp_data, pm->version);
}
}
}
+42 -38
View File
@@ -249,48 +249,52 @@ void neb2_regen();
// initialize neb2 stuff at game startup
void neb2_init()
{
int rval;
char name[MAX_FILENAME_LEN];
if ( ( rval = setjmp(parse_abort) ) != 0 ) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "nebula.tbl", rval));
try
{
// read in the nebula.tbl
read_file_text("nebula.tbl", CF_TYPE_TABLES);
reset_parse();
// background bitmaps
Neb2_bitmap_count = 0;
while (!optional_string("#end")) {
// nebula
required_string("+Nebula:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
if (Neb2_bitmap_count < MAX_NEB2_BITMAPS) {
strcpy_s(Neb2_bitmap_filenames[Neb2_bitmap_count++], name);
}
else {
WarningEx(LOCATION, "nebula.tbl\nExceeded maximum number of nebulas (%d)!\nSkipping %s.", MAX_NEB2_BITMAPS, name);
}
}
// poofs
Neb2_poof_count = 0;
while (!optional_string("#end")) {
// nebula
required_string("+Poof:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
if (Neb2_poof_count < MAX_NEB2_POOFS) {
strcpy_s(Neb2_poof_filenames[Neb2_poof_count++], name);
}
else {
WarningEx(LOCATION, "nebula.tbl\nExceeded maximum number of nebula poofs (%d)!\nSkipping %s.", MAX_NEB2_POOFS, name);
}
}
// should always have 6 neb poofs
Assert(Neb2_poof_count == 6);
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "nebula.tbl", e.what()));
return;
}
// read in the nebula.tbl
read_file_text("nebula.tbl", CF_TYPE_TABLES);
reset_parse();
// background bitmaps
Neb2_bitmap_count = 0;
while ( !optional_string("#end") ) {
// nebula
required_string("+Nebula:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
if ( Neb2_bitmap_count < MAX_NEB2_BITMAPS ) {
strcpy_s(Neb2_bitmap_filenames[Neb2_bitmap_count++], name);
} else {
WarningEx(LOCATION, "nebula.tbl\nExceeded maximum number of nebulas (%d)!\nSkipping %s.", MAX_NEB2_BITMAPS, name);
}
}
// poofs
Neb2_poof_count = 0;
while ( !optional_string("#end") ) {
// nebula
required_string("+Poof:");
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
if ( Neb2_poof_count < MAX_NEB2_POOFS ) {
strcpy_s(Neb2_poof_filenames[Neb2_poof_count++], name);
} else {
WarningEx(LOCATION, "nebula.tbl\nExceeded maximum number of nebula poofs (%d)!\nSkipping %s.", MAX_NEB2_POOFS, name);
}
}
// should always have 6 neb poofs
Assert(Neb2_poof_count == 6);
}
// set detail level
+116 -114
View File
@@ -155,123 +155,125 @@ DCF(lightning_intensity, "Sets lightning intensity between 0.0 and 1.0 (Default
void nebl_init()
{
char name[MAX_FILENAME_LEN];
int rval;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "lightning.tbl", rval));
try
{
// parse the lightning table
read_file_text("lightning.tbl", CF_TYPE_TABLES);
reset_parse();
// parse the individual lightning bolt types
required_string("#Bolts begin");
while (!optional_string("#Bolts end")){
bolt_type new_bolt_type;
// bolt title
required_string("$Bolt:");
stuff_string(new_bolt_type.name, F_NAME, NAME_LENGTH);
// b_scale
required_string("+b_scale:");
stuff_float(&new_bolt_type.b_scale);
// b_shrink
required_string("+b_shrink:");
stuff_float(&new_bolt_type.b_shrink);
// b_poly_pct
required_string("+b_poly_pct:");
stuff_float(&new_bolt_type.b_poly_pct);
// child rand
required_string("+b_rand:");
stuff_float(&new_bolt_type.b_rand);
// z add
required_string("+b_add:");
stuff_float(&new_bolt_type.b_add);
// # strikes
required_string("+b_strikes:");
stuff_int(&new_bolt_type.num_strikes);
// lifetime
required_string("+b_lifetime:");
stuff_int(&new_bolt_type.lifetime);
// noise
required_string("+b_noise:");
stuff_float(&new_bolt_type.noise);
// emp effect
required_string("+b_emp:");
stuff_float(&new_bolt_type.emp_intensity);
stuff_float(&new_bolt_type.emp_time);
// texture
required_string("+b_texture:");
stuff_string(name, F_NAME, sizeof(name));
if (!Fred_running){
new_bolt_type.texture = bm_load(name);
}
// glow
required_string("+b_glow:");
stuff_string(name, F_NAME, sizeof(name));
if (!Fred_running){
new_bolt_type.glow = bm_load(name);
}
// brightness
required_string("+b_bright:");
stuff_float(&new_bolt_type.b_bright);
Bolt_types.push_back(new_bolt_type);
}
// parse lightning storm types
required_string("#Storms begin");
while (!optional_string("#Storms end")){
storm_type new_storm_type;
// bolt title
required_string("$Storm:");
stuff_string(new_storm_type.name, F_NAME, NAME_LENGTH);
// bolt types
while (optional_string("+bolt:")){
if (new_storm_type.num_bolt_types < MAX_BOLT_TYPES_PER_STORM){
stuff_string(name, F_NAME, sizeof(name));
new_storm_type.bolt_types[new_storm_type.num_bolt_types] = nebl_get_bolt_index(name);
Assert(new_storm_type.bolt_types[new_storm_type.num_bolt_types] != (size_t)-1);
new_storm_type.num_bolt_types++;
}
}
// flavor
required_string("+flavor:");
stuff_float(&new_storm_type.flavor.xyz.x);
stuff_float(&new_storm_type.flavor.xyz.y);
stuff_float(&new_storm_type.flavor.xyz.z);
// frequencies
required_string("+random_freq:");
stuff_int(&new_storm_type.min);
stuff_int(&new_storm_type.max);
// counts
required_string("+random_count:");
stuff_int(&new_storm_type.min_count);
stuff_int(&new_storm_type.max_count);
Storm_types.push_back(new_storm_type);
}
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "lightning.tbl", e.what()));
return;
}
// parse the lightning table
read_file_text("lightning.tbl", CF_TYPE_TABLES);
reset_parse();
// parse the individual lightning bolt types
required_string("#Bolts begin");
while(!optional_string("#Bolts end")){
bolt_type new_bolt_type;
// bolt title
required_string("$Bolt:");
stuff_string(new_bolt_type.name, F_NAME, NAME_LENGTH);
// b_scale
required_string("+b_scale:");
stuff_float(&new_bolt_type.b_scale);
// b_shrink
required_string("+b_shrink:");
stuff_float(&new_bolt_type.b_shrink);
// b_poly_pct
required_string("+b_poly_pct:");
stuff_float(&new_bolt_type.b_poly_pct);
// child rand
required_string("+b_rand:");
stuff_float(&new_bolt_type.b_rand);
// z add
required_string("+b_add:");
stuff_float(&new_bolt_type.b_add);
// # strikes
required_string("+b_strikes:");
stuff_int(&new_bolt_type.num_strikes);
// lifetime
required_string("+b_lifetime:");
stuff_int(&new_bolt_type.lifetime);
// noise
required_string("+b_noise:");
stuff_float(&new_bolt_type.noise);
// emp effect
required_string("+b_emp:");
stuff_float(&new_bolt_type.emp_intensity);
stuff_float(&new_bolt_type.emp_time);
// texture
required_string("+b_texture:");
stuff_string(name, F_NAME, sizeof(name));
if(!Fred_running){
new_bolt_type.texture = bm_load(name);
}
// glow
required_string("+b_glow:");
stuff_string(name, F_NAME, sizeof(name));
if(!Fred_running){
new_bolt_type.glow = bm_load(name);
}
// brightness
required_string("+b_bright:");
stuff_float(&new_bolt_type.b_bright);
Bolt_types.push_back(new_bolt_type);
}
// parse lightning storm types
required_string("#Storms begin");
while(!optional_string("#Storms end")){
storm_type new_storm_type;
// bolt title
required_string("$Storm:");
stuff_string(new_storm_type.name, F_NAME, NAME_LENGTH);
// bolt types
while(optional_string("+bolt:")){
if(new_storm_type.num_bolt_types < MAX_BOLT_TYPES_PER_STORM){
stuff_string(name, F_NAME, sizeof(name));
new_storm_type.bolt_types[new_storm_type.num_bolt_types] = nebl_get_bolt_index(name);
Assert(new_storm_type.bolt_types[new_storm_type.num_bolt_types] != (size_t)-1);
new_storm_type.num_bolt_types++;
}
}
// flavor
required_string("+flavor:");
stuff_float(&new_storm_type.flavor.xyz.x);
stuff_float(&new_storm_type.flavor.xyz.y);
stuff_float(&new_storm_type.flavor.xyz.z);
// frequencies
required_string("+random_freq:");
stuff_int(&new_storm_type.min);
stuff_int(&new_storm_type.max);
// counts
required_string("+random_count:");
stuff_int(&new_storm_type.min_count);
stuff_int(&new_storm_type.max_count);
Storm_types.push_back(new_storm_type);
}
}
// initialize lightning before entering a level
+4
View File
@@ -269,6 +269,10 @@ int ship_ship_check_collision(collision_info_struct *ship_ship_hit_info, vec3d *
// reset flags to check MC_CHECK_MODEL | MC_CHECK_SPHERELINE and maybe MC_CHECK_INVISIBLE_FACES and MC_SUBMODEL_INSTANCE
mc.flags = copy_flags | MC_SUBMODEL_INSTANCE;
if (heavy_sip->collision_lod > -1) {
mc.lod = heavy_sip->collision_lod;
}
// check each submodel in turn
for (smv = submodel_vector.begin(); smv != submodel_vector.end(); ++smv) {
// turn on submodel for collision test
+15 -9
View File
@@ -168,6 +168,7 @@ int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, float ti
mc.pos = &ship_objp->pos;
mc.p0 = &weapon_objp->last_pos;
mc.p1 = &weapon_end_pos;
mc.lod = sip->collision_lod;
memcpy(&mc_shield, &mc, sizeof(mc_info));
memcpy(&mc_hull, &mc, sizeof(mc_info));
@@ -200,15 +201,16 @@ int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, float ti
// The weapon is not allowed to impact the shield before it reaches this point
vec3d shield_ignored_until = weapon_objp->last_pos;
float min_weapon_span = sip->auto_shield_spread_min_span;
float weapon_flown_for = vm_vec_dist(&wp->start_pos, &weapon_objp->last_pos);
// If weapon hasn't yet flown a distance greater than the maximum ignore
// range, then some part of the currently checked range needs to be
// ignored
if (weapon_flown_for < sip->auto_shield_spread) {
if (weapon_flown_for < min_weapon_span) {
vm_vec_sub(&shield_ignored_until, &weapon_end_pos, &wp->start_pos);
vm_vec_normalize(&shield_ignored_until);
vm_vec_scale(&shield_ignored_until, sip->auto_shield_spread);
vm_vec_scale(&shield_ignored_until, min_weapon_span);
vm_vec_add2(&shield_ignored_until, &wp->start_pos);
}
@@ -243,7 +245,7 @@ int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, float ti
// If no collision with the model found in the ignore range, only
// then do we check for sphereline collisions with the model during the
// non-ignored range
if (!shield_collision && weapon_flown_for + this_range > sip->auto_shield_spread) {
if (!shield_collision && weapon_flown_for + this_range > min_weapon_span) {
mc_shield.p0 = &shield_ignored_until;
mc_shield.p1 = &weapon_end_pos;
@@ -251,16 +253,14 @@ int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, float ti
mc_shield.radius = sip->auto_shield_spread;
if (sip->auto_shield_spread_from_lod > -1) {
pm = model_get(sip->model_num);
mc_shield.submodel_num = pm->detail[sip->auto_shield_spread_from_lod];
mc_shield.flags = MC_CHECK_MODEL | MC_SUBMODEL_INSTANCE | MC_CHECK_SPHERELINE;
} else {
mc_shield.flags = MC_CHECK_MODEL | MC_CHECK_SPHERELINE;
mc_shield.lod = sip->auto_shield_spread_from_lod;
}
mc_shield.flags = MC_CHECK_MODEL | MC_CHECK_SPHERELINE;
shield_collision = model_collide(&mc_shield);
mc_shield.lod = sip->collision_lod;
mc_shield.submodel_num = -1;
// Because we manipulated p0 and p1 above, hit_dist will be
@@ -407,6 +407,12 @@ int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, float ti
bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, weapon_objp);
if(!ship_override && !weapon_override) {
if (shield_collision && quadrant_num >= 0) {
if ((sip->shield_impact_explosion_anim > -1) && (wip->shield_impact_explosion_radius > 0)) {
// do in weapons.cpp for most parts just because that is how rest of the functions are handled
shield_impact_explosion(&mc.hit_point, ship_objp, wip->shield_impact_explosion_radius, sip->shield_impact_explosion_anim);
}
}
ship_weapon_do_hit_stuff(ship_objp, weapon_objp, &mc.hit_point_world, &mc.hit_point, quadrant_num, mc.hit_submodel, mc.hit_normal);
}
+14 -2
View File
@@ -49,10 +49,18 @@ void shield_add_strength(object *objp, float delta)
if (delta == 0.0f)
return;
float shield_str = shield_get_strength(objp);
float shield_recharge_limit = Ships[objp->instance].ship_max_shield_strength * Ships[objp->instance].max_shield_recharge;
if (shield_str >= shield_recharge_limit)
return;
if (!(Ai_info[Ships[objp->instance].ai_index].ai_profile_flags & AIPF_SMART_SHIELD_MANAGEMENT)
|| delta <= 0.0f) //SUSHI: We don't want smart shield management for negative delta
{
if ((delta > 0.0f) && ((shield_str + delta) > shield_recharge_limit))
delta = shield_recharge_limit - shield_str;
for (int i = 0; i < objp->n_quadrants; i++)
shield_add_quad(objp, i, delta / objp->n_quadrants);
}
@@ -81,7 +89,11 @@ void shield_add_strength(object *objp, float delta)
// all quads are at full strength
if (weakest >= section_max)
break;
// set the limit for the shield recharge
if ((delta > 0.0f) && ((shield_str + delta) > shield_recharge_limit))
delta = shield_recharge_limit - shield_str;
// throw all possible shield power at this quadrant
// if there's any left over then apply it to the next weakest on the next pass
float xfer_amount;
+12 -5
View File
@@ -521,17 +521,24 @@ void obj_snd_do_frame()
rot_vol_mult = 1.0f;
alive_vol_mult = 1.0f;
if ( objp->type == OBJ_SHIP ) {
if ( !(Ship_info[Ships[objp->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
ship_info *sip = &Ship_info[Ships[objp->instance].ship_info_index];
if ( !(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) ) {
if ( objp->phys_info.max_vel.xyz.z <= 0.0f ) {
percent_max = 0.0f;
}
else
percent_max = objp->phys_info.fspeed / objp->phys_info.max_vel.xyz.z;
if ( percent_max >= 0.5f )
speed_vol_multiplier = 1.0f;
else {
speed_vol_multiplier = 0.5f + (percent_max); // linear interp: 0.5->1.0 when 0.0->0.5
if ( sip->min_engine_vol == -1.0f) {
// Retail behavior: volume ramps from 0.5 (when stationary) to 1.0 (when at half speed)
if ( percent_max >= 0.5f ) {
speed_vol_multiplier = 1.0f;
} else {
speed_vol_multiplier = 0.5f + (percent_max); // linear interp: 0.5->1.0 when 0.0->0.5
}
} else {
// Volume ramps from min_engine_vol (when stationary) to 1.0 (when at full speed)
speed_vol_multiplier = MAX(sip->min_engine_vol, percent_max);
}
}
if (osp->ss != NULL)
+22 -20
View File
@@ -64,28 +64,30 @@ int palman_is_nondarkening(int r,int g, int b)
void palman_load_pixels()
{
int rval;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "pixels.tbl", rval));
try
{
// open pixels.tbl
read_file_text("pixels.tbl", CF_TYPE_TABLES);
reset_parse();
// parse pixels
while (!optional_string("#END")){
// nondarkening pixel
if (required_string("+ND")){
stuff_ubyte(&Palman_non_darkening_default[Palman_num_nondarkening_default][0]);
stuff_ubyte(&Palman_non_darkening_default[Palman_num_nondarkening_default][1]);
stuff_ubyte(&Palman_non_darkening_default[Palman_num_nondarkening_default++][2]);
}
}
// set this to be the active table
palman_set_nondarkening(Palman_non_darkening_default, Palman_num_nondarkening_default);
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "pixels.tbl", e.what()));
return;
}
// open pixels.tbl
read_file_text("pixels.tbl", CF_TYPE_TABLES);
reset_parse();
// parse pixels
while(!optional_string("#END")){
// nondarkening pixel
if(required_string("+ND")){
stuff_ubyte(&Palman_non_darkening_default[Palman_num_nondarkening_default][0]);
stuff_ubyte(&Palman_non_darkening_default[Palman_num_nondarkening_default][1]);
stuff_ubyte(&Palman_non_darkening_default[Palman_num_nondarkening_default++][2]);
}
}
// set this to be the active table
palman_set_nondarkening(Palman_non_darkening_default, Palman_num_nondarkening_default);
}
void palman_set_nondarkening(ubyte colors[MAX_NONDARK_COLORS][3], int size)
+24 -1
View File
@@ -2632,7 +2632,7 @@ ADE_VIRTVAR(RotationalVelocityDamping, l_Physics, "number", "Rotational damping,
return ade_set_args(L, "f", pih->pi->rotdamp);
}
ADE_VIRTVAR(RotationalVelocityDesired, l_Physics, "vector", "Desired rotational velocity", "vector", "Desired rotational velocity, or null vector if handle is invalid")
ADE_VIRTVAR(RotationalVelocityDesired, l_Physics, "lvector", "Desired rotational velocity", "number", "Desired rotational velocity, or 0 if handle is invalid")
{
physics_info_h *pih;
vec3d *v3=NULL;
@@ -15614,6 +15614,29 @@ ADE_FUNC(getStack, l_Testing, NULL, "Generates an ADE stackdump", "string", "Cur
return ade_set_args(L, "s", buf);
}
ADE_FUNC(setCurrentPlayerMulti, l_Testing, "boolean", "Sets whether current player is a multiplayer pilot or not.", "boolean", "True if successful, false if not.")
{
bool multi;
if(!ade_get_args(L, "b", &multi))
return ADE_RETURN_NIL;
if(Player == NULL)
return ade_set_error(L, "b", false);
if (multi) {
Game_mode &= ~GM_NORMAL;
Game_mode |= GM_MULTIPLAYER;
Player->flags |= PLAYER_FLAGS_IS_MULTI;
} else {
Game_mode &= ~GM_MULTIPLAYER;
Game_mode |= GM_NORMAL;
Player->flags &= ~PLAYER_FLAGS_IS_MULTI;
}
return ADE_RETURN_TRUE;
}
ADE_FUNC(isCurrentPlayerMulti, l_Testing, NULL, "Returns whether current player is a multiplayer pilot or not.", "boolean", "Whether current player is a multiplayer pilot or not")
{
if(Player == NULL)
+41 -41
View File
@@ -43,7 +43,6 @@ int Warning_count, Error_count;
int Warning_count_save = 0, Error_count_save = 0;
int fred_parse_flag = 0;
int Token_found_flag;
jmp_buf parse_abort;
char *Mission_text = NULL;
char *Mission_text_raw = NULL;
@@ -483,7 +482,7 @@ int required_string(char *pstr)
if (count == RS_MAX_TRIES) {
nprintf(("Error", "Error: Unable to find required token [%s]\n", pstr));
Warning(LOCATION, "Error: Unable to find required token [%s]\n", pstr);
longjmp(parse_abort, 1);
throw parse::ParseException("Required string not found");
}
Mp += strlen(pstr);
@@ -691,8 +690,8 @@ int required_string_either(char *str1, char *str2)
if (count == RS_MAX_TRIES) {
nprintf(("Error", "Error: Unable to find either required token [%s] or [%s]\n", str1, str2));
Warning(LOCATION, "Error: Unable to find either required token [%s] or [%s]\n", str1, str2);
longjmp(parse_abort, 2);
Warning(LOCATION, "Error: Unable to find either required token [%s] or [%s]\n", str1, str2);
throw parse::ParseException("Required string not found");
}
return -1;
@@ -887,8 +886,8 @@ char* alloc_text_until(char* instr, char* endstr)
if(foundstr == NULL)
{
Error(LOCATION, "Missing [%s] in file");
longjmp(parse_abort, 3);
Error(LOCATION, "Missing [%s] in file", endstr);
throw parse::ParseException("End string not found");
}
else
{
@@ -922,8 +921,8 @@ void copy_text_until(char *outstr, char *instr, char *endstr, int max_chars)
foundstr = stristr(instr, endstr);
if (foundstr == NULL) {
nprintf(("Error", "Error. Looking for [%s], but never found it.\n", endstr));
longjmp(parse_abort, 3);
nprintf(("Error", "Error. Looking for [%s], but never found it.\n", endstr));
throw parse::ParseException("End string not found");
}
if (foundstr - instr + strlen(endstr) < (uint) max_chars) {
@@ -934,7 +933,7 @@ void copy_text_until(char *outstr, char *instr, char *endstr, int max_chars)
nprintf(("Error", "Error. Too much text (%i chars, %i allowed) before %s\n",
foundstr - instr - strlen(endstr), max_chars, endstr));
longjmp(parse_abort, 4);
throw parse::ParseException("Too much text found");
}
diag_printf("Here's the partial wad of text:\n%.30s\n", outstr);
@@ -949,8 +948,8 @@ void copy_text_until(SCP_string &outstr, char *instr, char *endstr)
foundstr = stristr(instr, endstr);
if (foundstr == NULL) {
nprintf(("Error", "Error. Looking for [%s], but never found it.\n", endstr));
longjmp(parse_abort, 3);
nprintf(("Error", "Error. Looking for [%s], but never found it.\n", endstr));
throw parse::ParseException("End string not found");
}
outstr.assign(instr, foundstr - instr);
@@ -1046,8 +1045,8 @@ char* alloc_block(char* startstr, char* endstr, int extra_chars)
//Check that we left the file
if(level > 0)
{
Error(LOCATION, "Unclosed pair of \"%s\" and \"%s\" on line %d in file", startstr, endstr, get_line_num());
longjmp(parse_abort, 3);
Error(LOCATION, "Unclosed pair of \"%s\" and \"%s\" on line %d in file", startstr, endstr, get_line_num());
throw parse::ParseException("End string not found");
}
else
{
@@ -1967,8 +1966,9 @@ int parse_get_line(char *lineout, int max_line_len, char *start, int max_size, c
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
{
// copy the filename
if (!filename)
longjmp(parse_abort, 10);
if (!filename)
throw parse::ParseException("Invalid filename");
strcpy_s(Current_filename_sub, filename);
// if we are paused then processed_text and raw_text must not be NULL!!
@@ -2106,16 +2106,16 @@ void read_raw_file_text(const char *filename, int mode, char *raw_text)
mf = cfopen(filename, "rb", CFILE_NORMAL, mode);
if (mf == NULL)
{
nprintf(("Error", "Wokka! Error opening file (%s)!\n", filename));
longjmp(parse_abort, 5);
nprintf(("Error", "Wokka! Error opening file (%s)!\n", filename));
throw parse::ParseException("Failed to open file");
}
// read the entire file in
int file_len = cfilelength(mf);
if(!file_len) {
nprintf(("Error", "Oh noes!! File is empty! (%s)!\n", filename));
longjmp(parse_abort, 5);
nprintf(("Error", "Oh noes!! File is empty! (%s)!\n", filename));
throw parse::ParseException("Failed to open file");
}
// allocate, or reallocate, memory for Mission_text and Mission_text_raw based on size we need now
@@ -2567,8 +2567,8 @@ int stuff_bool_list(bool *blp, int max_bools)
ignore_white_space();
if (*Mp != '(') {
error_display(1, "Reading boolean list. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 6);
error_display(1, "Reading boolean list. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
@@ -2665,8 +2665,8 @@ int stuff_string_list(SCP_vector<SCP_string>& slp)
ignore_white_space();
if ( *Mp != '(' ) {
error_display(1, "Reading string list. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 100);
error_display(1, "Reading string list. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
@@ -2699,8 +2699,8 @@ int stuff_string_list(char slp[][NAME_LENGTH], int max_strings)
ignore_white_space();
if ( *Mp != '(' ) {
error_display(1, "Reading string list. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 100);
error_display(1, "Reading string list. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
@@ -2756,8 +2756,8 @@ int stuff_int_list(int *ilp, int max_ints, int lookup_type)
ignore_white_space();
if (*Mp != '(') {
error_display(1, "Reading integer list. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 6);
error_display(1, "Reading integer list. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
@@ -2858,8 +2858,8 @@ int stuff_loadout_list (int *ilp, int max_ints, int lookup_type)
ignore_white_space();
if (*Mp != '(') {
error_display(1, "Reading loadout list. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 6);
error_display(1, "Reading loadout list. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
@@ -2962,8 +2962,8 @@ int stuff_float_list(float* flp, int max_floats)
ignore_white_space();
if (*Mp != '(') {
error_display(1, "Reading float list. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 6);
error_display(1, "Reading float list. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
@@ -2995,8 +2995,8 @@ void mark_int_list(int *ilp, int max_ints, int lookup_type)
ignore_white_space();
if (*Mp != '(') {
error_display(1, "Marking integer list. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 6);
error_display(1, "Marking integer list. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
@@ -3062,15 +3062,15 @@ void stuff_parenthesized_vec3d(vec3d *vp)
ignore_white_space();
if (*Mp != '(') {
error_display(1, "Reading parenthesized vec3d. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 11);
error_display(1, "Reading parenthesized vec3d. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
} else {
Mp++;
stuff_vec3d(vp);
ignore_white_space();
if (*Mp != ')') {
error_display(1, "Reading parenthesized vec3d. Found [%c]. Expecting ')'.\n", *Mp);
longjmp(parse_abort, 12);
error_display(1, "Reading parenthesized vec3d. Found [%c]. Expecting ')'.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
}
@@ -3089,8 +3089,8 @@ int stuff_vec3d_list(vec3d *vlp, int max_vecs)
ignore_white_space();
if (*Mp != '(') {
error_display(1, "Reading vec3d list. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 6);
error_display(1, "Reading vec3d list. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
@@ -3120,8 +3120,8 @@ int stuff_vec3d_list(SCP_vector<vec3d> &vec_list)
ignore_white_space();
if (*Mp != '(') {
error_display(1, "Reading vec3d list. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 6);
error_display(1, "Reading vec3d list. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
+11 -4
View File
@@ -14,9 +14,7 @@
#include "cfile/cfile.h"
#include "globalincs/pstypes.h"
#include <csetjmp>
#include <cstdio>
#include <string>
#include <exception>
// NOTE: although the main game doesn't need this anymore, FRED2 still does
#define MISSION_TEXT_SIZE 1000000
@@ -27,7 +25,6 @@ extern char *Mp;
extern char *token_found;
extern int fred_parse_flag;
extern int Token_found_flag;
extern jmp_buf parse_abort;
#define COMMENT_CHAR (char)';'
@@ -257,4 +254,14 @@ int get_string_or_variable (SCP_string &str);
#define PARSING_FOUND_STRING 0
#define PARSING_FOUND_VARIABLE 1
namespace parse
{
class ParseException : public std::runtime_error
{
public:
ParseException(const std::string& msg) : std::runtime_error(msg) {}
~ParseException() throw() {}
};
}
#endif
+54 -52
View File
@@ -109,46 +109,42 @@ bool script_hook_valid(script_hook *hook)
void script_parse_table(const char *filename)
{
script_state *st = &Script_system;
int rval;
if ((rval = setjmp(parse_abort)) != 0)
try
{
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
return;
}
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
if (optional_string("#Global Hooks"))
{
//int num = 42;
//Script_system.SetHookVar("Version", 'i', &num);
if (optional_string("$Global:")) {
st->ParseChunk(&Script_globalhook, "Global");
}
if(optional_string("#Global Hooks"))
{
//int num = 42;
//Script_system.SetHookVar("Version", 'i', &num);
if(optional_string("$Global:")) {
st->ParseChunk(&Script_globalhook, "Global");
if (optional_string("$Splash:")) {
st->ParseChunk(&Script_splashhook, "Splash");
}
if (optional_string("$GameInit:")) {
st->ParseChunk(&Script_gameinithook, "GameInit");
}
if (optional_string("$Simulation:")) {
st->ParseChunk(&Script_simulationhook, "Simulation");
}
if (optional_string("$HUD:")) {
st->ParseChunk(&Script_hudhook, "HUD");
}
required_string("#End");
}
if(optional_string("$Splash:")) {
st->ParseChunk(&Script_splashhook, "Splash");
}
if(optional_string("$GameInit:")) {
st->ParseChunk(&Script_gameinithook, "GameInit");
}
if(optional_string("$Simulation:")) {
st->ParseChunk(&Script_simulationhook, "Simulation");
}
if(optional_string("$HUD:")) {
st->ParseChunk(&Script_hudhook, "HUD");
}
required_string("#End");
}
/*
if(optional_string("#State Hooks"))
{
while(optional_string("$State:")) {
/*
if(optional_string("#State Hooks"))
{
while(optional_string("$State:")) {
char buf[NAME_LENGTH];
int idx;
stuff_string(buf, F_NAME, sizeof(buf));
@@ -157,25 +153,31 @@ void script_parse_table(const char *filename)
if(optional_string("$Hook:"))
{
if(idx > -1) {
GS_state_hooks[idx] = st->ParseChunk(buf);
} else {
st->ParseChunk(buf);
}
if(idx > -1) {
GS_state_hooks[idx] = st->ParseChunk(buf);
} else {
st->ParseChunk(buf);
}
}
}
required_string("#End");
}
*/
if (optional_string("#Conditional Hooks"))
{
while (st->ParseCondition(filename));
required_string("#End");
}
required_string("#End");
}
*/
if(optional_string("#Conditional Hooks"))
{
while(st->ParseCondition(filename));
required_string("#End");
}
// add tbl/tbm to multiplayer validation list
extern void fs2netd_add_table_validation(const char *tblname);
fs2netd_add_table_validation(filename);
// add tbl/tbm to multiplayer validation list
extern void fs2netd_add_table_validation(const char *tblname);
fs2netd_add_table_validation(filename);
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
}
//Initializes the (global) scripting system, as well as any subsystems.
+5 -3
View File
@@ -3576,8 +3576,8 @@ int stuff_sexp_variable_list()
// check for start of list
if (*Mp != '(') {
error_display(1, "Reading sexp variable list. Found [%c]. Expecting '('.\n", *Mp);
longjmp(parse_abort, 6);
error_display(1, "Reading sexp variable list. Found [%c]. Expecting '('.\n", *Mp);
throw parse::ParseException("Syntax error");
}
Mp++;
@@ -16541,6 +16541,7 @@ void parse_copy_damage(p_object *target_pobjp, ship *source_shipp)
// ...and shields
target_pobjp->ship_max_shield_strength = source_shipp->ship_max_shield_strength;
target_pobjp->initial_shields = fl2i(get_shield_pct(source_objp) * 100.0f);
target_pobjp->max_shield_recharge = source_shipp->max_shield_recharge;
// search through all subsystems on source ship and map them onto target ship
@@ -31465,7 +31466,8 @@ sexp_help_struct Sexp_help[] = {
"friendly-stealth-invisible - If set, the ship can't be targeted even by ships on the same team\r\n"
"hide-ship-name - If set, the ship name can't be seen when the ship is targeted\r\n"
"hidden-from-sensors - If set, the ship can't be targeted and appears on radar as a blinking dot\r\n"
"no-dynamic - Will stop allowing the AI to persue dynamic goals (eg: chasing ships it was not ordered to)\r\n"},
"no-dynamic - Will stop allowing the AI to persue dynamic goals (eg: chasing ships it was not ordered to)\r\n"
"no-secondary-lock-on - Will disable target acquisition for secondaries of all types (does not affect turrets)\r\n"},
{ OP_SHIP_VISIBLE, "ship-visible\r\n"
"\tCauses the ships listed in this sexpression to be visible with player sensors.\r\n\r\n"
+1 -1
View File
@@ -1035,7 +1035,7 @@ typedef struct sexp_node {
typedef struct sexp_variable {
int type;
char text[TOKEN_LENGTH];
char text[256];
char variable_name[TOKEN_LENGTH];
} sexp_variable;
+4
View File
@@ -101,6 +101,10 @@ void init_new_pilot(player *p, int reset)
Mouse_sensitivity = 4;
Joy_sensitivity = 9;
Dead_zone_size = 10;
Master_sound_volume = Default_sound_volume;
Master_event_music_volume = Default_music_volume;
Master_voice_volume = Default_voice_volume;
}
// unassigned squadron
+4 -4
View File
@@ -637,22 +637,22 @@ void read_keyboard_controls( control_info * ci, float frame_time, physics_info *
if (Axis_map_to[JOY_HEADING_AXIS] >= 0) {
// check the heading on the x axis
if ( check_control(BANK_WHEN_PRESSED) ) {
delta = f2fl( axis[JOY_HEADING_AXIS] );
delta = f2fl( axis[Axis_map_to[JOY_HEADING_AXIS]] );
if ( (delta > 0.05f) || (delta < -0.05f) ) {
ci->bank -= delta;
}
} else {
ci->heading += f2fl( axis[JOY_HEADING_AXIS] );
ci->heading += f2fl( axis[Axis_map_to[JOY_HEADING_AXIS]] );
}
}
// check the pitch on the y axis
if (Axis_map_to[JOY_PITCH_AXIS] >= 0) {
ci->pitch -= f2fl( axis[JOY_PITCH_AXIS] );
ci->pitch -= f2fl( axis[Axis_map_to[JOY_PITCH_AXIS]] );
}
if (Axis_map_to[JOY_BANK_AXIS] >= 0) {
ci->bank -= f2fl( axis[JOY_BANK_AXIS] ) * 1.5f;
ci->bank -= f2fl( axis[Axis_map_to[JOY_BANK_AXIS]] ) * 1.5f;
}
// axis 2 is for throttle
+258 -105
View File
@@ -312,6 +312,7 @@ flag_def_list Ship_flags[] = {
{ "no lighting", SIF2_NO_LIGHTING, 1 },
{ "auto spread shields", SIF2_AUTO_SPREAD_SHIELDS, 1 },
{ "model point shields", SIF2_MODEL_POINT_SHIELDS, 1 },
{ "lock detail boxes", SIF2_LOCK_DETAIL_BOXES, 1 },
// to keep things clean, obsolete options go last
{ "ballistic primaries", -1, 255 }
@@ -385,6 +386,7 @@ ship_flag_name Ship_flag_names[] = {
{SF2_DONT_COLLIDE_INVIS, "don't-collide-invisible", 2, },
{SF2_NO_ETS, "no-ets", 2, },
{SF2_TOGGLE_SUBSYSTEM_SCANNING, "toggle-subsystem-scanning", 2, },
{SF2_NO_SECONDARY_LOCKON, "no-secondary-lock-on", 2, },
};
const int num_ai_tgt_weapon_flags = sizeof(ai_tgt_weapon_flags) / sizeof(flag_def_list);
@@ -690,6 +692,7 @@ void init_ship_entry(ship_info *sip)
sip->pof_file_hud[0] = '\0';
sip->num_detail_levels = 1;
sip->detail_distance[0] = 0;
sip->collision_lod = -1;
sip->cockpit_model_num = -1;
sip->model_num = -1;
sip->model_num_hud = -1;
@@ -865,9 +868,12 @@ void init_ship_entry(ship_info *sip)
sip->max_hull_strength = 100.0f;
sip->max_shield_strength = 0.0f;
sip->max_shield_recharge = 1.0f;
sip->auto_shield_spread = 0.0f;
sip->auto_shield_spread_bypass = false;
sip->auto_shield_spread_from_lod = -1;
sip->auto_shield_spread_min_span = -1.0f;
for (i = 0; i < 4; i++)
{
@@ -948,6 +954,7 @@ void init_ship_entry(ship_info *sip)
sip->thruster02_glow_len_factor = 1.0f;
sip->thruster_dist_rad_factor = 2.0f;
sip->thruster_dist_len_factor = 2.0f;
sip->thruster_glow_noise_mult = 1.0f;
sip->draw_distortion = true;
@@ -967,11 +974,14 @@ void init_ship_entry(ship_info *sip)
sip->newtonian_damp_override = false;
sip->autoaim_fov = 0.0f;
sip->autoaim_lock_snd = -1;
sip->autoaim_lost_snd = -1;
sip->topdown_offset_def = false;
vm_vec_zero(&sip->topdown_offset);
sip->engine_snd = -1;
sip->min_engine_vol = -1.0f;
sip->glide_start_snd = -1;
sip->glide_end_snd = -1;
@@ -1009,6 +1019,7 @@ void init_ship_entry(ship_info *sip)
sip->damage_lightning_type = SLT_DEFAULT;
sip->shield_impact_explosion_anim = -1;
sip->hud_gauges.clear();
sip->hud_enabled = false;
sip->hud_retail = false;
@@ -1664,6 +1675,13 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
sip->num_detail_levels = stuff_int_list(sip->detail_distance, MAX_SHIP_DETAIL_LEVELS, RAW_INTEGER_TYPE);
}
if(optional_string("$Collision LOD:")) {
stuff_int(&sip->collision_lod);
// Cap to sane values, just in case
sip->collision_lod = MAX(0, MIN(sip->collision_lod, sip->num_detail_levels));
}
// check for optional pixel colors
while(optional_string("$ND:")){
ubyte nr, ng, nb;
@@ -2000,6 +2018,9 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
if(optional_string("+Minimum Distance:"))
stuff_float(&sip->minimum_convergence_distance);
parse_sound("+Autoaim Lock Snd:", &sip->autoaim_lock_snd, sip->name);
parse_sound("+Autoaim Lost Snd:", &sip->autoaim_lost_snd, sip->name);
}
if(optional_string("$Convergence:"))
@@ -2306,6 +2327,11 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
if(optional_string("+Auto Spread:")) {
stuff_float(&sip->auto_shield_spread);
}
if(optional_string("+Minimum Weapon Span:")) {
stuff_float(&sip->auto_shield_spread_min_span);
} else {
sip->auto_shield_spread_min_span = sip->auto_shield_spread;
}
if(optional_string("+Allow Bypass:")) {
stuff_boolean(&sip->auto_shield_spread_bypass);
}
@@ -2355,6 +2381,19 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
stuff_ubyte(&sip->shield_color[2]);
}
if(optional_string("$Shield Impact Explosion:")) {
char fname[MAX_NAME_LEN];
stuff_string(fname, F_NAME, NAME_LENGTH);
if ( VALID_FNAME(fname) )
sip->shield_impact_explosion_anim = Weapon_explosions.Load(fname);
}
if(optional_string("$Max Shield Recharge:")){
stuff_float(&sip->max_shield_recharge);
CLAMP(sip->max_shield_recharge, 0.0f, 1.0f);
}
// The next five fields are used for the ETS
if (optional_string("$Power Output:"))
stuff_float(&sip->power_output);
@@ -2660,6 +2699,9 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
//Parse the engine sound
parse_sound("$EngineSnd:", &sip->engine_snd, sip->name);
if(optional_string("$Minimum Engine Volume:"))
stuff_float(&sip->min_engine_vol);
//Parse optional sound to be used for beginning of a glide
parse_sound("$GlideStartSnd:", &sip->glide_start_snd, sip->name);
@@ -2716,6 +2758,32 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
stuff_string(sip->icon_filename, F_NAME, MAX_FILENAME_LEN);
}
if ( optional_string("$Model Icon Direction:") ) {
char str[NAME_LENGTH];
stuff_string(str, F_NAME, NAME_LENGTH);
angles model_icon_angles = {0.0f,0.0f,0.0f};
if (!stricmp(str, "top")) {
model_icon_angles.p = -PI_2;
} else if (!stricmp(str, "bottom")) {
model_icon_angles.p = -PI_2;
model_icon_angles.b = 2 * PI_2;
} else if (!stricmp(str, "front")) {
model_icon_angles.h = 2 * PI_2;
} else if (!stricmp(str, "back")) {
model_icon_angles.h = 4 * PI_2;
} else if (!stricmp(str, "left")) {
model_icon_angles.h = -PI_2;
} else if (!stricmp(str, "right")) {
model_icon_angles.h = PI_2;
} else {
Warning(LOCATION, "Unrecognized value \"%s\" passed to $Model Icon Direction, ignoring...", str);
}
sip->model_icon_angles = model_icon_angles;
}
// read in filename for animation that is used in ship selection
if ( optional_string("$Ship_anim:") ) {
stuff_string(sip->anim_filename, F_NAME, MAX_FILENAME_LEN);
@@ -2865,6 +2933,10 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
stuff_boolean(&sip->draw_distortion);
}
if ( optional_string("$Thruster Glow Noise Mult:") ) {
stuff_float(&sip->thruster_glow_noise_mult);
}
while ( optional_string("$Thruster Particles:") ) {
bool afterburner = false;
thruster_particles tpart;
@@ -3139,6 +3211,15 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
stuff_vec3d(&metadata.departure_rvec);
}
if (optional_string("+arrive speed multiplier:"))
{
stuff_float(&metadata.arrive_speed_mult);
}
if (optional_string("+depart speed multiplier:"))
{
stuff_float(&metadata.depart_speed_mult);
}
//Add the new path_metadata to sip->pathMetadata keyed by path name
SCP_string pathName(path_name);
sip->pathMetadata[pathName] = metadata;
@@ -3934,46 +4015,47 @@ void parse_ship_type()
void parse_shiptype_tbl(const char *filename)
{
int rval;
try
{
if (filename != NULL)
read_file_text(filename, CF_TYPE_TABLES);
else
read_file_text_from_array(defaults_get_file("objecttypes.tbl"));
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
reset_parse();
if (optional_string("#Target Priorities"))
{
while (required_string_either("#End", "$Name:"))
parse_ai_target_priorities();
required_string("#End");
}
if (optional_string("#Weapon Targeting Priorities"))
{
while (required_string_either("#End", "$Name:"))
parse_weapon_targeting_priorities();
required_string("#End");
}
if (optional_string("#Ship Types"))
{
while (required_string_either("#End", "$Name:"))
parse_ship_type();
required_string("#End");
}
// add tbl/tbm to multiplayer validation list
fs2netd_add_table_validation(filename);
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
if (filename != NULL)
read_file_text(filename, CF_TYPE_TABLES);
else
read_file_text_from_array(defaults_get_file("objecttypes.tbl"));
reset_parse();
if (optional_string("#Target Priorities"))
{
while (required_string_either("#End", "$Name:"))
parse_ai_target_priorities();
required_string("#End");
}
if (optional_string("#Weapon Targeting Priorities"))
{
while (required_string_either("#End", "$Name:"))
parse_weapon_targeting_priorities();
required_string("#End");
}
if (optional_string("#Ship Types"))
{
while (required_string_either("#End", "$Name:"))
parse_ship_type();
required_string("#End");
}
// add tbl/tbm to multiplayer validation list
fs2netd_add_table_validation(filename);
}
// The E - Simple lookup function for FRED.
@@ -4029,56 +4111,56 @@ void ship_set_default_player_ship()
void parse_shiptbl(const char *filename)
{
int rval;
if ((rval = setjmp(parse_abort)) != 0)
try
{
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// parse default ship
//Override default player ship
if (optional_string("#Default Player Ship"))
{
required_string("$Name:");
stuff_string(default_player_ship, F_NAME, sizeof(default_player_ship));
required_string("#End");
}
//Add engine washes
//This will override if they already exist
if (optional_string("#Engine Wash Info"))
{
while (required_string_either("#End", "$Name:"))
{
parse_engine_wash(Parsing_modular_table);
}
required_string("#End");
}
//Add ship classes
if (optional_string("#Ship Classes"))
{
while (required_string_either("#End", "$Name:"))
{
if (parse_ship(filename, Parsing_modular_table)) {
continue;
}
}
required_string("#End");
}
//Set default player ship
ship_set_default_player_ship();
// add tbl/tbm to multiplayer validation list
fs2netd_add_table_validation(filename);
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// parse default ship
//Override default player ship
if(optional_string("#Default Player Ship"))
{
required_string("$Name:");
stuff_string(default_player_ship, F_NAME, sizeof(default_player_ship));
required_string("#End");
}
//Add engine washes
//This will override if they already exist
if(optional_string("#Engine Wash Info"))
{
while (required_string_either("#End", "$Name:"))
{
parse_engine_wash(Parsing_modular_table);
}
required_string("#End");
}
//Add ship classes
if(optional_string("#Ship Classes"))
{
while (required_string_either("#End","$Name:"))
{
if ( parse_ship(filename, Parsing_modular_table) ) {
continue;
}
}
required_string("#End");
}
//Set default player ship
ship_set_default_player_ship();
// add tbl/tbm to multiplayer validation list
fs2netd_add_table_validation(filename);
}
int ship_show_velocity_dot = 0;
@@ -5019,12 +5101,14 @@ void ship_set(int ship_index, int objnum, int ship_type)
}
objp->hull_strength = shipp->ship_max_hull_strength;
shipp->max_shield_recharge = sip->max_shield_recharge;
if (Fred_running) {
shipp->ship_max_shield_strength = 100.0f;
objp->shield_quadrant[0] = 100.0f;
} else {
shipp->ship_max_shield_strength = sip->max_shield_strength;
shield_set_strength(objp, shipp->ship_max_shield_strength);
shield_set_strength(objp, shipp->ship_max_shield_strength * shipp->max_shield_recharge);
}
if (sip->flags2 & SIF2_MODEL_POINT_SHIELDS) {
@@ -6105,7 +6189,7 @@ void ship_render(object * obj)
mst.distortion_bitmap = shipp->thruster_distortion_bitmap;
mst.use_ab = (obj->phys_info.flags & PF_AFTERBURNER_ON) || (obj->phys_info.flags & PF_BOOSTER_ON);
mst.glow_noise = shipp->thruster_glow_noise;
mst.glow_noise = shipp->thruster_glow_noise * sip->thruster_glow_noise_mult;
mst.rotvel = &Objects[shipp->objnum].phys_info.rotvel;
mst.glow_rad_factor = sip->thruster01_glow_rad_factor;
@@ -9184,6 +9268,8 @@ void change_ship_type(int n, int ship_type, int by_sexp)
objp->hull_strength = hull_pct * sp->ship_max_hull_strength;
}
sp->max_shield_recharge = sip->max_shield_recharge;
// set the correct shield strength
if (Fred_running) {
if (sp->ship_max_shield_strength)
@@ -9827,6 +9913,70 @@ int tracers[MAX_SHIPS][4][4];
float ship_get_subsystem_strength( ship *shipp, int type );
/**
* Checks whether a ship would use autoaim if it were to fire its primaries at
* the given object, taking lead into account.
*
* @param shipp the ship to check
* @param bank_to_fire the assumed primary bank
* @param obj the object to check; must be the ship's current target
*/
bool in_autoaim_fov(ship *shipp, int bank_to_fire, object *obj)
{
// Most of the code of this function has been duplicated from
// ship_fire_primary(), because it is not easy to encapsulate cleanly.
ship_info *sip;
ai_info *aip;
ship_weapon *swp;
bool has_autoaim, has_converging_autoaim;
float autoaim_fov = 0;
float dist_to_target = 0;
vec3d plr_to_target_vec;
vec3d player_forward_vec = Objects[shipp->objnum].orient.vec.fvec;
vec3d target_position;
sip = &Ship_info[shipp->ship_info_index];
aip = &Ai_info[shipp->ai_index];
swp = &shipp->weapons;
int weapon = swp->primary_bank_weapons[bank_to_fire];
weapon_info* winfo_p = &Weapon_info[weapon];
has_converging_autoaim = ((sip->aiming_flags & AIM_FLAG_AUTOAIM_CONVERGENCE || (The_mission.ai_profile->player_autoaim_fov[Game_skill_level] > 0.0f && !( Game_mode & GM_MULTIPLAYER ))) && aip->target_objnum != -1);
has_autoaim = ((has_converging_autoaim || (sip->aiming_flags & AIM_FLAG_AUTOAIM)) && aip->target_objnum != -1);
if (!has_autoaim)
return FALSE;
autoaim_fov = MAX(shipp->autoaim_fov, The_mission.ai_profile->player_autoaim_fov[Game_skill_level]);
if (aip->targeted_subsys != NULL)
{
get_subsystem_world_pos(&Objects[aip->target_objnum], aip->targeted_subsys, &target_position);
}
else
{
target_position = obj->pos;
}
dist_to_target = vm_vec_dist_quick(&Objects[shipp->objnum].pos, &target_position);
hud_calculate_lead_pos(&plr_to_target_vec, &target_position, obj, winfo_p, dist_to_target);
vm_vec_sub2(&plr_to_target_vec, &Objects[shipp->objnum].pos);
float angle_to_target = vm_vec_delta_ang(&player_forward_vec, &plr_to_target_vec, NULL);
if (angle_to_target <= autoaim_fov)
return true;
else
return false;
}
// fires a primary weapon for the given object. It also handles multiplayer cases.
// in multiplayer, the starting network signature, and number of banks fired are sent
// to all the clients in the game. All the info is passed to send_primary at the end of
@@ -12590,7 +12740,7 @@ float ship_calculate_rearm_duration( object *objp )
//find out time to repair shields
if(sip->sup_shield_repair_rate > 0.0f)
shield_rep_time = (sp->ship_max_shield_strength - shield_get_strength(objp)) / (sp->ship_max_shield_strength * sip->sup_shield_repair_rate);
shield_rep_time = ((sp->ship_max_shield_strength * sp->max_shield_recharge) - shield_get_strength(objp)) / (sp->max_shield_recharge * sp->ship_max_shield_strength * sip->sup_shield_repair_rate);
max_hull_repair = sp->ship_max_hull_strength * (The_mission.support_ships.max_hull_repair_val * 0.01f);
if ((The_mission.flags & MISSION_FLAG_SUPPORT_REPAIRS_HULL) && (max_hull_repair > objp->hull_strength) && (sip->sup_hull_repair_rate > 0.0f))
@@ -12726,7 +12876,7 @@ int ship_do_rearm_frame( object *objp, float frametime )
if ( !(objp->flags & OF_NO_SHIELDS) )
{
shield_str = shield_get_strength(objp);
if ( shield_str < shipp->ship_max_shield_strength ) {
if ( shield_str < (shipp->ship_max_shield_strength * shipp->max_shield_recharge) ) {
if ( objp == Player_obj ) {
player_maybe_start_repair_sound();
}
@@ -17481,28 +17631,29 @@ void parse_armor_type()
void armor_parse_table(const char *filename)
{
int rval;
try
{
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
return;
}
//Enumerate through all the armor types and add them.
while (optional_string("#Armor Type")) {
while (required_string_either("#End", "$Name:")) {
parse_armor_type();
continue;
}
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
//Enumerate through all the armor types and add them.
while ( optional_string("#Armor Type") ) {
while ( required_string_either("#End", "$Name:") ) {
parse_armor_type();
continue;
required_string("#End");
}
required_string("#End");
// add tbl/tbm to multiplayer validation list
fs2netd_add_table_validation(filename);
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
// add tbl/tbm to multiplayer validation list
fs2netd_add_table_validation(filename);
}
void armor_init()
@@ -17721,6 +17872,8 @@ int ship_get_subobj_model_num(ship_info* sip, char* subobj_name)
void init_path_metadata(path_metadata& metadata)
{
vm_vec_zero(&metadata.departure_rvec);
metadata.arrive_speed_mult = FLT_MIN;
metadata.depart_speed_mult = FLT_MIN;
}
int ship_get_sound(object *objp, GameSoundsIndex id)
+20 -4
View File
@@ -424,7 +424,7 @@ typedef struct ship_flag_name {
int flag_list; // is this flag in the 1st or 2nd ship flags list?
} ship_flag_name;
#define MAX_SHIP_FLAG_NAMES 17
#define MAX_SHIP_FLAG_NAMES 18
extern ship_flag_name Ship_flag_names[];
// states for the flags variable within the ship structure
@@ -505,6 +505,7 @@ extern ship_flag_name Ship_flag_names[];
#define SF2_WEAPONS_LOCKED (1<<25) // Karajorma - Prevents the player from changing the weapons on the ship on the loadout screen
#define SF2_SHIP_SELECTIVE_LINKING (1<<26) // RSAXVC - Allow pilot to pick firing configuration
#define SF2_SCRAMBLE_MESSAGES (1<<27) // Goober5000 - all messages sent from this ship appear scrambled
#define SF2_NO_SECONDARY_LOCKON (1<<28) // zookeeper - secondary lock-on disabled
// If any of these bits in the ship->flags are set, ignore this ship when targeting
extern int TARGET_SHIP_IGNORE_FLAGS;
@@ -592,6 +593,8 @@ public:
float ship_max_shield_strength;
float ship_max_hull_strength;
float max_shield_recharge;
int ship_guardian_threshold; // Goober5000 - now also determines whether ship is guardian'd
@@ -928,6 +931,7 @@ extern int ship_find_exited_ship_by_signature( int signature);
#define SIF2_AUTO_SPREAD_SHIELDS (1 << 16) // zookeeper - auto spread shields
#define SIF2_DRAW_WEAPON_MODELS (1 << 17) // the ship draws weapon models of any sort (used to be a boolean)
#define SIF2_MODEL_POINT_SHIELDS (1 << 18) // zookeeper - uses model-defined shield points instead of quadrants
#define SIF2_LOCK_DETAIL_BOXES (1 << 19) // zookeeper - don't scale detail boxes or spheres based on detail settings
#define SIF_DEFAULT_VALUE 0
#define SIF2_DEFAULT_VALUE 0
@@ -1144,6 +1148,8 @@ typedef struct ship_collision_physics {
typedef struct path_metadata {
vec3d departure_rvec;
float arrive_speed_mult;
float depart_speed_mult;
} path_metadata;
// The real FreeSpace ship_info struct.
@@ -1175,6 +1181,7 @@ public:
char pof_file_hud[MAX_FILENAME_LEN]; // POF file to load for the HUD target box
int num_detail_levels; // number of detail levels for this ship
int detail_distance[MAX_SHIP_DETAIL_LEVELS]; // distance to change detail levels at
int collision_lod; // check for collisions using a LOD
int cockpit_model_num; // cockpit model
int model_num; // ship model
int model_num_hud; // model to use when rendering to the HUD (eg, mini supercap)
@@ -1295,12 +1302,15 @@ public:
float max_hull_strength; // Max hull strength of this class of ship.
float max_shield_strength;
float auto_shield_spread;
bool auto_shield_spread_bypass;
int auto_shield_spread_from_lod;
float auto_shield_spread; // Thickness of the shield
bool auto_shield_spread_bypass; // Whether weapons fired up close can bypass shields
int auto_shield_spread_from_lod; // Which LOD to project the shield from
float auto_shield_spread_min_span; // Minimum distance weapons must travel until allowed to collide with the shield
int shield_point_augment_ctrls[4]; // Re-mapping of shield augmentation controls for model point shields
float max_shield_recharge;
float hull_repair_rate; //How much of the hull is repaired every second
float subsys_repair_rate; //How fast
@@ -1320,6 +1330,7 @@ public:
ubyte shield_icon_index; // index to locate ship-specific animation frames for the shield on HUD
char icon_filename[MAX_FILENAME_LEN]; // filename for icon that is displayed in ship selection
angles model_icon_angles; // angle from which the model icon should be rendered (if not 0,0,0)
char anim_filename[MAX_FILENAME_LEN]; // filename for animation that plays in ship selection
char overhead_filename[MAX_FILENAME_LEN]; // filename for animation that plays weapons loadout
int selection_effect;
@@ -1372,6 +1383,7 @@ public:
float thruster02_glow_len_factor;
float thruster_dist_rad_factor;
float thruster_dist_len_factor;
float thruster_glow_noise_mult;
bool draw_distortion;
@@ -1398,6 +1410,7 @@ public:
vec3d topdown_offset;
int engine_snd; // handle to engine sound for ship (-1 if no engine sound)
float min_engine_vol; // minimum volume modifier for engine sound when ship is stationary
int glide_start_snd; // handle to sound to play at the beginning of a glide maneuver (default is 0 for regular throttle down sound)
int glide_end_snd; // handle to sound to play at the end of a glide maneuver (default is 0 for regular throttle up sound)
@@ -1417,10 +1430,12 @@ public:
float minimum_convergence_distance;
float convergence_distance;
vec3d convergence_offset;
int autoaim_lock_snd, autoaim_lost_snd;
float emp_resistance_mod;
float piercing_damage_draw_limit;
int shield_impact_explosion_anim;
int damage_lightning_type;
@@ -1591,6 +1606,7 @@ extern void ship_cleanup(int shipnum, int cleanup_mode);
extern void ship_destroy_instantly(object *ship_obj, int shipnum);
extern void ship_actually_depart(int shipnum, int method = SHIP_DEPARTED_WARP);
extern bool in_autoaim_fov(ship *shipp, int bank_to_fire, object *obj);
extern int ship_fire_primary_debug(object *objp); // Fire the debug laser.
extern int ship_stop_fire_primary(object * obj);
extern int ship_fire_primary(object * objp, int stream_weapons, int force = 0);
+6 -4
View File
@@ -50,10 +50,12 @@ typedef struct sound {
SCP_vector<sound> Sounds;
int Sound_enabled = FALSE; // global flag to turn sound on/off
int Snd_sram; // mem (in bytes) used up by storing sounds in system memory
float Master_sound_volume = 1.0f; // range is 0 -> 1, used for non-music sound fx
float Master_voice_volume = 0.7f; // range is 0 -> 1, used for all voice playback
int Sound_enabled = FALSE; // global flag to turn sound on/off
int Snd_sram; // mem (in bytes) used up by storing sounds in system memory
float Default_sound_volume = 1.0f; // range is 0 -> 1, used for non-music sound fx
float Default_voice_volume = 0.7f; // range is 0 -> 1, used for all voice playback
float Master_sound_volume = Default_sound_volume;
float Master_voice_volume = Default_voice_volume;
unsigned int SND_ENV_DEFAULT = 0;
+2
View File
@@ -62,6 +62,8 @@ typedef struct sound_env
} sound_env;
extern int Sound_enabled;
extern float Default_sound_volume; // 0 -> 1.0
extern float Default_voice_volume; // 0 -> 1.0
extern float Master_sound_volume; // 0 -> 1.0
extern float Master_voice_volume; // 0 -> 1.0
extern int Snd_sram; // System memory consumed by sound data
+194 -192
View File
@@ -153,203 +153,205 @@ void parse_thrust_glows(species_info *species, bool no_create)
void parse_species_tbl(const char *filename)
{
int i, rval;
int i;
char species_name[NAME_LENGTH];
if ((rval = setjmp(parse_abort)) != 0)
try
{
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", (filename) ? filename : NOX("<default species_defs.tbl>"), rval));
if (filename == NULL)
read_file_text_from_array(defaults_get_file("species_defs.tbl"));
else
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// start parsing
required_string("#SPECIES DEFS");
// no longer required: counted automatically
if (optional_string("$NumSpecies:"))
{
int temp;
stuff_int(&temp);
}
// begin reading data
while (required_string_either("#END", "$Species_Name:"))
{
bool no_create = false;
species_info *species, new_species;
species = &new_species;
// Start Species - Get its name
required_string("$Species_Name:");
stuff_string(species_name, F_NAME, NAME_LENGTH);
if (optional_string("+nocreate"))
{
no_create = true;
for (i = 0; i < (int)Species_info.size(); i++)
{
if (!stricmp(Species_info[i].species_name, species_name))
{
species = &Species_info[i];
break;
}
}
}
else
{
strcpy_s(species->species_name, species_name);
}
// Goober5000 - IFF
if (optional_string("$Default IFF:"))
{
bool iff_found = false;
char temp_name[NAME_LENGTH];
stuff_string(temp_name, F_NAME, NAME_LENGTH);
// search for it in iffs
for (int iLoop = 0; iLoop < Num_iffs; iLoop++)
{
if (!stricmp(Iff_info[iLoop].iff_name, temp_name))
{
species->default_iff = iLoop;
iff_found = true;
}
}
if (!iff_found)
{
species->default_iff = 0;
Warning(LOCATION, "Species %s default IFF %s not found in iff_defs.tbl! Defaulting to %s.\n", species->species_name, temp_name, Iff_info[species->default_iff].iff_name);
}
}
else if (!no_create)
{
// we have no idea which it could be, so default to 0
species->default_iff = 0;
// let them know
Warning(LOCATION, "$Default IFF not specified for species %s in species_defs.tbl! Defaulting to %s.\n", species->species_name, Iff_info[species->default_iff].iff_name);
}
// Goober5000 - FRED color
if (optional_string("$FRED Color:") || optional_string("$FRED Colour:"))
{
stuff_int_list(species->fred_color.a1d, 3, RAW_INTEGER_TYPE);
}
else if (!no_create)
{
// set defaults to Volition's originals
if (!stricmp(species->species_name, "Terran"))
{
species->fred_color.rgb.r = 0;
species->fred_color.rgb.g = 0;
species->fred_color.rgb.b = 192;
}
else if (!stricmp(species->species_name, "Vasudan"))
{
species->fred_color.rgb.r = 0;
species->fred_color.rgb.g = 128;
species->fred_color.rgb.b = 0;
}
else if (!stricmp(species->species_name, "Shivan"))
{
species->fred_color.rgb.r = 192;
species->fred_color.rgb.g = 0;
species->fred_color.rgb.b = 0;
}
else if (!stricmp(species->species_name, "Ancients") || !stricmp(species->species_name, "Ancient"))
{
species->fred_color.rgb.r = 192;
species->fred_color.rgb.g = 0;
species->fred_color.rgb.b = 192;
}
else
{
species->fred_color.rgb.r = 0;
species->fred_color.rgb.g = 0;
species->fred_color.rgb.b = 0;
}
// let them know
Warning(LOCATION, "$FRED Color not specified for species %s in species_defs.tbl! Defaulting to (%d, %d, %d).\n", species->species_name, species->fred_color.rgb.r, species->fred_color.rgb.g, species->fred_color.rgb.b);
}
// stuff
optional_string("$MiscAnims:");
// Get its Debris Texture
if ((!no_create && required_string("+Debris_Texture:")) || optional_string("+Debris_Texture:"))
{
generic_bitmap_init(&species->debris_texture, NULL);
stuff_string(species->debris_texture.filename, F_NAME, MAX_FILENAME_LEN);
}
// Shield Hit Animation
if (optional_string("+Shield_Hit_ani:")) // Shouldn't be required -- LPine
{
generic_anim_init(&species->shield_anim, NULL);
stuff_string(species->shield_anim.filename, F_NAME, MAX_FILENAME_LEN);
}
else if (!no_create)
{
species->shield_anim.filename[0] = '\0';
species->shield_anim.first_frame = -1; // Landmine to trip up anyone who does end up using this
}
// Thruster Anims
parse_thrust_anims(species, no_create);
// Thruster Glow Anims
parse_thrust_glows(species, no_create);
// Goober5000 - AWACS multiplier
if (optional_string("$AwacsMultiplier:"))
{
stuff_float(&species->awacs_multiplier);
}
else if (!no_create)
{
// set defaults to Volition's originals
if (!stricmp(species->species_name, "Vasudan"))
species->awacs_multiplier = 1.25f;
else if (!stricmp(species->species_name, "Shivan"))
species->awacs_multiplier = 1.50f;
else
species->awacs_multiplier = 1.0f;
// let them know
Warning(LOCATION, "$AwacsMultiplier not specified for species %s in species_defs.tbl! Defaulting to %.2d.\n", species->species_name, species->awacs_multiplier);
}
// Goober5000 - countermeasure type
// (we won't be able to resolve it until after we've parsed the weapons table)
if (optional_string("$Countermeasure type:"))
stuff_string(species->cmeasure_name, F_NAME, NAME_LENGTH);
// don't add new entry if this is just a modified one
if (!no_create)
Species_info.push_back(new_species);
}
required_string("#END");
// add tbl/tbm to multiplayer validation list
extern void fs2netd_add_table_validation(const char *tblname);
fs2netd_add_table_validation(filename);
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", (filename) ? filename : NOX("<default species_defs.tbl>"), e.what()));
return;
}
if (filename == NULL)
read_file_text_from_array(defaults_get_file("species_defs.tbl"));
else
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// start parsing
required_string("#SPECIES DEFS");
// no longer required: counted automatically
if (optional_string("$NumSpecies:"))
{
int temp;
stuff_int(&temp);
}
// begin reading data
while (required_string_either("#END","$Species_Name:"))
{
bool no_create = false;
species_info *species, new_species;
species = &new_species;
// Start Species - Get its name
required_string("$Species_Name:");
stuff_string(species_name, F_NAME, NAME_LENGTH);
if (optional_string("+nocreate"))
{
no_create = true;
for (i = 0; i < (int)Species_info.size(); i++)
{
if (!stricmp(Species_info[i].species_name, species_name))
{
species = &Species_info[i];
break;
}
}
}
else
{
strcpy_s(species->species_name, species_name);
}
// Goober5000 - IFF
if (optional_string("$Default IFF:"))
{
bool iff_found = false;
char temp_name[NAME_LENGTH];
stuff_string(temp_name, F_NAME, NAME_LENGTH);
// search for it in iffs
for (int iLoop = 0; iLoop < Num_iffs; iLoop++)
{
if (!stricmp(Iff_info[iLoop].iff_name, temp_name))
{
species->default_iff = iLoop;
iff_found = true;
}
}
if (!iff_found)
{
species->default_iff = 0;
Warning(LOCATION, "Species %s default IFF %s not found in iff_defs.tbl! Defaulting to %s.\n", species->species_name, temp_name, Iff_info[species->default_iff].iff_name);
}
}
else if (!no_create)
{
// we have no idea which it could be, so default to 0
species->default_iff = 0;
// let them know
Warning(LOCATION, "$Default IFF not specified for species %s in species_defs.tbl! Defaulting to %s.\n", species->species_name, Iff_info[species->default_iff].iff_name);
}
// Goober5000 - FRED color
if (optional_string("$FRED Color:") || optional_string("$FRED Colour:"))
{
stuff_int_list(species->fred_color.a1d, 3, RAW_INTEGER_TYPE);
}
else if (!no_create)
{
// set defaults to Volition's originals
if (!stricmp(species->species_name, "Terran"))
{
species->fred_color.rgb.r = 0;
species->fred_color.rgb.g = 0;
species->fred_color.rgb.b = 192;
}
else if (!stricmp(species->species_name, "Vasudan"))
{
species->fred_color.rgb.r = 0;
species->fred_color.rgb.g = 128;
species->fred_color.rgb.b = 0;
}
else if (!stricmp(species->species_name, "Shivan"))
{
species->fred_color.rgb.r = 192;
species->fred_color.rgb.g = 0;
species->fred_color.rgb.b = 0;
}
else if (!stricmp(species->species_name, "Ancients") || !stricmp(species->species_name, "Ancient"))
{
species->fred_color.rgb.r = 192;
species->fred_color.rgb.g = 0;
species->fred_color.rgb.b = 192;
}
else
{
species->fred_color.rgb.r = 0;
species->fred_color.rgb.g = 0;
species->fred_color.rgb.b = 0;
}
// let them know
Warning(LOCATION, "$FRED Color not specified for species %s in species_defs.tbl! Defaulting to (%d, %d, %d).\n", species->species_name, species->fred_color.rgb.r, species->fred_color.rgb.g, species->fred_color.rgb.b);
}
// stuff
optional_string("$MiscAnims:");
// Get its Debris Texture
if ((!no_create && required_string("+Debris_Texture:")) || optional_string("+Debris_Texture:"))
{
generic_bitmap_init(&species->debris_texture, NULL);
stuff_string(species->debris_texture.filename, F_NAME, MAX_FILENAME_LEN);
}
// Shield Hit Animation
if (optional_string("+Shield_Hit_ani:")) // Shouldn't be required -- LPine
{
generic_anim_init(&species->shield_anim, NULL);
stuff_string(species->shield_anim.filename, F_NAME, MAX_FILENAME_LEN);
}
else if (!no_create)
{
species->shield_anim.filename[0] = '\0';
species->shield_anim.first_frame = -1; // Landmine to trip up anyone who does end up using this
}
// Thruster Anims
parse_thrust_anims(species, no_create);
// Thruster Glow Anims
parse_thrust_glows(species, no_create);
// Goober5000 - AWACS multiplier
if (optional_string("$AwacsMultiplier:"))
{
stuff_float(&species->awacs_multiplier);
}
else if (!no_create)
{
// set defaults to Volition's originals
if (!stricmp(species->species_name, "Vasudan"))
species->awacs_multiplier = 1.25f;
else if (!stricmp(species->species_name, "Shivan"))
species->awacs_multiplier = 1.50f;
else
species->awacs_multiplier = 1.0f;
// let them know
Warning(LOCATION, "$AwacsMultiplier not specified for species %s in species_defs.tbl! Defaulting to %.2d.\n", species->species_name, species->awacs_multiplier);
}
// Goober5000 - countermeasure type
// (we won't be able to resolve it until after we've parsed the weapons table)
if (optional_string("$Countermeasure type:"))
stuff_string(species->cmeasure_name, F_NAME, NAME_LENGTH);
// don't add new entry if this is just a modified one
if ( !no_create )
Species_info.push_back( new_species );
}
required_string("#END");
// add tbl/tbm to multiplayer validation list
extern void fs2netd_add_table_validation(const char *tblname);
fs2netd_add_table_validation(filename);
}
int Species_initted = 0;
+181 -172
View File
@@ -404,183 +404,192 @@ void parse_startbl(const char *filename)
{
char name[MAX_FILENAME_LEN], tempf[16];
starfield_bitmap sbm;
int idx, rval;
int idx;
bool in_check = false;
int rc = -1;
int run_count = 0;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
return;
try
{
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// freaky! ;)
while (!check_for_eof()) {
while ((rc = optional_string_either("$Bitmap:", "$BitmapX:")) != -1) {
in_check = true;
starfield_bitmap_entry_init(&sbm);
stuff_string(sbm.filename, F_NAME, MAX_FILENAME_LEN);
sbm.xparent = rc; // 0 == intensity alpha bitmap, 1 == green xparency bitmap
if ((idx = stars_find_bitmap(sbm.filename)) >= 0) {
if (sbm.xparent == Starfield_bitmaps[idx].xparent) {
if (!Parsing_modular_table)
Warning(LOCATION, "Starfield bitmap '%s' listed more than once!! Only using the first entry!", sbm.filename);
}
else {
Warning(LOCATION, "Starfield bitmap '%s' already listed as a %sxparent bitmap!! Only using the xparent version!",
(rc) ? "xparent" : "non-xparent", (rc) ? "xparent" : "non-xparent", sbm.filename);
}
}
else {
Starfield_bitmaps.push_back(sbm);
}
}
CHECK_END();
while (optional_string("$Sun:")) {
in_check = true;
starfield_bitmap_entry_init(&sbm);
stuff_string(sbm.filename, F_NAME, MAX_FILENAME_LEN);
// associated glow
required_string("$Sunglow:");
stuff_string(sbm.glow_filename, F_NAME, MAX_FILENAME_LEN);
// associated lighting values
required_string("$SunRGBI:");
stuff_float(&sbm.r);
stuff_float(&sbm.g);
stuff_float(&sbm.b);
stuff_float(&sbm.i);
if (optional_string("$SunSpecularRGB:")) {
stuff_float(&sbm.spec_r);
stuff_float(&sbm.spec_g);
stuff_float(&sbm.spec_b);
}
else {
sbm.spec_r = sbm.r;
sbm.spec_g = sbm.g;
sbm.spec_b = sbm.b;
}
// lens flare stuff
if (optional_string("$Flare:")) {
sbm.flare = 1;
required_string("+FlareCount:");
stuff_int(&sbm.n_flares);
// if there's a flare, it has to have at least one texture
required_string("$FlareTexture1:");
stuff_string(sbm.flare_bitmaps[0].filename, F_NAME, MAX_FILENAME_LEN);
sbm.n_flare_bitmaps = 1;
for (idx = 1; idx < MAX_FLARE_BMP; idx++) {
// allow 9999 textures (theoretically speaking, that is)
sprintf(tempf, "$FlareTexture%d:", idx + 1);
if (optional_string(tempf)) {
sbm.n_flare_bitmaps++;
stuff_string(sbm.flare_bitmaps[idx].filename, F_NAME, MAX_FILENAME_LEN);
}
// else break; //don't allow flaretexture1 and then 3, etc.
}
required_string("$FlareGlow1:");
required_string("+FlareTexture:");
stuff_int(&sbm.flare_infos[0].tex_num);
required_string("+FlarePos:");
stuff_float(&sbm.flare_infos[0].pos);
required_string("+FlareScale:");
stuff_float(&sbm.flare_infos[0].scale);
sbm.n_flares = 1;
for (idx = 1; idx < MAX_FLARE_COUNT; idx++) {
// allow a lot of glows
sprintf(tempf, "$FlareGlow%d:", idx + 1);
if (optional_string(tempf)) {
sbm.n_flares++;
required_string("+FlareTexture:");
stuff_int(&sbm.flare_infos[idx].tex_num);
required_string("+FlarePos:");
stuff_float(&sbm.flare_infos[idx].pos);
required_string("+FlareScale:");
stuff_float(&sbm.flare_infos[idx].scale);
}
// else break; //don't allow "flare 1" and then "flare 3"
}
}
sbm.glare = !optional_string("$NoGlare:");
sbm.xparent = 1;
if ((idx = stars_find_sun(sbm.filename)) >= 0) {
if (Parsing_modular_table)
Sun_bitmaps[idx] = sbm;
else
Warning(LOCATION, "Sun bitmap '%s' listed more than once!! Only using the first entry!", sbm.filename);
}
else {
Sun_bitmaps.push_back(sbm);
}
}
CHECK_END();
// normal debris pieces
while (optional_string("$Debris:")) {
in_check = true;
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
if (Num_debris_normal < MAX_DEBRIS_VCLIPS) {
strcpy_s(Debris_vclips_normal[Num_debris_normal++].name, name);
}
else {
Warning(LOCATION, "Could not load normal motion debris '%s'; maximum of %d exceeded.", name, MAX_DEBRIS_VCLIPS);
}
}
CHECK_END();
// nebula debris pieces
while (optional_string("$DebrisNeb:")) {
in_check = true;
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
if (Num_debris_nebula < MAX_DEBRIS_VCLIPS) {
strcpy_s(Debris_vclips_nebula[Num_debris_nebula++].name, name);
}
else {
Warning(LOCATION, "Could not load nebula motion debris '%s'; maximum of %d exceeded.", name, MAX_DEBRIS_VCLIPS);
}
}
CHECK_END();
// since it's possible for some idiot to have a tbl screwed up enough
// that this ends up in an endless loop, give an opportunity to advance
// through the file no matter what, because even the retail tbl has an
// extra "#end" line in it.
if (optional_string("#end") || (run_count++ > 5)) {
run_count = 0;
advance_to_eoln(NULL);
}
}
}
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// freaky! ;)
while ( !check_for_eof() ) {
while ( (rc = optional_string_either("$Bitmap:", "$BitmapX:")) != -1 ) {
in_check = true;
starfield_bitmap_entry_init( &sbm );
stuff_string(sbm.filename, F_NAME, MAX_FILENAME_LEN);
sbm.xparent = rc; // 0 == intensity alpha bitmap, 1 == green xparency bitmap
if ( (idx = stars_find_bitmap(sbm.filename)) >= 0 ) {
if (sbm.xparent == Starfield_bitmaps[idx].xparent) {
if ( !Parsing_modular_table )
Warning(LOCATION, "Starfield bitmap '%s' listed more than once!! Only using the first entry!", sbm.filename);
} else {
Warning(LOCATION, "Starfield bitmap '%s' already listed as a %sxparent bitmap!! Only using the xparent version!",
(rc) ? "xparent" : "non-xparent", (rc) ? "xparent" : "non-xparent", sbm.filename);
}
} else {
Starfield_bitmaps.push_back(sbm);
}
}
CHECK_END();
while ( optional_string("$Sun:") ) {
in_check = true;
starfield_bitmap_entry_init( &sbm );
stuff_string(sbm.filename, F_NAME, MAX_FILENAME_LEN);
// associated glow
required_string("$Sunglow:");
stuff_string(sbm.glow_filename, F_NAME, MAX_FILENAME_LEN);
// associated lighting values
required_string("$SunRGBI:");
stuff_float(&sbm.r);
stuff_float(&sbm.g);
stuff_float(&sbm.b);
stuff_float(&sbm.i);
if ( optional_string("$SunSpecularRGB:") ) {
stuff_float(&sbm.spec_r);
stuff_float(&sbm.spec_g);
stuff_float(&sbm.spec_b);
} else {
sbm.spec_r = sbm.r;
sbm.spec_g = sbm.g;
sbm.spec_b = sbm.b;
}
// lens flare stuff
if ( optional_string("$Flare:") ) {
sbm.flare = 1;
required_string("+FlareCount:");
stuff_int(&sbm.n_flares);
// if there's a flare, it has to have at least one texture
required_string("$FlareTexture1:");
stuff_string(sbm.flare_bitmaps[0].filename, F_NAME, MAX_FILENAME_LEN);
sbm.n_flare_bitmaps = 1;
for (idx = 1; idx < MAX_FLARE_BMP; idx++) {
// allow 9999 textures (theoretically speaking, that is)
sprintf(tempf, "$FlareTexture%d:", idx+1);
if (optional_string(tempf)) {
sbm.n_flare_bitmaps++;
stuff_string(sbm.flare_bitmaps[idx].filename, F_NAME, MAX_FILENAME_LEN);
}
// else break; //don't allow flaretexture1 and then 3, etc.
}
required_string("$FlareGlow1:");
required_string("+FlareTexture:");
stuff_int(&sbm.flare_infos[0].tex_num);
required_string("+FlarePos:");
stuff_float(&sbm.flare_infos[0].pos);
required_string("+FlareScale:");
stuff_float(&sbm.flare_infos[0].scale);
sbm.n_flares = 1;
for (idx = 1; idx < MAX_FLARE_COUNT; idx++) {
// allow a lot of glows
sprintf(tempf, "$FlareGlow%d:", idx+1);
if (optional_string(tempf)) {
sbm.n_flares++;
required_string("+FlareTexture:");
stuff_int(&sbm.flare_infos[idx].tex_num);
required_string("+FlarePos:");
stuff_float(&sbm.flare_infos[idx].pos);
required_string("+FlareScale:");
stuff_float(&sbm.flare_infos[idx].scale);
}
// else break; //don't allow "flare 1" and then "flare 3"
}
}
sbm.glare = !optional_string("$NoGlare:");
sbm.xparent = 1;
if ( (idx = stars_find_sun(sbm.filename)) >= 0 ) {
if (Parsing_modular_table)
Sun_bitmaps[idx] = sbm;
else
Warning(LOCATION, "Sun bitmap '%s' listed more than once!! Only using the first entry!", sbm.filename);
} else {
Sun_bitmaps.push_back(sbm);
}
}
CHECK_END();
// normal debris pieces
while ( optional_string("$Debris:") ) {
in_check = true;
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
if (Num_debris_normal < MAX_DEBRIS_VCLIPS) {
strcpy_s(Debris_vclips_normal[Num_debris_normal++].name, name);
} else {
Warning(LOCATION, "Could not load normal motion debris '%s'; maximum of %d exceeded.", name, MAX_DEBRIS_VCLIPS);
}
}
CHECK_END();
// nebula debris pieces
while ( optional_string("$DebrisNeb:") ) {
in_check = true;
stuff_string(name, F_NAME, MAX_FILENAME_LEN);
if (Num_debris_nebula < MAX_DEBRIS_VCLIPS) {
strcpy_s(Debris_vclips_nebula[Num_debris_nebula++].name, name);
} else {
Warning(LOCATION, "Could not load nebula motion debris '%s'; maximum of %d exceeded.", name, MAX_DEBRIS_VCLIPS);
}
}
CHECK_END();
// since it's possible for some idiot to have a tbl screwed up enough
// that this ends up in an endless loop, give an opportunity to advance
// through the file no matter what, because even the retail tbl has an
// extra "#end" line in it.
if ( optional_string("#end") || (run_count++ > 5) ) {
run_count = 0;
advance_to_eoln(NULL);
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
}
+175 -160
View File
@@ -245,190 +245,205 @@ const medal_stuff &medal_stuff::operator=(const medal_stuff &m)
void parse_medal_tbl()
{
int rval, i;
int i;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "medals.tbl", rval));
return;
}
read_file_text("medals.tbl", CF_TYPE_TABLES);
reset_parse();
required_string("#Medals");
// special background information
if (optional_string("+Background Bitmap:")) {
stuff_string(Medals_background_filename, F_NAME, NAME_LENGTH);
} else {
strcpy_s(Medals_background_filename, Default_medals_background_filename);
}
// special mask information
if (optional_string("+Mask Bitmap:")) {
stuff_string(Medals_mask_filename, F_NAME, NAME_LENGTH);
} else {
strcpy_s(Medals_mask_filename, Default_medals_mask_filename);
}
// special positioning for player callsign
if (optional_string("+Callsign Position 640:")) {
stuff_int(&Medals_callsign_coords[GR_640].x);
stuff_int(&Medals_callsign_coords[GR_640].y);
} else {
Medals_callsign_coords[GR_640].x = Default_medals_callsign_coords[GR_640][0];
Medals_callsign_coords[GR_640].y = Default_medals_callsign_coords[GR_640][1];
}
if (optional_string("+Callsign Position 1024:")) {
stuff_int(&Medals_callsign_coords[GR_1024].x);
stuff_int(&Medals_callsign_coords[GR_1024].y);
} else {
Medals_callsign_coords[GR_1024].x = Default_medals_callsign_coords[GR_1024][0];
Medals_callsign_coords[GR_1024].y = Default_medals_callsign_coords[GR_1024][1];
}
// special positioning for medal label
if (optional_string("+Label Position 640:")) {
stuff_int(&Medals_label_coords[GR_640].x);
stuff_int(&Medals_label_coords[GR_640].y);
stuff_int(&Medals_label_coords[GR_640].w);
} else {
Medals_label_coords[GR_640].x = Default_medals_label_coords[GR_640][0];
Medals_label_coords[GR_640].y = Default_medals_label_coords[GR_640][1];
Medals_label_coords[GR_640].w = Default_medals_label_coords[GR_640][2];
}
if (optional_string("+Label Position 1024:")) {
stuff_int(&Medals_label_coords[GR_1024].x);
stuff_int(&Medals_label_coords[GR_1024].y);
stuff_int(&Medals_label_coords[GR_1024].w);
} else {
Medals_label_coords[GR_1024].x = Default_medals_label_coords[GR_1024][0];
Medals_label_coords[GR_1024].y = Default_medals_label_coords[GR_1024][1];
Medals_label_coords[GR_1024].w = Default_medals_label_coords[GR_1024][2];
}
// parse in all the medal names
Num_medals = 0;
while ( required_string_either("#End", "$Name:") )
try
{
medal_stuff temp_medal;
medal_display_info temp_display;
read_file_text("medals.tbl", CF_TYPE_TABLES);
reset_parse();
required_string("$Name:");
stuff_string( temp_medal.name, F_NAME, NAME_LENGTH );
required_string("#Medals");
// is this rank? if so, save it
if (!stricmp(temp_medal.name, "Rank"))
Rank_medal_index = Num_medals;
required_string("$Bitmap:");
stuff_string( temp_medal.bitmap, F_NAME, MAX_FILENAME_LEN );
if (optional_string("+Position 640:")) {
stuff_int(&temp_display.coords[GR_640].x);
stuff_int(&temp_display.coords[GR_640].y);
} else if (Num_medals < NUM_MEDALS_FS2) {
temp_display.coords[GR_640].x = Default_medal_coords[GR_640][Num_medals][0];
temp_display.coords[GR_640].y = Default_medal_coords[GR_640][Num_medals][1];
} else {
Warning(LOCATION, "No default GR_640 position for medal '%s'!", temp_medal.name);
temp_display.coords[GR_640].x = 0;
temp_display.coords[GR_640].y = 0;
// special background information
if (optional_string("+Background Bitmap:")) {
stuff_string(Medals_background_filename, F_NAME, NAME_LENGTH);
}
if (optional_string("+Position 1024:")) {
stuff_int(&temp_display.coords[GR_1024].x);
stuff_int(&temp_display.coords[GR_1024].y);
} else if (Num_medals < NUM_MEDALS_FS2) {
temp_display.coords[GR_1024].x = Default_medal_coords[GR_1024][Num_medals][0];
temp_display.coords[GR_1024].y = Default_medal_coords[GR_1024][Num_medals][1];
} else {
Warning(LOCATION, "No default GR_1024 position for medal '%s'!", temp_medal.name);
temp_display.coords[GR_1024].x = 0;
temp_display.coords[GR_1024].y = 0;
else {
strcpy_s(Medals_background_filename, Default_medals_background_filename);
}
if (optional_string("+Debriefing Bitmap:")) {
stuff_string( temp_medal.debrief_bitmap, F_NAME, MAX_FILENAME_LEN );
} else if (Num_medals < NUM_MEDALS_FS2) {
strcpy_s(temp_medal.debrief_bitmap, Default_debriefing_bitmaps[Num_medals]);
} else {
Warning(LOCATION, "No default debriefing bitmap for medal '%s'!", temp_medal.name);
strcpy_s(temp_medal.debrief_bitmap, "");
// special mask information
if (optional_string("+Mask Bitmap:")) {
stuff_string(Medals_mask_filename, F_NAME, NAME_LENGTH);
}
else {
strcpy_s(Medals_mask_filename, Default_medals_mask_filename);
}
required_string("$Num mods:");
stuff_int( &temp_medal.num_versions );
// this is dumb
temp_medal.version_starts_at_1 = (Num_medals == Rank_medal_index);
if (optional_string("+Version starts at 1:")) {
stuff_boolean( &temp_medal.version_starts_at_1 );
// special positioning for player callsign
if (optional_string("+Callsign Position 640:")) {
stuff_int(&Medals_callsign_coords[GR_640].x);
stuff_int(&Medals_callsign_coords[GR_640].y);
}
else {
Medals_callsign_coords[GR_640].x = Default_medals_callsign_coords[GR_640][0];
Medals_callsign_coords[GR_640].y = Default_medals_callsign_coords[GR_640][1];
}
if (optional_string("+Callsign Position 1024:")) {
stuff_int(&Medals_callsign_coords[GR_1024].x);
stuff_int(&Medals_callsign_coords[GR_1024].y);
}
else {
Medals_callsign_coords[GR_1024].x = Default_medals_callsign_coords[GR_1024][0];
Medals_callsign_coords[GR_1024].y = Default_medals_callsign_coords[GR_1024][1];
}
if (optional_string("+Available From Start:")) {
stuff_boolean( &temp_medal.available_from_start );
// special positioning for medal label
if (optional_string("+Label Position 640:")) {
stuff_int(&Medals_label_coords[GR_640].x);
stuff_int(&Medals_label_coords[GR_640].y);
stuff_int(&Medals_label_coords[GR_640].w);
}
else {
Medals_label_coords[GR_640].x = Default_medals_label_coords[GR_640][0];
Medals_label_coords[GR_640].y = Default_medals_label_coords[GR_640][1];
Medals_label_coords[GR_640].w = Default_medals_label_coords[GR_640][2];
}
if (optional_string("+Label Position 1024:")) {
stuff_int(&Medals_label_coords[GR_1024].x);
stuff_int(&Medals_label_coords[GR_1024].y);
stuff_int(&Medals_label_coords[GR_1024].w);
}
else {
Medals_label_coords[GR_1024].x = Default_medals_label_coords[GR_1024][0];
Medals_label_coords[GR_1024].y = Default_medals_label_coords[GR_1024][1];
Medals_label_coords[GR_1024].w = Default_medals_label_coords[GR_1024][2];
}
// some medals are based on kill counts. When string +Num Kills: is present, we know that
// this medal is a badge and should be treated specially
if ( optional_string("+Num Kills:") ) {
char buf[MULTITEXT_LENGTH];
int persona;
stuff_int( &temp_medal.kills_needed );
// parse in all the medal names
Num_medals = 0;
while (required_string_either("#End", "$Name:"))
{
medal_stuff temp_medal;
medal_display_info temp_display;
if (optional_string("$Wavefile 1:"))
stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN);
required_string("$Name:");
stuff_string(temp_medal.name, F_NAME, NAME_LENGTH);
if (optional_string("$Wavefile 2:"))
stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN);
// is this rank? if so, save it
if (!stricmp(temp_medal.name, "Rank"))
Rank_medal_index = Num_medals;
if (optional_string("$Wavefile Base:"))
stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN);
required_string("$Bitmap:");
stuff_string(temp_medal.bitmap, F_NAME, MAX_FILENAME_LEN);
while (check_for_string("$Promotion Text:")) {
required_string("$Promotion Text:");
stuff_string(buf, F_MULTITEXT, sizeof(buf));
persona = -1;
if (optional_string("+Persona:")) {
stuff_int(&persona);
if (persona < 0) {
Warning(LOCATION, "Debriefing text for %s is assigned to an invalid persona: %i (must be 0 or greater).\n", temp_medal.name, persona);
continue;
if (optional_string("+Position 640:")) {
stuff_int(&temp_display.coords[GR_640].x);
stuff_int(&temp_display.coords[GR_640].y);
}
else if (Num_medals < NUM_MEDALS_FS2) {
temp_display.coords[GR_640].x = Default_medal_coords[GR_640][Num_medals][0];
temp_display.coords[GR_640].y = Default_medal_coords[GR_640][Num_medals][1];
}
else {
Warning(LOCATION, "No default GR_640 position for medal '%s'!", temp_medal.name);
temp_display.coords[GR_640].x = 0;
temp_display.coords[GR_640].y = 0;
}
if (optional_string("+Position 1024:")) {
stuff_int(&temp_display.coords[GR_1024].x);
stuff_int(&temp_display.coords[GR_1024].y);
}
else if (Num_medals < NUM_MEDALS_FS2) {
temp_display.coords[GR_1024].x = Default_medal_coords[GR_1024][Num_medals][0];
temp_display.coords[GR_1024].y = Default_medal_coords[GR_1024][Num_medals][1];
}
else {
Warning(LOCATION, "No default GR_1024 position for medal '%s'!", temp_medal.name);
temp_display.coords[GR_1024].x = 0;
temp_display.coords[GR_1024].y = 0;
}
if (optional_string("+Debriefing Bitmap:")) {
stuff_string(temp_medal.debrief_bitmap, F_NAME, MAX_FILENAME_LEN);
}
else if (Num_medals < NUM_MEDALS_FS2) {
strcpy_s(temp_medal.debrief_bitmap, Default_debriefing_bitmaps[Num_medals]);
}
else {
Warning(LOCATION, "No default debriefing bitmap for medal '%s'!", temp_medal.name);
strcpy_s(temp_medal.debrief_bitmap, "");
}
required_string("$Num mods:");
stuff_int(&temp_medal.num_versions);
// this is dumb
temp_medal.version_starts_at_1 = (Num_medals == Rank_medal_index);
if (optional_string("+Version starts at 1:")) {
stuff_boolean(&temp_medal.version_starts_at_1);
}
if (optional_string("+Available From Start:")) {
stuff_boolean(&temp_medal.available_from_start);
}
// some medals are based on kill counts. When string +Num Kills: is present, we know that
// this medal is a badge and should be treated specially
if (optional_string("+Num Kills:")) {
char buf[MULTITEXT_LENGTH];
int persona;
stuff_int(&temp_medal.kills_needed);
if (optional_string("$Wavefile 1:"))
stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN);
if (optional_string("$Wavefile 2:"))
stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN);
if (optional_string("$Wavefile Base:"))
stuff_string(temp_medal.voice_base, F_NAME, MAX_FILENAME_LEN);
while (check_for_string("$Promotion Text:")) {
required_string("$Promotion Text:");
stuff_string(buf, F_MULTITEXT, sizeof(buf));
persona = -1;
if (optional_string("+Persona:")) {
stuff_int(&persona);
if (persona < 0) {
Warning(LOCATION, "Debriefing text for %s is assigned to an invalid persona: %i (must be 0 or greater).\n", temp_medal.name, persona);
continue;
}
}
temp_medal.promotion_text[persona] = vm_strdup(buf);
}
if (temp_medal.promotion_text.find(-1) == temp_medal.promotion_text.end()) {
Warning(LOCATION, "%s medal is missing default debriefing text.\n", temp_medal.name);
temp_medal.promotion_text[-1] = "";
}
temp_medal.promotion_text[persona] = vm_strdup(buf);
}
if (temp_medal.promotion_text.find(-1) == temp_medal.promotion_text.end()) {
Warning(LOCATION, "%s medal is missing default debriefing text.\n", temp_medal.name);
temp_medal.promotion_text[-1] = "";
}
Medals.push_back(temp_medal);
Medal_display_info.push_back(temp_display);
Num_medals++;
}
Medals.push_back(temp_medal);
Medal_display_info.push_back(temp_display);
Num_medals++;
required_string("#End");
// be sure that we know where the rank is
if (Rank_medal_index < 0)
{
Warning(LOCATION, "Could not find the 'Rank' medal!");
Rank_medal_index = 0;
}
// be sure that the badges kill numbers show up in order
//WMC - I don't think this is needed anymore due to my changes to post-mission functions
//but I'm keeping it here to be sure.
int prev_badge_kills = 0;
for (i = 0; i < Num_medals; i++)
{
if (Medals[i].kills_needed < prev_badge_kills && Medals[i].kills_needed != 0)
Error(LOCATION, "Badges must appear sorted by lowest kill # first in medals.tbl\nFind Allender for most information.");
if (Medals[i].kills_needed > 0)
prev_badge_kills = Medals[i].kills_needed;
}
}
required_string("#End");
// be sure that we know where the rank is
if (Rank_medal_index < 0)
catch (const parse::ParseException& e)
{
Warning(LOCATION, "Could not find the 'Rank' medal!");
Rank_medal_index = 0;
}
// be sure that the badges kill numbers show up in order
//WMC - I don't think this is needed anymore due to my changes to post-mission functions
//but I'm keeping it here to be sure.
int prev_badge_kills = 0;
for (i = 0; i < Num_medals; i++ )
{
if ( Medals[i].kills_needed < prev_badge_kills && Medals[i].kills_needed != 0)
Error(LOCATION, "Badges must appear sorted by lowest kill # first in medals.tbl\nFind Allender for most information.");
if (Medals[i].kills_needed > 0)
prev_badge_kills = Medals[i].kills_needed;
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "medals.tbl", e.what()));
return;
}
}
+49 -46
View File
@@ -59,61 +59,64 @@ void parse_rank_tbl()
{
atexit(scoreing_close);
char buf[MULTITEXT_LENGTH];
int rval, idx, persona;
int idx, persona;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "rank.tbl", rval));
return;
}
try
{
read_file_text("rank.tbl", CF_TYPE_TABLES);
reset_parse();
read_file_text("rank.tbl", CF_TYPE_TABLES);
reset_parse();
// parse in all the rank names
idx = 0;
skip_to_string("[RANK NAMES]");
ignore_white_space();
while ( required_string_either("#End", "$Name:") ) {
Assert ( idx < NUM_RANKS );
required_string("$Name:");
stuff_string( Ranks[idx].name, F_NAME, NAME_LENGTH );
required_string("$Points:");
stuff_int( &Ranks[idx].points );
required_string("$Bitmap:");
stuff_string( Ranks[idx].bitmap, F_NAME, MAX_FILENAME_LEN );
required_string("$Promotion Voice Base:");
stuff_string( Ranks[idx].promotion_voice_base, F_NAME, MAX_FILENAME_LEN );
while (check_for_string("$Promotion Text:")) {
required_string("$Promotion Text:");
stuff_string(buf, F_MULTITEXT, sizeof(buf));
drop_white_space(buf);
compact_multitext_string(buf);
persona = -1;
if (optional_string("+Persona:")) {
stuff_int(&persona);
if (persona < 0) {
Warning(LOCATION, "Debriefing text for %s rank is assigned to an invalid persona: %i (must be 0 or greater).\n", Ranks[idx].name, persona);
continue;
// parse in all the rank names
idx = 0;
skip_to_string("[RANK NAMES]");
ignore_white_space();
while (required_string_either("#End", "$Name:")) {
Assert(idx < NUM_RANKS);
required_string("$Name:");
stuff_string(Ranks[idx].name, F_NAME, NAME_LENGTH);
required_string("$Points:");
stuff_int(&Ranks[idx].points);
required_string("$Bitmap:");
stuff_string(Ranks[idx].bitmap, F_NAME, MAX_FILENAME_LEN);
required_string("$Promotion Voice Base:");
stuff_string(Ranks[idx].promotion_voice_base, F_NAME, MAX_FILENAME_LEN);
while (check_for_string("$Promotion Text:")) {
required_string("$Promotion Text:");
stuff_string(buf, F_MULTITEXT, sizeof(buf));
drop_white_space(buf);
compact_multitext_string(buf);
persona = -1;
if (optional_string("+Persona:")) {
stuff_int(&persona);
if (persona < 0) {
Warning(LOCATION, "Debriefing text for %s rank is assigned to an invalid persona: %i (must be 0 or greater).\n", Ranks[idx].name, persona);
continue;
}
}
Ranks[idx].promotion_text[persona] = vm_strdup(buf);
}
Ranks[idx].promotion_text[persona] = vm_strdup(buf);
if (Ranks[idx].promotion_text.find(-1) == Ranks[idx].promotion_text.end()) {
Warning(LOCATION, "%s rank is missing default debriefing text.\n", Ranks[idx].name);
Ranks[idx].promotion_text[-1] = "";
}
idx++;
}
if (Ranks[idx].promotion_text.find(-1) == Ranks[idx].promotion_text.end()) {
Warning(LOCATION, "%s rank is missing default debriefing text.\n", Ranks[idx].name);
Ranks[idx].promotion_text[-1] = "";
}
idx++;
}
required_string("#End");
required_string("#End");
// be sure that all rank points are in order
// be sure that all rank points are in order
#ifndef NDEBUG
for ( idx = 0; idx < NUM_RANKS-1; idx++ ) {
if ( Ranks[idx].points >= Ranks[idx+1].points )
Int3();
}
for (idx = 0; idx < NUM_RANKS - 1; idx++) {
if (Ranks[idx].points >= Ranks[idx + 1].points)
Int3();
}
#endif
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", "rank.tbl", e.what()));
return;
}
}
// initialize a nice blank scoring element
+60 -58
View File
@@ -87,68 +87,70 @@ SCP_vector<mflash_info> Mflash_info;
void parse_mflash_tbl(const char *filename)
{
int rval;
uint i;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
try
{
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// header
required_string("#Muzzle flash types");
while (optional_string("$Mflash:")) {
mflash_info mflash;
bool override_mflash = false;
required_string("+name:");
stuff_string(mflash.name, F_NAME, MAX_FILENAME_LEN);
if (optional_string("+override"))
override_mflash = true;
// read in all blobs
while (optional_string("+blob_name:")) {
mflash_blob_info mblob;
stuff_string(mblob.name, F_NAME, MAX_FILENAME_LEN);
required_string("+blob_offset:");
stuff_float(&mblob.offset);
required_string("+blob_radius:");
stuff_float(&mblob.radius);
mflash.blobs.push_back(mblob);
}
for (i = 0; i < Mflash_info.size(); i++) {
if (!stricmp(mflash.name, Mflash_info[i].name)) {
if (override_mflash) {
Mflash_info[i] = mflash;
}
break;
}
}
// no matching name exists so add as new
if (i == Mflash_info.size()) {
Mflash_info.push_back(mflash);
}
// a mflash of the same name exists, don't add it again
else {
if (!override_mflash) {
Warning(LOCATION, "Muzzle flash \"%s\" already exists! Using existing entry instead.", mflash.name);
}
}
}
// close
required_string("#end");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// header
required_string("#Muzzle flash types");
while ( optional_string("$Mflash:") ) {
mflash_info mflash;
bool override_mflash = false;
required_string("+name:");
stuff_string(mflash.name, F_NAME, MAX_FILENAME_LEN);
if (optional_string("+override"))
override_mflash = true;
// read in all blobs
while ( optional_string("+blob_name:") ) {
mflash_blob_info mblob;
stuff_string(mblob.name, F_NAME, MAX_FILENAME_LEN);
required_string("+blob_offset:");
stuff_float(&mblob.offset);
required_string("+blob_radius:");
stuff_float(&mblob.radius);
mflash.blobs.push_back(mblob);
}
for (i = 0; i < Mflash_info.size(); i++) {
if ( !stricmp(mflash.name, Mflash_info[i].name) ) {
if (override_mflash) {
Mflash_info[i] = mflash;
}
break;
}
}
// no matching name exists so add as new
if (i == Mflash_info.size()) {
Mflash_info.push_back(mflash);
}
// a mflash of the same name exists, don't add it again
else {
if (!override_mflash) {
Warning(LOCATION, "Muzzle flash \"%s\" already exists! Using existing entry instead.", mflash.name);
}
}
}
// close
required_string("#end");
}
// initialize muzzle flash stuff for the whole game
+4
View File
@@ -141,6 +141,7 @@ extern int Num_weapon_subtypes;
#define WF_DESTROYED_BY_WEAPON (1<<6) // destroyed by damage from other weapon
#define WF_SPAWNED (1<<7) //Spawned from a spawning type weapon
#define WF_HOMING_UPDATE_NEEDED (1<<8) // this is a newly spawned homing weapon which needs to update client machines
#define WF_NO_HOMING (1<<9) // this weapon should ignore any homing behavior it'd usually have
// flags for setting burst fire
#define WBF_FAST_FIRING (1<<0) // burst is to use only the firewait to determine firing delays
@@ -416,6 +417,7 @@ typedef struct weapon_info {
int impact_weapon_expl_index; // Index into Weapon_expl_info of which ANI should play when this thing impacts something
float impact_explosion_radius; // How big the explosion should be
float shield_impact_explosion_radius; // How big the shield hit explosion should be
int dinky_impact_weapon_expl_index;
float dinky_impact_explosion_radius;
@@ -670,4 +672,6 @@ void weapon_pause_sounds();
// Unpauses all running weapon sounds
void weapon_unpause_sounds();
void shield_impact_explosion(vec3d *hitpos, object *objp, float radius, int idx);
#endif
+139 -109
View File
@@ -320,50 +320,52 @@ int weapon_explosions::GetAnim(int weapon_expl_index, vec3d *pos, float size)
void parse_weapon_expl_tbl(const char *filename)
{
int rval;
uint i;
lod_checker lod_check;
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
return;
}
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
required_string("#Start");
while (required_string_either("#End","$Name:"))
try
{
memset( &lod_check, 0, sizeof(lod_checker) );
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
// base filename
required_string("$Name:");
stuff_string(lod_check.filename, F_NAME, MAX_FILENAME_LEN);
//Do we have an LOD num
if (optional_string("$LOD:"))
required_string("#Start");
while (required_string_either("#End", "$Name:"))
{
stuff_int(&lod_check.num_lods);
}
memset(&lod_check, 0, sizeof(lod_checker));
// only bother with this if we have 1 or more lods and less than max lods,
// otherwise the stardard level loading will take care of the different effects
if ( (lod_check.num_lods > 0) || (lod_check.num_lods < MAX_WEAPON_EXPL_LOD) ) {
// name check, update lod count if it already exists
for (i = 0; i < LOD_checker.size(); i++) {
if ( !stricmp(LOD_checker[i].filename, lod_check.filename) ) {
LOD_checker[i].num_lods = lod_check.num_lods;
// base filename
required_string("$Name:");
stuff_string(lod_check.filename, F_NAME, MAX_FILENAME_LEN);
//Do we have an LOD num
if (optional_string("$LOD:"))
{
stuff_int(&lod_check.num_lods);
}
// only bother with this if we have 1 or more lods and less than max lods,
// otherwise the stardard level loading will take care of the different effects
if ((lod_check.num_lods > 0) || (lod_check.num_lods < MAX_WEAPON_EXPL_LOD)) {
// name check, update lod count if it already exists
for (i = 0; i < LOD_checker.size(); i++) {
if (!stricmp(LOD_checker[i].filename, lod_check.filename)) {
LOD_checker[i].num_lods = lod_check.num_lods;
}
}
// old entry not found, add new entry
if (i == LOD_checker.size()) {
LOD_checker.push_back(lod_check);
}
}
// old entry not found, add new entry
if ( i == LOD_checker.size() ) {
LOD_checker.push_back(lod_check);
}
}
required_string("#End");
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
required_string("#End");
}
/**
@@ -938,6 +940,8 @@ void init_weapon_entry(int weap_info_index)
wip->impact_explosion_radius = 1.0f;
wip->impact_weapon_expl_index = -1;
wip->shield_impact_explosion_radius = 1.0f;
wip->dinky_impact_explosion_radius = 1.0f;
wip->dinky_impact_weapon_expl_index = -1;
@@ -1063,6 +1067,7 @@ void init_weapon_entry(int weap_info_index)
wip->burst_delay = 1.0f; // 1 second, just incase its not defined
wip->burst_shots = 0;
wip->burst_flags = 0;
generic_anim_init( &wip->thruster_flame );
@@ -1909,6 +1914,12 @@ int parse_weapon(int subtype, bool replace)
if ( optional_string("$Impact Explosion Radius:") )
stuff_float(&wip->impact_explosion_radius);
if ( optional_string("$Shield Impact Explosion Radius:") ) {
stuff_float(&wip->shield_impact_explosion_radius);
} else if (first_time) {
wip->shield_impact_explosion_radius = wip->impact_explosion_radius;
}
if ( optional_string("$Dinky Impact Explosion:") ) {
stuff_string(fname, F_NAME, NAME_LENGTH);
@@ -2794,83 +2805,83 @@ static char Default_cmeasure_name[NAME_LENGTH] = "";
void parse_weaponstbl(const char *filename)
{
int rval;
if ((rval = setjmp(parse_abort)) != 0)
try
{
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", filename, rval));
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
if (optional_string("#Primary Weapons"))
{
while (required_string_either("#End", "$Name:")) {
// AL 28-3-98: If parse_weapon() fails, try next .tbl weapon
if (parse_weapon(WP_LASER, Parsing_modular_table) < 0) {
continue;
}
}
required_string("#End");
}
if (optional_string("#Secondary Weapons"))
{
while (required_string_either("#End", "$Name:")) {
// AL 28-3-98: If parse_weapon() fails, try next .tbl weapon
if (parse_weapon(WP_MISSILE, Parsing_modular_table) < 0) {
continue;
}
}
required_string("#End");
}
if (optional_string("#Beam Weapons"))
{
while (required_string_either("#End", "$Name:")) {
// AL 28-3-98: If parse_weapon() fails, try next .tbl weapon
if (parse_weapon(WP_BEAM, Parsing_modular_table) < 0) {
continue;
}
}
required_string("#End");
}
if (optional_string("#Countermeasures"))
{
while (required_string_either("#End", "$Name:"))
{
int idx = parse_weapon(WP_MISSILE, Parsing_modular_table);
if (idx < 0) {
continue;
}
//Make sure cmeasure flag is set
Weapon_info[idx].wi_flags |= WIF_CMEASURE;
//Set cmeasure index
if (!strlen(Default_cmeasure_name)) {
//We can't be sure that index will be the same after sorting, so save the name
strcpy_s(Default_cmeasure_name, Weapon_info[idx].name);
}
}
required_string("#End");
}
// Read in a list of weapon_info indicies that are an ordering of the player weapon precedence.
// This list is used to select an alternate weapon when a particular weapon is not available
// during weapon selection.
if ((!Parsing_modular_table && required_string("$Player Weapon Precedence:")) || optional_string("$Player Weapon Precedence:"))
{
Num_player_weapon_precedence = stuff_int_list(Player_weapon_precedence, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
}
// add tbl/tbm to multiplayer validation list
fs2netd_add_table_validation(filename);
}
catch (const parse::ParseException& e)
{
mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
return;
}
read_file_text(filename, CF_TYPE_TABLES);
reset_parse();
if(optional_string("#Primary Weapons"))
{
while (required_string_either("#End", "$Name:")) {
// AL 28-3-98: If parse_weapon() fails, try next .tbl weapon
if ( parse_weapon(WP_LASER, Parsing_modular_table) < 0 ) {
continue;
}
}
required_string("#End");
}
if(optional_string("#Secondary Weapons"))
{
while (required_string_either("#End", "$Name:")) {
// AL 28-3-98: If parse_weapon() fails, try next .tbl weapon
if ( parse_weapon(WP_MISSILE, Parsing_modular_table) < 0) {
continue;
}
}
required_string("#End");
}
if(optional_string("#Beam Weapons"))
{
while (required_string_either("#End", "$Name:")) {
// AL 28-3-98: If parse_weapon() fails, try next .tbl weapon
if ( parse_weapon(WP_BEAM, Parsing_modular_table) < 0) {
continue;
}
}
required_string("#End");
}
if(optional_string("#Countermeasures"))
{
while (required_string_either("#End", "$Name:"))
{
int idx = parse_weapon(WP_MISSILE, Parsing_modular_table);
if(idx < 0) {
continue;
}
//Make sure cmeasure flag is set
Weapon_info[idx].wi_flags |= WIF_CMEASURE;
//Set cmeasure index
if(!strlen(Default_cmeasure_name)) {
//We can't be sure that index will be the same after sorting, so save the name
strcpy_s(Default_cmeasure_name, Weapon_info[idx].name);
}
}
required_string("#End");
}
// Read in a list of weapon_info indicies that are an ordering of the player weapon precedence.
// This list is used to select an alternate weapon when a particular weapon is not available
// during weapon selection.
if ( (!Parsing_modular_table && required_string("$Player Weapon Precedence:")) || optional_string("$Player Weapon Precedence:") )
{
Num_player_weapon_precedence = stuff_int_list(Player_weapon_precedence, MAX_WEAPON_TYPES, WEAPON_LIST_TYPE);
}
// add tbl/tbm to multiplayer validation list
fs2netd_add_table_validation(filename);
}
//uses a simple bucket sort to sort weapons, order of importance is:
@@ -4770,7 +4781,7 @@ void weapon_process_post(object * obj, float frame_time)
}
// a single player or multiplayer server function -- it affects actual weapon movement.
if (wip->wi_flags & WIF_HOMING) {
if (wip->wi_flags & WIF_HOMING && !(wp->weapon_flags & WF_NO_HOMING)) {
weapon_home(obj, num, frame_time);
// If this is a swarm type missile,
@@ -4942,6 +4953,10 @@ void weapon_set_tracking_info(int weapon_objnum, int parent_objnum, int target_o
wp = &Weapons[Objects[weapon_objnum].instance];
wip = &Weapon_info[wp->weapon_info_index];
if (wp->weapon_flags & WF_NO_HOMING) {
return;
}
if (parent_objnum >= 0) {
parent_objp = &Objects[parent_objnum];
Assert(parent_objp->type == OBJ_SHIP);
@@ -4949,6 +4964,16 @@ void weapon_set_tracking_info(int weapon_objnum, int parent_objnum, int target_o
parent_objp = NULL;
}
if (parent_objp != NULL && (Ships[parent_objp->instance].flags2 & SF2_NO_SECONDARY_LOCKON)) {
wp->weapon_flags |= WF_NO_HOMING;
wp->homing_object = NULL;
wp->homing_subsys = NULL;
wp->target_num = -1;
wp->target_sig = -1;
return;
}
if ( parent_objp == NULL || Ships[parent_objp->instance].ai_index >= 0 ) {
int target_team = -1;
if ( target_objnum >= 0 ) {
@@ -7034,3 +7059,8 @@ void weapon_unpause_sounds()
// Pause all beam sounds
beam_unpause_sounds();
}
void shield_impact_explosion(vec3d *hitpos, object *objp, float radius, int idx) {
int expl_ani_handle = Weapon_explosions.GetAnim(idx, hitpos, radius);
particle_create( hitpos, &vmd_zero_vector, 0.0f, radius, PARTICLE_BITMAP_PERSISTENT, expl_ani_handle, -1.0f, objp );
}