File: iff_defs.cpp

package info (click to toggle)
freespace2 3.7.0%2Brepack-2
  • links: PTS, VCS
  • area: non-free
  • in suites: jessie, jessie-kfreebsd
  • size: 22,848 kB
  • ctags: 41,897
  • sloc: cpp: 369,931; makefile: 1,060; xml: 129; sh: 112
file content (712 lines) | stat: -rw-r--r-- 17,999 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
/*
 * 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.
 */



#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"

extern int radar_target_id_flags;

int Num_iffs;
iff_info Iff_info[MAX_IFFS];

int Iff_traitor;

int radar_iff_color[5][2][4];
int iff_bright_delta;
int *iff_color_brightness = &iff_bright_delta;

// global only to file
color Iff_colors[MAX_IFF_COLORS][2];		// AL 1-2-97: Create two IFF colors, regular and bright

flag_def_list rti_flags[] = {
	{ "crosshairs",			RTIF_CROSSHAIRS,	0 },
	{ "blink",				RTIF_BLINK,			0 },
	{ "pulsate",			RTIF_PULSATE,		0 },
	{ "enlarge",			RTIF_ENLARGE,		0 }
};

int Num_rti_flags = sizeof(rti_flags)/sizeof(flag_def_list);

/**
 * Borrowed from ship.cpp, ship_iff_init_colors
 *
 * @param is_bright Whether set to bright
 */
int iff_get_alpha_value(bool is_bright)
{
	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
 *
 * @param r Red
 * @param g Green
 * @param b Blue
 *
 * @return The new IFF colour slot in ::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 i, j, k;
	int string_idx;

	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", 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]);
		}
	}
	
	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(char *tblname);
	fs2netd_add_table_validation("iff_defs.tbl");
}

/**
 * Find the iff name
 *
 * @param iff_name Pointer to name as a string
 * @return Index into ::Iff_info array
 */
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
 *
 * @param attacker_team Team of attacker
 * @return Bitmask
 */
int iff_get_attackee_mask(int attacker_team)
{
	Assert(attacker_team >= 0 && attacker_team < Num_iffs);

	//	All teams attack all other teams.
	if (Mission_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
 *
 * @param attackee_team Team of attacker
 * @return Bitmask
 */
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
 *
 * @param team_x Team of attacker
 * @param team_y Team of attackee
 *
 * @return >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
 *
 * @param team Team to generate mask for
 */
int iff_get_mask(int team)
{
	return (1 << team);
}

/**
 * See if the mask contains the team
 *
 * @param team Team to test
 * @param mask Mask
 *
 * @return 1 if matches, 0 if does not match
 */
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];
}

/**
 * Get the color index, taking objective vs. subjective into account
 * 
 * this one for the function calls that include some - any - of object
 */
color *iff_get_color_by_team_and_object(int team, int seen_from_team, int is_bright, object *objp)
{
	Assert(team >= 0 && team < Num_iffs);
	Assert(seen_from_team < Num_iffs);
	Assert(is_bright == 0 || is_bright == 1);

	int alt_color_index = -1;

	// is this guy being seen by anyone?
	if (seen_from_team < 0)
		return &Iff_colors[Iff_info[team].color_index][is_bright];

	int color_index = Iff_info[seen_from_team].observed_color_index[team];

	// switch incase some sort of parent iff color inheritance for example for bombs is wanted...
	switch(objp->type)
	{
		case OBJ_SHIP:
			if (Ships[objp->instance].ship_iff_color[seen_from_team][team] >= 0)
			{
				alt_color_index = Ships[objp->instance].ship_iff_color[seen_from_team][team];
			}
			else
			{
				alt_color_index = Ship_info[Ships[objp->instance].ship_info_index].ship_iff_info[seen_from_team][team];
			}
			break;
		default:
			break;
	}

	// temporary solution.... 
	if (alt_color_index >= 0)
		color_index = alt_color_index;
	if (color_index < 0)
		color_index = Iff_info[team].color_index;


	return &Iff_colors[color_index][is_bright];
}