Пример #1
0
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;
	}

	reset_parse();

	int rgba[4] = {0,0,0,0};

	// 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:",
		};

		// 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;
			}
		}

		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");
	}
}
void parse_species_tbl(const char *filename)
{
	int i, rval;
	char species_name[NAME_LENGTH];

	if ((rval = setjmp(parse_abort)) != 0)
	{
		mprintf(("TABLES: Unable to parse '%s'!  Error code = %i.\n", (filename) ? filename : NOX("<default species_defs.tbl>"), rval));
		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);
}
Пример #3
0
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"))
	{
		// vars for holding rgba values
		int rgba[4] = {0,0,0,0};
		int i, j;

		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) {
							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]);
			}
		}
		required_string("#End");
	}
}
Пример #4
0
/**
 * 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 i, j, k;
	int string_idx;

	try
	{
		// 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;
	}
}