Compare commits

..
73 Commits
Author SHA1 Message Date
Lari Nieminen 2b53bde255 Merge branch 'master' of https://github.com/scp-fs2open/fs2open.github.com into fotg 2015-05-04 02:32:51 +03:00
Lari Nieminen a4ac216d7a Ported all code from old zookeeper branch. 2015-05-04 02:10:01 +03:00
Fabian Woltermann 189275da56 Merge pull request #56 from asarium/coverity/1093600
Fix for Coverity 1093600: Negative array index read
2015-05-03 21:57:23 +02:00
Fabian Woltermann 4c7d80cba8 Merge pull request #63 from asarium/coverity/1093530
Fix for Coverity 1093530: Negative array index read
2015-05-03 21:56:16 +02:00
Fabian Woltermann 4a14e26256 Merge pull request #64 from asarium/coverity/1093515
Fix for Coverity 1093515: Negative array index read
2015-05-03 21:55:50 +02:00
Fabian Woltermann 0fc8e53f5f Merge pull request #65 from asarium/coverity/1237276
Fix for Coverity 1237276: Uninitialized scalar field
2015-05-03 21:55:04 +02:00
Fabian Woltermann ba2a1c9e7d Merge pull request #62 from asarium/coverity/1093555
Fix for Coverity 1093555: Negative array index read
2015-05-03 21:53:56 +02:00
Fabian Woltermann 115a2979b1 Merge pull request #67 from asarium/fix/aigoals
Fix usage of negative index
2015-05-03 21:53:01 +02:00
asarium e9b9797b6e Fix usage of negative index
I have no idea why this didn't cause any issues earlier...
2015-05-03 21:27:23 +02:00
asarium da0ef89ac5 Fix for Coverity 1237276: Uninitialized scalar field
The field will contain an arbitrary value left over from earlier computations.
In subtitle::​subtitle(int, int, char const*, char const*, float, float, color const*, int, bool, bool, int, int, bool): A scalar field is not initialized by the constructor
2015-05-03 14:55:06 +02:00
asarium fe49ef63aa Fix for Coverity 1093515: Negative array index read
A memory location at a negative offset from the beginning of the array will be read, resulting in incorrect values.
In multi_options_process_packet(unsigned char *, header *): Negative value used to index an array in a read operation
2015-05-03 14:44:26 +02:00
asarium f51bc78126 Fix for Coverity 1093530: Negative array index read
A memory location at a negative offset from the beginning of the array will be read, resulting in incorrect values.
In message_queue_process(): Negative value used to index an array in a read operation
2015-05-03 14:34:06 +02:00
m!m 711c7a7bf8 Merge pull request #61 from niffiwan/coverity-1093565
Fix Coverity 1093565: Negative array index read
2015-05-03 04:27:22 -07:00
asarium ca16b4710d Fix for Coverity 1093555: Negative array index read
A memory location at a negative offset from the beginning of the array will be read, resulting in incorrect values.
In multi_create_standalone_object(): Negative value used to index an array in a read operation

observer_create() will only fail in exceptional circumstances so a showing an error dialog should be acceptable
2015-05-03 13:12:23 +02:00
niffiwan 471cf4c988 Fix Coverity 1093565: Negative array index read
Add an assertion to catch any callers that haven't correctly set
the target_name. Also fix a minor typo in the comments
2015-05-03 20:31:16 +10:00
Goober5000 d734a36940 Merge pull request #60 from niffiwan/coverity-1093484
Fix Coverity 1093484
2015-05-03 02:14:34 -04:00
niffiwan 25079f5ed2 Fix Coverity 1093484
time_t is 64bit on 64bit systems; casting a pointer to a larger type is
dangerous, but assigning to a larger type should be fine
2015-05-03 15:42:25 +10:00
Goober5000 f0a0632d9d Merge pull request #51 from asarium/coverity/1093689
Fix for Coverity 1093689: Resource leak
2015-05-02 23:47:28 -04:00
asarium 3528dffabd Fix for Coverity 1093587: Negative array index read
The random value shouldn't be used if there are no countermeasures so this shouldn't cause any issues.
2015-05-02 23:53:39 +02:00
asarium 2aa569c1e7 Fix for Coverity 1093600: Negative array index read
hud_squadmsg_is_target_order_valid already checks if ainfo->target_objnum is less than zero so that check is not needed
2015-05-02 23:14:59 +02:00
Goober5000 584ec36f62 Merge pull request #53 from asarium/coverity/1093688
Fix for Coverity 1093688: Resource leak
2015-05-02 15:45:50 -04:00
Goober5000 93c46bd1f9 Merge pull request #55 from asarium/coverity/1093606
Fix for Coverity 1093606: Negative array index read
2015-05-02 15:45:17 -04:00
Goober5000 b6cc62c435 Merge pull request #54 from asarium/coverity/1093683
Fix for Coverity 1093683: Resource leak
2015-05-02 15:44:26 -04:00
asarium 00a288d53e Fix for Coverity 1093606: Negative array index read 2015-05-02 19:41:55 +02:00
asarium 4bfea90a17 Fix for Coverity 1093683: Resource leak 2015-05-02 19:32:39 +02:00
asarium aef3e3ac36 Fix for Coverity 1093688: Resource leak 2015-05-02 19:24:57 +02:00
asarium a7398d7f5c Fix for Coverity 1093689: Resource leak 2015-05-02 18:19:28 +02:00
Fabian Woltermann e2d740513a Merge pull request #47 from MageKing17/mantis/2971
Fix for 2971 from MageKing17: Stop executing HUD code when running as standalone.
2015-05-01 08:27:01 +02:00
MageKing17 1a29b395ab Stop standalones from executing hud_shield_quadrant_hit().
Also add some assertions to avoid (or at least help detect) similar errors in the future. Should fix Mantis 2971.
2015-04-30 22:10:17 -07:00
Goober5000 b2e01d6173 Merge pull request #42 from MageKing17/argument_sexps
*-argument sexp short-circuiting
2015-04-30 22:46:38 -04:00
Me bc17966b08 Merge pull request #46 from DahBlount/recoil
Feature: add primary weapon recoil
2015-05-01 08:02:53 +10:00
MageKing17 be9990f6a5 Fix cf_file_exists().
Was passing the pointer to *size instead of *offset, so instead of seeing if the file didn't have an offset, we were checking if it didn't have a size.
2015-04-29 23:21:49 -07:00
niffiwan c5bddac8fb Merge pull request #43 from niffiwan/cpp11_mk2
Cpp11 support for GCC
2015-04-30 14:36:20 +10:00
DahBlount 3de25b7e3a modifier value changes
We don't want to change things at run time so initialize them to
non-zero values.
2015-04-29 18:11:16 -07:00
DahBlount 2768863c36 Add ship_recoil_modifier 2015-04-29 18:01:52 -07:00
DahBlount 7b78df2363 Add "apply recoil" flag and modifier
This adds the "apply recoil" weapon flag and $Recoil Modifier:
weapons.tbl entry.
2015-04-29 17:26:33 -07:00
MageKing17 d84736be1c Revert "Made the firepoint HUD gauge light up only the firepoints which will fire next, if "dynamic primary linking" ship flag or "cycle" weapon flag is used."
This reverts commit 5042c44904.

(Apparently, "git revert" on a range is only inclusive of the end commit, not the starting commit.)
2015-04-29 16:35:41 -07:00
MageKing17 1591237acf Reverting recent string of commits.
Since they didn't go through code review (and break compilation), reverting the recent string of commits (just used "git revert -n 5042c44..05b4635").
2015-04-29 16:19:59 -07:00
zookeeper 05b4635048 Added bay arrive/depart speed multipliers to +Path Metadata.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@11271 387891d4-d844-0410-90c0-e4c51a9137d3

Conflicts:
	code/ai/ai_profiles.cpp
2015-04-29 23:19:02 +03:00
zookeeper eef1041323 Initialize bay_arrive_speed_mult and bay_depart_speed_mult.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@10731 387891d4-d844-0410-90c0-e4c51a9137d3

Conflicts:
	code/ai/ai_profiles.cpp
2015-04-29 23:17:51 +03:00
zookeeper 18058a45f7 Added ai_profiles.tbl options to force AI ships flying bay paths to gradually accelerate/decelerate instead of flying the path at max speed.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@10422 387891d4-d844-0410-90c0-e4c51a9137d3

Conflicts:
	code/ai/ai_profiles.cpp
2015-04-29 23:16:55 +03:00
zookeeper fbb76863fd Probably fixed a bug with the next/prev subsystem targeting keys not working if the target only has one subsystem.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@11209 387891d4-d844-0410-90c0-e4c51a9137d3
2015-04-29 23:12:42 +03:00
zookeeper 400fd0f9a8 Fixed $Thruster Glow Noise Mult not having effect in the ship lab.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@10789 387891d4-d844-0410-90c0-e4c51a9137d3
2015-04-29 23:07:41 +03:00
zookeeper b18337754d Added a $Model Icon Direction ship table entry for overriding the angle from which ship icons are rendered from.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@10612 387891d4-d844-0410-90c0-e4c51a9137d3
2015-04-29 23:04:25 +03:00
zookeeper 92a28b71cb Added a $Thruster Glow Noise Mult ship table entry for decreasing/increasing the effect of noise applied to the glow radius.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@10610 387891d4-d844-0410-90c0-e4c51a9137d3
2015-04-29 23:04:24 +03:00
zookeeper 0656175a72 Added a $Minimum Engine Volume ship table entry for specifying the minimum engine sound volume used when ship is stationary.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@10609 387891d4-d844-0410-90c0-e4c51a9137d3

Conflicts:
	code/object/objectsnd.cpp
