1 /*
2  * Created by Ian "Goober5000" Warfield for the FreeSpace2 Source Code Project.
3  * You may not sell or otherwise commercially exploit the source or things you
4  * create based on the source.
5  */
6 
7 
8 
9 #include "globalincs/def_files.h"
10 #include "iff_defs/iff_defs.h"
11 #include "parse/parselo.h"
12 #include "hud/hud.h"
13 #include "mission/missionparse.h"
14 #include "ship/ship.h"
15 #include "io/timer.h"
16 
17 extern int radar_target_id_flags;
18 
19 int Num_iffs;
20 iff_info Iff_info[MAX_IFFS];
21 
22 int Iff_traitor;
23 
24 int radar_iff_color[5][2][4];
25 int iff_bright_delta;
26 int *iff_color_brightness = &iff_bright_delta;
27 
28 // global only to file
29 color Iff_colors[MAX_IFF_COLORS][2];		// AL 1-2-97: Create two IFF colors, regular and bright
30 
31 flag_def_list rti_flags[] = {
32 	{ "crosshairs",			RTIF_CROSSHAIRS,	0 },
33 	{ "blink",				RTIF_BLINK,			0 },
34 	{ "pulsate",			RTIF_PULSATE,		0 },
35 	{ "enlarge",			RTIF_ENLARGE,		0 }
36 };
37 
38 int Num_rti_flags = sizeof(rti_flags)/sizeof(flag_def_list);
39 
40 /**
41  * Borrowed from ship.cpp, ship_iff_init_colors
42  *
43  * @param is_bright Whether set to bright
44  */
iff_get_alpha_value(bool is_bright)45 int iff_get_alpha_value(bool is_bright)
46 {
47 	if (is_bright == false)
48 		return (HUD_COLOR_ALPHA_MAX - iff_bright_delta) * 16;
49 	else
50 		return HUD_COLOR_ALPHA_MAX * 16;
51 }
52 
53 /**
54  * Init a color and add it to the ::Iff_colors array
55  *
56  * @param r Red
57  * @param g Green
58  * @param b Blue
59  *
60  * @return The new IFF colour slot in ::Iff_colors array
61  */
iff_init_color(int r,int g,int b)62 int iff_init_color(int r, int g, int b)
63 {
64 	typedef struct temp_color_t {
65 		int	r;
66 		int g;
67 		int b;
68 	} temp_color_t;
69 
70 	int i, idx;
71 	temp_color_t *c;
72 
73 	static int num_iff_colors = 0;
74 	static temp_color_t temp_colors[MAX_IFF_COLORS];
75 
76 	Assert(r >= 0 && r <= 255);
77 	Assert(g >= 0 && g <= 255);
78 	Assert(b >= 0 && b <= 255);
79 
80 	// make sure we're under the limit
81 	if (num_iff_colors >= MAX_IFF_COLORS)
82 	{
83 		Warning(LOCATION, "Too many iff colors!  Ignoring the rest...\n");
84 		return 0;
85 	}
86 
87 	// find out if this color is in use
88 	for (i = 0; i < num_iff_colors; i++)
89 	{
90 		c = &temp_colors[i];
91 
92 		if (c->r == r && c->g == g && c->b == b)
93 			return i;
94 	}
95 
96 	// not in use, so add a new slot
97 	idx = num_iff_colors;
98 	num_iff_colors++;
99 
100 	// save the values
101 	c = &temp_colors[idx];
102 	c->r = r;
103 	c->g = g;
104 	c->b = b;
105 
106 	// init it
107 	gr_init_alphacolor(&Iff_colors[idx][0], r, g, b, iff_get_alpha_value(false));
108 	gr_init_alphacolor(&Iff_colors[idx][1], r, g, b, iff_get_alpha_value(true));
109 
110 	// return the new slot
111 	return idx;
112 }
113 
114 /**
115  * Parse the table
116  */
iff_init()117 void iff_init()
118 {
119 	char traitor_name[NAME_LENGTH];
120 	char attack_names[MAX_IFFS][MAX_IFFS][NAME_LENGTH];
121 	struct {
122 		char iff_name[NAME_LENGTH];
123 		int color_index;
124 	} observed_color_table[MAX_IFFS][MAX_IFFS];
125 
126 	int num_attack_names[MAX_IFFS];
127 	int num_observed_colors[MAX_IFFS];
128 	int i, j, k;
129 	int string_idx;
130 
131 	int rval;
132 	if ((rval = setjmp(parse_abort)) != 0)
133 	{
134 		mprintf(("TABLES: Unable to parse '%s'!  Error code = %i.\n", "iff_defs.tbl", rval));
135 		return;
136 	}
137 
138 	// Goober5000 - if table doesn't exist, use the default table
139 	if (cf_exists_full("iff_defs.tbl", CF_TYPE_TABLES))
140 		read_file_text("iff_defs.tbl", CF_TYPE_TABLES);
141 	else
142 		read_file_text_from_array(defaults_get_file("iff_defs.tbl"));
143 
144 	reset_parse();
145 
146 	// parse the table --------------------------------------------------------
147 
148 	required_string("#IFFs");
149 
150 	// get the traitor
151 	required_string("$Traitor IFF:");
152 	stuff_string(traitor_name, F_NAME, NAME_LENGTH);
153 
154 	int rgb[3];
155 
156 	// check if alternate colours are wanted to be used for these
157 	// Marks various stuff... like asteroids
158 	if ((optional_string("$Selection Color:")) || (optional_string("$Selection Colour:")))
159 	{
160 		stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
161 		iff_init_color(rgb[0], rgb[1], rgb[2]);
162 	}
163 	else
164 		iff_init_color(0xff, 0xff, 0xff);
165 
166 	// Marks the ship currently saying something
167 	if ((optional_string("$Message Color:")) || (optional_string("$Message Colour:")))
168 	{
169 		stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
170 		iff_init_color(rgb[0], rgb[1], rgb[2]);
171 	}
172 	else
173 		iff_init_color(0x7f, 0x7f, 0x7f);
174 
175 	// Marks the tagged ships
176 	if ((optional_string("$Tagged Color:")) || (optional_string("$Tagged Colour:")))
177 	{
178 		stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
179 		iff_init_color(rgb[0], rgb[1], rgb[2]);
180 	}
181 	else
182 		iff_init_color(0xff, 0xff, 0x00);
183 
184 	// init radar blips colour table
185 	int a_bright,a_dim;
186 	bool alternate_blip_color = false;
187 	for (i=0;i<5;i++)
188 	{
189 		for (j=0;j<2;j++)
190 		{
191 			for (k=0;k<3;k++)
192 			{
193 				radar_iff_color[i][j][k] = -1;
194 			}
195 		}
196 	}
197 
198 	// if the bright/dim scaling is wanted to be changed
199 	if (optional_string("$Dimmed IFF brightness:"))
200 	{
201 		int dim_iff_brightness;
202 		stuff_int(&dim_iff_brightness);
203 		Assert(dim_iff_brightness >= 0 && dim_iff_brightness <= HUD_COLOR_ALPHA_MAX);
204 		*iff_color_brightness = dim_iff_brightness;
205 	}
206 	else
207 		*iff_color_brightness = 4;
208 
209 	// alternate = use same method as with ship blips
210 	// retail = use 1/2 intensities
211 	if (optional_string("$Use Alternate Blip Coloring:") || optional_string("$Use Alternate Blip Colouring:"))
212 	{
213 		stuff_boolean(&alternate_blip_color);
214 	}
215 
216 	// Parse blip colours, their order is hardcoded.
217 	if ((optional_string("$Missile Blip Color:")) || (optional_string("$Missile Blip Colour:")))
218 	{
219 		stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
220 		for (i=0;i<3;i++)
221 		{
222 			Assert(rgb[i] >= 0 && rgb[i] <= 255);
223 			radar_iff_color[0][1][i] = rgb[i];
224 			radar_iff_color[0][0][i] = rgb[i]/2;
225 		}
226 	}
227 
228 	if ((optional_string("$Navbuoy Blip Color:")) || (optional_string("$Navbuoy Blip Colour:")))
229 	{
230 		stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
231 		for (i=0;i<3;i++)
232 		{
233 			Assert(rgb[i] >= 0 && rgb[i] <= 255);
234 			radar_iff_color[1][1][i] = rgb[i];
235 			radar_iff_color[1][0][i] = rgb[i]/2;
236 		}
237 	}
238 
239 	if ((optional_string("$Warping Blip Color:")) || (optional_string("$Warping Blip Colour:")))
240 	{
241 		stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
242 		for (i=0;i<3;i++)
243 		{
244 			Assert(rgb[i] >= 0 && rgb[i] <= 255);
245 			radar_iff_color[2][1][i] = rgb[i];
246 			radar_iff_color[2][0][i] = rgb[i]/2;
247 		}
248 	}
249 
250 	if ((optional_string("$Node Blip Color:")) || (optional_string("$Node Blip Colour:")))
251 	{
252 		stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
253 		for (i=0;i<3;i++)
254 		{
255 			Assert(rgb[i] >= 0 && rgb[i] <= 255);
256 			radar_iff_color[3][1][i] = rgb[i];
257 			radar_iff_color[3][0][i] = rgb[i]/2;
258 		}
259 	}
260 
261 	if ((optional_string("$Tagged Blip Color:")) || (optional_string("$Tagged Blip Colour:")))
262 	{
263 		stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
264 		for (i=0;i<3;i++)
265 		{
266 			Assert(rgb[i] >= 0 && rgb[i] <= 255);
267 			radar_iff_color[4][1][i] = rgb[i];
268 			radar_iff_color[4][0][i] = rgb[i]/2;
269 		}
270 	}
271 
272 	if (alternate_blip_color == true)
273 	{
274 		a_bright = iff_get_alpha_value(true);
275 		a_dim = iff_get_alpha_value(false);
276 		for (i=0;i<5;i++)
277 		{
278 			if (radar_iff_color[i][0][0] >= 0)
279 			{
280 				for (j=0;j<3;j++)
281 				{
282 					radar_iff_color[i][0][j] = radar_iff_color[i][1][j];
283 				}
284 
285 				radar_iff_color[i][1][3] = a_bright;
286 				radar_iff_color[i][0][3] = a_dim;
287 			}
288 		}
289 	}
290 	else
291 	{
292 		for (i=0;i<5;i++)
293 		{
294 			if (radar_iff_color[i][0][0] >= 0)
295 			{
296 				radar_iff_color[i][0][3] = 255;
297 				radar_iff_color[i][1][3] = 255;
298 			}
299 		}
300 	}
301 
302 	if (optional_string("$Radar Target ID Flags:")) {
303 		parse_string_flag_list((int*)&radar_target_id_flags, rti_flags, Num_rti_flags);
304 		if (optional_string("+reset"))
305 			radar_target_id_flags = 0;
306 	}
307 
308 	// begin reading data
309 	Num_iffs = 0;
310 	while (required_string_either("#End", "$IFF Name:"))
311 	{
312 		iff_info *iff;
313 		int cur_iff;
314 
315 		// make sure we're under the limit
316 		if (Num_iffs >= MAX_IFFS)
317 		{
318 			Warning(LOCATION, "Too many iffs in iffs_defs.tbl!  Max is %d.\n", MAX_IFFS);
319 			skip_to_start_of_string("#End", NULL);
320 			break;
321 		}
322 
323 		// add new IFF
324 		iff = &Iff_info[Num_iffs];
325 		cur_iff = Num_iffs;
326 		Num_iffs++;
327 
328 
329 		// get required IFF info ----------------------------------------------
330 
331 		// get the iff name
332 		required_string("$IFF Name:");
333 		stuff_string(iff->iff_name, F_NAME, NAME_LENGTH);
334 
335 		// get the iff color
336 		if (check_for_string("$Colour:"))
337 			required_string("$Colour:");
338 		else
339 			required_string("$Color:");
340 		stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
341 		iff->color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
342 
343 
344 		// get relationships between IFFs -------------------------------------
345 
346 		// get the list of iffs attacked
347 		if (optional_string("$Attacks:"))
348 			num_attack_names[cur_iff] = stuff_string_list(attack_names[cur_iff], MAX_IFFS);
349 		else
350 			num_attack_names[cur_iff] = 0;
351 
352 		// get the list of observed colors
353 		num_observed_colors[cur_iff] = 0;
354 		while (optional_string("+Sees"))
355 		{
356 			// get iff observed
357 			stuff_string_until(observed_color_table[cur_iff][num_observed_colors[cur_iff]].iff_name, "As:", NAME_LENGTH);
358 			required_string("As:");
359 
360 			// get color observed
361 			stuff_int_list(rgb, 3, RAW_INTEGER_TYPE);
362 			observed_color_table[cur_iff][num_observed_colors[cur_iff]].color_index = iff_init_color(rgb[0], rgb[1], rgb[2]);
363 
364 			// increment
365 			num_observed_colors[cur_iff]++;
366 		}
367 
368 
369 		// get flags ----------------------------------------------------------
370 
371 		// get iff flags
372 		iff->flags = 0;
373 		if (optional_string("$Flags:"))
374 		{
375 			char flag_strings[MAX_IFF_FLAGS][NAME_LENGTH];
376 
377 			int num_strings = stuff_string_list(flag_strings, MAX_IFF_FLAGS);
378 			for (string_idx = 0; string_idx < num_strings; string_idx++)
379 			{
380 				if (!stricmp(NOX("support allowed"), flag_strings[string_idx]))
381 					iff->flags |= IFFF_SUPPORT_ALLOWED;
382 				else if (!stricmp(NOX("exempt from all teams at war"), flag_strings[string_idx]))
383 					iff->flags |= IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR;
384 				else if (!stricmp(NOX("orders hidden"), flag_strings[string_idx]))
385 					iff->flags |= IFFF_ORDERS_HIDDEN;
386 				else if (!stricmp(NOX("orders shown"), flag_strings[string_idx]))
387 					iff->flags |= IFFF_ORDERS_SHOWN;
388 				else if (!stricmp(NOX("wing name hidden"), flag_strings[string_idx]))
389 					iff->flags |= IFFF_WING_NAME_HIDDEN;
390 				else
391 					Warning(LOCATION, "Bogus string in iff flags: %s\n", flag_strings[string_idx]);
392 			}
393 		}
394 
395 		// get default ship flags
396 		iff->default_parse_flags = 0;
397 		if (optional_string("$Default Ship Flags:"))
398 		{
399 			i = 0;
400 			j = 0;
401 			char flag_strings[MAX_PARSE_OBJECT_FLAGS][NAME_LENGTH];
402 			int num_strings = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS);
403 			for (i = 0; i < num_strings; i++)
404 			{
405 				for (j = 0; j < MAX_PARSE_OBJECT_FLAGS; j++)
406 				{
407 					if (!stricmp(flag_strings[i], Parse_object_flags[j]))
408 					{
409 						iff->default_parse_flags |= (1 << j);
410 						break;
411 					}
412 				}
413 			}
414 
415 			if (j == MAX_PARSE_OBJECT_FLAGS)
416 				Warning(LOCATION, "Bogus string in iff default ship flags: %s\n", flag_strings[i]);
417 		}
418 
419 		// again
420 		iff->default_parse_flags2 = 0;
421 		if (optional_string("$Default Ship Flags2:"))
422 		{
423 			i = 0;
424 			j = 0;
425 			char flag_strings[MAX_PARSE_OBJECT_FLAGS_2][NAME_LENGTH];
426 			int num_strings = stuff_string_list(flag_strings, MAX_PARSE_OBJECT_FLAGS_2);
427 			for (i = 0; i < num_strings; i++)
428 			{
429 				for (j = 0; j < MAX_PARSE_OBJECT_FLAGS_2; j++)
430 				{
431 					if (!stricmp(flag_strings[i], Parse_object_flags_2[j]))
432 					{
433 						iff->default_parse_flags2 |= (1 << j);
434 						break;
435 					}
436 				}
437 			}
438 
439 			if (j == MAX_PARSE_OBJECT_FLAGS_2)
440 				Warning(LOCATION, "Bogus string in iff default ship flags2: %s\n", flag_strings[i]);
441 		}
442 
443 		// this is cleared between each level but let's just set it here for thoroughness
444 		iff->ai_rearm_timestamp = timestamp(-1);
445 	}
446 
447 	required_string("#End");
448 
449 
450 	// now resolve the relationships ------------------------------------------
451 
452 	// first get the traitor
453 	Iff_traitor = iff_lookup(traitor_name);
454 	if (Iff_traitor < 0)
455 	{
456 		Iff_traitor = 0;
457 		Warning(LOCATION, "Traitor IFF %s not found in iff_defs.tbl!  Defaulting to %s.\n", traitor_name, Iff_info[Iff_traitor].iff_name);
458 	}
459 
460 	// next get the attackees and colors
461 	for (int cur_iff = 0; cur_iff < Num_iffs; cur_iff++)
462 	{
463 		iff_info *iff = &Iff_info[cur_iff];
464 
465 		// clear the iffs to be attacked
466 		iff->attackee_bitmask = 0;
467 		iff->attackee_bitmask_all_teams_at_war = 0;
468 
469 		// clear the observed colors
470 		for (j = 0; j < MAX_IFFS; j++)
471 			iff->observed_color_index[j] = -1;
472 
473 		// resolve the list names
474 		for (int list_index = 0; list_index < MAX_IFFS; list_index++)
475 		{
476 			// are we within the number of attackees listed?
477 			if (list_index < num_attack_names[cur_iff])
478 			{
479 				// find out who
480 				int target_iff = iff_lookup(attack_names[cur_iff][list_index]);
481 
482 				// valid?
483 				if (target_iff >= 0)
484 					iff->attackee_bitmask |= iff_get_mask(target_iff);
485 				else
486 					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);
487 			}
488 
489 			// are we within the number of colors listed?
490 			if (list_index < num_observed_colors[cur_iff])
491 			{
492 				// find out who
493 				int target_iff = iff_lookup(observed_color_table[cur_iff][list_index].iff_name);
494 
495 				// valid?
496 				if (target_iff >= 0)
497 					iff->observed_color_index[target_iff] = observed_color_table[cur_iff][list_index].color_index;
498 				else
499 					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);
500 			}
501 		}
502 
503 		// resolve the all teams at war relationships
504 		if (iff->flags & IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR)
505 		{
506 			// exempt, so use standard attacks
507 			iff->attackee_bitmask_all_teams_at_war = iff->attackee_bitmask;
508 		}
509 		else
510 		{
511 			// nonexempt, so build bitmask of all other nonexempt teams
512 			for (int other_iff = 0; other_iff < Num_iffs; other_iff++)
513 			{
514 				// skip myself (unless I attack myself normally)
515 				if ((other_iff == cur_iff) && !iff_x_attacks_y(cur_iff, cur_iff))
516 					continue;
517 
518 				// skip anyone exempt
519 				if (Iff_info[other_iff].flags & IFFF_EXEMPT_FROM_ALL_TEAMS_AT_WAR)
520 					continue;
521 
522 				// add everyone else
523 				iff->attackee_bitmask_all_teams_at_war |= iff_get_mask(other_iff);
524 			}
525 		}
526 	}
527 
528 	// add tbl/tbm to multiplayer validation list
529 	extern void fs2netd_add_table_validation(const char *tblname);
530 	fs2netd_add_table_validation("iff_defs.tbl");
531 }
532 
533 /**
534  * Find the iff name
535  *
536  * @param iff_name Pointer to name as a string
537  * @return Index into ::Iff_info array
538  */
iff_lookup(char * iff_name)539 int iff_lookup(char *iff_name)
540 {
541 	// bogus
542 	Assert(iff_name);
543 
544 	if(iff_name == NULL)
545 		return -1;
546 
547 	for (int i = 0; i < Num_iffs; i++)
548 		if (!stricmp(iff_name, Iff_info[i].iff_name))
549 			return i;
550 
551 	return -1;
552 }
553 
554 /**
555  * Get the mask, taking All Teams At War into account
556  *
557  * @param attacker_team Team of attacker
558  * @return Bitmask
559  */
iff_get_attackee_mask(int attacker_team)560 int iff_get_attackee_mask(int attacker_team)
561 {
562 	Assert(attacker_team >= 0 && attacker_team < Num_iffs);
563 
564 	//	All teams attack all other teams.
565 	if (Mission_all_attack)
566 	{
567 		return Iff_info[attacker_team].attackee_bitmask_all_teams_at_war;
568 	}
569 	// normal
570 	else
571 	{
572 		return Iff_info[attacker_team].attackee_bitmask;
573 	}
574 }
575 
576 /**
577  * Rather slower, since it has to construct a mask
578  *
579  * @param attackee_team Team of attacker
580  * @return Bitmask
581  */
iff_get_attacker_mask(int attackee_team)582 int iff_get_attacker_mask(int attackee_team)
583 {
584 	Assert(attackee_team >= 0 && attackee_team < Num_iffs);
585 
586 	int i, attacker_bitmask = 0;
587 	for (i = 0; i < Num_iffs; i++)
588 	{
589 		if (iff_x_attacks_y(i, attackee_team))
590 			attacker_bitmask |= iff_get_mask(i);
591 	}
592 
593 	return attacker_bitmask;
594 }
595 
596 /**
597  * Similar to above
598  *
599  * @param team_x Team of attacker
600  * @param team_y Team of attackee
601  *
602  * @return >0 if true, 0 if false
603  */
iff_x_attacks_y(int team_x,int team_y)604 int iff_x_attacks_y(int team_x, int team_y)
605 {
606 	return iff_matches_mask(team_y, iff_get_attackee_mask(team_x));
607 }
608 
609 /**
610  * Generate a mask for a team
611  *
612  * @param team Team to generate mask for
613  */
iff_get_mask(int team)614 int iff_get_mask(int team)
615 {
616 	return (1 << team);
617 }
618 
619 /**
620  * See if the mask contains the team
621  *
622  * @param team Team to test
623  * @param mask Mask
624  *
625  * @return 1 if matches, 0 if does not match
626  */
iff_matches_mask(int team,int mask)627 int iff_matches_mask(int team, int mask)
628 {
629 	return (iff_get_mask(team) & mask) ? 1 : 0;
630 }
631 
632 /**
633  * Get the color from the color index
634  */
iff_get_color(int color_index,int is_bright)635 color *iff_get_color(int color_index, int is_bright)
636 {
637 	return &Iff_colors[color_index][is_bright];
638 }
639 
640 /**
641  * Get the color index, taking objective vs. subjective into account
642  */
iff_get_color_by_team(int team,int seen_from_team,int is_bright)643 color *iff_get_color_by_team(int team, int seen_from_team, int is_bright)
644 {
645 	Assert(team >= 0 && team < Num_iffs);
646 	Assert(seen_from_team < Num_iffs);
647 	Assert(is_bright == 0 || is_bright == 1);
648 
649 
650 	// is this guy being seen by anyone?
651 	if (seen_from_team < 0)
652 		return &Iff_colors[Iff_info[team].color_index][is_bright];
653 
654 	// Goober5000 - base the following on "sees X as" from iff code
655 	// c.f. AL's comment:
656 
657 	// AL 12-26-97:	it seems IFF color needs to be set relative to the player team.  If
658 	//						the team in question is the same as the player, then it should be
659 	//						drawn friendly.  If the team is different than the player's, then draw the
660 	//						appropriate IFF.
661 
662 
663 	// assume an observed color is defined; if not, use normal color
664 	int color_index = Iff_info[seen_from_team].observed_color_index[team];
665 	if (color_index < 0)
666 		color_index = Iff_info[team].color_index;
667 
668 
669 	return &Iff_colors[color_index][is_bright];
670 }
671 
672 /**
673  * Get the color index, taking objective vs. subjective into account
674  *
675  * this one for the function calls that include some - any - of object
676  */
iff_get_color_by_team_and_object(int team,int seen_from_team,int is_bright,object * objp)677 color *iff_get_color_by_team_and_object(int team, int seen_from_team, int is_bright, object *objp)
678 {
679 	Assert(team >= 0 && team < Num_iffs);
680 	Assert(seen_from_team < Num_iffs);
681 	Assert(is_bright == 0 || is_bright == 1);
682 
683 	int alt_color_index = -1;
684 
685 	// is this guy being seen by anyone?
686 	if (seen_from_team < 0)
687 		return &Iff_colors[Iff_info[team].color_index][is_bright];
688 
689 	int color_index = Iff_info[seen_from_team].observed_color_index[team];
690 
691 	// switch incase some sort of parent iff color inheritance for example for bombs is wanted...
692 	switch(objp->type)
693 	{
694 		case OBJ_SHIP:
695 			if (Ships[objp->instance].ship_iff_color[seen_from_team][team] >= 0)
696 			{
697 				alt_color_index = Ships[objp->instance].ship_iff_color[seen_from_team][team];
698 			}
699 			else
700 			{
701 				alt_color_index = Ship_info[Ships[objp->instance].ship_info_index].ship_iff_info[seen_from_team][team];
702 			}
703 			break;
704 		default:
705 			break;
706 	}
707 
708 	// temporary solution....
709 	if (alt_color_index >= 0)
710 		color_index = alt_color_index;
711 	if (color_index < 0)
712 		color_index = Iff_info[team].color_index;
713 
714 
715 	return &Iff_colors[color_index][is_bright];
716 }
717