1 /*
2 Copyright (C) 1994-1995 Apogee Software, Ltd.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 /**********************************************************************
21    module: RT_BATTL.C
22 
23    author: James R. Dose
24    phone:  (214)-271-1365 Ext #221
25    date:   September 8, 1994
26 
27    Battle mode support routines for Rise of the Triad.
28 
29    (c) Copyright 1994 Apogee Software.  All Rights Reserved.
30 **********************************************************************/
31 
32 #include <string.h>
33 #include "rt_def.h"
34 #include "rottnet.h"
35 #include "isr.h"
36 #include "rt_battl.h"
37 #include "rt_actor.h"
38 #include "rt_rand.h"
39 #include "rt_playr.h"
40 #include "rt_game.h"
41 #include "rt_sound.h"
42 #include "rt_com.h"
43 #include "rt_msg.h"
44 #include "rt_view.h"
45 
46 #include "rt_util.h"
47 #include "rt_main.h"
48 //MED
49 #include "memcheck.h"
50 
51 #define INFINITE -1
52 
53 static battle_status BATTLE_StartRound( void );
54 
55 static int Timer;
56 static int TimeLimit;
57 static int NumberOfPlayers;
58 static int BattleRound;
59 static int BattleMode;
60 
61 static boolean RoundOver;
62 static boolean KillsEndGame;
63 static boolean KeepTrackOfKills;
64 boolean UpdateKills;
65 
66 static boolean SwapFlag;
67 
68 static battle_type BattleOptions;
69 
70 specials BattleSpecialsTimes =
71       {
72       60, // god
73       60, // dog
74       20, // shrooms
75       20, // elasto
76       60, // asbestos vest
77       60, // bullet proof vest
78       GASTICS / VBLCOUNTER, // gas mask
79       60, // mercury mode
80 
81       300, // god respawn
82       60, // dog respawn
83       60, // shrooms respawn
84       60, // elasto respawn
85       60, // asbestos vest respawn
86       60, // bullet proof vest respawn
87       60, // gas mask respawn
88       60  // mercury mode respawn
89       };
90 
91 short WhoKilledWho[ MAXPLAYERS ][ MAXPLAYERS ];
92 short BATTLE_Points[ MAXPLAYERS ];
93 short BATTLE_PlayerOrder[ MAXPLAYERS ];
94 short BATTLE_Team[ MAXPLAYERS ];
95 short BATTLE_TeamLeader[ MAXPLAYERS ];
96 int   BATTLE_NumberOfTeams;
97 int   BATTLE_NumCollectorItems;
98 int   PointGoal;
99 int   DisplayPoints;
100 int   BATTLE_It;
101 
102 boolean BATTLE_ShowKillCount;
103 
104 boolean BATTLEMODE = false;
105 
106 /*---------------------------------------------------------------------
107 	Function Prototypes:
108 ---------------------------------------------------------------------*/
109 
110 static int BATTLE_CheckKills
111 	(
112 	battle_event reason,
113 	int player
114 	);
115 
116 /*---------------------------------------------------------------------
117 	Function: BATTLE_Init
118 
119 	Initializes the battle information.
120 ---------------------------------------------------------------------*/
121 
BATTLE_Init(int battlemode,int numplayers)122 void BATTLE_Init
123 	(
124 	int battlemode,
125 	int numplayers
126 	)
127 
128 	{
129 	int index;
130    int index2;
131    int team;
132    int TeamNumber[ MAXPLAYERCOLORS ];
133 
134    #if (BATTLECHECK == 1)
135       if ( ( gamestate.teamplay ) && ( BattleMode == battle_Tag ) )
136          {
137          Error( "BATTLE_Init : Cannot play Tag in team mode.\n" );
138          }
139 
140       if ( ( gamestate.teamplay ) && ( BattleMode == battle_CaptureTheTriad ) )
141          {
142          Error( "BATTLE_Init : Can only play Capture the Triad in team mode.\n" );
143          }
144    #endif
145 
146 	Timer   = 0;
147 	RoundOver = false;
148 
149 	BattleRound = -1;
150    BATTLE_It = 0;
151 
152 	BattleMode = battlemode;
153 
154 	BATTLEMODE = false;
155 
156    UpdateKills = true;
157 
158 	gamestate.BattleOptions.Gravity       = NORMAL_GRAVITY;
159 	gamestate.BattleOptions.Speed         = bo_normal_speed;
160 	gamestate.BattleOptions.Ammo          = bo_normal_shots;
161 	gamestate.BattleOptions.HitPoints     = bo_character_hitpoints;
162 	gamestate.BattleOptions.LightLevel    = bo_light_normal;
163    gamestate.BattleOptions.Kills         = bo_kills_default;
164 	gamestate.BattleOptions.DangerDamage  = bo_danger_normal;
165 	gamestate.BattleOptions.TimeLimit     = bo_time_infinite;
166    gamestate.BattleOptions.RespawnTime   = bo_normal_respawn_time;
167    gamestate.BattleOptions.RandomWeapons = false;
168    gamestate.BattleOptions.FriendlyFire  = true;
169    gamestate.BattleOptions.WeaponPersistence = false;
170 	gamestate.BattleOptions.SpawnMines    = false;
171 
172 	if ( BattleMode != battle_StandAloneGame )
173 		{
174 		BATTLEMODE = true;
175 
176       if ( gamestate.Product == ROTT_SHAREWARE )
177          {
178          switch( battlemode )
179             {
180             case battle_Normal :
181             case battle_Collector :
182             case battle_Hunter :
183                break;
184 
185             default :
186                Error( "Shareware version can only play Normal, Collector, "
187                   "or Hunter in Comm-bat game." );
188             }
189          }
190 
191 		gamestate.BattleOptions.Gravity       = BattleOptions.Gravity;
192 		gamestate.BattleOptions.Speed         = BattleOptions.Speed;
193 		gamestate.BattleOptions.Ammo          = BattleOptions.Ammo;
194 		gamestate.BattleOptions.HitPoints     = BattleOptions.HitPoints;
195 		gamestate.BattleOptions.LightLevel    = BattleOptions.LightLevel;
196 		gamestate.BattleOptions.Kills         = BattleOptions.Kills;
197 		gamestate.BattleOptions.DangerDamage  = BattleOptions.DangerDamage;
198 		gamestate.BattleOptions.TimeLimit     = BattleOptions.TimeLimit;
199       gamestate.BattleOptions.RespawnTime   = BattleOptions.RespawnTime;
200       gamestate.BattleOptions.RandomWeapons = BattleOptions.RandomWeapons;
201       gamestate.BattleOptions.FriendlyFire  = BattleOptions.FriendlyFire;
202       gamestate.BattleOptions.SpawnMines    = BattleOptions.SpawnMines;
203       gamestate.BattleOptions.WeaponPersistence = BattleOptions.WeaponPersistence;
204       }
205 
206 	gamestate.ShowScores                 = true;
207 	gamestate.BattleOptions.SpawnHealth  = true;
208 	gamestate.BattleOptions.SpawnWeapons = true;
209    gamestate.BattleOptions.SpawnDangers = true;
210 	gamestate.SpawnCollectItems          = false;
211 	gamestate.SpawnEluder                = false;
212 	gamestate.SpawnDeluder               = false;
213 	gamestate.BattleOptions.RespawnItems = false;
214 
215 	NumberOfPlayers = numplayers;
216 
217 
218    BATTLE_NumberOfTeams = numplayers;
219 	for( index = 0; index < MAXPLAYERS; index++ )
220 		{
221       BATTLE_PlayerOrder[ index ] = index;
222 		BATTLE_Points[ index ] = 0;
223       for( index2 = 0; index2 < MAXPLAYERS; index2++ )
224          {
225          WhoKilledWho[ index ][ index2 ] = 0;
226          }
227 
228       BATTLE_Team[ index ] = index;
229       BATTLE_TeamLeader[ index ] = index;
230       }
231 
232 
233    if ( gamestate.teamplay )
234       {
235       for( index = 0; index < MAXPLAYERCOLORS; index++ )
236          {
237          TeamNumber[ index ] = -1;
238          }
239 
240       BATTLE_NumberOfTeams = 0;
241 
242       for( index = 0; index < numplayers; index++ )
243          {
244          team = PLAYERSTATE[ index ].uniformcolor;
245          if ( TeamNumber[ team ] == -1 )
246             {
247             TeamNumber[ team ] = BATTLE_NumberOfTeams;
248             BATTLE_TeamLeader[ BATTLE_NumberOfTeams ] = index;
249             BATTLE_NumberOfTeams++;
250             }
251          BATTLE_Team[ index ] = TeamNumber[ team ];
252          }
253       }
254 
255 	PointGoal = gamestate.BattleOptions.Kills;
256 	if ( ( gamestate.BattleOptions.Kills == bo_kills_random ) ||
257 		( gamestate.BattleOptions.Kills == bo_kills_blind ) )
258 		{
259 		// Possibility of playing from 5 to 50 kills
260 		PointGoal = ( GameRandomNumber( "BATTLE_Init", 0 ) % 46 ) + 5;
261 		}
262 
263    DisplayPoints = PointGoal;
264 
265 	for( index = 0; index < MAXPLAYERS; index++ )
266 		{
267 		gamestate.PlayerHasGun[ index ] = true;
268 		}
269 
270 	KillsEndGame = true;
271 	KeepTrackOfKills = true;
272 
273 	switch( BattleMode )
274 		{
275 		case battle_StandAloneGame :
276 			KillsEndGame      = false;
277 			KeepTrackOfKills  = false;
278 			break;
279 
280 		case battle_Normal :
281 			break;
282 
283 		case battle_ScoreMore :
284 			break;
285 
286 		case battle_Collector :
287 			for( index = 0; index < MAXPLAYERS; index++ )
288 				{
289 				gamestate.PlayerHasGun[ index ] = false;
290 				}
291 			KillsEndGame     = false;
292 			KeepTrackOfKills = false;
293 			gamestate.BattleOptions.SpawnHealth  = false;
294 			gamestate.BattleOptions.SpawnWeapons = false;
295 			gamestate.SpawnCollectItems          = true;
296 			break;
297 
298 		case battle_Scavenger :
299 			KillsEndGame     = false;
300 			KeepTrackOfKills = false;
301 			gamestate.BattleOptions.SpawnWeapons = true;
302 			gamestate.BattleOptions.SpawnHealth  = true;
303 			gamestate.SpawnCollectItems          = true;
304 			break;
305 
306 		case battle_Hunter :
307          PointGoal *= BATTLE_NumberOfTeams;
308 			KillsEndGame      = false;
309 			KeepTrackOfKills  = true;
310          BATTLE_It = 0;
311          for( index = 0; index < NumberOfPlayers; index++ )
312             {
313             if ( BATTLE_Team[ index ] == 0 )
314                {
315                gamestate.PlayerHasGun[ index ] = false;
316                }
317             }
318 			break;
319 
320 		case battle_Tag :
321 			for( index = 0; index < MAXPLAYERS; index++ )
322 				{
323 				gamestate.PlayerHasGun[ index ] = false;
324 				}
325 
326 			gamestate.BattleOptions.SpawnHealth  = false;
327 			gamestate.BattleOptions.SpawnWeapons = false;
328 			gamestate.BattleOptions.SpawnDangers = true;
329 			KeepTrackOfKills = true;
330 			KillsEndGame     = true;
331 			break;
332 
333 		case battle_Eluder :
334 			KeepTrackOfKills   = false;
335 			KillsEndGame       = false;
336 
337 			for( index = 0; index < MAXPLAYERS; index++ )
338 				{
339 				gamestate.PlayerHasGun[ index ] = false;
340 				}
341 
342 			gamestate.BattleOptions.SpawnWeapons = false;
343 			gamestate.SpawnEluder                = true;
344 			break;
345 
346 		case battle_Deluder :
347 			KeepTrackOfKills    = false;
348 			KillsEndGame        = false;
349 			gamestate.SpawnDeluder = true;
350 			break;
351 
352 		case battle_CaptureTheTriad :
353          KillsEndGame     = false;
354          KeepTrackOfKills = false;
355 			break;
356 		}
357 
358 	if ( BattleMode != battle_StandAloneGame )
359 		{
360 		if ( BattleOptions.RespawnItems )
361 			{
362 			gamestate.BattleOptions.RespawnItems = true;
363 			}
364 
365 		if ( !BattleOptions.SpawnDangers )
366 			{
367 			gamestate.BattleOptions.SpawnDangers = false;
368 			}
369 
370 		if ( !BattleOptions.SpawnHealth )
371 			{
372 			gamestate.BattleOptions.SpawnHealth = false;
373 			}
374 
375 		if ( !BattleOptions.SpawnWeapons )
376 			{
377 			gamestate.BattleOptions.SpawnWeapons = false;
378 			}
379 
380 		if ( gamestate.BattleOptions.Kills == bo_kills_blind )
381 			{
382 			gamestate.ShowScores = false;
383 			}
384 
385       GRAVITY = gamestate.BattleOptions.Gravity;
386 
387       if ( gamestate.BattleOptions.Kills == bo_kills_infinite )
388          {
389          KillsEndGame = false;
390          }
391 		}
392 
393 	BATTLE_StartRound();
394 
395    #if (BATTLEINFO == 1)
396       SoftError( "GRAVITY      = %d\n", GRAVITY );
397       SoftError( "BO_Gravity   = %d\n", BattleOptions.Gravity );
398       SoftError( "BO_Speed     = %d\n", BattleOptions.Speed );
399       SoftError( "BO_Ammo      = %d\n", BattleOptions.Ammo );
400       SoftError( "BO_HitPoints = %d\n", BattleOptions.HitPoints );
401       SoftError( "BO_Dangers   = %d\n", BattleOptions.SpawnDangers );
402       SoftError( "BO_Health    = %d\n", BattleOptions.SpawnHealth );
403       SoftError( "BO_Weapons   = %d\n", BattleOptions.SpawnWeapons );
404       SoftError( "BO_Respawn   = %d\n", BattleOptions.RespawnItems );
405       SoftError( "BO_Light     = %d\n", BattleOptions.LightLevel );
406       SoftError( "BO_Kills     = %d\n", BattleOptions.Kills );
407       SoftError( "BO_DangerDam = %d\n", BattleOptions.DangerDamage );
408       SoftError( "BO_TimeLimit = %d\n", BattleOptions.TimeLimit );
409    #endif
410 	}
411 
412 
413 /*---------------------------------------------------------------------
414    Function: BATTLE_GetSpecials
415 
416    Set the battle special times.
417 ---------------------------------------------------------------------*/
418 
BATTLE_GetSpecials(void)419 void BATTLE_GetSpecials
420 	(
421    void
422 	)
423 
424    {
425    int *src;
426    int *dest;
427 
428    src  = ( int * )&BattleSpecialsTimes;
429    dest = ( int * )&gamestate.SpecialsTimes;
430 
431    while( src < ( int * )( &BattleSpecialsTimes + 1 ) )
432       {
433       *dest = *src * VBLCOUNTER;
434       dest++;
435       src++;
436       }
437    }
438 
439 
440 /*---------------------------------------------------------------------
441 	Function: BATTLE_SetOptions
442 
443 	Set the battle options.
444 ---------------------------------------------------------------------*/
445 
BATTLE_SetOptions(battle_type * options)446 void BATTLE_SetOptions
447 	(
448 	battle_type *options
449 	)
450 
451 	{
452 	memcpy( &BattleOptions, options, sizeof( battle_type ) );
453 	}
454 
455 
456 /*---------------------------------------------------------------------
457    Function: BATTLE_GetOptions
458 
459    Returns the battle options.
460 ---------------------------------------------------------------------*/
461 
BATTLE_GetOptions(battle_type * options)462 void BATTLE_GetOptions
463    (
464    battle_type *options
465    )
466 
467    {
468 	memcpy( options, &BattleOptions, sizeof( battle_type ) );
469    }
470 
471 
472 /*---------------------------------------------------------------------
473    Function: BATTLE_Shutdown
474 
475    Shutsdown the battle information.
476 ---------------------------------------------------------------------*/
477 
BATTLE_Shutdown(void)478 void BATTLE_Shutdown
479    (
480    void
481    )
482 
483    {
484    int index;
485    int index2;
486 
487    Timer             = 0;
488    RoundOver         = false;
489    BattleRound       = 0;
490    BattleMode        = battle_StandAloneGame;
491    BATTLEMODE        = false;
492    NumberOfPlayers   = 1;
493    BATTLE_NumberOfTeams = 1;
494    PointGoal         = 0;
495    KillsEndGame      = false;
496    KeepTrackOfKills  = false;
497 
498    for( index = 0; index < MAXPLAYERS; index++ )
499       {
500       BATTLE_Points[ index ] = 0;
501       for( index2 = 0; index2 < MAXPLAYERS; index2++ )
502          {
503          WhoKilledWho[ index ][ index2 ] = 0;
504          }
505 		gamestate.PlayerHasGun[ index ] = true;
506 		}
507 	gamestate.BattleOptions.SpawnHealth  = true;
508 	gamestate.BattleOptions.SpawnWeapons = true;
509 	gamestate.BattleOptions.SpawnDangers = true;
510    gamestate.BattleOptions.RandomWeapons = false;
511    gamestate.BattleOptions.FriendlyFire  = true;
512    gamestate.BattleOptions.WeaponPersistence = false;
513 	gamestate.BattleOptions.SpawnMines    = false;
514 
515 	gamestate.ShowScores        = true;
516 	gamestate.SpawnCollectItems = false;
517 	gamestate.SpawnEluder       = false;
518 	gamestate.SpawnDeluder      = false;
519 	}
520 
521 
522 
523 /*---------------------------------------------------------------------
524 	Function: BATTLE_StartRound
525 
526 	Begins a round of battle.
527 ---------------------------------------------------------------------*/
528 
BATTLE_StartRound(void)529 static battle_status BATTLE_StartRound
530 	(
531 	void
532 	)
533 
534 	{
535 	int index;
536 
537 	Timer     = 0;
538 	TimeLimit = INFINITE;
539 	RoundOver = false;
540 
541 	if ( !BATTLEMODE )
542 		{
543 		return( battle_no_event );
544 		}
545 
546 	BattleRound++;
547 
548 	if ( gamestate.BattleOptions.TimeLimit == bo_time_infinite )
549       {
550 		if ( BattleMode == battle_Hunter )
551 			{
552 	      TimeLimit = MINUTES_TO_GAMECOUNT( 99 );
553          }
554       else
555          {
556          TimeLimit = INFINITE;
557          }
558       }
559    else
560       {
561       TimeLimit = MINUTES_TO_GAMECOUNT( gamestate.BattleOptions.TimeLimit );
562       }
563 
564 	if ( BattleMode == battle_Hunter )
565 		{
566 		for( index = 0; index < MAXPLAYERS; index++ )
567 			{
568 			gamestate.PlayerHasGun[ index ] = true;
569 			}
570 
571 		if ( ( gamestate.BattleOptions.Kills != bo_kills_infinite ) &&
572          ( BattleRound >= PointGoal ) )
573 			{
574 			return( battle_end_game );
575 			}
576 
577       BATTLE_It = BattleRound % BATTLE_NumberOfTeams;
578       for( index = 0; index < NumberOfPlayers; index++ )
579          {
580          if ( BATTLE_Team[ index ] == BATTLE_It )
581             {
582             gamestate.PlayerHasGun[ index ] = false;
583             }
584          }
585 		}
586 
587 	return( battle_no_event );
588 	}
589 
590 /*---------------------------------------------------------------------
591 	Function: BATTLE_CheckGameStatus
592 
593 	Checks if certain battle mode conditions have been met and
594 	determines the appropriate response.
595 ---------------------------------------------------------------------*/
596 
BATTLE_CheckGameStatus(battle_event reason,int player)597 battle_status BATTLE_CheckGameStatus
598    (
599    battle_event reason,
600    int player
601    )
602 
603    {
604    battle_status status;
605    int team;
606 
607    if ( ( player < 0 ) || ( player >= MAXPLAYERS ) )
608       {
609       #if (BATTLECHECK == 1)
610          Error( "BATTLE_CheckGameStatus - reason %d : Player out of range!\n",
611             reason );
612       #else
613          return( battle_no_event );
614       #endif
615       }
616 
617    if ( !BATTLEMODE )
618       {
619       return( battle_no_event );
620       }
621 
622    team = BATTLE_Team[ player ];
623 
624    status = battle_no_event;
625 
626    switch( reason )
627       {
628       case battle_refresh :
629          Timer++;
630          if ( ( TimeLimit != INFINITE ) &&
631             ( Timer > TimeLimit ) )
632             {
633             RoundOver = true;
634 
635             if ( BattleMode == battle_Hunter )
636                {
637                status = BATTLE_StartRound();
638                if ( status == battle_no_event )
639                   {
640                   status = battle_end_round;
641                   }
642                }
643             else
644                {
645                status = battle_out_of_time;
646                }
647 
648             UpdateKills = true;
649             }
650 
651          if ( UpdateKills )
652             {
653             BATTLE_SortPlayerRanks();
654             if ( gamestate.ShowScores )
655                {
656                DrawKills (false);
657                }
658             UpdateKills = false;
659             }
660 
661          if ( RoundOver )
662             {
663             return( battle_end_game );
664             }
665          break;
666 
667       case battle_player_killed :
668          #if (BATTLEINFO == 1)
669             SoftError( "BATTLE_CheckGameStatus: Player %d Died", player );
670             SoftError( "---ticks = %d\n", Timer );
671          #endif
672 
673          switch( BattleMode )
674             {
675             case battle_Normal :
676             case battle_ScoreMore :
677             case battle_Hunter :
678                if ( BattleOptions.FriendlyFire )
679                   {
680                   BATTLE_Points[ team ]--;
681                   UpdateKills = true;
682                   }
683                break;
684 
685             case battle_Tag :
686                // Same as being tagged
687                if ( BattleOptions.FriendlyFire )
688                   {
689                   BATTLE_Points[ team ]++;
690                   UpdateKills = true;
691                   }
692                break;
693             }
694 
695          WhoKilledWho[ player ][ player ]++;
696          break;
697 
698       case battle_get_collector_item :
699 
700          if ( ( BattleMode != battle_Collector ) &&
701             ( BattleMode != battle_Scavenger ) )
702             {
703             #if (BATTLECHECK == 1)
704                Error( "BATTLE_CheckGameStatus : Got collector item on wrong battle mode!" );
705             #else
706                return( battle_no_event );
707             #endif
708             }
709          BATTLE_Points[ team ]++;
710          UpdateKills = true;
711 
712          BATTLE_NumCollectorItems--;
713          if ( BATTLE_NumCollectorItems <= 0 )
714             {
715             RoundOver = true;
716             return( battle_end_game );
717             }
718          break;
719 
720       case battle_caught_eluder :
721          if ( BattleMode == battle_Deluder )
722             {
723             return( battle_no_event );
724             }
725 
726          if ( BattleMode != battle_Eluder )
727             {
728             #if (BATTLECHECK == 1)
729                Error( "BATTLE_CheckGameStatus : Caught Eluder on non-Eluder battle mode!" );
730             #else
731                return( battle_no_event );
732             #endif
733             }
734 
735          BATTLE_Points[ team ]++;
736          UpdateKills = true;
737 
738          if ( ( gamestate.BattleOptions.Kills != bo_kills_infinite ) &&
739             ( BATTLE_Points[ team ] >= PointGoal ) )
740             {
741             RoundOver = true;
742             return( battle_end_game );
743             }
744          RespawnEluder();
745          break;
746 
747       case battle_shot_deluder :
748          if ( BattleMode == battle_Eluder )
749             {
750             return( battle_no_event );
751             }
752 
753          if ( BattleMode != battle_Deluder )
754             {
755             #if (BATTLECHECK == 1)
756                Error( "BATTLE_CheckGameStatus : Shot Eluder on non-Eluder battle mode!" );
757             #else
758                return( battle_no_event );
759             #endif
760             }
761 
762          BATTLE_Points[ team ]++;
763          UpdateKills = true;
764 
765          if ( ( gamestate.BattleOptions.Kills != bo_kills_infinite ) &&
766             ( BATTLE_Points[ team ] >= PointGoal ) )
767             {
768             RoundOver = true;
769             return( battle_end_game );
770             }
771          RespawnEluder();
772          break;
773 
774       case battle_captured_triad :
775          if ( BattleMode != battle_CaptureTheTriad )
776             {
777             #if (BATTLECHECK == 1)
778                Error( "BATTLE_CheckGameStatus : Triad Captured on invalid battle mode!" );
779             #else
780                return( battle_no_event );
781             #endif
782             }
783 
784          if ( consoleplayer == player )
785             {
786             AddMessage( "You captured a triad!  You rule!", MSG_GAME );
787             }
788 
789          BATTLE_Points[ team ]++;
790          UpdateKills = true;
791 
792          if ( ( gamestate.BattleOptions.Kills != bo_kills_infinite ) &&
793             ( BATTLE_Points[ team ] >= PointGoal ) )
794             {
795             RoundOver = true;
796             return( battle_end_game );
797             }
798          break;
799 
800       default :
801          #if (BATTLECHECK == 1)
802             Error( "BATTLE_CheckGameStatus called with a reason of %d.",
803                reason );
804          #else
805             return( battle_no_event );
806          #endif
807          break;
808       }
809 
810    return( status );
811    }
812 
813 /*---------------------------------------------------------------------
814    Function: BATTLE_SortPlayerRanks
815 
816    Sorts the players in order of score.
817 ---------------------------------------------------------------------*/
818 
BATTLE_SortPlayerRanks(void)819 void BATTLE_SortPlayerRanks
820    (
821    void
822    )
823 
824    {
825    int i;
826    int j;
827    int temp;
828 
829    SwapFlag = false;
830 
831    if ( BattleMode == battle_Tag )
832       {
833       for( i = 0; i < BATTLE_NumberOfTeams - 1; i++ )
834          {
835          for( j = i + 1; j < BATTLE_NumberOfTeams; j++ )
836             {
837             if ( BATTLE_Points[ BATTLE_PlayerOrder[ i ] ] >
838                BATTLE_Points[ BATTLE_PlayerOrder[ j ] ] )
839                {
840                SwapFlag = true;
841                temp = BATTLE_PlayerOrder[ i ];
842                BATTLE_PlayerOrder[ i ] = BATTLE_PlayerOrder[ j ];
843                BATTLE_PlayerOrder[ j ] = temp;
844                }
845             }
846          }
847       }
848    else
849       {
850       for( i = 0; i < BATTLE_NumberOfTeams - 1; i++ )
851          {
852          for( j = i + 1; j < BATTLE_NumberOfTeams; j++ )
853             {
854             if ( BATTLE_Points[ BATTLE_PlayerOrder[ i ] ] <
855                BATTLE_Points[ BATTLE_PlayerOrder[ j ] ] )
856                {
857                SwapFlag = true;
858                temp = BATTLE_PlayerOrder[ i ];
859                BATTLE_PlayerOrder[ i ] = BATTLE_PlayerOrder[ j ];
860                BATTLE_PlayerOrder[ j ] = temp;
861                }
862             }
863 
864          if ( BattleMode != battle_Hunter )
865             {
866             BATTLE_It = BATTLE_PlayerOrder[ 0 ];
867             }
868          }
869       }
870 
871    #if (BATTLEINFO == 1)
872       for( i = 0; i < BATTLE_NumberOfTeams; i++ )
873          {
874          SoftError( "Sorted rank %d = player %d : Score = %d\n", i,
875             BATTLE_PlayerOrder[ i ], BATTLE_Points[ BATTLE_PlayerOrder[ i ] ] );
876          }
877    #endif
878 
879    if ( ( SwapFlag == true ) && ( gamestate.ShowScores ) &&
880       ( SHOW_TOP_STATUS_BAR() || SHOW_KILLS() ) )
881       {
882       SD_Play ( SD_ENDBONUS1SND );
883       }
884    }
885 
886 
887 /*---------------------------------------------------------------------
888    Function: BATTLE_PlayerKilledPlayer
889 
890    Increases the number of kills a player has.
891 ---------------------------------------------------------------------*/
892 
BATTLE_PlayerKilledPlayer(battle_event reason,int killer,int victim)893 battle_status BATTLE_PlayerKilledPlayer
894    (
895    battle_event reason,
896    int killer,
897    int victim
898    )
899 
900    {
901    int points;
902    int status;
903    int killerteam;
904    int victimteam;
905 
906    #if (BATTLEINFO == 1)
907       SoftError( "PlayerKilledPlayer:\nMode = %d\n", BattleMode );
908       SoftError( "Reason = %d\n", reason );
909       SoftError( "killer = %d, team = %d\n", killer, killerteam );
910       SoftError( "victim = %d, team = %d\n", victim, victimteam );
911       SoftError( "---ticks = %d\n", Timer );
912    #endif
913 
914    if ( ( killer < 0 ) || ( killer >= MAXPLAYERS ) )
915       {
916       #if (BATTLECHECK == 1)
917          Error( "BATTLE_PlayerKilledPlayer - reason %d : Killer out of range!\n",
918             reason );
919       #else
920          return( battle_no_event );
921       #endif
922       }
923    if ( ( victim < 0 ) || ( victim >= MAXPLAYERS ) )
924       {
925       #if (BATTLECHECK == 1)
926          Error( "BATTLE_PlayerKilledPlayer - reason %d : Victim out of range!\n",
927             reason );
928       #else
929          return( battle_no_event );
930       #endif
931       }
932 
933    if ( ( killer == victim ) && ( reason != battle_kill_with_missile ) &&
934       ( reason != battle_kill_with_missile_in_air ) )
935       {
936       #if (BATTLECHECK == 1)
937          Error( "BATTLE_PlayerKilledPlayer : Player "
938          "killed self with illegal reason of %d.", reason );
939       #else
940          return( battle_no_event );
941       #endif
942       }
943 
944    killerteam = BATTLE_Team[ killer ];
945    victimteam = BATTLE_Team[ victim ];
946 
947    if ( ( killerteam < 0 ) || ( killerteam >= BATTLE_NumberOfTeams ) ||
948       ( victimteam < 0 ) || ( victimteam >= BATTLE_NumberOfTeams ) )
949       {
950       #if (BATTLECHECK == 1)
951          Error( "BATTLE_PlayerKilledPlayer - reason %d : Team out of range!\n",
952             reason );
953       #else
954          return( battle_no_event );
955       #endif
956       }
957 
958    if ( !BATTLEMODE )
959       {
960       return( battle_no_event );
961       }
962 
963    if ( ( consoleplayer == victim ) &&
964       ( reason == battle_kill_by_crushing ) )
965       {
966       AddMessage( "Oh yeah.  You've been crushed.", MSG_GAME );
967       }
968 
969    status = battle_no_event;
970    if ( BattleMode == battle_ScoreMore )
971       {
972       points = 0;
973       switch( reason )
974          {
975          case battle_kill_with_missile :
976             points = 1;
977             break;
978 
979          case battle_kill_with_bullet :
980             points = 2;
981             break;
982 
983          case battle_kill_with_missile_in_air :
984             points = 2;
985             break;
986 
987          case battle_kill_with_bullet_in_air :
988             points = 3;
989             break;
990 
991          case battle_kill_by_crushing :
992             points = 4;
993             break;
994 
995          default :
996             #if (BATTLECHECK == 1)
997                Error( "BATTLE_PlayerKilledPlayer called with a reason of %d.",
998                   reason );
999             #else
1000                return( battle_no_event );
1001             #endif
1002          }
1003 
1004       if ( killerteam == victimteam )
1005          {
1006          if ( BattleOptions.FriendlyFire )
1007             {
1008             BATTLE_Points[ killerteam ]--;
1009             WhoKilledWho[ killer ][ victim ]++;
1010             }
1011          }
1012       else
1013          {
1014          BATTLE_Points[ killerteam ]      += points;
1015          WhoKilledWho[ killer ][ victim ] += points;
1016          }
1017       UpdateKills = true;
1018       }
1019    else if ( BattleMode == battle_Tag )
1020       {
1021       if ( reason == battle_player_tagged )
1022          {
1023          WhoKilledWho[ killer ][ victim ]++;
1024          BATTLE_Points[ victimteam ]++;
1025          UpdateKills = true;
1026          BATTLE_It   = victimteam;
1027 
1028          if ( ( gamestate.BattleOptions.Kills != bo_kills_infinite ) &&
1029             ( BATTLE_Points[ victimteam ] >= PointGoal ) )
1030             {
1031             RoundOver = true;
1032             status = battle_end_game;
1033             }
1034          }
1035       #if (BATTLECHECK == 1)
1036       else if ( reason != battle_kill_by_crushing )
1037          {
1038          Error( "BATTLE_PlayerKilledPlayer - reason %d : "
1039             "Illegal reason in Tag!\n", reason );
1040          }
1041       #endif
1042 
1043       return( status );
1044       }
1045    else if ( BattleMode == battle_Hunter )
1046       {
1047       switch( reason )
1048          {
1049          case battle_kill_with_missile :
1050          case battle_kill_with_bullet :
1051          case battle_kill_with_missile_in_air :
1052          case battle_kill_with_bullet_in_air :
1053          case battle_kill_by_crushing :
1054             if ( victimteam == BATTLE_It )
1055                {
1056                WhoKilledWho[ killer ][ victim ]++;
1057                if ( killerteam == victimteam )
1058                   {
1059                   if ( BattleOptions.FriendlyFire )
1060                      {
1061                      BATTLE_Points[ killerteam ]--;
1062                      UpdateKills = true;
1063                      }
1064                   }
1065                else
1066                   {
1067                   BATTLE_Points[ killerteam ]++;
1068                   UpdateKills = true;
1069                   }
1070                }
1071             break;
1072          default :
1073          #if (BATTLECHECK == 1)
1074             Error( "BATTLE_PlayerKilledPlayer called with a "
1075                "reason of %d in Hunter.", reason );
1076          #else
1077 	    ;
1078          #endif
1079          }
1080       }
1081    else
1082       {
1083       switch( reason )
1084          {
1085          case battle_kill_with_missile :
1086          case battle_kill_with_bullet :
1087          case battle_kill_with_missile_in_air :
1088          case battle_kill_with_bullet_in_air :
1089          case battle_kill_by_crushing :
1090             WhoKilledWho[ killer ][ victim ]++;
1091             if ( KeepTrackOfKills )
1092                {
1093                if ( killerteam == victimteam )
1094                   {
1095                   if ( BattleMode == battle_Normal )
1096                      {
1097                      if ( BattleOptions.FriendlyFire )
1098                         {
1099                         BATTLE_Points[ killerteam ]--;
1100                         UpdateKills = true;
1101                         }
1102                      }
1103                   }
1104                else
1105                   {
1106                   BATTLE_Points[ killerteam ]++;
1107                   UpdateKills = true;
1108                   }
1109                }
1110             break;
1111 
1112          default :
1113             #if (BATTLECHECK == 1)
1114                Error( "BATTLE_PlayerKilledPlayer called with a reason of %d.",
1115                   reason );
1116             #else
1117                return( battle_no_event );
1118             #endif
1119          }
1120       }
1121 
1122    if ( ( KillsEndGame ) && ( BATTLE_Points[ killerteam ] >= PointGoal ) )
1123       {
1124       RoundOver = true;
1125       status = battle_end_game;
1126       }
1127 
1128    return( status );
1129    }
1130