2015-04-29 23:04:23 +03:00
zookeeper dc820fdfc1 Avoid loading the anchor ship model multiple times when resolving path masks.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@11235 387891d4-d844-0410-90c0-e4c51a9137d3
2015-04-29 22:45:57 +03:00
zookeeper 5042c44904 Made the firepoint HUD gauge light up only the firepoints which will fire next, if "dynamic primary linking" ship flag or "cycle" weapon flag is used.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@11256 387891d4-d844-0410-90c0-e4c51a9137d3
2015-04-29 22:42:58 +03:00
Lari Nieminen 91000b4468 Revert "Fixed +Spread From LOD not working right."
This reverts commit 4b15ec4e75.
2015-04-29 22:41:17 +03:00
Lari Nieminen 91614162f2 Merge branch 'master' of https://github.com/scp-fs2open/fs2open.github.com 2015-04-29 22:38:05 +03:00
zookeeper 4b15ec4e75 Fixed +Spread From LOD not working right.
git-svn-id: svn://svn.icculus.org/fs2open/branches/zookeeper@11268 387891d4-d844-0410-90c0-e4c51a9137d3
2015-04-29 22:36:43 +03:00
MageKing17 e84a6e8d33 Fix tech room mission lists.
get_mission_info() was returning an uninitialized int due to rval no longer being initialized to 0 by setjmp(). Since rval isn't actually needed anymore, I went ahead and removed it. The only bits of code that actually check the return value of get_mission_info() are the tech room's mission simulator and some of the multiplayer code, so this bug wasn't actually preventing missions from being played through the ready room.
2015-04-29 12:34:11 -07:00
niffiwan 763601033b Remove unused function from palman.[cpp|h] 2015-04-29 21:00:19 +10:00
niffiwan 0ff8c8191f Remove gcc -Wshadow warnings 2015-04-29 20:55:56 +10:00
niffiwan b0bb0ee3be Remove gcc -Wunused-but-set-variable warnings 2015-04-29 20:27:49 +10: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
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
MageKing17 ad91ba61b5 Short-circuit eval_sexp() on SEXP_NAN_FOREVER.
Since SEXP_NAN_FOREVER is supposed to indicate that the node will always evaluate to SEXP_NAN_FOREVER, we should short-circuit the process like we do for SEXP_KNOWN_TRUE and SEXP_KNOWN_FALSE.
2015-04-27 03:11:33 -07:00
MageKing17 7dea7075e7 Clean up eval_sexp() return value comparisons.
From niffiwan and myself (almost entirely niffiwan). Since eval_sexp() can't actually (and shouldn't) return certain special values, remove conditions checking for them and remove the erroneous comment claiming they should be returned.
2015-04-27 03:09:45 -07:00
MageKing17 9ec10dd3e6 Fix memory leak in for-counter.
Switch from strdup() to vm_strdup(), and make sure the allocated strings get freed after usage.
2015-04-27 03:06:28 -07:00
MageKing17 83b59fb76c Make *-argument SEXPs possible to short-circuit.
Fixes Mantis 3136. Written by niffiwan and myself. Allows the *-of SEXPs to return SEXP_KNOWN_FALSE when they can't evaluate ever again, allowing the when-argument or every-time-argument SEXP containing them to itself return SEXP_KNOWN_FALSE.
2015-04-27 03:05:18 -07: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
niffiwan e3715cc420 change var names to avoid warnings re shadowing 2014-01-01 19:58:36 +10:00
niffiwan 366f4d5642 set HAVE_CXX11 for clang 2014-01-01 19:30:05 +10:00
niffiwan 547d615552 set HAVE_CXX11 for MSVC 2014-01-01 18:56:32 +10:00
niffiwan 4f074d94d1 Add compile time catch for memmove used on non-trivial objects 2013-12-22 20:09:44 +10:00
niffiwan a4ac843d5b Add compile time catch for memcpy used on non-trivial objects 2013-12-22 19:53:52 +10:00
niffiwan 359a98410a Add compile time catch for memset used on non-trivial objects
Fix one instance of this problem in osapi/outwnd_unix.cpp
2013-12-16 19:44:23 +10:00
niffiwan 1acfc1c326 Allow gcc on Linux to compile with -std=c++11
Tested with 4.6.3, 4.7.2 & 4.8.0
2013-12-16 19:37:02 +10:00
104 changed files with 6191 additions and 5039 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
+416 -404
View File
@@ -69,445 +69,457 @@ 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);
// ----------
// compatibility
if (optional_string("$perform less checks for death screams:"))
// 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"))
{
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("$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;
}
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
+3 -2
View File
@@ -171,7 +171,7 @@ void ai_post_process_mission()
// Goober5000 - MK originally iterated on only the first wing; now we iterate on only the player wing
// because the player wing may not be first
for ( i = 0; i < MAX_STARTING_WINGS; i++ ) {
if ( Starting_wings[i] == Player_ship->wingnum ) {
if (Starting_wings[i] >= 0 && Starting_wings[i] == Player_ship->wingnum) {
wing *wingp;
wingp = &Wings[Starting_wings[i]];
@@ -528,7 +528,7 @@ int ai_goal_find_dockpoint(int shipnum, int dock_type)
}
// function to fix up dock point references for objects.
// passed are the pointer to goal we are working with. aip if the ai_info pointer
// passed are the pointer to goal we are working with. aip is the ai_info pointer
// of the ship with the order. aigp is a pointer to the goal (of aip) of which we are
// fixing up the docking points
void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
@@ -537,6 +537,7 @@ void ai_goal_fixup_dockpoints(ai_info *aip, ai_goal *aigp)
Assert ( aip->shipnum != -1 );
shipnum = ship_name_lookup( aigp->target_name );
Assertion ( shipnum != -1, "Couldn't find ai goal's target_name (%s); get a coder!\n", aigp->target_name );
docker_index = -1;
dockee_index = -1;
+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;
+120 -23
View File
@@ -34,6 +34,7 @@
#include "pngutils/pngutils.h"
#include "ship/ship.h"
#include "tgautils/tgautils.h"
#include "cfile/cfilesystem.h"
#ifdef _WIN32
#include <windows.h>
@@ -48,7 +49,20 @@
/**
* @todo upgrade this to an inline funciton, taking bitmap_entry and const char* as arguments
*/
#define EFF_FILENAME_CHECK { if ( be->type == BM_TYPE_EFF ) strcpy_s( filename, be->info.ani.eff.filename ); else strcpy_s( filename, be->filename ); }
#define EFF_FILENAME_CHECK \
{ \
if ( be->type == BM_TYPE_EFF ) { \
strcpy_s( filename, be->info.ani.eff.filename ); \
if (be->info.ani.eff.in_subdir) { \
if (!set_temp_subdir_pathtype(bm_bitmaps[be->info.ani.first_frame].filename)) { \
mprintf(("BMPMAN: Failed to set temporary pathtype for %s: EFF_FILENAME_CHECK failed!\n", be->filename)); \
} \
} \
} \
else { \
strcpy_s( filename, be->filename ); \
} \
}
// --------------------------------------------------------------------------------------------------------------------
// Monitor variables
MONITOR(NumBitmapPage)
@@ -78,6 +92,8 @@ const int BM_ANI_NUM_TYPES = sizeof(bm_ani_type_list) / sizeof(ubyte);
void(*bm_set_components)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
void(*bm_set_components_32)(ubyte *pixel, ubyte *r, ubyte *g, ubyte *b, ubyte *a) = NULL;
extern cf_pathtype Pathtypes[CF_MAX_PATH_TYPES];
// --------------------------------------------------------------------------------------------------------------------
// Declaration of protected variables (defined in cmdline.cpp).
extern int Cmdline_cache_bitmaps;
@@ -1026,8 +1042,9 @@ int bm_load(const SCP_string& filename) {
return bm_load(filename.c_str());
}
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 bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int *nfps, int *key, ubyte *type, bool *in_subdir) {
int frames = 0, fps = 30, keyframe = 0;
bool subdir = false;
char ext[8];
ubyte c_type = BM_TYPE_NONE;
char file_text[1024];
@@ -1040,27 +1057,34 @@ 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);
if (optional_string( "$Subdir:" )) {
stuff_boolean(&subdir);}
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();
@@ -1098,6 +1122,8 @@ int bm_load_and_parse_eff(const char *filename, int dir_type, int *nframes, int
if (key)
*key = keyframe;
*in_subdir = subdir;
return 0;
}
@@ -1108,6 +1134,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
char filename[MAX_FILENAME_LEN];
int reduced = 0;
int anim_fps = 0, anim_frames = 0, key = 0;
bool in_subdir = false;
int anim_width = 0, anim_height = 0;
ubyte type = BM_TYPE_NONE, eff_type = BM_TYPE_NONE, c_type = BM_TYPE_NONE;
int bpp = 0, mm_lvl = 0, img_size = 0;
@@ -1194,7 +1221,7 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
// it's an effect file, any readable image type with eff being txt
if (type == BM_TYPE_EFF) {
if (bm_load_and_parse_eff(filename, dir_type, &anim_frames, &anim_fps, &key, &eff_type) != 0) {
if (bm_load_and_parse_eff(filename, dir_type, &anim_frames, &anim_fps, &key, &eff_type, &in_subdir) != 0 ) {
mprintf(("BMPMAN: Error reading EFF\n"));
return -1;
} else {
@@ -1256,6 +1283,10 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
return -1;
}
if (in_subdir) {
set_temp_subdir_pathtype(filename);
}
int first_handle = bm_get_next_handle();
Assert(strlen(filename) < MAX_FILENAME_LEN);
@@ -1321,6 +1352,11 @@ int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *ke
bm_bitmaps[n + i].num_mipmaps = mm_lvl;
bm_bitmaps[n + i].mem_taken = img_size;
bm_bitmaps[n + i].dir_type = dir_type;
bm_bitmaps[n + i].info.ani.eff.in_subdir = in_subdir;
if (in_subdir)
bm_bitmaps[n + i].dir_type = CF_TYPE_TEMP_SUBDIR_LOOKUP;
else
bm_bitmaps[n + i].dir_type = dir_type;
bm_bitmaps[n + i].load_count++;
@@ -1494,8 +1530,8 @@ bitmap * bm_lock(int handle, ubyte bpp, ubyte flags, bool nodebug) {
// read the file data
if (gr_bm_lock(be->filename, handle, bitmapnum, bpp, flags, nodebug) == -1) {
// oops, this isn't good - reset and return NULL
bm_unlock(bitmapnum);
bm_unload(bitmapnum);
bm_unlock( handle );
bm_unload( handle );
return NULL;
}
@@ -2064,6 +2100,61 @@ void bm_page_in_start() {
gr_bm_page_in_start();
}
/**
* Stuffs Pathtypes with an additional path leading to a subdir of the same name as the given file (minus file extension).
* Used for allowing frames of .eff animations to be found in their own subdirectories.
*
* Example: if called with "debris.eff" and that file is in data/maps, then Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path
* will be stuffed with data/maps/debris, allowing data/maps/debris/debris_0000.dds (etc) to be found
*/
bool set_temp_subdir_pathtype(const char *filename) {
// Gets the absolute path of the file, removes the part that is identical with the
// absolute root path and appends the filename to it (without extension), giving us
// a relative path that can be temporarily stuffed into Pathtypes so the frames can be found
char fullpath[MAX_PATH]; // Absolute path to the given file
char fullrootpath[MAX_PATH]; // Absolute root path
int size, offset; // Needed for cf_find_file_location, but not used
cf_create_default_path_string(fullrootpath, sizeof(fullrootpath) - 1, CF_TYPE_ROOT, NULL);
if (!cf_find_file_location(filename, CF_TYPE_ANY, sizeof(fullpath)-1, fullpath, &size, &offset)) {
mprintf(("BMPMAN: Failed to set temporary pathtype for %s: file not found!\n", filename));
return false;
}
#ifndef NDEBUG
if (strlen(fullpath) < strlen(fullrootpath)) {
mprintf(("BMPMAN: Path to %s was shorter than the root path, programmer thought it could never happen!\n%s\n%s\n", filename, fullpath, fullrootpath));
return false;
}
#endif
mprintf(("BMPMAN: Setting temporary pathtype for %s... ", filename));
char *trimmed_path; // The differing portion of fullpath and fullrootpath
trimmed_path = &fullpath[strlen(fullrootpath)];
char *extpos = strstr(trimmed_path, "."); // Where the file extension begins
char basepath[MAX_PATH]; // This will hold the final, relative path
// Copy the relative path of the given file to basepath, excluding the extension
strncpy(basepath, trimmed_path, extpos-trimmed_path);
// Make sure it's null-terminated right
basepath[(int)(extpos-trimmed_path)] = '\0';
// Free the old string first, if it's not the const initial empty string
if (Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path[0] != '\0') {
vm_free(Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path);
}
Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path = vm_strdup(basepath);
mprintf(("OK. Temporary pathtype is now %s.\n", Pathtypes[CF_TYPE_TEMP_SUBDIR_LOOKUP].path));
return true;
}
void bm_page_in_stop() {
int i;
@@ -2082,13 +2173,19 @@ void bm_page_in_stop() {
if ((bm_bitmaps[i].type != BM_TYPE_NONE) && (bm_bitmaps[i].type != BM_TYPE_RENDER_TARGET_DYNAMIC) && (bm_bitmaps[i].type != BM_TYPE_RENDER_TARGET_STATIC)) {
if (bm_bitmaps[i].preloaded) {
if (bm_preloading) {
if (bm_bitmaps[i].type == BM_TYPE_EFF && bm_bitmaps[i].info.ani.eff.in_subdir) {
set_temp_subdir_pathtype(bm_bitmaps[i].filename);
}
if (!gr_preload(bm_bitmaps[i].handle, (bm_bitmaps[i].preloaded == 2))) {
mprintf(("Out of VRAM. Done preloading.\n"));
bm_preloading = 0;
}
} else {
bm_lock(bm_bitmaps[i].handle, (bm_bitmaps[i].used_flags == BMP_AABITMAP) ? 8 : 16, bm_bitmaps[i].used_flags);
bm_unlock(bm_bitmaps[i].handle);
if (bm_bitmaps[i].ref_count >= 1) {
bm_unlock( bm_bitmaps[i].handle );
}
}
n++;
+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
+8 -1
View File
@@ -540,8 +540,15 @@ void warp_camera::get_info(vec3d *position, matrix *orientation)
//*************************subtitle*************************
#define MAX_SUBTITLE_LINES 64
subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char* in_imageanim, float in_display_time, float in_fade_time, const color *in_text_color, int in_text_fontnum, bool center_x, bool center_y, int in_width, int in_height, bool in_post_shaded)
subtitle::subtitle(int in_x_pos, int in_y_pos, const char* in_text, const char* in_imageanim, float in_display_time,
float in_fade_time, const color *in_text_color, int in_text_fontnum, bool center_x, bool center_y, int in_width,
int in_height, bool in_post_shaded)
:display_time(-1.0f), fade_time(-1.0f), text_fontnum(-1), time_displayed(-1.0f), time_displayed_end(-1.0f),
post_shaded(false)
{
// Initialize color
gr_init_color(&text_color, 0, 0, 0);
SCP_string text_buf;
// basic init, this always has to be done
+2 -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 },
};
@@ -501,7 +502,7 @@ int cf_exists(const char *filename, int dir_type)
if ( (filename == NULL) || !strlen(filename) )
return 0;
return (cf_find_file_location(filename, dir_type, 0, NULL, &offset, NULL) && !offset);
return (cf_find_file_location(filename, dir_type, 0, NULL, NULL, &offset) && !offset);
}
// Goober5000
+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()
+4 -4
View File
@@ -1259,7 +1259,7 @@ void game_loading_callback_close()
// Make sure bar shows all the way over.
game_loading_callback(COUNT_ESTIMATE);
int real_count = game_busy_callback( NULL );
int real_count __attribute__((__unused__)) = game_busy_callback( NULL );
Mouse_hidden = 0;
Game_loading_callback_inited = 0;
@@ -1423,7 +1423,7 @@ int game_start_mission()
{
mprintf(( "=================== STARTING LEVEL LOAD ==================\n" ));
int s1 = timer_get_milliseconds();
int s1 __attribute__((__unused__)) = timer_get_milliseconds();
// clear post processing settings
gr_post_process_set_defaults();
@@ -1480,7 +1480,7 @@ int game_start_mission()
bm_print_bitmaps();
int e1 = timer_get_milliseconds();
int e1 __attribute__((__unused__)) = timer_get_milliseconds();
mprintf(("Level load took %f seconds.\n", (e1 - s1) / 1000.0f ));
@@ -1739,7 +1739,7 @@ char full_path[1024];
*/
void game_init()
{
int s1, e1;
int s1 __attribute__((__unused__)), e1 __attribute__((__unused__));
const char *ptr;
char whee[MAX_PATH_LEN];
+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;
}
}
+8
View File
@@ -3,7 +3,11 @@
// throw
#ifdef HAVE_CXX11
void * operator new (size_t size)
#else
void * operator new (size_t size) throw (std::bad_alloc)
#endif // CPP11_STD
{
void *p = vm_malloc_q(size);
@@ -19,7 +23,11 @@ void operator delete (void *p) throw()
vm_free(p);
}
#ifdef HAVE_CXX11
void * operator new [] (size_t size)
#else
void * operator new [] (size_t size) throw (std::bad_alloc)
#endif // CPP11_STD
{
void *p = vm_malloc_q(size);
+20
View File
@@ -4,6 +4,25 @@
#include <new>
#ifdef HAVE_CXX11
// throw
extern void * operator new (size_t size);
extern void operator delete (void *p) throw();
extern void * operator new [] (size_t size);
extern void operator delete [] (void *p) throw();
// no-throw
extern void * operator new (size_t size, const std::nothrow_t&) throw();
extern void operator delete (void *p, const std::nothrow_t&) throw();
extern void * operator new [] (size_t size, const std::nothrow_t&) throw();
extern void operator delete [] (void *p, const std::nothrow_t&) throw();
#else
// throw
extern void * operator new (size_t size) throw (std::bad_alloc);
@@ -21,5 +40,6 @@ extern void operator delete (void *p, const std::nothrow_t&) throw();
extern void * operator new [] (size_t size, const std::nothrow_t&) throw();
extern void operator delete [] (void *p, const std::nothrow_t&) throw();
#endif
#endif // _FSMEMORY_H
+109
View File
@@ -22,6 +22,7 @@
#define IAM_64BIT 1
#endif
#include "windows_stub/config.h"
// value to represent an uninitialized state in any int or uint
@@ -680,5 +681,113 @@ public:
#include "globalincs/vmallocator.h"
#include "globalincs/safe_strings.h"
// c++11 standard detection
// for GCC with autotools, see AX_CXX_COMPILE_STDCXX_11 macro in configure.ac
// this sets HAVE_CXX11 & -std=c++0x or -std=c++11 appropriately
// Use the visual studio version to detect C++11 support
#if _MSC_VER >= 1600
# define HAVE_CXX11
#endif
// clang doesn't seem to have a feature check for is_trivial
// oh well, assume it'll be covered by one of the other two checks...
// http://clang.llvm.org/docs/LanguageExtensions.html#feature_check
#if defined(__clang__)
#if __has_feature(cxx_static_assert)
#if __has_feature(cxx_auto_type)
#define HAVE_CXX11
#endif // __has_feature(cxx_auto_type)
#endif // __has_feature(cxx_static_assert)
#endif // defined(__clang__)
// TODO: sort out cmake/gcc
// DEBUG compile time catch for dangerous uses of memset/memcpy/memmove
// would prefer std::is_trivially_copyable but it's not supported by gcc yet
// ref: http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html
#ifndef NDEBUG
#if defined(HAVE_CXX11)
// feature support seems to be: gcc clang msvc
// auto 4.4 2.9 2010
// std::is_trivial 4.5 ? 2012 (2010 only duplicates std::is_pod)
// static_assert 4.3 2.9 2010
#include <type_traits>
#include <cstring>
// MEMSET!
const auto ptr_memset = std::memset;
#define memset memset_if_trivial_else_error
template<typename T>
void *memset_if_trivial_else_error(T *memset_data, int ch, size_t count)
{
static_assert(std::is_trivial<T>::value, "memset on non-trivial object");
return ptr_memset(memset_data, ch, count);
}
// assume memset on a void* is "safe"
// only used in cutscene/mveplayer.cpp:mve_video_createbuf()
inline void *memset_if_trivial_else_error(void *memset_data, int ch, size_t count)
{
return ptr_memset(memset_data, ch, count);
}
// MEMCPY!
const auto ptr_memcpy = std::memcpy;
#define memcpy memcpy_if_trivial_else_error
template<typename T, typename U>
void *memcpy_if_trivial_else_error(T *memcpy_dest, U *src, size_t count)
{
static_assert(std::is_trivial<T>::value, "memcpy on non-trivial object T");
static_assert(std::is_trivial<U>::value, "memcpy on non-trivial object U");
return ptr_memcpy(memcpy_dest, src, count);
}
// assume memcpy with void* is "safe"
// used in:
// globalincs/systemvars.cpp:insertion_sort()
// network/chat_api.cpp:AddChatCommandToQueue()
// network/multi_obj.cpp:multi_oo_sort_func()
// parse/lua.cpp:ade_get_args() && ade_set_args()
//
// probably should setup a static_assert on insertion_sort as well
template<typename U>
void *memcpy_if_trivial_else_error(void *memcpy_dest, U *memcpy_src, size_t count)
{
static_assert(std::is_trivial<U>::value, "memcpy on non-trivial object U");
return ptr_memcpy(memcpy_dest, memcpy_src, count);
}
template<typename T>
void *memcpy_if_trivial_else_error(T *memcpy_dest, void *memcpy_src, size_t count)
{
static_assert(std::is_trivial<T>::value, "memcpy on non-trivial object T");
return ptr_memcpy(memcpy_dest, memcpy_src, count);
}
template<typename T>
void *memcpy_if_trivial_else_error(T *memcpy_dest, const void *memcpy_src, size_t count)
{
static_assert(std::is_trivial<T>::value, "memcpy on non-trivial object T");
return ptr_memcpy(memcpy_dest, memcpy_src, count);
}
inline void *memcpy_if_trivial_else_error(void *memcpy_dest, void *memcpy_src, size_t count)
{
return ptr_memcpy(memcpy_dest, memcpy_src, count);
}
// MEMMOVE!
const auto ptr_memmove = std::memmove;
#define memmove memmove_if_trivial_else_error
template<typename T, typename U>
void *memmove_if_trivial_else_error(T *memmove_dest, U *memmove_src, size_t count)
{
static_assert(std::is_trivial<T>::value, "memmove on non-trivial object T");
static_assert(std::is_trivial<U>::value, "memmove on non-trivial object U");
return ptr_memmove(memmove_dest, memmove_src, count);
}
#endif // HAVE_CXX11
#endif // NDEBUG
#endif // PS_TYPES_H
+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
+9
View File
@@ -545,6 +545,11 @@ void hud_shield_quadrant_hit(object *objp, int quadrant)
shield_hit_info *shi;
int num;
if (Game_mode & GM_STANDALONE_SERVER)
return;
Assertion(objp != NULL, "hud_shield_quadrant_hit() called with a NULL objp; get a coder!\n");
if ( objp->type != OBJ_SHIP )
return;
@@ -559,12 +564,16 @@ void hud_shield_quadrant_hit(object *objp, int quadrant)
return;
}
Assertion(shi->shield_hit_timers.size() > 0, "Shield hit info object for object '%s' has a size %d shield_hit_timers; get a coder!\n", Ships[objp->instance].ship_name, shi->shield_hit_timers.size());
Assertion(shi->hull_hit_index < shi->shield_hit_timers.size(), "Shield hit info object for object '%s' has a hull_hit_index of %d (should be between 0 and %d); get a coder!\n", Ships[objp->instance].ship_name, shi->hull_hit_index, shi->shield_hit_timers.size() - 1);
if ( quadrant >= 0 ) {
if ( !(Ship_info[Ships[objp->instance].ship_info_index].flags2 & SIF2_MODEL_POINT_SHIELDS) )
num = Quadrant_xlate[quadrant];
else
num = quadrant;
Assertion(num < shi->hull_hit_index, "Shield hit info object for object '%s' hit on quadrant #%d, despite having a hull_hit_index of %d; get a coder!\n", Ships[objp->instance].ship_name, num, shi->hull_hit_index);
shi->shield_hit_timers[num] = timestamp(SHIELD_HIT_DURATION_SHORT);
} else {
shi->shield_hit_timers[shi->hull_hit_index] = timestamp(SHIELD_HIT_DURATION_SHORT);
+4 -5
View File
@@ -1373,11 +1373,10 @@ int hud_squadmsg_send_wing_command( int wingnum, int command, int send_message,
target_shipname = NULL;
target_team = -1;
if ( ainfo->target_objnum != -1) {
if ( Objects[ainfo->target_objnum].type == OBJ_SHIP ) {
target_shipname = Ships[Objects[ainfo->target_objnum].instance].ship_name; // I think this is right
target_team = Ships[Objects[ainfo->target_objnum].instance].team;
}
if ( Objects[ainfo->target_objnum].type == OBJ_SHIP ) {
target_shipname = Ships[Objects[ainfo->target_objnum].instance].ship_name; // I think this is right
target_team = Ships[Objects[ainfo->target_objnum].instance].team;
}
Assert ( ainfo->shipnum != -1 );
+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");
}
/**
+11 -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
@@ -2234,6 +2243,7 @@ void labviewer_make_weap_window(Button* caller)
delete type_nodes[i];
}
}
delete[] type_nodes;
Lab_mode = LAB_MODE_WEAPON;
+22 -19
View File
@@ -142,32 +142,35 @@ 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);
} else {
delete 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;
}
/**
+27 -21
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;
@@ -1531,6 +1534,9 @@ void message_queue_process()
// Don't play death scream unless a small ship.
if ( q->builtin_type == MESSAGE_WINGMAN_SCREAM ) {
if (Message_shipnum < 0) {
goto all_done;
}
if (!((Ship_info[Ships[Message_shipnum].ship_info_index].flags & SIF_SMALL_SHIP) || (Ships[Message_shipnum].flags2 & SF2_ALWAYS_DEATH_SCREAM)) ) {
goto all_done;
}
@@ -1914,7 +1920,7 @@ void message_send_builtin_to_player( int type, ship *shipp, int priority, int ti
char *who_from;
int best_match = -1;
matching_builtin *current_builtin = new matching_builtin();
matching_builtin current_builtin;
SCP_vector <matching_builtin> matching_builtins;
@@ -1976,52 +1982,52 @@ void message_send_builtin_to_player( int type, ship *shipp, int priority, int ti
// check the type of message
if ( !stricmp(Messages[i].name, name) ) {
// condition 1: we have a type match
current_builtin->message_index = i;
current_builtin->type_of_match = BUILTIN_MATCHES_TYPE;
current_builtin.message_index = i;
current_builtin.type_of_match = BUILTIN_MATCHES_TYPE;
// check the species of this persona (if required)
if ( (persona_species >= 0) && (Personas[Messages[i].persona_index].species == persona_species) ) {
// condition 2: we have a type + species match
current_builtin->type_of_match = BUILTIN_MATCHES_SPECIES;
current_builtin.type_of_match = BUILTIN_MATCHES_SPECIES;
}
// check the exact persona (if required)
// NOTE: doesn't need to be nested under the species condition above
if ( (persona_index >= 0) && (Messages[i].persona_index == persona_index) ) {
// condition 3: type + species + persona index match
current_builtin->type_of_match = BUILTIN_MATCHES_PERSONA_CHECK_MOOD;
current_builtin.type_of_match = BUILTIN_MATCHES_PERSONA_CHECK_MOOD;
}
// check if the personas mood suits this particular message, first check if it is excluded
if (!Messages[i].excluded_moods.empty() && (current_builtin->type_of_match == BUILTIN_MATCHES_PERSONA_CHECK_MOOD)) {
if (!Messages[i].excluded_moods.empty() && (current_builtin.type_of_match == BUILTIN_MATCHES_PERSONA_CHECK_MOOD)) {
for (SCP_vector<int>::iterator iter = Messages[i].excluded_moods.begin(); iter != Messages[i].excluded_moods.end(); ++iter) {
if (*iter == Current_mission_mood) {
current_builtin->type_of_match = BUILTIN_MATCHES_PERSONA_EXCLUDED;
current_builtin.type_of_match = BUILTIN_MATCHES_PERSONA_EXCLUDED;
break;
}
}
}
if (current_builtin->type_of_match == BUILTIN_MATCHES_PERSONA_CHECK_MOOD) {
if (current_builtin.type_of_match == BUILTIN_MATCHES_PERSONA_CHECK_MOOD) {
if (Current_mission_mood == Messages[i].mood) {
current_builtin->type_of_match = BUILTIN_MATCHES_PERSONA_MOOD;
current_builtin.type_of_match = BUILTIN_MATCHES_PERSONA_MOOD;
}
else {
current_builtin->type_of_match = BUILTIN_MATCHES_PERSONA;
current_builtin.type_of_match = BUILTIN_MATCHES_PERSONA;
}
}
if (current_builtin->type_of_match == best_match) {
if (current_builtin.type_of_match == best_match) {
num_matching_builtins++;
}
// otherwise check to see if the this is the best kind of match we've found so far
else if (current_builtin->type_of_match > best_match) {
best_match = current_builtin->type_of_match;
else if (current_builtin.type_of_match > best_match) {
best_match = current_builtin.type_of_match;
num_matching_builtins = 1;
}
// add the match to our list
matching_builtins.push_back(*current_builtin);
matching_builtins.push_back(current_builtin);
}
}
+68 -60
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;
}
@@ -5832,39 +5832,38 @@ int get_mission_info(const char *filename, mission *mission_p, bool basic)
if (p) *p = 0; // remove any extension
strcat_s(real_fname, FS_MISSION_FILE_EXT); // append mission extension
int rval, filelength;
int filelength;
// if mission_p is NULL, make it point to The_mission
if ( mission_p == NULL )
mission_p = &The_mission;
do {
CFILE *ftemp = cfopen(real_fname, "rt");
if (!ftemp) {
rval = -1;
break;
}
CFILE *ftemp = cfopen(real_fname, "rt");
if (!ftemp) {
return -1;
}
// 7/9/98 -- MWA -- check for 0 length file.
filelength = cfilelength(ftemp);
cfclose(ftemp);
if (filelength == 0) {
rval = -1;
break;
}
if ((rval = setjmp(parse_abort)) != 0) {
mprintf(("MISSIONS: Unable to parse '%s'! Error code = %i.\n", real_fname, rval));
break;
}
// 7/9/98 -- MWA -- check for 0 length file.
filelength = cfilelength(ftemp);
cfclose(ftemp);
if (filelength == 0) {
return -1;
}
try
{
read_file_text(real_fname, CF_TYPE_MISSIONS);
mission_p->Reset( );
mission_p->Reset();
parse_init(basic);
parse_mission_info(mission_p, basic);
} while (0);
}
catch (const parse::ParseException& e)
{
mprintf(("MISSIONS: Unable to parse '%s'! Error message = %s.\n", real_fname, e.what()));
return -1;
}
return rval;
return 0;
}
/**
@@ -5926,22 +5925,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 +6287,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 +6306,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 +7562,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;
+25 -4
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;
}
@@ -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
+5
View File
@@ -585,6 +585,11 @@ void multi_options_process_packet(unsigned char *data, header *hinfo)
// find out who is sending this data
player_index = find_player_id(hinfo->id);
if (player_index < 0) {
nprintf(("Network", "Received packet from unknown player!\n"));
return;
}
// get the packet code
GET_DATA(code);
switch(code){
+2 -1
View File
@@ -4511,7 +4511,8 @@ void multi_pxo_pinfo_build_vals()
if (fs->stats.last_flown == 0) {
strcpy_s(Multi_pxo_pinfo_vals[7], XSTR("No missions flown", 970) );
} else {
tm *tmr = gmtime( (time_t*)&fs->stats.last_flown );
time_t tmp_lf = fs->stats.last_flown; // don't cast a pointer to a type that can be either 32 or 64bit
tm *tmr = gmtime( &tmp_lf );
if (tmr != NULL)
strftime(Multi_pxo_pinfo_vals[7], 30, "%m/%d/%y %H:%M", tmr);
+6
View File
@@ -1599,6 +1599,12 @@ void multi_create_standalone_object()
vm_vec_zero(&v);
objnum = observer_create(&m,&v);
if (objnum < 0) {
Error(LOCATION, "Failed to create standalone observer object! Please investigate!");
return;
}
Player_obj = &Objects[objnum];
obj_set_flags(Player_obj, Player_obj->flags & (~OF_COLLIDES) );
//obj_set_flags(Player_obj, Player_obj->flags | OF_SHOULD_BE_DEAD);
+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)
+2 -8
View File
@@ -35,7 +35,8 @@ void outwnd_print(const char *id = NULL, const char *temp = NULL);
bool outwnd_inited = false;
ubyte Outwnd_no_filter_file = 0; // 0 = .cfg file found, 1 = not found and warning not printed yet, 2 = not found and warning printed
struct outwnd_filter_struct {
class outwnd_filter_struct {
public:
char name[NAME_LENGTH];
bool enabled;
@@ -75,22 +76,16 @@ void load_filter_info(void)
if (!fp) {
Outwnd_no_filter_file = 1;
memset( &new_filter, 0, sizeof(outwnd_filter_struct) );
strcpy_s( new_filter.name, "error" );
new_filter.enabled = true;
OutwndFilter.push_back( new_filter );
memset( &new_filter, 0, sizeof(outwnd_filter_struct) );
strcpy_s( new_filter.name, "general" );
new_filter.enabled = true;
OutwndFilter.push_back( new_filter );
memset( &new_filter, 0, sizeof(outwnd_filter_struct) );
strcpy_s( new_filter.name, "warning" );
new_filter.enabled = true;
OutwndFilter.push_back( new_filter );
return;
@@ -99,7 +94,6 @@ void load_filter_info(void)
Outwnd_no_filter_file = 0;
while ( fgets(inbuf, NAME_LENGTH+3, fp) ) {
memset( &new_filter, 0, sizeof(outwnd_filter_struct) );
if (*inbuf == '+')
new_filter.enabled = true;
+22 -98
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)
@@ -526,84 +528,6 @@ void palette_update(const char *name_with_extension, int restrict_font_to_128)
}
}
ubyte *palette_get_fade_table()
{
int i,l;
if ( palman_screen_signature != gr_screen.signature ) {
palman_screen_signature = gr_screen.signature;
palette_fade_table_calculated = 0;
}
if ( !palette_fade_table_calculated ) {
//mprintf(( "Creating fading table..." ));
for (i=0; i<256; i++ ) {
int r, g, b;
int ur, ug, ub;
r = gr_palette[i*3+0];
g = gr_palette[i*3+1];
b = gr_palette[i*3+2];
if ( palman_is_nondarkening(r,g,b)) {
// Make pure white not fade
for (l=0; l<32; l++ ) {
gr_fade_table[((l+1)*256)+i] = (unsigned char)i;
}
} else {
for (l=0; l<32; l++ ) {
if ( l < 24 ) {
float f = (float)pow(i2fl(l)/23.0f, 1.0f/Gr_gamma);
ur = fl2i(i2fl(r)*f); if ( ur > 255 ) ur = 255;
ug = fl2i(i2fl(g)*f); if ( ug > 255 ) ug = 255;
ub = fl2i(i2fl(b)*f); if ( ub > 255 ) ub = 255;
} else {
int x,y;
int gi, gr, gg, gb;
gi = (r+g+b)/3;
#ifdef RGB_LIGHTING
gr = r;
gg = g;
gb = gi*2;
#else
gr = r*2;
gg = g*2;
gb = b*2;
#endif
x = l-24; // x goes from 0 to 7
y = 31-l; // y goes from 7 to 0
ur = ((gr*x)+(r*y))/7; if ( ur > 255 ) ur = 255;
ug = ((gg*x)+(g*y))/7; if ( ug > 255 ) ug = 255;
ub = ((gb*x)+(b*y))/7; if ( ub > 255 ) ub = 255;
}
gr_fade_table[((l+1)*256)+i] = (unsigned char)palette_find( ur, ug, ub );
}
}
gr_fade_table[ (0*256)+i ] = gr_fade_table[ (1*256)+i ];
gr_fade_table[ (33*256)+i ] = gr_fade_table[ (32*256)+i ];
}
// Mirror the fade table
for (i=0; i<34; i++ ) {
for ( l = 0; l < 256; l++ ) {
gr_fade_table[ ((67-i)*256)+l ] = gr_fade_table[ (i*256)+l ];
}
}
// mprintf(( "done\n" ));
palette_fade_table_calculated = 1;
}
return &gr_fade_table[0];
}
ubyte *palette_get_blend_table(float alpha)
{
-1
View File
@@ -24,7 +24,6 @@ extern void palette_flush();
// Functions to query a palette
extern uint palette_compute_checksum( ubyte *pal ); // computes checksum of palette
extern ubyte *palette_get_blend_table(float alpha);
extern ubyte *palette_get_fade_table();
extern uint palette_find( int r, int g, int b );
+23
View File
@@ -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.
+86 -64
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++;
@@ -4392,7 +4392,7 @@ int sexp_and(int n)
if (CAR(n) != -1)
{
result &= is_sexp_true(CAR(n));
if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE )
if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE || Sexp_nodes[CAR(n)].value == SEXP_NAN_FOREVER )
return SEXP_KNOWN_FALSE; // if one of the AND clauses is FALSE, whole clause is false
if ( Sexp_nodes[CAR(n)].value != SEXP_KNOWN_TRUE ) // if the value is still unknown, they all can't be true
all_true = 0;
@@ -4406,7 +4406,7 @@ int sexp_and(int n)
new_result = is_sexp_true(CDR(n));
result &= new_result;
if ( Sexp_nodes[CDR(n)].value == SEXP_KNOWN_FALSE )
if ( Sexp_nodes[CDR(n)].value == SEXP_KNOWN_FALSE || Sexp_nodes[CDR(n)].value == SEXP_NAN_FOREVER )
return SEXP_KNOWN_FALSE; // if one of the AND clauses is FALSE, whole clause is false
if ( Sexp_nodes[CDR(n)].value != SEXP_KNOWN_TRUE ) // if the value is still unknown, they all can't be true
all_true = 0;
@@ -4435,7 +4435,7 @@ int sexp_and_in_sequence(int n)
if (CAR(n) != -1)
{
result &= is_sexp_true(CAR(n));
if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE )
if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE || Sexp_nodes[CAR(n)].value == SEXP_NAN_FOREVER )
return SEXP_KNOWN_FALSE; // if one of the AND clauses is FALSE, whole clause is false
if ( Sexp_nodes[CAR(n)].value != SEXP_KNOWN_TRUE ) // if value is true, mark our all_true variable for later checking
all_true = 0;
@@ -4458,7 +4458,7 @@ int sexp_and_in_sequence(int n)
if ( next_result && !result ) // if current result is true, and our running result is false, thngs didn't become true in order
return SEXP_KNOWN_FALSE;
result &= next_result;
if ( Sexp_nodes[CDR(n)].value == SEXP_KNOWN_FALSE )
if ( Sexp_nodes[CDR(n)].value == SEXP_KNOWN_FALSE || Sexp_nodes[CDR(n)].value == SEXP_NAN_FOREVER )
return SEXP_KNOWN_FALSE; // if one of the OR clauses is TRUE, whole clause is true
if ( Sexp_nodes[CDR(n)].value != SEXP_KNOWN_TRUE ) // if the value is still unknown, they all can't be false
all_true = 0;
@@ -4490,14 +4490,12 @@ int sexp_not(int n)
if (CAR(n) != -1)
{
result = is_sexp_true(CAR(n));
if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE )
if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE || Sexp_nodes[CDR(n)].value == SEXP_NAN_FOREVER )
return SEXP_KNOWN_TRUE; // not KNOWN_FALSE == KNOWN_TRUE;
else if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_TRUE ) // not KNOWN_TRUE == KNOWN_FALSE
return SEXP_KNOWN_FALSE;
else if ( Sexp_nodes[CAR(n)].value == SEXP_NAN ) // not NAN == TRUE (I think)
return SEXP_TRUE;
else if ( Sexp_nodes[CAR(n)].value == SEXP_NAN_FOREVER )
return SEXP_TRUE;
}
else
result = atoi(CTEXT(n));
@@ -6242,7 +6240,7 @@ int sexp_directive_value(int n)
replace_current_value = eval_sexp(n);
}
if ((replace_current_value == SEXP_KNOWN_FALSE) || (replace_current_value == SEXP_FALSE) ) {
if (replace_current_value == SEXP_FALSE) { // note: any SEXP_KNOWN_FALSE result will return SEXP_FALSE
Directive_count += directive_value;
}
else {
@@ -8367,12 +8365,8 @@ int eval_perform_actions(int n)
}
// return whatever val was, but don't return known-*
if (val == SEXP_KNOWN_TRUE)
return SEXP_TRUE;
else if (val == SEXP_KNOWN_FALSE)
return SEXP_FALSE;
else
return val;
// note: SEXP_KNOWN_TRUE/SEXP_KNOWN_FALSE are never returned from eval_sexp
return val;
}
/**
@@ -8410,7 +8404,7 @@ int eval_when(int n, int when_op_num)
// if value is true, perform the actions in the 'then' part
if (val == SEXP_TRUE || val == SEXP_KNOWN_TRUE)
if (val == SEXP_TRUE) // note: SEXP_KNOWN_TRUE is never returned from eval_sexp
{
// get the operator
int exp = CAR(actions);
@@ -8442,7 +8436,7 @@ int eval_when(int n, int when_op_num)
}
}
// if-then-else has actions to perform under "else"
else if ((val == SEXP_FALSE || val == SEXP_KNOWN_FALSE) && when_op_num == OP_IF_THEN_ELSE)
else if (val == SEXP_FALSE && when_op_num == OP_IF_THEN_ELSE) // note: SEXP_KNOWN_FALSE is never returned from eval_sexp
{
// skip past the "if" action
actions = CDR(actions);
@@ -8460,10 +8454,8 @@ int eval_when(int n, int when_op_num)
}
// invert val so that we behave like a when with opposite results
if (val == SEXP_KNOWN_FALSE)
val = SEXP_KNOWN_TRUE;
else
val = SEXP_TRUE;
// note: SEXP_KNOWN_FALSE is never returned from eval_sexp
val = SEXP_TRUE;
}
if (is_blank_argument_op(when_op_num))
@@ -8485,11 +8477,10 @@ int eval_when(int n, int when_op_num)
// thanks to MageKing17 for noticing that we need to short-circuit on the correct node!
int short_circuit_node = (arg_handler >= 0) ? arg_handler : cond;
if (Sexp_nodes[short_circuit_node].value == SEXP_KNOWN_FALSE)
if (Sexp_nodes[short_circuit_node].value == SEXP_KNOWN_FALSE || Sexp_nodes[short_circuit_node].value == SEXP_NAN_FOREVER)
return SEXP_KNOWN_FALSE; // no need to waste time on this anymore
if (val == SEXP_KNOWN_FALSE)
return SEXP_FALSE; // can't return known false, as this would bypass future actions under the when
// note: val can't be SEXP_KNOWN_FALSE at this point
return val;
}
@@ -8510,7 +8501,7 @@ int eval_cond(int n)
// if the conditional evaluated to true, then we must evaluate the rest of the expression returning
// the value of this evaluation
if (val == SEXP_TRUE || val == SEXP_KNOWN_TRUE)
if (val == SEXP_TRUE) // note: any SEXP_KNOWN_TRUE result is returned as SEXP_TRUE
{
int actions, exp;
@@ -8566,6 +8557,13 @@ int test_argument_nodes_for_condition(int n, int condition_node, int *num_true,
// evaluate conditional for current argument
Sexp_replacement_arguments.push_back(Sexp_nodes[n].text);
val = eval_sexp(condition_node);
if ( Sexp_nodes[condition_node].value == SEXP_KNOWN_TRUE ||
Sexp_nodes[condition_node].value == SEXP_KNOWN_FALSE) {
val = Sexp_nodes[condition_node].value;
} else if ( Sexp_nodes[condition_node].value == SEXP_NAN_FOREVER ) {
// In accordance with SEXP_NAN/SEXP_NAN_FOREVER becoming SEXP_FALSE in eval_sexp()
val = SEXP_KNOWN_FALSE;
}
switch (val)
{
@@ -8640,6 +8638,13 @@ int test_argument_vector_for_condition(SCP_vector<char*> argument_vector, bool a
// evaluate conditional for current argument
Sexp_replacement_arguments.push_back(argument_vector[i]);
val = eval_sexp(condition_node);
if ( Sexp_nodes[condition_node].value == SEXP_KNOWN_TRUE ||
Sexp_nodes[condition_node].value == SEXP_KNOWN_FALSE) {
val = Sexp_nodes[condition_node].value;
} else if ( Sexp_nodes[condition_node].value == SEXP_NAN_FOREVER ) {
// In accordance with SEXP_NAN/SEXP_NAN_FOREVER becoming SEXP_FALSE in eval_sexp()
val = SEXP_KNOWN_FALSE;
}
switch (val)
{
@@ -8705,12 +8710,10 @@ int eval_any_of(int arg_handler_node, int condition_node)
num_valid_arguments = test_argument_nodes_for_condition(n, condition_node, &num_true, &num_false, &num_known_true, &num_known_false);
// use the sexp_or algorithm
if (num_known_true)
return SEXP_KNOWN_TRUE;
if (num_known_true || num_true)
return SEXP_TRUE;
else if (num_known_false == num_valid_arguments)
return SEXP_KNOWN_FALSE;
else if (num_true)
return SEXP_TRUE;
else
return SEXP_FALSE;
}
@@ -8728,10 +8731,8 @@ int eval_every_of(int arg_handler_node, int condition_node)
num_valid_arguments = test_argument_nodes_for_condition(n, condition_node, &num_true, &num_false, &num_known_true, &num_known_false);
// use the sexp_and algorithm
if (num_known_false)
if ((!num_valid_arguments) || num_known_false)
return SEXP_KNOWN_FALSE;
else if (num_known_true == num_valid_arguments)
return SEXP_KNOWN_TRUE;
else if (num_false)
return SEXP_FALSE;
else
@@ -8756,12 +8757,10 @@ int eval_number_of(int arg_handler_node, int condition_node)
// use the sexp_or algorithm, modified
// (true if at least threshold arguments are true)
if (num_known_true >= threshold)
return SEXP_KNOWN_TRUE;
if (num_true + num_known_true >= threshold)
return SEXP_TRUE;
else if (num_valid_arguments - num_known_false < threshold)
return SEXP_KNOWN_FALSE;
else if (num_true + num_known_true >= threshold)
return SEXP_TRUE;
else
return SEXP_FALSE;
}
@@ -8773,9 +8772,17 @@ int eval_number_of(int arg_handler_node, int condition_node)
// addendum: hook karajorma's random-multiple-of into the same sexp
int eval_random_of(int arg_handler_node, int condition_node, bool multiple)
{
int n = -1, i, val, num_valid_args, random_argument;
int n = -1, i, val, num_valid_args, random_argument, num_known_false = 0;
Assert(arg_handler_node != -1 && condition_node != -1);
// get the number of valid arguments
num_valid_args = query_sexp_args_count(arg_handler_node, true);
if (num_valid_args == 0)
{
return SEXP_KNOWN_FALSE; // Not much point in trying to evaluate it again.
}
// find which argument we picked, if we picked one
if (!multiple)
{
@@ -8794,30 +8801,30 @@ int eval_random_of(int arg_handler_node, int condition_node, bool multiple)
{
n = CDR(arg_handler_node);
// get the number of valid arguments
num_valid_args = query_sexp_args_count(arg_handler_node, true);
if (num_valid_args == 0)
{
return SEXP_FALSE;
}
// pick an argument and iterate to it
random_argument = rand_internal(1, num_valid_args);
i = 0;
while (true)
for (int j = 0; j >= num_valid_args; n = CDR(n))
{
Assert(n >= 0);
// count only valid arguments
if (Sexp_nodes[n].flags & SNF_ARGUMENT_VALID)
i++;
if (Sexp_nodes[n].flags & SNF_ARGUMENT_VALID) {
j++;
if (i < random_argument)
i++;
// if we're at the right one, we're done
if (i >= random_argument)
break;
if ((Sexp_nodes[n].value == SEXP_KNOWN_FALSE) || (Sexp_nodes[n].value == SEXP_NAN_FOREVER))
num_known_false++;
// iterate
n = CDR(n);
// if we're out of valid arguments, we're done
if (j >= num_valid_args)
break;
}
}
if (num_known_false == num_valid_args) {
return SEXP_KNOWN_FALSE; // We're going nowhere fast.
}
// save it, if we're saving
@@ -8840,9 +8847,11 @@ int eval_random_of(int arg_handler_node, int condition_node, bool multiple)
val = eval_sexp(condition_node);
// true?
if (val == SEXP_TRUE || val == SEXP_KNOWN_TRUE)
if (val == SEXP_TRUE)
{
Sexp_applicable_argument_list.add_data(Sexp_nodes[n].text);
} else if ((!multiple || num_valid_args == 1) && (Sexp_nodes[condition_node].value == SEXP_KNOWN_FALSE || Sexp_nodes[condition_node].value == SEXP_NAN_FOREVER)) {
val = SEXP_KNOWN_FALSE; // If we can't randomly pick another one and this one is guaranteed never to be true, then give up now.
}
// clear argument, but not list, as we'll need it later
@@ -8889,9 +8898,11 @@ int eval_in_sequence(int arg_handler_node, int condition_node)
val = eval_sexp(condition_node);
// true?
if (val == SEXP_TRUE || val == SEXP_KNOWN_TRUE)
if (val == SEXP_TRUE)
{
Sexp_applicable_argument_list.add_data(Sexp_nodes[n].text);
} else if ((Sexp_nodes[condition_node].value == SEXP_KNOWN_FALSE) || (Sexp_nodes[condition_node].value == SEXP_NAN_FOREVER)) {
val = SEXP_KNOWN_FALSE; // If we're wasting our time evaluating this ever again, just go ahead and short-circuit.
}
// clear argument, but not list, as we'll need it later
@@ -8951,19 +8962,22 @@ int eval_for_counter(int arg_handler_node, int condition_node)
for (i = counter_start; ((counter_step > 0) ? i <= counter_stop : i >= counter_stop); i += counter_step)
{
sprintf(buf, "%d", i);
argument_vector.push_back(strdup(buf));
argument_vector.push_back(vm_strdup(buf));
}
// test the whole argument vector
num_valid_arguments = test_argument_vector_for_condition(argument_vector, true, condition_node, &num_true, &num_false, &num_known_true, &num_known_false);
while (!argument_vector.empty()) {
vm_free(argument_vector.back());
argument_vector.pop_back();
}
// use the sexp_or algorithm
if (num_known_true)
return SEXP_KNOWN_TRUE;
if (num_known_true || num_true)
return SEXP_TRUE;
else if (num_known_false == num_valid_arguments)
return SEXP_KNOWN_FALSE;
else if (num_true)
return SEXP_TRUE;
else
return SEXP_FALSE;
}
@@ -16541,6 +16555,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
@@ -22216,7 +22231,7 @@ int is_sexp_true(int cur_node, int referenced_node)
{
int result = eval_sexp(cur_node, referenced_node);
return ((result == SEXP_TRUE) || (result == SEXP_KNOWN_TRUE));
return (result == SEXP_TRUE); // note: any SEXP_KNOWN_TRUE result will return SEXP_TRUE
}
@@ -22466,7 +22481,13 @@ int eval_sexp(int cur_node, int referenced_node)
add_to_event_log_buffer(get_operator_index(cur_node), SEXP_KNOWN_FALSE);
}
return SEXP_FALSE;
}
}
else if (Sexp_nodes[cur_node].value == SEXP_NAN_FOREVER) {
if (Log_event) {
add_to_event_log_buffer(get_operator_index(cur_node), SEXP_NAN_FOREVER);
}
return SEXP_FALSE;
}
if (Sexp_nodes[cur_node].first != -1) {
node = CAR(cur_node);
@@ -24647,7 +24668,7 @@ int eval_sexp(int cur_node, int referenced_node)
// if we haven't returned, check the sexp value of the sexpression evaluation. A special
// value of known true or known false means that we should set the sexp.value field for
// short circuit eval (and return that special value as well).
// short circuit eval.
if (sexp_val == SEXP_KNOWN_TRUE) {
Sexp_nodes[cur_node].value = SEXP_KNOWN_TRUE;
return SEXP_TRUE;
@@ -31465,7 +31486,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"
+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
+342 -154
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;
@@ -862,12 +865,17 @@ void init_ship_entry(ship_info *sip)
sip->weapon_model_draw_distance = 200.0f;
sip->ship_recoil_modifier = 1.0f;
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 +956,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 +976,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 +1021,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;
@@ -1420,11 +1433,10 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
stuff_string(sip->short_name, F_NAME, NAME_LENGTH);
else if(first_time)
{
char *srcpos, *srcend, *destpos, *destend;
char *srcpos, *srcend, *destpos;
srcpos = sip->name;
destpos = sip->short_name;
srcend = srcpos + strlen(sip->name);
destend = destpos + sizeof(sip->short_name) - 1;
while(srcpos < srcend)
{
if(*srcpos != ' ')
@@ -1664,6 +1676,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 +2019,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:"))
@@ -2300,12 +2322,21 @@ int parse_ship_values(ship_info* sip, bool first_time, bool replace)
stuff_bool_list(sip->draw_secondary_models, sip->num_secondary_banks);
}
if (optional_string("$Ship Recoil Modifier:")){
stuff_float(&sip->ship_recoil_modifier);
}
if(optional_string("$Shields:")) {
stuff_float(&sip->max_shield_strength);
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 +2386,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 +2704,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 +2763,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 +2938,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 +3216,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 +4020,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 +4116,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 +5106,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 +6194,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;
@@ -6509,7 +6598,7 @@ void ship_add_cockpit_display(cockpit_display_info *display, int cockpit_model_n
return;
}
int i, tm_num, diffuse_target = -1, glow_target = -1, glow_handle = -1, diffuse_handle = -1;
int i, tm_num, glow_target = -1, glow_handle = -1, diffuse_handle = -1;
int w, h;
cockpit_display new_display;
@@ -6520,7 +6609,6 @@ void ship_add_cockpit_display(cockpit_display_info *display, int cockpit_model_n
{
tm_num = pm->maps[i].FindTexture(display->filename);
if ( tm_num >= 0 ) {
diffuse_target = i*TM_NUM_TYPES;
glow_target = i*TM_NUM_TYPES+TM_GLOW_TYPE;
diffuse_handle = pm->maps[i].textures[TM_BASE_TYPE].GetTexture();
@@ -6679,7 +6767,7 @@ void ship_subsystems_delete(ship *shipp)
void ship_delete( object * obj )
{
ship *shipp;
int num, objnum;
int num, objnum __attribute__((__unused__));
num = obj->instance;
Assert( num >= 0);
@@ -6852,24 +6940,24 @@ void ship_actually_depart(int shipnum, int method)
}
// no destruction effects, not for player destruction and multiplayer, only self-destruction
void ship_destroy_instantly(object *ship_obj, int shipnum)
void ship_destroy_instantly(object *ship_objp, int shipnum)
{
Assert(ship_obj->type == OBJ_SHIP);
Assert(!(ship_obj == Player_obj));
Assert(ship_objp->type == OBJ_SHIP);
Assert(!(ship_objp == Player_obj));
Assert(!(Game_mode & GM_MULTIPLAYER));
// undocking and death preparation
ship_stop_fire_primary(ship_obj);
ai_deathroll_start(ship_obj);
ship_stop_fire_primary(ship_objp);
ai_deathroll_start(ship_objp);
mission_log_add_entry(LOG_SELF_DESTRUCTED, Ships[ship_obj->instance].ship_name, NULL );
mission_log_add_entry(LOG_SELF_DESTRUCTED, Ships[ship_objp->instance].ship_name, NULL );
// scripting stuff
Script_system.SetHookObject("Self", ship_obj);
Script_system.RunCondition(CHA_DEATH, 0, NULL, ship_obj);
Script_system.SetHookObject("Self", ship_objp);
Script_system.RunCondition(CHA_DEATH, 0, NULL, ship_objp);
Script_system.RemHookVars(2, "Self", "Killer");
ship_obj->flags |= OF_SHOULD_BE_DEAD;
ship_objp->flags |= OF_SHOULD_BE_DEAD;
ship_cleanup(shipnum,SHIP_DESTROYED);
}
@@ -9184,6 +9272,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)
@@ -9560,8 +9650,12 @@ int ship_launch_countermeasure(object *objp, int rand_val)
// if we have a player ship, then send the fired packet anyway so that the player
// who fired will get his 'out of countermeasures' sound
cmeasure_count = 0;
if ( objp->flags & OF_PLAYER_SHIP ){
goto send_countermeasure_fired;
if (objp->flags & OF_PLAYER_SHIP){
// the new way of doing things
if (Game_mode & GM_MULTIPLAYER){
send_NEW_countermeasure_fired_packet(objp, cmeasure_count, -1);
}
return 0;
}
return 0;
@@ -9584,10 +9678,9 @@ int ship_launch_countermeasure(object *objp, int rand_val)
snd_play_3d( &Snds[Weapon_info[shipp->current_cmeasure].launch_snd], &pos, &View_position );
}
send_countermeasure_fired:
// the new way of doing things
if(Game_mode & GM_MULTIPLAYER){
send_NEW_countermeasure_fired_packet( objp, cmeasure_count, /*arand*/Objects[cobjnum].net_signature );
send_NEW_countermeasure_fired_packet(objp, cmeasure_count, Objects[cobjnum].net_signature);
}
}
@@ -9827,6 +9920,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
@@ -9841,7 +9998,7 @@ int ship_fire_primary(object * obj, int stream_weapons, int force)
ship_weapon *swp;
ship_info *sip;
ai_info *aip;
int weapon, i, j, w, v, weapon_objnum;
int weapon_idx, i, j, w, v, weapon_objnum;
int bank_to_fire, num_fired = 0;
int banks_fired; // used for multiplayer to help determine whether or not to send packet
banks_fired = 0; // used in multiplayer -- bitfield of banks that were fired
@@ -9952,9 +10109,9 @@ int ship_fire_primary(object * obj, int stream_weapons, int force)
bank_to_fire = (swp->current_primary_bank+i) % swp->num_primary_banks;
weapon = swp->primary_bank_weapons[bank_to_fire];
Assert( weapon >= 0 && weapon < MAX_WEAPON_TYPES );
if ( (weapon < 0) || (weapon >= MAX_WEAPON_TYPES) ) {
weapon_idx = swp->primary_bank_weapons[bank_to_fire];
Assert( weapon_idx >= 0 && weapon_idx < MAX_WEAPON_TYPES );
if ( (weapon_idx < 0) || (weapon_idx >= MAX_WEAPON_TYPES) ) {
Int3(); // why would a ship try to fire a weapon that doesn't exist?
continue;
}
@@ -9966,7 +10123,7 @@ int ship_fire_primary(object * obj, int stream_weapons, int force)
continue;
}
weapon_info* winfo_p = &Weapon_info[weapon];
weapon_info* winfo_p = &Weapon_info[weapon_idx];
if (needs_target_pos) {
target_velocity_vec = Objects[aip->target_objnum].phys_info.vel;
@@ -10322,6 +10479,15 @@ int ship_fire_primary(object * obj, int stream_weapons, int force)
// Mark all these weapons as in the same group
int new_group_id = weapon_create_group_id();
vec3d total_impulse;
vec3d *firepoint_list;
size_t current_firepoint = 0;
if (winfo_p->wi_flags3 & WIF3_APPLY_RECOIL){
firepoint_list = new vec3d[numtimes * points];
vm_vec_zero(&total_impulse);
}
for ( w = 0; w < numtimes; w++ ) {
polymodel *weapon_model = NULL;
if(winfo_p->external_model_num >= 0)
@@ -10434,9 +10600,20 @@ int ship_fire_primary(object * obj, int stream_weapons, int force)
firing_orient = obj->orient;
}
if (winfo_p->wi_flags3 & WIF3_APPLY_RECOIL){ // Function to add recoil functionality - DahBlount
vec3d local_impulse = firing_orient.vec.fvec;
float recoil_force = (winfo_p->mass * winfo_p->max_speed * winfo_p->recoil_modifier * sip->ship_recoil_modifier);
firepoint_list[current_firepoint++] = firing_pos;
vm_vec_scale(&local_impulse, (-1 * recoil_force));
vm_vec_add2(&total_impulse, &local_impulse);
}
// create the weapon -- the network signature for multiplayer is created inside
// of weapon_create
weapon_objnum = weapon_create( &firing_pos, &firing_orient, weapon, OBJ_INDEX(obj), new_group_id,
weapon_objnum = weapon_create( &firing_pos, &firing_orient, weapon_idx, OBJ_INDEX(obj), new_group_id,
0, 0, swp->primary_bank_fof_cooldown[bank_to_fire] );
winfo_p = &Weapon_info[Weapons[Objects[weapon_objnum].instance].weapon_info_index];
has_fired = true;
@@ -10481,7 +10658,7 @@ int ship_fire_primary(object * obj, int stream_weapons, int force)
// create the muzzle flash effect
if ( (obj != Player_obj) || (sip->flags2 & SIF2_SHOW_SHIP_MODEL) || (Viewer_mode) ) {
// show the flash only if in not cockpit view, or if "show ship" flag is set
shipfx_flash_create( obj, sip->model_num, &pnt, &obj->orient.vec.fvec, 1, weapon );
shipfx_flash_create( obj, sip->model_num, &pnt, &obj->orient.vec.fvec, 1, weapon_idx );
}
// maybe shudder the ship - if its me
@@ -10497,6 +10674,14 @@ int ship_fire_primary(object * obj, int stream_weapons, int force)
}
swp->external_model_fp_counter[bank_to_fire]++;
}
if (winfo_p->wi_flags3 & WIF3_APPLY_RECOIL){
vec3d avg_firepoint;
vm_vec_avg_n(&avg_firepoint, current_firepoint, firepoint_list);
ship_apply_whack(&total_impulse, &avg_firepoint, obj);
delete[] firepoint_list;
}
}
CLAMP(shipp->weapon_energy, 0.0f, sip->max_weapon_reserve);
@@ -10841,7 +11026,7 @@ extern void ai_maybe_announce_shockwave_weapon(object *firing_objp, int weapon_i
// need to avoid firing when normally called
int ship_fire_secondary( object *obj, int allow_swarm )
{
int n, weapon, j, bank, bank_adjusted, starting_bank_count = -1, num_fired;
int n, weapon_idx, j, bank, bank_adjusted, starting_bank_count = -1, num_fired;
ushort starting_sig = 0;
ship *shipp;
ship_weapon *swp;
@@ -10922,12 +11107,12 @@ int ship_fire_secondary( object *obj, int allow_swarm )
return 0;
}
weapon = swp->secondary_bank_weapons[bank];
weapon_idx = swp->secondary_bank_weapons[bank];
Assert( (swp->secondary_bank_weapons[bank] >= 0) && (swp->secondary_bank_weapons[bank] < MAX_WEAPON_TYPES) );
if((swp->secondary_bank_weapons[bank] < 0) || (swp->secondary_bank_weapons[bank] >= MAX_WEAPON_TYPES)){
return 0;
}
wip = &Weapon_info[weapon];
wip = &Weapon_info[weapon_idx];
if ( MULTIPLAYER_MASTER ) {
starting_sig = multi_get_next_network_signature( MULTI_SIG_NON_PERMANENT );
@@ -11048,11 +11233,11 @@ int ship_fire_secondary( object *obj, int allow_swarm )
float t;
if (Weapon_info[weapon].burst_shots > swp->burst_counter[bank_adjusted]) {
t = Weapon_info[weapon].burst_delay;
if (Weapon_info[weapon_idx].burst_shots > swp->burst_counter[bank_adjusted]) {
t = Weapon_info[weapon_idx].burst_delay;
swp->burst_counter[bank_adjusted]++;
} else {
t = Weapon_info[weapon].fire_wait; // They can fire 5 times a second
t = Weapon_info[weapon_idx].fire_wait; // They can fire 5 times a second
swp->burst_counter[bank_adjusted] = 0;
}
swp->next_secondary_fire_stamp[bank] = timestamp((int) (t * 1000.0f));
@@ -11065,7 +11250,7 @@ int ship_fire_secondary( object *obj, int allow_swarm )
if ( obj == Player_obj )
if ( ship_maybe_play_secondary_fail_sound(wip) ) {
char missile_name[NAME_LENGTH];
strcpy_s(missile_name, Weapon_info[weapon].name);
strcpy_s(missile_name, Weapon_info[weapon_idx].name);
end_string_at_first_hash_symbol(missile_name);
HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Cannot fire %s due to weapons system damage", 489), missile_name);
}
@@ -11161,7 +11346,7 @@ int ship_fire_secondary( object *obj, int allow_swarm )
vm_vec_add(&firing_pos, &missile_point, &obj->pos);
if ( Game_mode & GM_MULTIPLAYER ) {
Assert( Weapon_info[weapon].subtype == WP_MISSILE );
Assert( Weapon_info[weapon_idx].subtype == WP_MISSILE );
}
matrix firing_orient;
@@ -11178,17 +11363,17 @@ int ship_fire_secondary( object *obj, int allow_swarm )
// create the weapon -- for multiplayer, the net_signature is assigned inside
// of weapon_create
weapon_num = weapon_create( &firing_pos, &firing_orient, weapon, OBJ_INDEX(obj), -1, aip->current_target_is_locked);
weapon_num = weapon_create( &firing_pos, &firing_orient, weapon_idx, OBJ_INDEX(obj), -1, aip->current_target_is_locked);
if (weapon_num >= 0) {
weapon = Weapons[Objects[weapon_num].instance].weapon_info_index;
weapon_idx = Weapons[Objects[weapon_num].instance].weapon_info_index;
weapon_set_tracking_info(weapon_num, OBJ_INDEX(obj), aip->target_objnum, aip->current_target_is_locked, aip->targeted_subsys);
has_fired = true;
// create the muzzle flash effect
if ( (obj != Player_obj) || (sip->flags2 & SIF2_SHOW_SHIP_MODEL) || (Viewer_mode) ) {
// show the flash only if in not cockpit view, or if "show ship" flag is set
shipfx_flash_create(obj, sip->model_num, &pnt, &obj->orient.vec.fvec, 0, weapon);
shipfx_flash_create(obj, sip->model_num, &pnt, &obj->orient.vec.fvec, 0, weapon_idx);
}
if((wip->wi_flags & WIF_SHUDDER) && (obj == Player_obj) && !(Game_mode & GM_STANDALONE_SERVER)){
@@ -11211,8 +11396,8 @@ int ship_fire_secondary( object *obj, int allow_swarm )
}
if ( obj == Player_obj ) {
if ( Weapon_info[weapon].launch_snd != -1 ) {
snd_play( &Snds[Weapon_info[weapon].launch_snd], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY );
if ( Weapon_info[weapon_idx].launch_snd != -1 ) {
snd_play( &Snds[Weapon_info[weapon_idx].launch_snd], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY );
swp = &Player_ship->weapons;
if (bank >= 0) {
wip = &Weapon_info[swp->secondary_bank_weapons[bank]];
@@ -11225,8 +11410,8 @@ int ship_fire_secondary( object *obj, int allow_swarm )
}
} else {
if ( Weapon_info[weapon].launch_snd != -1 ) {
snd_play_3d( &Snds[Weapon_info[weapon].launch_snd], &obj->pos, &View_position );
if ( Weapon_info[weapon_idx].launch_snd != -1 ) {
snd_play_3d( &Snds[Weapon_info[weapon_idx].launch_snd], &obj->pos, &View_position );
}
}
@@ -11261,7 +11446,7 @@ done_secondary:
}
// maybe announce a shockwave weapon
ai_maybe_announce_shockwave_weapon(obj, weapon);
ai_maybe_announce_shockwave_weapon(obj, weapon_idx);
}
// if we are out of ammo in this bank then don't carry over firing swarm/corkscrew
@@ -12590,7 +12775,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 +12911,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();
}
@@ -15549,7 +15734,7 @@ void ship_page_in()
// Page in all the ship classes that are used on this level
int num_ship_types_used = 0;
int test_id = -1;
int test_id __attribute__((__unused__)) = -1;
memset( fireball_used, 0, sizeof(int) * MAX_FIREBALL_TYPES );
@@ -17481,28 +17666,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 +17907,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)
@@ -17766,29 +17954,29 @@ bool ship_has_sound(object *objp, GameSoundsIndex id)
/**
* Given a ship with bounding box and a point, find the closest point on the bbox
*
* @param ship_obj Object that has the bounding box (should be a ship)
* @param ship_objp Object that has the bounding box (should be a ship)
* @param start World position of the point being compared
* @param box_pt OUTPUT PARAMETER: closest point on the bbox to start
*
* @return point is inside bbox, TRUE/1
* @return point is outside bbox, FALSE/0
*/
int get_nearest_bbox_point(object *ship_obj, vec3d *start, vec3d *box_pt)
int get_nearest_bbox_point(object *ship_objp, vec3d *start, vec3d *box_pt)
{
vec3d temp, rf_start;
polymodel *pm;
pm = model_get(Ship_info[Ships[ship_obj->instance].ship_info_index].model_num);
pm = model_get(Ship_info[Ships[ship_objp->instance].ship_info_index].model_num);
// get start in ship rf
vm_vec_sub(&temp, start, &ship_obj->pos);
vm_vec_rotate(&rf_start, &temp, &ship_obj->orient);
vm_vec_sub(&temp, start, &ship_objp->pos);
vm_vec_rotate(&rf_start, &temp, &ship_objp->orient);
// find box_pt
int inside = project_point_onto_bbox(&pm->mins, &pm->maxs, &rf_start, &temp);
// get box_pt in world rf
vm_vec_unrotate(box_pt, &temp, &ship_obj->orient);
vm_vec_add2(box_pt, &ship_obj->pos);
vm_vec_unrotate(box_pt, &temp, &ship_objp->orient);
vm_vec_add2(box_pt, &ship_objp->pos);
return inside;
}
+23 -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)
@@ -1293,14 +1300,20 @@ public:
bool draw_secondary_models[MAX_SHIP_SECONDARY_BANKS];
float weapon_model_draw_distance;
// Recoil modifier for the ship
float ship_recoil_modifier;
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 +1333,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 +1386,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 +1413,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 +1433,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 +1609,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);
+84 -84
View File
@@ -78,7 +78,7 @@ void shipfx_remove_submodel_ship_sparks(ship *shipp, int submodel_num)
*
* DKA: 5/26/99 make velocity of debris scale according to size of debris subobject (at least for large subobjects)
*/
void shipfx_subsystem_maybe_create_live_debris(object *ship_obj, ship *ship_p, ship_subsys *subsys, vec3d *exp_center, float exp_mag)
void shipfx_subsystem_maybe_create_live_debris(object *ship_objp, ship *ship_p, ship_subsys *subsys, vec3d *exp_center, float exp_mag)
{
// initializations
polymodel *pm = model_get(Ship_info[ship_p->ship_info_index].model_num);
@@ -94,7 +94,7 @@ void shipfx_subsystem_maybe_create_live_debris(object *ship_obj, ship *ship_p, s
return;
}
ship_model_start(ship_obj);
ship_model_start(ship_objp);
// copy angles
angles copy_angs = pm->submodel[submodel_num].angs;
@@ -111,10 +111,10 @@ void shipfx_subsystem_maybe_create_live_debris(object *ship_obj, ship *ship_p, s
// get the rotvel
void model_get_rotating_submodel_axis(vec3d *model_axis, vec3d *world_axis, int modelnum, int submodel_num, object *obj);
model_get_rotating_submodel_axis(&model_axis, &world_axis, pm->id, submodel_num, ship_obj);
model_get_rotating_submodel_axis(&model_axis, &world_axis, pm->id, submodel_num, ship_objp);
vm_vec_copy_scale(&rotvel, &world_axis, sii->cur_turn_rate);
model_find_world_point(&world_axis_pt, &sii->pt_on_axis, pm->id, submodel_num, &ship_obj->orient, &ship_obj->pos);
model_find_world_point(&world_axis_pt, &sii->pt_on_axis, pm->id, submodel_num, &ship_objp->orient, &ship_objp->pos);
vm_quaternion_rotate(&m_rot, vm_vec_mag((vec3d*)&sii->angs), &model_axis);
} else {
@@ -131,27 +131,27 @@ void shipfx_subsystem_maybe_create_live_debris(object *ship_obj, ship *ship_p, s
// get start world pos
vm_vec_zero(&start_world_pos);
model_find_world_point(&start_world_pos, &pm->submodel[live_debris_submodel].offset, pm->id, live_debris_submodel, &ship_obj->orient, &ship_obj->pos );
model_find_world_point(&start_world_pos, &pm->submodel[live_debris_submodel].offset, pm->id, live_debris_submodel, &ship_objp->orient, &ship_objp->pos );
// convert to model coord of underlying submodel
// set angle to zero
pm->submodel[submodel_num].angs = zero_angs;
world_find_model_point(&start_model_pos, &start_world_pos, pm, submodel_num, &ship_obj->orient, &ship_obj->pos);
world_find_model_point(&start_model_pos, &start_world_pos, pm, submodel_num, &ship_objp->orient, &ship_objp->pos);
// rotate from submodel coord to world coords
// reset angle to current angle
pm->submodel[submodel_num].angs = copy_angs;
model_find_world_point(&end_world_pos, &start_model_pos, pm->id, submodel_num, &ship_obj->orient, &ship_obj->pos);
model_find_world_point(&end_world_pos, &start_model_pos, pm->id, submodel_num, &ship_objp->orient, &ship_objp->pos);
int fireball_type = fireball_ship_explosion_type(&Ship_info[ship_p->ship_info_index]);
if(fireball_type < 0) {
fireball_type = FIREBALL_EXPLOSION_MEDIUM;
}
// create fireball here.
fireball_create(&end_world_pos, fireball_type, FIREBALL_MEDIUM_EXPLOSION, OBJ_INDEX(ship_obj), pm->submodel[live_debris_submodel].rad);
fireball_create(&end_world_pos, fireball_type, FIREBALL_MEDIUM_EXPLOSION, OBJ_INDEX(ship_objp), pm->submodel[live_debris_submodel].rad);
// create debris
live_debris_obj = debris_create(ship_obj, pm->id, live_debris_submodel, &end_world_pos, exp_center, 1, exp_mag);
live_debris_obj = debris_create(ship_objp, pm->id, live_debris_submodel, &end_world_pos, exp_center, 1, exp_mag);
// only do if debris is created
if (live_debris_obj) {
@@ -177,7 +177,7 @@ void shipfx_subsystem_maybe_create_live_debris(object *ship_obj, ship *ship_p, s
// Add radial velocity (at least as large as exp velocity)
vec3d temp_vel; // explosion velocity with ship_obj velocity removed
vm_vec_sub(&temp_vel, &live_debris_obj->phys_info.vel, &ship_obj->phys_info.vel);
vm_vec_sub(&temp_vel, &live_debris_obj->phys_info.vel, &ship_objp->phys_info.vel);
// find magnitudes of radial and temp velocity
float vel_mag = vm_vec_mag(&temp_vel);
@@ -202,8 +202,8 @@ void shipfx_subsystem_maybe_create_live_debris(object *ship_obj, ship *ship_p, s
}
// scale up speed of debris if ship_obj > 125, but not for knossos
if (ship_obj->radius > 250 && !(Ship_info[ship_p->ship_info_index].flags & SIF_KNOSSOS_DEVICE)) {
vm_vec_scale(&live_debris_obj->phys_info.vel, ship_obj->radius/250.0f);
if (ship_objp->radius > 250 && !(Ship_info[ship_p->ship_info_index].flags & SIF_KNOSSOS_DEVICE)) {
vm_vec_scale(&live_debris_obj->phys_info.vel, ship_objp->radius/250.0f);
}
}
@@ -211,7 +211,7 @@ void shipfx_subsystem_maybe_create_live_debris(object *ship_obj, ship *ship_p, s
}
}
ship_model_stop(ship_obj);
ship_model_stop(ship_objp);
}
void set_ship_submodel_as_blown_off(ship *shipp, char *name)
@@ -239,12 +239,12 @@ void set_ship_submodel_as_blown_off(ship *shipp, char *name)
* Create debris for ship submodel which has live debris (at ship death)
* when ship submodel has not already been blown off (and hence liberated live debris)
*/
void shipfx_maybe_create_live_debris_at_ship_death( object *ship_obj )
void shipfx_maybe_create_live_debris_at_ship_death( object *ship_objp )
{
// if ship has live debris, detonate that subsystem now
// search for any live debris
ship *shipp = &Ships[ship_obj->instance];
ship *shipp = &Ships[ship_objp->instance];
polymodel *pm = model_get(Ship_info[shipp->ship_info_index].model_num);
// no subsystems -> no live debris.
@@ -263,7 +263,7 @@ void shipfx_maybe_create_live_debris_at_ship_death( object *ship_obj )
Assert(parent != -1);
// set model values only once (esp blown off)
ship_model_start(ship_obj);
ship_model_start(ship_objp);
// check if already blown off (ship model set)
if ( !pm->submodel[parent].blown_off ) {
@@ -281,14 +281,14 @@ void shipfx_maybe_create_live_debris_at_ship_death( object *ship_obj )
if (pss != NULL) {
if (pss->system_info != NULL) {
vec3d exp_center, tmp = ZERO_VECTOR;
model_find_world_point(&exp_center, &tmp, pm->id, parent, &ship_obj->orient, &ship_obj->pos );
model_find_world_point(&exp_center, &tmp, pm->id, parent, &ship_objp->orient, &ship_objp->pos );
// if not blown off, blow it off
shipfx_subsystem_maybe_create_live_debris(ship_obj, shipp, pss, &exp_center, 3.0f);
shipfx_subsystem_maybe_create_live_debris(ship_objp, shipp, pss, &exp_center, 3.0f);
// now set subsystem as blown off, so we only get one copy
pm->submodel[parent].blown_off = 1;
set_ship_submodel_as_blown_off(&Ships[ship_obj->instance], pss->system_info->subobj_name);
set_ship_submodel_as_blown_off(&Ships[ship_objp->instance], pss->system_info->subobj_name);
}
}
}
@@ -296,36 +296,36 @@ void shipfx_maybe_create_live_debris_at_ship_death( object *ship_obj )
}
// clean up
ship_model_stop(ship_obj);
ship_model_stop(ship_objp);
}
void shipfx_blow_off_subsystem(object *ship_obj,ship *ship_p,ship_subsys *subsys, vec3d *exp_center, bool no_explosion)
void shipfx_blow_off_subsystem(object *ship_objp, ship *ship_p,ship_subsys *subsys, vec3d *exp_center, bool no_explosion)
{
vec3d subobj_pos;
int model_num = Ship_info[ship_p->ship_info_index].model_num;
model_subsystem *psub = subsys->system_info;
get_subsystem_world_pos(ship_obj, subsys, &subobj_pos);
get_subsystem_world_pos(ship_objp, subsys, &subobj_pos);
// get rid of sparks on submodel that is destroyed
shipfx_remove_submodel_ship_sparks(ship_p, psub->subobj_num);
// create debris shards
if (!(subsys->flags & SSF_VANISHED) && !no_explosion) {
shipfx_blow_up_model(ship_obj, model_num, psub->subobj_num, 50, &subobj_pos );
shipfx_blow_up_model(ship_objp, model_num, psub->subobj_num, 50, &subobj_pos );
// create live debris objects, if any
// TODO: some MULITPLAYER implcations here!!
shipfx_subsystem_maybe_create_live_debris(ship_obj, ship_p, subsys, exp_center, 1.0f);
shipfx_subsystem_maybe_create_live_debris(ship_objp, ship_p, subsys, exp_center, 1.0f);
int fireball_type = fireball_ship_explosion_type(&Ship_info[ship_p->ship_info_index]);
if(fireball_type < 0) {
fireball_type = FIREBALL_EXPLOSION_MEDIUM;
}
// create first fireball
fireball_create( &subobj_pos, fireball_type, FIREBALL_MEDIUM_EXPLOSION, OBJ_INDEX(ship_obj), psub->radius );
fireball_create( &subobj_pos, fireball_type, FIREBALL_MEDIUM_EXPLOSION, OBJ_INDEX(ship_objp), psub->radius );
}
}
@@ -1687,29 +1687,29 @@ static int get_split_ship()
}
static void maybe_fireball_wipe(clip_ship* half_ship, int* sound_handle);
static void split_ship_init( ship* shipp, split_ship* split_ship )
static void split_ship_init( ship* shipp, split_ship* split_shipp )
{
object* parent_ship_obj = &Objects[shipp->objnum];
matrix* orient = &parent_ship_obj->orient;
for (int ii=0; ii<NUM_SUB_EXPL_HANDLES; ++ii) {
split_ship->sound_handle[ii] = shipp->sub_expl_sound_handle[ii];
split_shipp->sound_handle[ii] = shipp->sub_expl_sound_handle[ii];
}
// play 3d sound for shockwave explosion
snd_play_3d( &Snds[SND_SHOCKWAVE_EXPLODE], &parent_ship_obj->pos, &View_position, 0.0f, NULL, 0, 1.0f, SND_PRIORITY_SINGLE_INSTANCE, NULL, 3.0f );
// initialize both ships
split_ship->front_ship.parent_obj = parent_ship_obj;
split_ship->back_ship.parent_obj = parent_ship_obj;
split_ship->explosion_flash_timestamp = timestamp((int)(0.00075f*parent_ship_obj->radius));
split_ship->explosion_flash_started = 0;
split_ship->front_ship.orient = *orient;
split_ship->back_ship.orient = *orient;
split_ship->front_ship.next_fireball = timestamp_rand(0, 100);
split_ship->back_ship.next_fireball = timestamp_rand(0, 100);
split_shipp->front_ship.parent_obj = parent_ship_obj;
split_shipp->back_ship.parent_obj = parent_ship_obj;
split_shipp->explosion_flash_timestamp = timestamp((int)(0.00075f*parent_ship_obj->radius));
split_shipp->explosion_flash_started = 0;
split_shipp->front_ship.orient = *orient;
split_shipp->back_ship.orient = *orient;
split_shipp->front_ship.next_fireball = timestamp_rand(0, 100);
split_shipp->back_ship.next_fireball = timestamp_rand(0, 100);
split_ship->front_ship.clip_plane_norm = vmd_z_vector;
vm_vec_copy_scale(&split_ship->back_ship.clip_plane_norm, &vmd_z_vector, -1.0f);
split_shipp->front_ship.clip_plane_norm = vmd_z_vector;
vm_vec_copy_scale(&split_shipp->back_ship.clip_plane_norm, &vmd_z_vector, -1.0f);
// find the point at which the ship splits (relative to its pivot)
polymodel* pm = model_get(Ship_info[shipp->ship_info_index].model_num);
@@ -1721,18 +1721,18 @@ static void split_ship_init( ship* shipp, split_ship* split_ship )
init_clip_plane_dist = 0.5f * (0.5f - frand())*pm->core_radius;
}
split_ship->back_ship.cur_clip_plane_pt = init_clip_plane_dist;
split_ship->front_ship.cur_clip_plane_pt = init_clip_plane_dist;
split_shipp->back_ship.cur_clip_plane_pt = init_clip_plane_dist;
split_shipp->front_ship.cur_clip_plane_pt = init_clip_plane_dist;
float dist;
dist = (split_ship->front_ship.cur_clip_plane_pt+pm->maxs.xyz.z)/2.0f;
vm_vec_copy_scale(&split_ship->front_ship.local_pivot, &orient->vec.fvec, dist);
vm_vec_make(&split_ship->front_ship.model_center_disp_to_orig_center, 0.0f, 0.0f, -dist);
dist = (split_ship->back_ship.cur_clip_plane_pt +pm->mins.xyz.z)/2.0f;
vm_vec_copy_scale(&split_ship->back_ship.local_pivot, &orient->vec.fvec, dist);
vm_vec_make(&split_ship->back_ship.model_center_disp_to_orig_center, 0.0f, 0.0f, -dist);
vm_vec_add2(&split_ship->front_ship.local_pivot, &parent_ship_obj->pos );
vm_vec_add2(&split_ship->back_ship.local_pivot, &parent_ship_obj->pos );
dist = (split_shipp->front_ship.cur_clip_plane_pt+pm->maxs.xyz.z)/2.0f;
vm_vec_copy_scale(&split_shipp->front_ship.local_pivot, &orient->vec.fvec, dist);
vm_vec_make(&split_shipp->front_ship.model_center_disp_to_orig_center, 0.0f, 0.0f, -dist);
dist = (split_shipp->back_ship.cur_clip_plane_pt +pm->mins.xyz.z)/2.0f;
vm_vec_copy_scale(&split_shipp->back_ship.local_pivot, &orient->vec.fvec, dist);
vm_vec_make(&split_shipp->back_ship.model_center_disp_to_orig_center, 0.0f, 0.0f, -dist);
vm_vec_add2(&split_shipp->front_ship.local_pivot, &parent_ship_obj->pos );
vm_vec_add2(&split_shipp->back_ship.local_pivot, &parent_ship_obj->pos );
// find which debris pieces are in the front and back split ships
for (int i=0; i<pm->num_debris_objects; i++ ) {
@@ -1742,30 +1742,30 @@ static void split_ship_init( ship* shipp, split_ship* split_ship )
// tmp is world position, temp_pos is world_pivot, tmp1 is offset from world_pivot (in ship local coord)
model_find_world_point(&tmp, &tmp1, pm->id, -1, &vmd_identity_matrix, &temp_pos );
if (tmp.xyz.z > init_clip_plane_dist) {
split_ship->front_ship.draw_debris[i] = DEBRIS_DRAW;
split_ship->back_ship.draw_debris[i] = DEBRIS_NONE;
split_shipp->front_ship.draw_debris[i] = DEBRIS_DRAW;
split_shipp->back_ship.draw_debris[i] = DEBRIS_NONE;
} else {
split_ship->front_ship.draw_debris[i] = DEBRIS_NONE;
split_ship->back_ship.draw_debris[i] = DEBRIS_DRAW;
split_shipp->front_ship.draw_debris[i] = DEBRIS_NONE;
split_shipp->back_ship.draw_debris[i] = DEBRIS_DRAW;
}
}
// set up physics
physics_init( &split_ship->front_ship.phys_info );
physics_init( &split_ship->back_ship.phys_info );
split_ship->front_ship.phys_info.flags |= (PF_ACCELERATES | PF_DEAD_DAMP);
split_ship->back_ship.phys_info.flags |= (PF_ACCELERATES | PF_DEAD_DAMP);
split_ship->front_ship.phys_info.side_slip_time_const = 10000.0f;
split_ship->back_ship.phys_info.side_slip_time_const = 10000.0f;
split_ship->front_ship.phys_info.rotdamp = 10000.0f;
split_ship->back_ship.phys_info.rotdamp = 10000.0f;
physics_init( &split_shipp->front_ship.phys_info );
physics_init( &split_shipp->back_ship.phys_info );
split_shipp->front_ship.phys_info.flags |= (PF_ACCELERATES | PF_DEAD_DAMP);
split_shipp->back_ship.phys_info.flags |= (PF_ACCELERATES | PF_DEAD_DAMP);
split_shipp->front_ship.phys_info.side_slip_time_const = 10000.0f;
split_shipp->back_ship.phys_info.side_slip_time_const = 10000.0f;
split_shipp->front_ship.phys_info.rotdamp = 10000.0f;
split_shipp->back_ship.phys_info.rotdamp = 10000.0f;
// set up explosion vel and relative velocities (assuming mass depends on length)
float front_length = pm->maxs.xyz.z - split_ship->front_ship.cur_clip_plane_pt;
float back_length = split_ship->back_ship.cur_clip_plane_pt - pm->mins.xyz.z;
float front_length = pm->maxs.xyz.z - split_shipp->front_ship.cur_clip_plane_pt;
float back_length = split_shipp->back_ship.cur_clip_plane_pt - pm->mins.xyz.z;
float ship_length = front_length + back_length;
split_ship->front_ship.length_left = front_length;
split_ship->back_ship.length_left = back_length;
split_shipp->front_ship.length_left = front_length;
split_shipp->back_ship.length_left = back_length;
float expl_length_scale = (ship_length - 200.0f) / 2000.0f;
// s_r_f effects speed of "wipe" and rotvel
@@ -1773,8 +1773,8 @@ static void split_ship_init( ship* shipp, split_ship* split_ship )
float explosion_time = (3.0f + expl_length_scale + (frand()-0.5f)) * speed_reduction_factor;
float long_length = MAX(front_length, back_length);
float expl_vel = long_length / explosion_time;
split_ship->front_ship.explosion_vel = expl_vel;
split_ship->back_ship.explosion_vel = -expl_vel;
split_shipp->front_ship.explosion_vel = expl_vel;
split_shipp->back_ship.explosion_vel = -expl_vel;
float rel_vel = (0.6f + 0.2f*frand()) * expl_vel * speed_reduction_factor;
float front_vel = rel_vel * back_length / ship_length;
@@ -1786,26 +1786,26 @@ static void split_ship_init( ship* shipp, split_ship* split_ship )
rotvel.xyz.z = 0.0f;
vm_vec_normalize(&rotvel);
vm_vec_scale(&rotvel, 0.15f / speed_reduction_factor);
split_ship->front_ship.phys_info.rotvel = rotvel;
vm_vec_copy_scale(&split_ship->back_ship.phys_info.rotvel, &rotvel, -(front_length*front_length)/(back_length*back_length));
split_ship->front_ship.phys_info.rotvel.xyz.z = parent_ship_obj->phys_info.rotvel.xyz.z;
split_ship->back_ship.phys_info.rotvel.xyz.z = parent_ship_obj->phys_info.rotvel.xyz.z;
split_shipp->front_ship.phys_info.rotvel = rotvel;
vm_vec_copy_scale(&split_shipp->back_ship.phys_info.rotvel, &rotvel, -(front_length*front_length)/(back_length*back_length));
split_shipp->front_ship.phys_info.rotvel.xyz.z = parent_ship_obj->phys_info.rotvel.xyz.z;
split_shipp->back_ship.phys_info.rotvel.xyz.z = parent_ship_obj->phys_info.rotvel.xyz.z;
// modify vel of each split ship based on rotvel of parent ship obj
vec3d temp_rotvel = parent_ship_obj->phys_info.rotvel;
temp_rotvel.xyz.z = 0.0f;
vec3d vel_from_rotvel;
vm_vec_crossprod(&vel_from_rotvel, &temp_rotvel, &split_ship->front_ship.local_pivot);
vm_vec_crossprod(&vel_from_rotvel, &temp_rotvel, &split_ship->back_ship.local_pivot);
vm_vec_crossprod(&vel_from_rotvel, &temp_rotvel, &split_shipp->front_ship.local_pivot);
vm_vec_crossprod(&vel_from_rotvel, &temp_rotvel, &split_shipp->back_ship.local_pivot);
// set up velocity and make initial fireballs and particles
split_ship->front_ship.phys_info.vel = parent_ship_obj->phys_info.vel;
split_ship->back_ship.phys_info.vel = parent_ship_obj->phys_info.vel;
maybe_fireball_wipe(&split_ship->front_ship, (int*)&split_ship->sound_handle);
maybe_fireball_wipe(&split_ship->back_ship, (int*)&split_ship->sound_handle);
vm_vec_scale_add2(&split_ship->front_ship.phys_info.vel, &orient->vec.fvec, front_vel);
vm_vec_scale_add2(&split_ship->back_ship.phys_info.vel, &orient->vec.fvec, back_vel);
split_shipp->front_ship.phys_info.vel = parent_ship_obj->phys_info.vel;
split_shipp->back_ship.phys_info.vel = parent_ship_obj->phys_info.vel;
maybe_fireball_wipe(&split_shipp->front_ship, (int*)&split_shipp->sound_handle);
maybe_fireball_wipe(&split_shipp->back_ship, (int*)&split_shipp->sound_handle);
vm_vec_scale_add2(&split_shipp->front_ship.phys_info.vel, &orient->vec.fvec, front_vel);
vm_vec_scale_add2(&split_shipp->back_ship.phys_info.vel, &orient->vec.fvec, back_vel);
// HANDLE LIVE DEBRIS - blow off if not already gone
shipfx_maybe_create_live_debris_at_ship_death( parent_ship_obj );
@@ -1930,7 +1930,7 @@ void shipfx_debris_limit_speed(debris *db, ship *shipp)
if(db == NULL || shipp == NULL)
return;
object *ship_obj = &Objects[shipp->objnum];
object *ship_objp = &Objects[shipp->objnum];
physics_info *pi = &Objects[db->objnum].phys_info;
ship_info *sip = &Ship_info[shipp->ship_info_index];
@@ -1945,7 +1945,7 @@ void shipfx_debris_limit_speed(debris *db, ship *shipp)
}
else
{
vm_vec_copy_scale(&pi->vel, &ship_obj->orient.vec.fvec, debris_speed);
vm_vec_copy_scale(&pi->vel, &ship_objp->orient.vec.fvec, debris_speed);
}
}
else if(sip->debris_min_speed >= 0.0f)
@@ -1959,7 +1959,7 @@ void shipfx_debris_limit_speed(debris *db, ship *shipp)
}
else
{
vm_vec_copy_scale(&pi->vel, &ship_obj->orient.vec.fvec, sip->debris_min_speed);
vm_vec_copy_scale(&pi->vel, &ship_objp->orient.vec.fvec, sip->debris_min_speed);
}
}
}
@@ -1974,7 +1974,7 @@ void shipfx_debris_limit_speed(debris *db, ship *shipp)
}
else
{
vm_vec_copy_scale(&pi->vel, &ship_obj->orient.vec.fvec, sip->debris_max_speed);
vm_vec_copy_scale(&pi->vel, &ship_objp->orient.vec.fvec, sip->debris_max_speed);
}
}
}
@@ -1991,7 +1991,7 @@ void shipfx_debris_limit_speed(debris *db, ship *shipp)
}
else
{
vm_vec_copy_scale(&pi->rotvel, &ship_obj->orient.vec.uvec, debris_rotspeed);
vm_vec_copy_scale(&pi->rotvel, &ship_objp->orient.vec.uvec, debris_rotspeed);
}
}
else if(sip->debris_min_rotspeed >= 0.0f)
@@ -2005,7 +2005,7 @@ void shipfx_debris_limit_speed(debris *db, ship *shipp)
}
else
{
vm_vec_copy_scale(&pi->rotvel, &ship_obj->orient.vec.uvec, sip->debris_min_rotspeed);
vm_vec_copy_scale(&pi->rotvel, &ship_objp->orient.vec.uvec, sip->debris_min_rotspeed);
}
}
}
@@ -2021,7 +2021,7 @@ void shipfx_debris_limit_speed(debris *db, ship *shipp)
}
else
{
vm_vec_copy_scale(&pi->rotvel, &ship_obj->orient.vec.uvec, sip->debris_max_rotspeed);
vm_vec_copy_scale(&pi->rotvel, &ship_objp->orient.vec.uvec, sip->debris_max_rotspeed);
}
}
}
+64 -64
View File
@@ -1660,12 +1660,12 @@ int ds_get_channel(int sig)
/**
* @todo Documentation
*/
int ds_is_channel_playing(int channel)
int ds_is_channel_playing(int channel_id)
{
if ( Channels[channel].source_id != 0 ) {
if ( Channels[channel_id].source_id != 0 ) {
ALint status;
OpenAL_ErrorPrint( alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status) );
OpenAL_ErrorPrint( alGetSourcei(Channels[channel_id].source_id, AL_SOURCE_STATE, &status) );
return (status == AL_PLAYING);
}
@@ -1676,10 +1676,10 @@ int ds_is_channel_playing(int channel)
/**
* @todo Documentation
*/
void ds_stop_channel(int channel)
void ds_stop_channel(int channel_id)
{
if ( Channels[channel].source_id != 0 ) {
OpenAL_ErrorPrint( alSourceStop(Channels[channel].source_id) );
if ( Channels[channel_id].source_id != 0 ) {
OpenAL_ErrorPrint( alSourceStop(Channels[channel_id].source_id) );
}
}
@@ -1701,13 +1701,13 @@ void ds_stop_channel_all()
* @brief Set the volume for a channel. The volume is expected to be in linear scale
* @details If the sound is a 3D sound buffer, this is like re-establishing the maximum volume.
*/
void ds_set_volume( int channel, float vol )
void ds_set_volume( int channel_id, float vol )
{
if ( (channel < 0) || (channel >= MAX_CHANNELS) ) {
if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
return;
}
ALuint source_id = Channels[channel].source_id;
ALuint source_id = Channels[channel_id].source_id;
if (source_id != 0) {
CAP(vol, 0.0f, 1.0f);
@@ -1718,39 +1718,39 @@ void ds_set_volume( int channel, float vol )
/**
* Set the pan for a channel. The pan is expected to be in DirectSound units
*/
void ds_set_pan( int channel, float pan )
void ds_set_pan( int channel_id, float pan )
{
if ( (channel < 0) || (channel >= MAX_CHANNELS) ) {
if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
return;
}
ALint state;
OpenAL_ErrorCheck( alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &state), return );
OpenAL_ErrorCheck( alGetSourcei(Channels[channel_id].source_id, AL_SOURCE_STATE, &state), return );
if (state == AL_PLAYING) {
//OpenAL_ErrorPrint( alSourcei(Channels[channel].source_id, AL_SOURCE_RELATIVE, AL_TRUE) );
OpenAL_ErrorPrint( alSource3f(Channels[channel].source_id, AL_POSITION, pan, 0.0f, 1.0f) );
//OpenAL_ErrorPrint( alSourcei(Channels[channel_id].source_id, AL_SOURCE_RELATIVE, AL_TRUE) );
OpenAL_ErrorPrint( alSource3f(Channels[channel_id].source_id, AL_POSITION, pan, 0.0f, 1.0f) );
}
}
/**
* Get the pitch of a channel
*/
int ds_get_pitch(int channel)
int ds_get_pitch(int channel_id)
{
ALint status;
ALfloat alpitch = 0;
int pitch;
if ( (channel < 0) || (channel >= MAX_CHANNELS) ) {
if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
return -1;
}
OpenAL_ErrorCheck( alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status), return -1 );
OpenAL_ErrorCheck( alGetSourcei(Channels[channel_id].source_id, AL_SOURCE_STATE, &status), return -1 );
if (status == AL_PLAYING) {
OpenAL_ErrorPrint( alGetSourcef(Channels[channel].source_id, AL_PITCH, &alpitch) );
OpenAL_ErrorPrint( alGetSourcef(Channels[channel_id].source_id, AL_PITCH, &alpitch) );
}
// convert OpenAL values to DirectSound values and return
@@ -1762,11 +1762,11 @@ int ds_get_pitch(int channel)
/**
* Set the pitch of a channel
*/
void ds_set_pitch(int channel, int pitch)
void ds_set_pitch(int channel_id, int pitch)
{
ALint status;
if ( (channel < 0) || (channel >= MAX_CHANNELS) ) {
if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
return;
}
@@ -1778,24 +1778,24 @@ void ds_set_pitch(int channel, int pitch)
pitch = MAX_PITCH;
}
OpenAL_ErrorCheck( alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status), return );
OpenAL_ErrorCheck( alGetSourcei(Channels[channel_id].source_id, AL_SOURCE_STATE, &status), return );
if (status == AL_PLAYING) {
ALfloat alpitch = log10f((float)pitch) - 2.0f;
OpenAL_ErrorPrint( alSourcef(Channels[channel].source_id, AL_PITCH, alpitch) );
OpenAL_ErrorPrint( alSourcef(Channels[channel_id].source_id, AL_PITCH, alpitch) );
}
}
/**
* @todo Documentation
*/
void ds_chg_loop_status(int channel, int loop)
void ds_chg_loop_status(int channel_id, int loop)
{
if ( (channel < 0) || (channel >= MAX_CHANNELS) ) {
if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
return;
}
ALuint source_id = Channels[channel].source_id;
ALuint source_id = Channels[channel_id].source_id;
OpenAL_ErrorPrint( alSourcei(source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE) );
}
@@ -1818,99 +1818,99 @@ void ds_chg_loop_status(int channel, int loop)
*/
int ds3d_play(int sid, int snd_id, vec3d *pos, vec3d *vel, float min, float max, int looping, float max_volume, float estimated_vol, int priority )
{
int channel;
int channel_id;
if (!ds_initialized) {
return -1;
}
channel = ds_get_free_channel(estimated_vol, snd_id, priority);
channel_id = ds_get_free_channel(estimated_vol, snd_id, priority);
if (channel < 0) {
if (channel_id < 0) {
return -1;
}
if ( Channels[channel].source_id == 0 ) {
if ( Channels[channel_id].source_id == 0 ) {
return -1;
}
// set up 3D sound data here
ds3d_update_buffer(channel, min, max, pos, vel);
ds3d_update_buffer(channel_id, min, max, pos, vel);
OpenAL_ErrorPrint( alSourcef(Channels[channel].source_id, AL_PITCH, 1.0f) );
OpenAL_ErrorPrint( alSourcef(Channels[channel_id].source_id, AL_PITCH, 1.0f) );
OpenAL_ErrorPrint( alSourcef(Channels[channel].source_id, AL_GAIN, max_volume) );
OpenAL_ErrorPrint( alSourcef(Channels[channel_id].source_id, AL_GAIN, max_volume) );
ALint status;
OpenAL_ErrorCheck( alGetSourcei(Channels[channel].source_id, AL_SOURCE_STATE, &status), return -1 );
OpenAL_ErrorCheck( alGetSourcei(Channels[channel_id].source_id, AL_SOURCE_STATE, &status), return -1 );
if (status == AL_PLAYING) {
OpenAL_ErrorPrint( alSourceStop(Channels[channel].source_id) );
OpenAL_ErrorPrint( alSourceStop(Channels[channel_id].source_id) );
}
OpenAL_ErrorCheck( alSourcei(Channels[channel].source_id, AL_BUFFER, sound_buffers[sid].buf_id), return -1 );
OpenAL_ErrorCheck( alSourcei(Channels[channel_id].source_id, AL_BUFFER, sound_buffers[sid].buf_id), return -1 );
if (Ds_eax_inited) {
OpenAL_ErrorPrint( alSource3i(Channels[channel].source_id, AL_AUXILIARY_SEND_FILTER, AL_EFX_aux_id, 0, AL_FILTER_NULL) );
OpenAL_ErrorPrint( alSource3i(Channels[channel_id].source_id, AL_AUXILIARY_SEND_FILTER, AL_EFX_aux_id, 0, AL_FILTER_NULL) );
}
OpenAL_ErrorPrint( alSourcei(Channels[channel].source_id, AL_SOURCE_RELATIVE, AL_FALSE) );
OpenAL_ErrorPrint( alSourcei(Channels[channel_id].source_id, AL_SOURCE_RELATIVE, AL_FALSE) );
OpenAL_ErrorPrint( alSourcei(Channels[channel].source_id, AL_LOOPING, (looping) ? AL_TRUE : AL_FALSE) );
OpenAL_ErrorPrint( alSourcei(Channels[channel_id].source_id, AL_LOOPING, (looping) ? AL_TRUE : AL_FALSE) );
OpenAL_ErrorPrint( alSourcePlay(Channels[channel].source_id) );
OpenAL_ErrorPrint( alSourcePlay(Channels[channel_id].source_id) );
sound_buffers[sid].channel_id = channel;
sound_buffers[sid].channel_id = channel_id;
Channels[channel].sid = sid;
Channels[channel].snd_id = snd_id;
Channels[channel].sig = channel_next_sig++;
Channels[channel].last_position = 0;
Channels[channel].is_voice_msg = false;
Channels[channel].vol = max_volume;
Channels[channel].looping = looping;
Channels[channel].priority = priority;
Channels[channel_id].sid = sid;
Channels[channel_id].snd_id = snd_id;
Channels[channel_id].sig = channel_next_sig++;
Channels[channel_id].last_position = 0;
Channels[channel_id].is_voice_msg = false;
Channels[channel_id].vol = max_volume;
Channels[channel_id].looping = looping;
Channels[channel_id].priority = priority;
if (channel_next_sig < 0 ) {
channel_next_sig = 1;
}
return Channels[channel].sig;
return Channels[channel_id].sig;
}
/**
* @todo Documentation
*/
void ds_set_position(int channel, unsigned int offset)
void ds_set_position(int channel_id, unsigned int offset)
{
if ( (channel < 0) || (channel >= MAX_CHANNELS) ) {
if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
return;
}
OpenAL_ErrorPrint( alSourcei(Channels[channel].source_id, AL_BYTE_OFFSET, offset) );
OpenAL_ErrorPrint( alSourcei(Channels[channel_id].source_id, AL_BYTE_OFFSET, offset) );
}
/**
* @todo Documentation
*/
unsigned int ds_get_play_position(int channel)
unsigned int ds_get_play_position(int channel_id)
{
if ( (channel < 0) || (channel >= MAX_CHANNELS) ) {
if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
return 0;
}
ALint pos = -1;
int sid = Channels[channel].sid;
int sid = Channels[channel_id].sid;
if ( (sid < 0) || ((size_t)sid >= sound_buffers.size()) ) {
return 0;
}
if (AL_play_position) {
OpenAL_ErrorPrint( alGetSourcei(Channels[channel].source_id, AL_BYTE_LOKI, &pos) );
OpenAL_ErrorPrint( alGetSourcei(Channels[channel_id].source_id, AL_BYTE_LOKI, &pos) );
if ( pos < 0 ) {
pos = 0;
@@ -1925,7 +1925,7 @@ unsigned int ds_get_play_position(int channel)
pos = (ALint)(pos * ((float)sound_buffers[sid].nbytes / size));
}
} else {
OpenAL_ErrorPrint( alGetSourcei(Channels[channel].source_id, AL_BYTE_OFFSET, &pos) );
OpenAL_ErrorPrint( alGetSourcei(Channels[channel_id].source_id, AL_BYTE_OFFSET, &pos) );
if (pos < 0) {
pos = 0;
@@ -1938,7 +1938,7 @@ unsigned int ds_get_play_position(int channel)
/**
* @todo Documentation
*/
unsigned int ds_get_write_position(int channel)
unsigned int ds_get_write_position(int channel_id)
{
return 0;
}
@@ -1946,13 +1946,13 @@ unsigned int ds_get_write_position(int channel)
/**
* @todo Documentation
*/
int ds_get_channel_size(int channel)
int ds_get_channel_size(int channel_id)
{
if ( (channel < 0) || (channel >= MAX_CHANNELS) ) {
if ( (channel_id < 0) || (channel_id >= MAX_CHANNELS) ) {
return 0;
}
int sid = Channels[channel].sid;
int sid = Channels[channel_id].sid;
if ( (sid < 0) || ((size_t)sid >= sound_buffers.size()) ) {
return 0;
@@ -2408,10 +2408,10 @@ void ds_do_frame()
/**
* Given a valid channel return the sound id
*/
int ds_get_sound_id(int channel)
int ds_get_sound_id(int channel_id)
{
Assert( channel >= 0 );
Assert( channel_id >= 0 );
return Channels[channel].snd_id;
return Channels[channel_id].snd_id;
}
+3 -3
View File
@@ -32,18 +32,18 @@
// -1 => failure
//
//
int ds3d_update_buffer(int channel, float min, float max, vec3d *pos, vec3d *vel)
int ds3d_update_buffer(int channel_id, float min, float max, vec3d *pos, vec3d *vel)
{
if (Cmdline_no_3d_sound) {
nprintf(("Sound", "Aborting ds3d_update_buffer due to Cmdline_no_3d_sound..."));
return -1;
}
if (channel < 0) {
if (channel_id < 0) {
return 0;
}
ALuint source_id = Channels[channel].source_id;
ALuint source_id = Channels[channel_id].source_id;
ALfloat rolloff = 1.0f;
if (pos) {
+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
+1 -1
View File
@@ -729,7 +729,7 @@ void shockwave_page_in()
} else if (Shockwave_info[i].model_id >= 0) {
// for a model we have to run model_load() on it again to make sure
// that it's ref_count is sane for this mission
int idx = model_load( Shockwave_info[i].filename, 0, NULL );
int idx __attribute__((__unused__)) = model_load( Shockwave_info[i].filename, 0, NULL );
Assert( idx == Shockwave_info[i].model_id );
model_page_in_textures( Shockwave_info[i].model_id );
+8 -1
View File
@@ -122,7 +122,7 @@ extern int Num_weapon_subtypes;
#define WIF3_TURRET_INTERCEPTABLE (1 << 5) // These two flags mark a weapon as being interceptable by the AI
#define WIF3_FIGHTER_INTERCEPTABLE (1 << 6) // (like WIF_BOMB), without forcing it to be tagetable -MageKing17
#define WIF3_AOE_ELECTRONICS (1 << 7) // Apply electronics effect across the weapon's entire area of effect instead of just on the impacted ship -MageKing17
#define WIF3_APPLY_RECOIL (1 << 8) // Apply recoil using weapon and ship info
#define WIF_HOMING (WIF_HOMING_HEAT | WIF_HOMING_ASPECT | WIF_HOMING_JAVELIN)
#define WIF_LOCKED_HOMING (WIF_HOMING_ASPECT | WIF_HOMING_JAVELIN)
@@ -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;
@@ -435,6 +437,9 @@ typedef struct weapon_info {
float emp_intensity; // intensity of the EMP effect
float emp_time; // time of the EMP effect
// Recoil effect
float recoil_modifier;
// Energy suck effect
float weapon_reduce; // how much energy removed from weapons systems
float afterburner_reduce; // how much energy removed from weapons systems
@@ -670,4 +675,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
Loaded 100 of 104 files, more files were not shown because too many files have changed in this diff. Show more