mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-11 04:31:35 -10:00
git-svn-id: svn://svn.icculus.org/fs2open/trunk/fs2_open@4251 387891d4-d844-0410-90c0-e4c51a9137d3
506 lines
13 KiB
C++
506 lines
13 KiB
C++
/*
|
|
* Created by Ian "Goober5000" Warfield for the FreeSpace2 Source Code Project.
|
|
* You may not sell or otherwise commercially exploit the source or things you
|
|
* create based on the source.
|
|
*/
|
|
|
|
/*
|
|
* $Logfile: /Freespace2/code/iff_defs/iff_defs.cpp $
|
|
* $Revision: 1.14 $
|
|
* $Date: 2007-09-02 02:10:26 $
|
|
* $Author: Goober5000 $
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 1.13 2007/02/08 07:39:32 Goober5000
|
|
* fix two bugs:
|
|
* --default ship flags in the iff_defs table were not correctly translated from parse flags to ship/object flags
|
|
* --ships were created with default allowed comm orders regardless of which team they were on
|
|
*
|
|
* Revision 1.12 2007/01/07 01:00:18 Goober5000
|
|
* convert a mission variable to a mission flag
|
|
*
|
|
* Revision 1.11 2006/09/11 06:49:39 taylor
|
|
* fixes for stuff_string() bounds checking
|
|
*
|
|
* Revision 1.10 2006/07/08 19:35:52 Goober5000
|
|
* iff defs should allow specification of both flag fields
|
|
* --Goober5000
|
|
*
|
|
* Revision 1.9 2006/04/20 06:32:07 Goober5000
|
|
* proper capitalization according to Volition
|
|
*
|
|
* Revision 1.8 2006/02/13 00:20:45 Goober5000
|
|
* more tweaks, plus clarification of checks for the existence of files
|
|
* --Goober5000
|
|
*
|
|
* Revision 1.7 2006/01/28 04:33:06 Goober5000
|
|
* fix all teams at war IFF behavior
|
|
* --Goober5000
|
|
*
|
|
* Revision 1.6 2006/01/16 11:02:23 wmcoolmon
|
|
* Various warning fixes, scripting globals fix; added "plr" and "slf" global variables for in-game hooks; various lua functions; GCC fixes for scripting.
|
|
*
|
|
* Revision 1.5 2006/01/13 03:31:09 Goober5000
|
|
* übercommit of custom IFF stuff :)
|
|
*
|
|
* Revision 1.4 2005/12/29 08:08:36 wmcoolmon
|
|
* Codebase commit, most notably including objecttypes.tbl
|
|
*
|
|
* Revision 1.3 2005/09/30 03:40:40 Goober5000
|
|
* hooray for more work on the iff code
|
|
* --Goober5000
|
|
*
|
|
* Revision 1.2 2005/09/29 04:26:08 Goober5000
|
|
* parse fixage
|
|
* --Goober5000
|
|
*
|
|
* Revision 1.1 2005/09/27 05:25:18 Goober5000
|
|
* initial commit of basic IFF code
|
|
* --Goober5000
|
|
*
|
|
*/
|
|
|
|
#include "globalincs/def_files.h"
|
|
#include "iff_defs/iff_defs.h"
|
|
#include "parse/parselo.h"
|
|
#include "hud/hud.h"
|
|
#include "mission/missionparse.h"
|
|
#include "ship/ship.h"
|
|
|
|
|
|
int Num_iffs;
|
|
iff_info Iff_info[MAX_IFFS];
|
|
|
|
int Iff_traitor;
|
|
|
|
// global only to file
|
|
color Iff_colors[MAX_IFF_COLORS][2]; // AL 1-2-97: Create two IFF colors, regular and bright
|
|
|
|
|
|
// borrowed from ship.cpp, ship_iff_init_colors
|
|
int iff_get_alpha_value(bool is_bright)
|
|
{
|
|
int iff_bright_delta = 4;
|
|
|
|
if (is_bright == false)
|
|
return (HUD_COLOR_ALPHA_MAX - iff_bright_delta) * 16;
|
|
else
|
|
return HUD_COLOR_ALPHA_MAX * 16;
|
|
}
|
|
|
|
// init a color and add it to the Iff_colors array
|
|
int iff_init_color(int r, int g, int b)
|
|
{
|
|
typedef struct temp_color_t {
|
|
int r;
|
|
int g;
|
|
int b;
|
|
} temp_color_t;
|
|
|
|
int i, idx;
|
|
temp_color_t *c;
|
|
|
|
static int num_iff_colors = 0;
|
|
static temp_color_t temp_colors[MAX_IFF_COLORS];
|
|
|
|
|
|
Assert(r >= 0 && r <= 255);
|
|
Assert(g >= 0 && g <= 255);
|
|
Assert(b >= 0 && b <= 255);
|
|
|
|
|
|
// make sure we're under the limit
|
|
if (num_iff_colors >= MAX_IFF_COLORS)
|
|
{
|
|
Warning(LOCATION, "Too many iff colors! Ignoring the rest...\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
// find out if this color is in use
|
|
for (i = 0; i < num_iff_colors; i++)
|
|
{
|
|
c = &temp_colors[i];
|
|
|
|
if (c->r == r && c->g == g && c->b == b)
|
|
return i;
|
|
}
|
|
|
|
|
|
// not in use, so add a new slot
|
|
idx = num_iff_colors;
|
|
num_iff_colors++;
|
|
|
|
// save the values
|
|
c = &temp_colors[idx];
|
|
c->r = r;
|
|
c->g = g;
|
|
c->b = b;
|
|
|
|
// init it
|
|
gr_init_alphacolor(&Iff_colors[idx][0], r, g, b, iff_get_alpha_value(false));
|
|
gr_init_alphacolor(&Iff_colors[idx][1], r, g, b, iff_get_alpha_value(true));
|
|
|
|
|
|
// return the new slot
|
|
return idx;
|
|
}
|
|
|
|
// parse the table
|
|
void iff_init()
|
|
{
|
|
char traitor_name[NAME_LENGTH];
|
|
char attack_names[MAX_IFFS][MAX_IFFS][NAME_LENGTH];
|
|
struct {
|
|
char iff_name[NAME_LENGTH];
|
|
int color_index;
|
|
} observed_color_table[MAX_IFFS][MAX_IFFS];
|
|
|
|
int num_attack_names[MAX_IFFS];
|
|
int num_observed_colors[MAX_IFFS];
|
|
|
|
int rval;
|
|
if ((rval = setjmp(parse_abort)) != 0)
|
|
{
|
|
mprintf(("TABLES: Unable to parse '%s'! Error code = %i.\n", "iff_defs.tbl", rval));
|
|
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");
|
|
else
|
|
read_file_text_from_array(defaults_get_file("iff_defs.tbl"));
|
|
|
|
reset_parse();
|
|
|
|
|
|
// before parsing, set up the predefined colors
|
|
// NOTE: THESE MUST OCCUR IN THE ORDER DEFINED IN IFF_DEFS.H!!
|
|
iff_init_color(0xff, 0xff, 0xff); // IFF_COLOR_SELECTION
|
|
iff_init_color(0x7f, 0x7f, 0x7f); // IFF_COLOR_MESSAGE
|
|
iff_init_color(0xff, 0xff, 0x00); // IFF_COLOR_TAGGED
|
|
|
|
|
|
// parse the table --------------------------------------------------------
|
|
|
|
required_string("#IFFs");
|
|
|
|
// get the traitor
|
|
required_string("$Traitor IFF:");
|
|
stuff_string(traitor_name, F_NAME, NAME_LENGTH);
|
|
|
|
// begin reading data
|
|
Num_iffs = 0;
|
|
while (required_string_either("#End","$IFF Name:"))
|
|
{
|
|
iff_info *iff;
|
|
int rgb[3];
|
|
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:"))
|
|
{
|
|
int i;
|
|
char flag_strings[MAX_IFF_FLAGS][NAME_LENGTH];
|
|
|
|
int num_strings = stuff_string_list(flag_strings, MAX_IFF_FLAGS);
|
|
for (i = 0; i < num_strings; i++)
|
|
{
|
|
if (!stricmp(NOX("support allowed"), flag_strings[i]))
|
|
iff->flags |= IFFF_SUPPORT_ALLOWED;
|
|
else if (!stricmp(NOX("exempt from all teams at war"), flag_strings[i]))
|
|
iff->flags |= IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR;
|
|
else
|
|
Warning(LOCATION, "Bogus string in iff flags: %s\n", flag_strings[i]);
|
|
}
|
|
}
|
|
|
|
// get default ship flags
|
|
iff->default_parse_flags = 0;
|
|
if (optional_string("$Default Ship Flags:"))
|
|
{
|
|
int i, 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:"))
|
|
{
|
|
int i, 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]);
|
|
}
|
|
}
|
|
|
|
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 (int 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// find the iff name
|
|
int iff_lookup(char *iff_name)
|
|
{
|
|
// bogus
|
|
Assert(iff_name);
|
|
if(iff_name == NULL)
|
|
return -1;
|
|
|
|
for (int i = 0; i < Num_iffs; i++)
|
|
if (!stricmp(iff_name, Iff_info[i].iff_name))
|
|
return i;
|
|
|
|
return -1;
|
|
}
|
|
|
|
// get the mask, taking All Teams At War into account
|
|
int iff_get_attackee_mask(int attacker_team)
|
|
{
|
|
Assert(attacker_team >= 0 && attacker_team < Num_iffs);
|
|
|
|
// All teams attack all other teams.
|
|
if (The_mission.flags & MISSION_FLAG_ALL_ATTACK)
|
|
{
|
|
return Iff_info[attacker_team].attackee_bitmask_all_teams_at_war;
|
|
}
|
|
// normal
|
|
else
|
|
{
|
|
return Iff_info[attacker_team].attackee_bitmask;
|
|
}
|
|
}
|
|
|
|
// rather slower, since it has to construct a mask
|
|
int iff_get_attacker_mask(int attackee_team)
|
|
{
|
|
Assert(attackee_team >= 0 && attackee_team < Num_iffs);
|
|
|
|
int i, attacker_bitmask = 0;
|
|
for (i = 0; i < Num_iffs; i++)
|
|
{
|
|
if (iff_x_attacks_y(i, attackee_team))
|
|
attacker_bitmask |= iff_get_mask(i);
|
|
}
|
|
|
|
return attacker_bitmask;
|
|
}
|
|
|
|
// similar to above; >0 if true, 0 if false
|
|
int iff_x_attacks_y(int team_x, int team_y)
|
|
{
|
|
return iff_matches_mask(team_y, iff_get_attackee_mask(team_x));
|
|
}
|
|
|
|
// generate a mask for a team
|
|
int iff_get_mask(int team)
|
|
{
|
|
return (1 << team);
|
|
}
|
|
|
|
// see if the mask contains the team
|
|
int iff_matches_mask(int team, int mask)
|
|
{
|
|
return (iff_get_mask(team) & mask) ? 1 : 0;
|
|
}
|
|
|
|
// get the color from the color index
|
|
color *iff_get_color(int color_index, int is_bright)
|
|
{
|
|
return &Iff_colors[color_index][is_bright];
|
|
}
|
|
|
|
// get the color index, taking objective vs. subjective into account
|
|
color *iff_get_color_by_team(int team, int seen_from_team, int is_bright)
|
|
{
|
|
Assert(team >= 0 && team < Num_iffs);
|
|
Assert(seen_from_team < Num_iffs);
|
|
Assert(is_bright == 0 || is_bright == 1);
|
|
|
|
|
|
// is this guy being seen by anyone?
|
|
if (seen_from_team < 0)
|
|
return &Iff_colors[Iff_info[team].color_index][is_bright];
|
|
|
|
|
|
// Goober5000 - base the following on "sees X as" from iff code
|
|
// c.f. AL's comment:
|
|
|
|
// AL 12-26-97: it seems IFF color needs to be set relative to the player team. If
|
|
// the team in question is the same as the player, then it should be
|
|
// drawn friendly. If the team is different than the player's, then draw the
|
|
// appropriate IFF.
|
|
|
|
|
|
// assume an observed color is defined; if not, use normal color
|
|
int color_index = Iff_info[seen_from_team].observed_color_index[team];
|
|
if (color_index < 0)
|
|
color_index = Iff_info[team].color_index;
|
|
|
|
|
|
return &Iff_colors[color_index][is_bright];
|
|
}
|