1 /* Patrick 19/3/97 -----------------------------------------------------
2   Source for Multi-Player game support
3   ----------------------------------------------------------------------*/
4 
5 #include <ctype.h>
6 #include "3dc.h"
7 #include "inline.h"
8 #include "module.h"
9 #include "stratdef.h"
10 #include "gamedef.h"
11 #include "bh_types.h"
12 #include "dynblock.h"
13 #include "dynamics.h"
14 #include "bh_debri.h"
15 #include "pvisible.h"
16 #include "bh_plift.h"
17 #include "pldnet.h"
18 #include "pldghost.h"
19 #include "equipmnt.h"
20 #include "weapons.h"
21 #include "multmenu.h"
22 #include "bh_gener.h"
23 #include "bh_lnksw.h"
24 #include "bh_track.h"
25 #include "psnd.h"
26 #include "kshape.h"
27 #include "pfarlocs.h"
28 #include "avpview.h"
29 #include "net.h"
30 #include "los.h"
31 #include "maths.h"
32 #include "opengl.h"
33 
34 /* these required sequence enumerations...*/
35 #include "bh_pred.h"
36 #include "bh_alien.h"
37 #include "bh_marin.h"
38 #include "bh_binsw.h"
39 #include "bh_agun.h"
40 #include "bh_weap.h"
41 
42 #include "bh_corpse.h"
43 #include "bh_light.h"
44 
45 #include "scream.h"
46 
47 #include "targeting.h"
48 
49 #include "iofocus.h"
50 
51 #define UseLocalAssert Yes
52 #include "ourasert.h"
53 #include "showcmds.h"
54 #define DB_LEVEL 3
55 #include "db.h"
56 
57 /* in net.c */
58 extern DPID AVPDPNetID;
59 extern int QuickStartMultiplayer;
60 extern DPNAME AVPDPplayerName;
61 extern int glpDP;
62 
63 #define CalculateBytesSentPerSecond 0
64 
65 /*----------------------------------------------------------------------
66   Some globals for use in this file
67   ----------------------------------------------------------------------*/
68 NETGAME_GAMEDATA netGameData=
69 {
70 	0,	//NETGAME_STATES myGameState;
71 	0,	//NETGAME_CHARACTERTYPE myCharacterType;
72 	0,	//NETGAME_CHARACTERTYPE myNextCharacterType; //if player is currently dead and about to become a new character
73 	0,	//NETGAME_SPECIALISTCHARACTERTYPE myCharacterSubType;
74 	0,	//unsigned char myStartFlag;
75 	{{0},},	//NETGAME_PLAYERDATA playerData[NET_MAXPLAYERS];
76 	{0,},	//int teamScores[3];
77 	0,	//NETGAME_TYPE gameType;
78 	0,	//unsigned char levelNumber;
79 	1000000,	//unsigned int scoreLimit;
80 	255,	//unsigned char timeLimit;
81 	5,	//int invulnerableTime;//in seconds after respawn
82 	0,	//int GameTimeElapsed;
83 
84 	//scoring system stuff
85 	{100,150,75},	//int characterKillValues[3];
86 	100,	//int baseKillValue;
87 	TRUE,	//BOOL useDynamicScoring;
88 	TRUE,	//BOOL useCharacterKillValues;
89 
90 	{75,100,150},	//int aiKillValues[3];
91 
92 	//for last man standing game
93 	-1,	//int LMS_AlienIndex;
94 	0,	//int LMS_RestartTimer;
95 
96 	0,	//int stateCheckTimeDelay;
97 
98 	/*following timer used to prevent the game description from being sent every frame*/
99 	0,	//int gameDescriptionTimeDelay;
100 
101 	/*sendFrequencey - how often to send messages in fixed point seconds*/
102 	0,	//int sendFrequency;
103 	0,	//int sendTimer;
104 
105 	//player type limits
106 	8,	//unsigned int maxPredator;
107 	8,	//unsigned int maxAlien;
108 	8,	//unsigned int maxMarine;
109 
110 	8,	//unsigned int maxMarineGeneral;
111 	8,	//unsigned int maxMarinePulseRifle;
112 	8,	//unsigned int maxMarineSmartgun;
113 	8,	//unsigned int maxMarineFlamer;
114 	8,	//unsigned int maxMarineSadar;
115 	8,	//unsigned int maxMarineGrenade;
116 	8,	//unsigned int maxMarineMinigun;
117 	8,	//unsigned int maxMarineSmartDisc;
118 	8,	//unsigned int maxMarinePistols;
119 
120 	//weapons allowed
121 	TRUE,	//BOOL allowSmartgun;
122 	TRUE,	//BOOL allowFlamer;
123 	TRUE,	//BOOL allowSadar;
124 	TRUE,	//BOOL allowGrenadeLauncher;
125 	TRUE,	//BOOL allowMinigun;
126 	TRUE,	//BOOL allowDisc;
127 	TRUE,	//BOOL allowPistol;
128 	TRUE,	//BOOL allowPlasmaCaster;
129 	TRUE,	//BOOL allowSpeargun;
130 	TRUE,	//BOOL allowMedicomp;
131 	TRUE,	//BOOL allowSmartDisc;
132 	TRUE,	//BOOL allowPistols;
133 
134 	0,		//int maxLives;
135 	FALSE,	//BOOL useSharedLives;
136 	{0,0,0},//int numDeaths[3];
137 
138 	0,		//int pointsForResapwn;
139 	40,		//int timeForRespawn; //seconds
140 
141 	0,		//int lastPointsBasedRespawn;
142 
143 	TRUE,	//BOOL sendDecals;
144 	0,	//unsigned int needGameDescription :1;
145 	FALSE,	//BOOL skirmishMode
146 
147 	-1, //char myLastScream;
148 
149 	NETGAMESPEED_100PERCENT, //int gameSpeed;
150 	0,	//BOOL preDestroyLights;
151 	0,	//BOOL disableFriendlyFire;
152 	1,	//BOOL fallingDamage;
153 	1,	//BOOL pistolInfiniteAmmo;
154 	1,	//BOOL specialistPistols;
155 	0,	//int myStrategyCheckSum;
156 
157 	0,	//unsigned int tcpip_available :1;
158 	0,	//unsigned int ipx_available :1;
159 	0,	//unsigned int modem_available :1;
160 	0,	//unsigned int serial_available :1;
161 	0,	//NETGAME_CONNECTIONTYPE connectionType;
162 
163 	0,	//landingNoise:1;
164 	0,	//int joiningGameStatus;
165 	"", //char customLevelName[];
166 };
167 
SetDefaultMultiplayerConfig()168 void SetDefaultMultiplayerConfig()
169 {
170 	netGameData.scoreLimit=1000000;
171 	netGameData.timeLimit=255;
172 	netGameData.invulnerableTime=5;
173 	netGameData.characterKillValues[0]=100;
174 	netGameData.characterKillValues[1]=150;
175 	netGameData.characterKillValues[2]=75;
176 
177 	netGameData.baseKillValue=100;
178 	netGameData.useDynamicScoring=1;
179 	netGameData.useCharacterKillValues=1;
180 
181 	netGameData.aiKillValues[0]=75;
182 	netGameData.aiKillValues[1]=100;
183 	netGameData.aiKillValues[2]=150;
184 
185 	netGameData.maxMarine=8;
186 	netGameData.maxAlien=8;
187 	netGameData.maxPredator=8;
188 	netGameData.maxMarineGeneral=8;
189 	netGameData.maxMarinePulseRifle=8;
190 	netGameData.maxMarineSmartgun=8;
191 	netGameData.maxMarineFlamer=8;
192 	netGameData.maxMarineSadar=8;
193 	netGameData.maxMarineGrenade=8;
194 	netGameData.maxMarineMinigun=8;
195 	netGameData.maxMarineSmartDisc=8;
196 	netGameData.maxMarinePistols=8;
197 
198 	netGameData.allowSmartgun=1;
199 	netGameData.allowFlamer=1;
200 	netGameData.allowSadar=1;
201 	netGameData.allowGrenadeLauncher=1;
202 	netGameData.allowMinigun=1;
203 	netGameData.allowDisc=1;
204 	netGameData.allowPistol=1;
205 	netGameData.allowPlasmaCaster=1;
206 	netGameData.allowSpeargun=1;
207 	netGameData.allowMedicomp=1;
208 	netGameData.allowSmartDisc=1;
209 	netGameData.allowPistols=1;
210 
211 	netGameData.maxLives=0;
212 	netGameData.useSharedLives=0;
213 	netGameData.pointsForRespawn=0;
214 	netGameData.timeForRespawn=40;
215 
216 	netGameData.gameSpeed=NETGAMESPEED_100PERCENT;
217 
218 	netGameData.preDestroyLights=FALSE;
219 	netGameData.disableFriendlyFire=FALSE;
220 	netGameData.fallingDamage=TRUE;
221 	netGameData.pistolInfiniteAmmo=TRUE;
222 	netGameData.specialistPistols=TRUE;
223 }
224 
225 int LobbiedGame=0;
226 
227 
228 
229 
230 static char sendBuffer[NET_MESSAGEBUFFERSIZE];
231 static char *endSendBuffer;
232 static int netNextLocalObjectId = 1;
233 DPID myNetworkKillerId = 0;
234 DPID myIgniterId = 0;
235 int MyHitBodyPartId=-1;
236 DPID MultiplayerObservedPlayer=0;
237 
238 /* for testing */
239 static int numMessagesReceived = 0;
240 static int numMessagesTransmitted = 0;
241 
242 static char OnScreenMessageBuffer[300];
243 
244 static unsigned char FragmentalObjectStatus[NUMBER_OF_FRAGMENTAL_OBJECTS];
245 static unsigned char StrategySynchArray[NUMBER_OF_STRATEGIES_TO_SYNCH>>2];
246 
247 int numMarineStartPos=0;
248 int numAlienStartPos=0;
249 int numPredatorStartPos=0;
250 
251 MULTIPLAYER_START* marineStartPositions=0;
252 MULTIPLAYER_START* alienStartPositions=0;
253 MULTIPLAYER_START* predatorStartPositions=0;
254 
255 
256 int ShowMultiplayerScoreTimer=0;
257 int MultiplayerRestartSeed=0;
258 
259 static int GameTimeSinceLastSend=0;
260 
261 static unsigned int TimeCounterForExtrapolation=0;
262 
263 /*----------------------------------------------------------------------
264   External globals (& protoypes)
265   ----------------------------------------------------------------------*/
266 extern int NormalFrameTime;
267 extern int RealFrameTime;
268 extern int TimeScale;
269 extern int PrevNormalFrameTime;
270 
271 extern void UpdateAlienAIGhostAnimSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime);
272 extern void RemovePickedUpObject(STRATEGYBLOCK *objectPtr);
273 extern void PrintStringTableEntryInConsole(enum TEXTSTRING_ID string_id);
274 extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock;
275 extern int DebouncedGotAnyKey;
276 extern int LastHand;  // For alien claws and two pistols
277 
278 extern void CreateSpearPossiblyWithFragment(DISPLAYBLOCK *dispPtr, VECTORCH *spearPositionPtr, VECTORCH *spearDirectionPtr);
279 extern void NewOnScreenMessage(unsigned char *messagePtr);
280 /*----------------------------------------------------------------------
281   Some protoypes for this file
282   ----------------------------------------------------------------------*/
283 static void ProcessSystemMessage(char *msgP,unsigned int msgSize);
284 static void ProcessGameMessage(DPID senderId, char *msgP,unsigned int msgSize);
285 static void AddPlayerToGame(DPID id, char*name);
286 static void AddPlayerAndObjectUpdateMessages(void);
287 static void UpdateNetworkGameScores(DPID playerKilledId, DPID killerId,NETGAME_CHARACTERTYPE playerKilledType,NETGAME_CHARACTERTYPE killerType);
288 //static void ConvertNetNameToUpperCase(char *strPtr);
289 
290 static void ProcessNetMsg_GameDescription(NETMESSAGE_GAMEDESCRIPTION *msgPtr);
291 static void ProcessNetMsg_PlayerDescription(NETMESSAGE_PLAYERDESCRIPTION *msgPtr, DPID senderId);
292 static void ProcessNetMsg_StartGame(void);
293 static void ProcessNetMsg_PlayerState(NETMESSAGE_PLAYERSTATE *msgPtr, DPID senderId);
294 static void ProcessNetMsg_PlayerState_Minimal(NETMESSAGE_PLAYERSTATE_MINIMAL *msgPtr, DPID senderId,BOOL orientation);
295 static void ProcessNetMsg_FrameTimer(unsigned short frame_time, DPID senderId);
296 static void ProcessNetMsg_PlayerKilled(NETMESSAGE_PLAYERKILLED *msgPtr, DPID senderId);
297 static void ProcessNetMsg_PlayerDeathAnim(NETMESSAGE_CORPSEDEATHANIM* messagePtr,DPID senderId);
298 static void ProcessNetMsg_PlayerLeaving(DPID senderId);
299 static void ProcessNetMsg_AllGameScores(NETMESSAGE_ALLGAMESCORES *msgPtr);
300 static void ProcessNetMsg_PlayerScores(NETMESSAGE_PLAYERSCORES *msgPtr);
301 static void ProcessNetMsg_SpeciesScores(NETMESSAGE_SPECIESSCORES *msgPtr);
302 static void ProcessNetMsg_LocalRicochet(NETMESSAGE_LOCALRICOCHET *msgPtr);
303 static void ProcessNetMsg_LocalObjectState(NETMESSAGE_LOBSTATE *msgPtr, DPID senderId);
304 static void ProcessNetMsg_LocalObjectDamaged(char *msgPtr, DPID senderId);
305 static void ProcessNetMsg_LocalObjectDestroyed(NETMESSAGE_LOBDESTROYED *msgPtr, DPID senderId);
306 static void ProcessNetMsg_ObjectPickedUp(NETMESSAGE_OBJECTPICKEDUP *messagePtr);
307 static void ProcessNetMsg_EndGame(void);
308 static void ProcessNetMsg_InanimateObjectDamaged(char *msgPtr);
309 static void ProcessNetMsg_InanimateObjectDestroyed(NETMESSAGE_INANIMATEDESTROYED *msgPtr);
310 static void ProcessNetMsg_LOSRequestBinarySwitch(NETMESSAGE_LOSREQUESTBINARYSWITCH *msgPtr);
311 static void ProcessNetMsg_PlatformLiftState(NETMESSAGE_PLATFORMLIFTSTATE *msgPtr);
312 static void ProcessNetMsg_RequestPlatformLiftActivate(NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE *msgPtr);
313 static void ProcessNetMsg_PlayerAutoGunState(NETMESSAGE_AGUNSTATE *msgPtr, DPID senderId);
314 static char *ProcessNetMsg_ChatBroadcast(char *subMessagePtr, DPID senderId);
315 static void ProcessNetMsg_MakeExplosion(NETMESSAGE_MAKEEXPLOSION *messagePtr);
316 static void ProcessNetMsg_MakeFlechetteExplosion(NETMESSAGE_MAKEFLECHETTEEXPLOSION *messagePtr);
317 static void ProcessNetMsg_MakePlasmaExplosion(NETMESSAGE_MAKEPLASMAEXPLOSION *messagePtr);
318 static void ProcessNetMsg_PredatorSights(NETMESSAGE_PREDATORSIGHTS *messagePtr, DPID senderId);
319 static void ProcessNetMsg_FragmentalObjectsStatus(NETMESSAGE_FRAGMENTALOBJECTSSTATUS *messagePtr);
320 static void ProcessNetMsg_StrategySynch(NETMESSAGE_STRATEGYSYNCH *messagePtr);
321 static void ProcessNetMsg_LocalObjectOnFire(NETMESSAGE_LOBONFIRE *messagePtr, DPID senderId);
322 static void ProcessNetMsg_AlienAIState(NETMESSAGE_ALIENAISTATE *messagePtr, DPID senderId);
323 static void ProcessNetMsg_FarAlienPosition(NETMESSAGE_FARALIENPOSITION *messagePtr, DPID senderId);
324 static void ProcessNetMsg_SpotAlienSound(NETMESSAGE_SPOTALIENSOUND *messagePtr, DPID senderId);
325 static void ProcessNetMsg_LocalObjectDestroyed_Request(NETMESSAGE_LOBDESTROYED_REQUEST *messagePtr, DPID senderId);
326 static void ProcessNetMsg_ScoreChange(NETMESSAGE_SCORECHANGE *messagePtr);
327 static void ProcessNetMsg_CreateWeapon(NETMESSAGE_CREATEWEAPON *messagePtr);
328 static void ProcessNetMsg_Gibbing(NETMESSAGE_GIBBING* messagePtr,DPID senderId);
329 static void ProcessNetMsg_GhostHierarchyDamaged(char *messagePtr, DPID senderId);
330 static void ProcessNetMsg_MakeDecal(NETMESSAGE_MAKEDECAL *messagePtr);
331 static void ProcessNetMsg_AlienAISequenceChange(NETMESSAGE_ALIENSEQUENCECHANGE *messagePtr, DPID senderId);
332 static void ProcessNetMsg_AlienAIKilled(NETMESSAGE_ALIENAIKILLED *messagePtr, DPID senderId);
333 static void ProcessNetMsg_SpotOtherSound(NETMESSAGE_SPOTOTHERSOUND *messagePtr, DPID senderId);
334 void StartOfGame_PlayerPlacement(STRATEGYBLOCK *playerSbPtr,int seed);
335 
336 static void CheckLastManStandingState();
337 static void Handle_LastManStanding_Restart(DPID alienID,int seed);
338 static void Handle_LastManStanding_RestartInfo(DPID alienID);
339 static void Handle_LastManStanding_LastMan(DPID marineID);
340 static void Handle_LastManStanding_RestartTimer(unsigned char time);
341 
342 static void CheckSpeciesTagState();
343 static void Handle_SpeciesTag_NewPersonIt(DPID predatorID);
344 static int CountPlayersOfType(NETGAME_CHARACTERTYPE species);
345 
346 static int GetSizeOfLocalObjectDamagedMessage(char* messagePtr);
347 static int GetSizeOfGhostHierarchyDamagedMessage(char* messagePtr);
348 static int GetSizeOfInanimateDamagedMessage(char *messagePtr);
349 
350 static STRATEGYBLOCK *FindObjectFromNetIndex(int obIndex);
351 static STRATEGYBLOCK *FindEnvironmentObjectFromName(char *name);
352 static void InitialiseSendMessageBuffer(void);
353 
354 static MARINE_SEQUENCE GetMyMarineSequence(void);
355 static ALIEN_SEQUENCE GetMyAlienSequence(void);
356 static PREDATOR_SEQUENCE GetMyPredatorSequence(void);
357 
358 
359 static void Inform_PlayerHasDied(DPID killer, DPID victim,NETGAME_CHARACTERTYPE killerType,char weaponIcon);
360 static void Inform_AiHasDied(DPID killer,ALIEN_TYPE type,char weaponIcon);
361 static void Inform_PlayerHasLeft(DPID player);
362 static void Inform_PlayerHasJoined(DPID player);
363 static void Inform_PlayerHasConnected(DPID player);
364 static void Inform_NewHost(void);
365 
366 static void WriteFragmentStatus(int fragmentNumber, int status);
367 static int ReadFragmentStatus(int fragmentNumber);
368 
369 static void WriteStrategySynch(int objectNumber, int status);
370 static int ReadStrategySynch(int objectNumber);
371 
372 static int GetStrategySynchObjectChecksum();
373 
374 static int GetDynamicScoreMultiplier(int playerKilledIndex,int killerIndex);
375 static int GetNetScoreForKill(int playerKilledIndex,int killerIndex);
376 
377 static void NetworkGameConsoleMessage(enum TEXTSTRING_ID stringID,const char* name1,const char* name2);
378 static void NetworkGameConsoleMessageWithWeaponIcon(enum TEXTSTRING_ID stringID,const char* name1,const char* name2,const char* weaponSymbol);
379 
380 static void CheckForPointBasedObjectRespawn();
381 
382 static int CalculateMyScore();
383 
384 static void PeriodicScoreUpdate();
385 
386 void CheckStateOfObservedPlayer();
387 static int MyPlayerHasAMuzzleFlash(STRATEGYBLOCK *sbPtr);
388 
389 /*----------------------------------------------------------------------
390   Initalisation of net game
391   ----------------------------------------------------------------------*/
InitAVPNetGame(void)392 void InitAVPNetGame(void)
393 {
394 	extern int QuickStartMultiplayer;
395 	/* init garry's dp extended */
396 	DpExtInit(0,0,0);
397 
398 	/* init the send message buffer */
399 	InitialiseSendMessageBuffer();
400 
401 	/* base initialisation of game description */
402 	{
403 		int i,j;
404 		for(i=0;i<(NET_MAXPLAYERS);i++)
405 		{
406 			netGameData.playerData[i].playerId = 0;
407 			for(j=0;j<(NET_PLAYERNAMELENGTH);j++) netGameData.playerData[i].name[j] = '\0';
408 			netGameData.playerData[i].characterType = NGCT_Marine;
409 			netGameData.playerData[i].characterSubType = NGSCT_General;
410 			for(j=0;j<(NET_MAXPLAYERS);j++) netGameData.playerData[i].playerFrags[j] = 0;
411 			netGameData.playerData[i].playerScore=0;
412 			netGameData.playerData[i].playerScoreAgainst=0;
413 			netGameData.playerData[i].aliensKilled[0]=0;
414 			netGameData.playerData[i].aliensKilled[1]=0;
415 			netGameData.playerData[i].aliensKilled[2]=0;
416 			netGameData.playerData[i].deathsFromAI=0;
417 			netGameData.playerData[i].playerAlive=1;
418 			netGameData.playerData[i].playerHasLives=1;
419 			netGameData.playerData[i].startFlag = 0;
420 		}
421 		for(j=0;j<3;j++) netGameData.teamScores[j] = 0;
422 		netGameData.myGameState = NGS_Joining;
423 		switch (QuickStartMultiplayer)
424 		{
425 			default:
426 			case 1:
427 				netGameData.myCharacterType = NGCT_Marine;
428 				netGameData.myNextCharacterType = NGCT_Marine;
429 				break;
430 
431 			case 2:
432 				netGameData.myCharacterType = NGCT_Alien;
433 				netGameData.myNextCharacterType = NGCT_Alien;
434 				break;
435 
436 			case 3:
437 				netGameData.myCharacterType = NGCT_Predator;
438 				netGameData.myNextCharacterType = NGCT_Predator;
439 				break;
440 		}
441 
442 		netGameData.myStartFlag = 0;
443 		netGameData.gameType = NGT_Individual;
444 		netGameData.levelNumber = 0;
445 		netGameData.scoreLimit = 0;
446 		netGameData.timeLimit = 0;
447 		netGameData.invulnerableTime = 5;
448 		netGameData.GameTimeElapsed = 0;
449 
450 		netGameData.LMS_AlienIndex=-1;
451 		netGameData.stateCheckTimeDelay=0;
452 		netGameData.LMS_RestartTimer=0;
453 	}
454 
455 	myNetworkKillerId = AVPDPNetID;	/* init global id of player who killed me last */
456 	netNextLocalObjectId = 1;	/* init local object network id */
457 	numMessagesReceived = 0;	/* these are for testing */
458 	numMessagesTransmitted = 0;
459 
460 	/* If I'm the host, add myself to the game data */
461 	if(AvP.Network==I_Host)
462 	{
463 		netGameData.playerData[0].playerId = AVPDPNetID;
464 		strncpy(netGameData.playerData[0].name,AVPDPplayerName.lpszShortNameA,NET_PLAYERNAMELENGTH-1);
465 		netGameData.playerData[0].name[NET_PLAYERNAMELENGTH-1] = '\0';
466 //		ConvertNetNameToUpperCase(netGameData.playerData[0].name);
467 	}
468 
469 	InitNetLog();
470 }
471 
InitAVPNetGameForHost(int species,int gamestyle,int level)472 void InitAVPNetGameForHost(int species, int gamestyle, int level)
473 {
474 	AvP.GameMode = I_GM_Playing;
475 	AvP.Network = I_Host;
476 	AvP.NetworkAIServer = (gamestyle==NGT_Coop);
477 	/* init garry's dp extended */
478 	if(!netGameData.skirmishMode)
479 	{
480 		DpExtInit(0,0,0);
481 	}
482 
483 	/* init the send message buffer */
484 	InitialiseSendMessageBuffer();
485 
486 	netGameData.myGameState = NGS_Joining;
487 	/* base initialisation of game description */
488 	{
489 		int i,j;
490 		for(i=0;i<(NET_MAXPLAYERS);i++)
491 		{
492 			netGameData.playerData[i].playerId = 0;
493 			for(j=0;j<(NET_PLAYERNAMELENGTH);j++) netGameData.playerData[i].name[j] = '\0';
494 			netGameData.playerData[i].characterType = NGCT_Marine;
495 			netGameData.playerData[i].characterSubType = NGSCT_General;
496 			for(j=0;j<(NET_MAXPLAYERS);j++) netGameData.playerData[i].playerFrags[j] = 0;
497 			netGameData.playerData[i].playerScore = 0;
498 			netGameData.playerData[i].playerScoreAgainst = 0;
499 			netGameData.playerData[i].aliensKilled[0]=0;
500 			netGameData.playerData[i].aliensKilled[1]=0;
501 			netGameData.playerData[i].aliensKilled[2]=0;
502 			netGameData.playerData[i].deathsFromAI=0;
503 			netGameData.playerData[i].playerAlive=1;
504 			netGameData.playerData[i].playerHasLives=1;
505 			netGameData.playerData[i].startFlag = 0;
506 		}
507 		for(j=0;j<3;j++) netGameData.teamScores[j] = 0;
508 //		netGameData.myGameState = NGS_Playing;
509 
510 
511 		netGameData.myCharacterSubType=NGSCT_General;
512 		switch (species)
513 		{
514 			default:
515 			case 0:
516 				netGameData.myCharacterType = NGCT_Marine;
517 				netGameData.myNextCharacterType = NGCT_Marine;
518 				AvP.PlayerType = I_Marine;
519 				break;
520 			case 1:
521 				netGameData.myCharacterType = NGCT_Predator;
522 				netGameData.myNextCharacterType = NGCT_Predator;
523 				AvP.PlayerType = I_Predator;
524 				break;
525 			case 2:
526 				netGameData.myCharacterType = NGCT_Alien;
527 				netGameData.myNextCharacterType = NGCT_Alien;
528 				AvP.PlayerType = I_Alien;
529 				break;
530 			case 3:	//various marine subtypes
531 			case 4:
532 			case 5:
533 			case 6:
534 			case 7:
535 			case 8:
536 			case 9:
537 			case 10:
538 				netGameData.myCharacterType = NGCT_Marine;
539 				netGameData.myNextCharacterType = NGCT_Marine;
540 				netGameData.myCharacterSubType =(NETGAME_SPECIALISTCHARACTERTYPE) (species-2);
541 				AvP.PlayerType = I_Marine;
542 				break;
543 		}
544 
545 		netGameData.myStartFlag = 0;
546 		netGameData.gameType = gamestyle;
547 		netGameData.levelNumber = level;
548 //		netGameData.scoreLimit = 0;
549 //		netGameData.timeLimit = 0;
550 //		netGameData.invulnerableTime = 5;
551 		netGameData.GameTimeElapsed = 0;
552 
553 //		netGameData.characterKillValues[NGCT_Marine]=100;
554 //		netGameData.characterKillValues[NGCT_Predator]=150;
555 //		netGameData.characterKillValues[NGCT_Alien]=75;
556 //		netGameData.baseKillValue=100;
557 //		netGameData.useDynamicScoring=1;
558 //		netGameData.useCharacterKillValues=1;
559 
560 		netGameData.stateCheckTimeDelay=0;
561 		netGameData.gameDescriptionTimeDelay=0;
562 
563 		netGameData.sendTimer=0;
564 		if(LobbiedGame || netGameData.connectionType==CONN_Modem)
565 		{
566 			netGameData.sendFrequency=ONE_FIXED/15;
567    	   		netGameData.sendDecals=FALSE;
568 		}
569 		else
570 		{
571 			netGameData.sendFrequency=0;//ONE_FIXED/15;
572    	   		netGameData.sendDecals=TRUE;
573 		}
574 	}
575 
576 	myNetworkKillerId = AVPDPNetID;	/* init global id of player who killed me last */
577 	netNextLocalObjectId = 1;	/* init local object network id */
578 	numMessagesReceived = 0;	/* these are for testing */
579 	numMessagesTransmitted = 0;
580 
581 	/* If I'm the host, add myself to the game data */
582 	netGameData.playerData[0].playerId = AVPDPNetID;
583 	strncpy(netGameData.playerData[0].name,AVPDPplayerName.lpszShortNameA,NET_PLAYERNAMELENGTH-1);
584 	netGameData.playerData[0].name[NET_PLAYERNAMELENGTH-1] = '\0';
585 //	ConvertNetNameToUpperCase(netGameData.playerData[0].name);
586 
587 	{
588 		int myIndex;
589 		myIndex = PlayerIdInPlayerList(AVPDPNetID);
590 		LOCALASSERT(myIndex!=NET_IDNOTINPLAYERLIST);
591 		netGameData.playerData[myIndex].characterType = netGameData.myCharacterType;
592 		netGameData.playerData[myIndex].characterSubType = netGameData.myCharacterSubType;
593 	}
594 
595 	netGameData.LMS_AlienIndex=-1;
596 
597 	InitNetLog();
598 
599 	//make sure our time scale is set correctly
600 	switch(netGameData.gameSpeed)
601 	{
602 		case NETGAMESPEED_70PERCENT :
603 			TimeScale=(ONE_FIXED*70)/100;
604 			break;
605 
606 		case NETGAMESPEED_80PERCENT :
607 			TimeScale=(ONE_FIXED*80)/100;
608 			break;
609 
610 		case NETGAMESPEED_90PERCENT :
611 			TimeScale=(ONE_FIXED*90)/100;
612 			break;
613 
614 		case NETGAMESPEED_100PERCENT :
615 			TimeScale=(ONE_FIXED*100)/100;
616 			break;
617 
618 	}
619 
620 	netGameData.myStrategyCheckSum=0;
621 
622 	netGameData.numDeaths[0]=0;
623 	netGameData.numDeaths[1]=0;
624 	netGameData.numDeaths[2]=0;
625 
626 }
InitAVPNetGameForJoin(void)627 void InitAVPNetGameForJoin(void)
628 {
629 	AvP.GameMode = I_GM_Playing;
630 	AvP.Network = I_Peer;
631 
632 	AvP.NetworkAIServer = 0;
633 
634 	/* init garry's dp extended */
635 	DpExtInit(0,0,0);
636 
637 	/* init the send message buffer */
638 	InitialiseSendMessageBuffer();
639 
640 	netGameData.myGameState = NGS_Joining;
641 	/* base initialisation of game description */
642 	{
643 		int i,j;
644 		for(i=0;i<(NET_MAXPLAYERS);i++)
645 		{
646 			netGameData.playerData[i].playerId = 0;
647 			for(j=0;j<(NET_PLAYERNAMELENGTH);j++) netGameData.playerData[i].name[j] = '\0';
648 			netGameData.playerData[i].characterType = NGCT_Marine;
649 			netGameData.playerData[i].characterSubType = NGSCT_General;
650 			for(j=0;j<(NET_MAXPLAYERS);j++) netGameData.playerData[i].playerFrags[j] = 0;
651 			netGameData.playerData[i].playerScore = 0;
652 			netGameData.playerData[i].playerScoreAgainst = 0;
653 			netGameData.playerData[i].aliensKilled[0]=0;
654 			netGameData.playerData[i].aliensKilled[1]=0;
655 			netGameData.playerData[i].aliensKilled[2]=0;
656 			netGameData.playerData[i].deathsFromAI=0;
657 			netGameData.playerData[i].playerAlive=1;
658 			netGameData.playerData[i].playerHasLives=1;
659 			netGameData.playerData[i].startFlag = 0;
660 		}
661 		for(j=0;j<3;j++) netGameData.teamScores[j] = 0;
662 		netGameData.myStartFlag = 0;
663 		netGameData.myGameState = NGS_Joining;
664 
665 		netGameData.myCharacterType = NGCT_Marine;
666 		netGameData.myNextCharacterType = NGCT_Marine;
667 		netGameData.myCharacterSubType=NGSCT_General;
668 
669 		netGameData.stateCheckTimeDelay=0;
670 		netGameData.gameDescriptionTimeDelay=0;
671 
672 		if(LobbiedGame || netGameData.connectionType==CONN_Modem)
673 		{
674 			netGameData.sendFrequency=ONE_FIXED/15;
675    	   		netGameData.sendDecals=FALSE;
676 		}
677 		else
678 		{
679 			netGameData.sendFrequency=0;//ONE_FIXED/15;
680    	   		netGameData.sendDecals=TRUE;
681 		}
682 		netGameData.sendTimer=0;
683 
684 		netGameData.needGameDescription=1;
685 	}
686 
687 	myNetworkKillerId = AVPDPNetID;	/* init global id of player who killed me last */
688 	netNextLocalObjectId = 1;	/* init local object network id */
689 	numMessagesReceived = 0;	/* these are for testing */
690 	numMessagesTransmitted = 0;
691 	InitNetLog();
692 
693 
694 	netGameData.myStrategyCheckSum=0;
695 
696 	netGameData.numDeaths[0]=0;
697 	netGameData.numDeaths[1]=0;
698 	netGameData.numDeaths[2]=0;
699 
700 	netGameData.joiningGameStatus = JOINNETGAME_WAITFORSTART;
701 }
702 
703 /*----------------------------------------------------------------------
704   Core message collection function
705   ----------------------------------------------------------------------*/
MinimalNetCollectMessages(void)706 void MinimalNetCollectMessages(void)
707 {
708 	HRESULT res = DP_OK;
709 	DPID	dPlayFromId = 0;
710 	DPID 	dPlayToId = 0;
711 	unsigned char *msgP = NULL;
712 	unsigned msgSize = 0;
713 
714 	/* collects messages until something other than DP_OK is returned (eg DP_NoMessages) */
715 	if(!netGameData.skirmishMode)
716 	{
717 		while((res==DP_OK) && glpDP && AVPDPNetID)
718 		{
719 			res = DpExtRecv(glpDP,&dPlayFromId,&dPlayToId,DPRECEIVE_ALL,&msgP,(LPDWORD)&msgSize);
720 			if(res==DP_OK)
721 			{
722 				/* process last message, if there is one */
723 				if(dPlayFromId == DPID_SYSMSG)
724 				{
725 					ProcessSystemMessage(msgP,msgSize);
726 				}
727 				else ProcessGameMessage(dPlayFromId,msgP,msgSize);
728 			}
729 		}
730 	}
731 }
NetCollectMessages(void)732 void NetCollectMessages(void)
733 {
734 	HRESULT res = DP_OK;
735 	DPID	dPlayFromId = 0;
736 	DPID 	dPlayToId = 0;
737 	unsigned char *msgP = NULL;
738 	unsigned msgSize = 0;
739 
740 	/* first off, some assertions about our game state */
741 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Leaving)));
742 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_GameFull)));
743 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_GameStarted)));
744 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_HostLost)));
745 
746 	/* only bother colecting messages under certain game conditions... */
747 	if((netGameData.myGameState!=NGS_StartUp)&&(netGameData.myGameState!=NGS_Playing)&&(netGameData.myGameState!=NGS_Joining)&&(netGameData.myGameState!=NGS_EndGameScreen)) return;
748 
749 	InitNetLog();
750 	LogNetInfo("Collecting Messages... \n");
751 
752 	/* collects messages until something other than DP_OK is returned (eg DP_NoMessages) */
753 	if(!netGameData.skirmishMode)
754 	{
755 		while((res==DP_OK) && glpDP && AVPDPNetID)
756 		{
757 			res = DpExtRecv(glpDP,&dPlayFromId,&dPlayToId,DPRECEIVE_ALL,&msgP,(LPDWORD)&msgSize);
758 			if(res==DP_OK)
759 			{
760 				numMessagesReceived++;
761 				/* process last message, if there is one */
762 				if(dPlayFromId == DPID_SYSMSG)
763 				{
764 					ProcessSystemMessage(msgP,msgSize);
765 				}
766 				else ProcessGameMessage(dPlayFromId,msgP,msgSize);
767 			}
768 		}
769 	}
770 	LogNetInfo("... Finished collecting Messages\n");
771 
772 	/* check ghost integrities */
773 	MaintainGhosts();
774 
775 	/* time and score limit checks...*/
776 	{
777 		//update timer
778 		if(netGameData.myGameState==NGS_Playing)
779 		{
780 			netGameData.GameTimeElapsed += RealFrameTime;
781 		}
782 
783 		if((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Playing))
784 		{
785 			if(netGameData.timeLimit>0)
786 			{
787 				if(((netGameData.GameTimeElapsed>>16)/60) >= netGameData.timeLimit)
788 				{
789 					/* game has timed-out */
790 					TransmitEndOfGameNetMsg();
791 					netGameData.myGameState = NGS_EndGameScreen;
792 				 //	AvP.MainLoopRunning = 0;
793 				}
794 			}
795 			if(netGameData.scoreLimit>0)
796 			{
797 				/* nb this doesn't check team scores */
798 				int i,j;
799 				for(i=0;i<NET_MAXPLAYERS;i++)
800 				{
801 					if(netGameData.playerData[i].playerId)
802 					{
803 						int score=0;
804 						for(j=0;j<3;j++)
805 						{
806 							score+=netGameData.playerData[i].aliensKilled[j]*netGameData.aiKillValues[j];
807 						}
808 						if(netGameData.playerData[i].playerScore >= netGameData.scoreLimit || score>=netGameData.scoreLimit)
809 						{
810 							/* someone has reached the score limit */
811 							TransmitEndOfGameNetMsg();
812 							netGameData.myGameState = NGS_EndGameScreen;
813 							break;
814 						//	AvP.MainLoopRunning = 0;
815 						}
816 					}
817 				}
818 			}
819 			if(netGameData.maxLives>0)
820 			{
821 				int i;
822 				int numPlayers=0;
823 				int numPlayersWithLifeLeft=0;
824 				int numAliens=0;
825 				int numAliensWithLifeLeft=0;
826 				int numMarines=0;
827 				int numMarinesWithLifeLeft=0;
828 				int numPredators=0;
829 				int numPredatorsWithLifeLeft=0;
830 				BOOL gameOver=FALSE;
831 				for(i=0;i<NET_MAXPLAYERS;i++)
832 				{
833 					if(netGameData.playerData[i].playerId)
834 					{
835 						numPlayers++;
836 						numPlayersWithLifeLeft+=netGameData.playerData[i].playerHasLives;
837 
838 						switch(netGameData.playerData[i].characterType)
839 						{
840 							case NGCT_Alien :
841 								numAliens++;
842 								numAliensWithLifeLeft+=netGameData.playerData[i].playerHasLives;
843 								break;
844 
845 							case NGCT_Marine :
846 								numMarines++;
847 								numMarinesWithLifeLeft+=netGameData.playerData[i].playerHasLives;
848 								break;
849 
850 							case NGCT_Predator :
851 								numPredators++;
852 								numPredatorsWithLifeLeft+=netGameData.playerData[i].playerHasLives;
853 								break;
854 
855 							default:
856 								break;
857 						}
858 					}
859 				}
860 
861 				//game is over if no one has life left
862 				if(numPlayersWithLifeLeft==0)
863 				{
864 					gameOver=TRUE;
865 				}
866 
867 				if(netGameData.gameType==NGT_Individual)
868 				{
869 					if(numPlayersWithLifeLeft<=1 && numPlayers>1)
870 					{
871 						//if in a deathmatch game and there is only one player with life , then thats it
872 						gameOver=TRUE;
873 					}
874 				}
875 
876 				if(netGameData.gameType==NGT_CoopDeathmatch)
877 				{
878 					/*
879 					In a cooperative deathmatch ,the game ends when only one team has life left
880 					*/
881 					int numTeams=0;
882 					int numTeamsWithLifeLeft=0;
883 
884 					if(numAliens) numTeams++;
885 					if(numAliensWithLifeLeft) numTeamsWithLifeLeft++;
886 					if(numPredators) numTeams++;
887 					if(numPredatorsWithLifeLeft) numTeamsWithLifeLeft++;
888 					if(numMarines) numTeams++;
889 					if(numMarinesWithLifeLeft) numTeamsWithLifeLeft++;
890 
891 					if(numTeams>1 && numTeamsWithLifeLeft<=1)
892 					{
893 						gameOver=TRUE;
894 					}
895 				}
896 
897 				if(gameOver)
898 				{
899 					TransmitEndOfGameNetMsg();
900 					netGameData.myGameState = NGS_EndGameScreen;
901 				}
902 
903 			}
904 		}
905 	}
906 
907 
908 	/* print my score on the screen (temporary) */
909 	if(netGameData.myGameState==NGS_Playing)
910 	{
911 		#if 0
912 		int myScore;
913 		int myIndex = PlayerIdInPlayerList(AVPDPNetID);
914 		myScore = AddUpPlayerFrags(myIndex);
915 		LOCALASSERT(myIndex!=NET_IDNOTINPLAYERLIST);
916 		#if PreBeta
917 		{
918 			extern void	jtextprint(const char *t,...);
919 			jtextprint("NET GAME SCORE: %d \n", myScore);
920 		}
921 		#else
922 			textprint("NET GAME SCORE: %d \n", myScore);
923 		#endif
924 
925 		#else
926 		#endif
927 
928 		#if EXTRAPOLATION_TEST
929 		{
930 			extern void PlayerGhostExtrapolation();
931 			PlayerGhostExtrapolation();
932 		}
933 		#endif
934 	}
935 
936 	LogNetInfo("Finished message collection post-processing \n");
937 
938 	if(MultiplayerObservedPlayer)
939 	{
940 		CheckStateOfObservedPlayer();
941 	}
942 
943 }
944 
945 /*----------------------------------------------------------------------
946   Functions for processing system messages
947   ----------------------------------------------------------------------*/
ProcessSystemMessage(char * msgP,unsigned int msgSize)948 static void ProcessSystemMessage(char *msgP,unsigned int msgSize)
949 {
950 	LPDPMSG_GENERIC systemMessage = (LPDPMSG_GENERIC)msgP;
951 
952 	/* currently, only the host deals with system mesages */
953 	/* check for invalid parameters */
954 	if((msgSize==0)||(msgP==NULL)) return;
955 
956 	switch(systemMessage->dwType)
957 	{
958 		case DPSYS_ADDPLAYERTOGROUP:
959 		{
960 			/* ignore */
961 			break;
962 		}
963 		case DPSYS_CREATEPLAYERORGROUP:
964 		{
965 			/* only useful during startup: during main game, connecting player should
966 			detect game state and exit immediately */
967 			if((AvP.Network==I_Host))
968 			{
969 				LPDPMSG_CREATEPLAYERORGROUP createMessage;
970 				createMessage = (LPDPMSG_CREATEPLAYERORGROUP)systemMessage;
971 				if(createMessage->dwPlayerType == DPPLAYERTYPE_PLAYER)
972 				{
973 					DPID id = createMessage->dpId;
974 					char *name = &(createMessage->dpnName.lpszShortNameA[0]);
975 					AddPlayerToGame(id,name);
976 				}
977 			}
978 			LogNetInfo("system message:  DPSYS_CREATEPLAYERORGROUP \n");
979 			break;
980 		}
981 		case DPSYS_DELETEPLAYERFROMGROUP:
982 		{
983 //					NewOnScreenMessage("A PLAYER HAS DISCONNECTED");
984 			/* ignore */
985 			break;
986 		}
987 		case DPSYS_DESTROYPLAYERORGROUP:
988 		{
989 			/* Aha. Either a player has left (should have sent a leaving message)
990 			or s/he has exited abnormally. In either case, only need to act on
991 			this during start-up. During the main game, the ghosts will time-out
992 			anyway */
993 			if((AvP.Network==I_Host))
994 			{
995 				LPDPMSG_DESTROYPLAYERORGROUP destroyMessage;
996 				destroyMessage = (LPDPMSG_DESTROYPLAYERORGROUP)systemMessage;
997 				if(destroyMessage->dwPlayerType == DPPLAYERTYPE_PLAYER)
998 				{
999 					DPID id = destroyMessage->dpId;
1000 					RemovePlayerFromGame(id);
1001 //					NewOnScreenMessage("A PLAYER HAS DISCONNECTED");
1002 				}
1003 			}
1004 			LogNetInfo("system message:  DPSYS_DESTROYPLAYERORGROUP \n");
1005 			break;
1006 		}
1007 		case DPSYS_HOST:
1008 		{
1009 			/* Aha... the host has died, then. This is a terminal game state,
1010 			as the host was managing the game. Thefore, temporarily adopt host
1011 			duties for the purpose of ending the game...
1012 			This is most important during the playing state, but also happens in
1013 			startup. In startup, peers keep a host timeout which should fire before
1014 			this message arrives anyway. */
1015 			LOCALASSERT(AvP.Network==I_Peer);
1016 			if((netGameData.myGameState==NGS_StartUp)||(netGameData.myGameState==NGS_Playing)||(netGameData.myGameState==NGS_Joining)||(netGameData.myGameState==NGS_EndGameScreen))
1017 			{
1018 				AvP.Network=I_Host;
1019 				/* Eek, I guess the old AIs bite the dust? */
1020 				//but the new host can create some more
1021 				AvP.NetworkAIServer = (netGameData.gameType==NGT_Coop);
1022 				Inform_NewHost();
1023 //				TransmitEndOfGameNetMsg();
1024 //				netGameData.myGameState = NGS_EndGame;
1025 //				AvP.MainLoopRunning = 0;
1026 
1027 				if(LobbiedGame)
1028 				{
1029 					//no longer a lowly client
1030 					LobbiedGame=LobbiedGame_Server;
1031 				}
1032 			}
1033 			LogNetInfo("system message:  DPSYS_HOST \n");
1034 			break;
1035 		}
1036 		case DPSYS_SESSIONLOST:
1037 		{
1038 			/* Aha. I have lost my connection. Time to exit the game gracefully.*/
1039 			NewOnScreenMessage("Session lost!!");
1040 			/*
1041 			if((netGameData.myGameState==NGS_StartUp)||(netGameData.myGameState==NGS_Joining)||(netGameData.myGameState==NGS_Playing))
1042 			{
1043 				netGameData.myGameState = NGS_Error_HostLost;
1044 			}
1045 
1046 			LogNetInfo("system message:  DPSYS_SESSIONLOST \n");
1047 			*/
1048 			break;
1049 		}
1050 		case DPSYS_SETPLAYERORGROUPDATA:
1051 		{
1052 			/* ignore */
1053 			break;
1054 		}
1055 		case DPSYS_SETPLAYERORGROUPNAME:
1056 		{
1057 			/* ignore */
1058 			break;
1059 		}
1060 		default:
1061 		{
1062 			/* invalid system message type: ignore */
1063 			break;
1064 		}
1065 	}
1066 }
1067 
AddPlayerToGame(DPID id,char * name)1068 static void AddPlayerToGame(DPID id, char* name)
1069 {
1070 	int freePlayerIndex;
1071 
1072 	LOCALASSERT(AvP.Network==I_Host);
1073 
1074 
1075 	/* find a free slot for the player */
1076 	freePlayerIndex = EmptySlotInPlayerList();
1077 	if(freePlayerIndex == NET_NOEMPTYSLOTINPLAYERLIST) return;
1078 
1079 	/* initialise the slot */
1080 	netGameData.playerData[freePlayerIndex].playerId = id;
1081 
1082 	strncpy(netGameData.playerData[freePlayerIndex].name,name,NET_PLAYERNAMELENGTH-1);
1083 	netGameData.playerData[freePlayerIndex].name[NET_PLAYERNAMELENGTH-1] = '\0';
1084 //	ConvertNetNameToUpperCase(netGameData.playerData[freePlayerIndex].name);
1085 
1086 	netGameData.playerData[freePlayerIndex].characterType = NGCT_Marine;
1087 	netGameData.playerData[freePlayerIndex].characterSubType = NGSCT_General;
1088 	netGameData.playerData[freePlayerIndex].startFlag = 0;
1089 	{
1090 		int i;
1091 		for(i=0;i<NET_MAXPLAYERS;i++)
1092 		{
1093 			netGameData.playerData[freePlayerIndex].playerFrags[i] = 0;
1094 		}
1095 		netGameData.playerData[freePlayerIndex].playerScore = 0;
1096 		netGameData.playerData[freePlayerIndex].playerScoreAgainst = 0;
1097 		netGameData.playerData[freePlayerIndex].aliensKilled[0] = 0;
1098 		netGameData.playerData[freePlayerIndex].aliensKilled[1] = 0;
1099 		netGameData.playerData[freePlayerIndex].aliensKilled[2] = 0;
1100 		netGameData.playerData[freePlayerIndex].deathsFromAI=0;
1101 		netGameData.playerData[freePlayerIndex].playerAlive = 1;
1102 		netGameData.playerData[freePlayerIndex].playerHasLives = 1;
1103 
1104 		netGameData.playerData[freePlayerIndex].lastKnownPosition.vx=0;
1105 		netGameData.playerData[freePlayerIndex].lastKnownPosition.vy=100000000;
1106 		netGameData.playerData[freePlayerIndex].lastKnownPosition.vz=0;
1107 	}
1108 
1109 	Inform_PlayerHasConnected(id);
1110 }
1111 
RemovePlayerFromGame(DPID id)1112 void RemovePlayerFromGame(DPID id)
1113 {
1114 	int playerIndex,j;
1115 
1116 	//LOCALASSERT(AvP.Network==I_Host);
1117 
1118 	/* get player index from dpid */
1119 	playerIndex = PlayerIdInPlayerList(id);
1120 	if(playerIndex==NET_IDNOTINPLAYERLIST)
1121 	{
1122 		/* the player is not actually in the game, so do nothing. This might occur, for
1123 		example if a player tries to join when the game is full */
1124 		return;
1125 	}
1126 
1127 	/* free the slot */
1128 	netGameData.playerData[playerIndex].playerId = 0;
1129 	for(j=0;j<NET_PLAYERNAMELENGTH;j++) netGameData.playerData[playerIndex].name[j] = '\0';
1130 	netGameData.playerData[playerIndex].characterType = NGCT_Marine;
1131 	netGameData.playerData[playerIndex].characterSubType = NGSCT_General;
1132 	netGameData.playerData[playerIndex].startFlag = 0;
1133 	{
1134 		int i;
1135 		for(i=0;i<NET_MAXPLAYERS;i++)
1136 		{
1137 			netGameData.playerData[playerIndex].playerFrags[i] = 0;
1138 			netGameData.playerData[i].playerFrags[playerIndex] = 0;
1139 		}
1140 		netGameData.playerData[playerIndex].playerScore = 0;
1141 		netGameData.playerData[playerIndex].playerScoreAgainst = 0;
1142 		netGameData.playerData[playerIndex].aliensKilled[0] = 0;
1143 		netGameData.playerData[playerIndex].aliensKilled[1] = 0;
1144 		netGameData.playerData[playerIndex].aliensKilled[2] = 0;
1145 		netGameData.playerData[playerIndex].deathsFromAI=0;
1146 		netGameData.playerData[playerIndex].playerAlive = 1;
1147 		netGameData.playerData[playerIndex].playerHasLives = 1;
1148 
1149 		netGameData.playerData[playerIndex].lastKnownPosition.vx=0;
1150 		netGameData.playerData[playerIndex].lastKnownPosition.vy=100000000;
1151 		netGameData.playerData[playerIndex].lastKnownPosition.vz=0;
1152 
1153 	}
1154 }
1155 
1156 /*----------------------------------------------------------------------
1157   Core function for processing game messages
1158   ----------------------------------------------------------------------*/
ProcessGameMessage(DPID senderId,char * msgP,unsigned int msgSize)1159 static void ProcessGameMessage(DPID senderId, char *msgP,unsigned int msgSize)
1160 {
1161 	char* subMessagePtr;
1162 	NETMESSAGEHEADER *headerPtr;
1163 	char *endOfMessage;
1164 
1165 	LogNetInfo("Processing a game message \n");
1166 
1167 	/* check the dp message */
1168 	{
1169 		/* check for invalid parameters */
1170 		if((msgSize==0)||(msgP==NULL)) return;
1171 		/* check for an empty message, ie a message that is only the size of
1172 		the dpext header.  We shouldn't get any of these.  */
1173 		if(msgSize <= DPEXT_HEADER_SIZE) return;
1174 	}
1175 
1176 	/* some assertions about our game state */
1177 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Leaving)));
1178 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_GameFull)));
1179 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_GameStarted)));
1180 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_HostLost)));
1181 
1182 	/* In leaving or error states, we can ignore game messages */
1183 	if((netGameData.myGameState!=NGS_StartUp)&&(netGameData.myGameState!=NGS_Playing)&&(netGameData.myGameState!=NGS_Joining)&&(netGameData.myGameState!=NGS_EndGameScreen)) return;
1184 
1185 	/* validate the sender from our player list, unless we're in startup mode */
1186 //	if((netGameData.myGameState!=NGS_StartUp)&&
1187 //	   (PlayerIdInPlayerList(senderId)==NET_IDNOTINPLAYERLIST)) return;
1188 
1189 	/* the message includes garry's dp extented header, so skip past this
1190 	and find the end of the message (for checking integrity) */
1191 	subMessagePtr = msgP + DPEXT_HEADER_SIZE;
1192 	endOfMessage = (char *)(subMessagePtr + (msgSize - DPEXT_HEADER_SIZE));
1193 
1194 	/* Read through to the end of the message... */
1195 	while(subMessagePtr<endOfMessage)
1196 	{
1197 		headerPtr = (NETMESSAGEHEADER *)subMessagePtr;
1198 		subMessagePtr += sizeof(NETMESSAGEHEADER);
1199 
1200 		switch(headerPtr->type)
1201 		{
1202 			case(NetMT_GameDescription):
1203 			{
1204 				ProcessNetMsg_GameDescription((NETMESSAGE_GAMEDESCRIPTION *)subMessagePtr);
1205 				subMessagePtr += sizeof(NETMESSAGE_GAMEDESCRIPTION);
1206 				break;
1207 			}
1208 			case(NetMT_PlayerDescription):
1209 			{
1210 				ProcessNetMsg_PlayerDescription((NETMESSAGE_PLAYERDESCRIPTION *)subMessagePtr, senderId);
1211 				subMessagePtr += sizeof(NETMESSAGE_PLAYERDESCRIPTION);
1212 				break;
1213 			}
1214 			case(NetMT_StartGame):
1215 			{
1216 				ProcessNetMsg_StartGame();
1217 				break;
1218 			}
1219 			case(NetMT_PlayerState):
1220 			{
1221 				ProcessNetMsg_PlayerState((NETMESSAGE_PLAYERSTATE *)subMessagePtr, senderId);
1222 				subMessagePtr += sizeof(NETMESSAGE_PLAYERSTATE);
1223 				break;
1224 			}
1225 			case(NetMT_PlayerState_Minimal):
1226 			{
1227 				ProcessNetMsg_PlayerState_Minimal((NETMESSAGE_PLAYERSTATE_MINIMAL *)subMessagePtr, senderId,FALSE);
1228 				subMessagePtr += sizeof(NETMESSAGE_PLAYERSTATE_MINIMAL);
1229 				break;
1230 			}
1231 			case(NetMT_PlayerState_Medium):
1232 			{
1233 				ProcessNetMsg_PlayerState_Minimal((NETMESSAGE_PLAYERSTATE_MINIMAL *)subMessagePtr, senderId,TRUE);
1234 				subMessagePtr += sizeof(NETMESSAGE_PLAYERSTATE_MEDIUM);
1235 				break;
1236 			}
1237 			case (NetMT_FrameTimer) :
1238 			{
1239 				ProcessNetMsg_FrameTimer(((NETMESSAGE_FRAMETIMER *)subMessagePtr)->frame_time, senderId);
1240 				subMessagePtr += sizeof(NETMESSAGE_FRAMETIMER);
1241 				break;
1242 			}
1243 			case(NetMT_PlayerKilled):
1244 			{
1245 				ProcessNetMsg_PlayerKilled((NETMESSAGE_PLAYERKILLED *)subMessagePtr, senderId);
1246 				subMessagePtr += sizeof(NETMESSAGE_PLAYERKILLED);
1247 				break;
1248 			}
1249 			case(NetMT_CorpseDeathAnim):
1250 			{
1251 				ProcessNetMsg_PlayerDeathAnim((NETMESSAGE_CORPSEDEATHANIM *)subMessagePtr, senderId);
1252 				subMessagePtr += sizeof(NETMESSAGE_CORPSEDEATHANIM);
1253 				break;
1254 			}
1255 			case(NetMT_PlayerLeaving):
1256 			{
1257 				ProcessNetMsg_PlayerLeaving(senderId);
1258 				break;
1259 			}
1260 			case(NetMT_AllGameScores):
1261 			{
1262 				ProcessNetMsg_AllGameScores((NETMESSAGE_ALLGAMESCORES *)subMessagePtr);
1263 				subMessagePtr += sizeof(NETMESSAGE_ALLGAMESCORES);
1264 				break;
1265 			}
1266 			case(NetMT_PlayerScores):
1267 			{
1268 				ProcessNetMsg_PlayerScores((NETMESSAGE_PLAYERSCORES *)subMessagePtr);
1269 				subMessagePtr += sizeof(NETMESSAGE_PLAYERSCORES);
1270 				break;
1271 			}
1272 			case(NetMT_LocalRicochet):
1273 			{
1274 				ProcessNetMsg_LocalRicochet((NETMESSAGE_LOCALRICOCHET *)subMessagePtr);
1275 				subMessagePtr += sizeof(NETMESSAGE_LOCALRICOCHET);
1276 				break;
1277 			}
1278 			case(NetMT_LocalObjectState):
1279 			{
1280 				ProcessNetMsg_LocalObjectState((NETMESSAGE_LOBSTATE *)subMessagePtr, senderId);
1281 				subMessagePtr += sizeof(NETMESSAGE_LOBSTATE);
1282 				break;
1283 			}
1284 			case(NetMT_LocalObjectDamaged):
1285 			{
1286 				ProcessNetMsg_LocalObjectDamaged((char*)subMessagePtr, senderId);
1287 				subMessagePtr += GetSizeOfLocalObjectDamagedMessage((char*)subMessagePtr);
1288 				break;
1289 			}
1290 			case(NetMT_LocalObjectDestroyed):
1291 			{
1292 				ProcessNetMsg_LocalObjectDestroyed((NETMESSAGE_LOBDESTROYED *)subMessagePtr, senderId);
1293 				subMessagePtr += sizeof(NETMESSAGE_LOBDESTROYED);
1294 				break;
1295 			}
1296 			case(NetMT_ObjectPickedUp):
1297 			{
1298 				ProcessNetMsg_ObjectPickedUp((NETMESSAGE_OBJECTPICKEDUP *)subMessagePtr);
1299 				subMessagePtr += sizeof(NETMESSAGE_OBJECTPICKEDUP);
1300 				break;
1301 			}
1302 			case(NetMT_EndGame):
1303 			{
1304 				ProcessNetMsg_EndGame();
1305 				break;
1306 			}
1307 			case(NetMT_InanimateObjectDamaged):
1308 			{
1309 				ProcessNetMsg_InanimateObjectDamaged((char *)subMessagePtr);
1310 				subMessagePtr += GetSizeOfInanimateDamagedMessage((char *)subMessagePtr);
1311 				break;
1312 			}
1313 			case(NetMT_InanimateObjectDestroyed):
1314 			{
1315 				ProcessNetMsg_InanimateObjectDestroyed((NETMESSAGE_INANIMATEDESTROYED *)subMessagePtr);
1316 				subMessagePtr += sizeof(NETMESSAGE_INANIMATEDESTROYED);
1317 				break;
1318 			}
1319 			case(NetMT_LOSRequestBinarySwitch):
1320 			{
1321 				ProcessNetMsg_LOSRequestBinarySwitch((NETMESSAGE_LOSREQUESTBINARYSWITCH *)subMessagePtr);
1322 				subMessagePtr += sizeof(NETMESSAGE_LOSREQUESTBINARYSWITCH);
1323 				break;
1324 			}
1325 			case(NetMT_PlatformLiftState):
1326 			{
1327 				ProcessNetMsg_PlatformLiftState((NETMESSAGE_PLATFORMLIFTSTATE *)subMessagePtr);
1328 				subMessagePtr += sizeof(NETMESSAGE_PLATFORMLIFTSTATE);
1329 				break;
1330 			}
1331 			case(NetMT_RequestPlatformLiftActivate):
1332 			{
1333 				ProcessNetMsg_RequestPlatformLiftActivate((NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE *)subMessagePtr);
1334 				subMessagePtr += sizeof(NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE);
1335 				break;
1336 			}
1337 			case(NetMT_PlayerAutoGunState):
1338 			{
1339 				ProcessNetMsg_PlayerAutoGunState((NETMESSAGE_AGUNSTATE *)subMessagePtr, senderId);
1340 				subMessagePtr += sizeof(NETMESSAGE_AGUNSTATE);
1341 				break;
1342 			}
1343 			case(NetMT_MakeDecal):
1344 			{
1345 				ProcessNetMsg_MakeDecal((NETMESSAGE_MAKEDECAL *)subMessagePtr);
1346 				subMessagePtr += sizeof(NETMESSAGE_MAKEDECAL);
1347 				break;
1348 			}
1349 			case(NetMT_ChatBroadcast):
1350 			{
1351 				subMessagePtr = ProcessNetMsg_ChatBroadcast(subMessagePtr, senderId);
1352 				break;
1353 			}
1354 			case(NetMT_MakeExplosion):
1355 			{
1356 				ProcessNetMsg_MakeExplosion((NETMESSAGE_MAKEEXPLOSION *)subMessagePtr);
1357 				subMessagePtr += sizeof(NETMESSAGE_MAKEEXPLOSION);
1358 				break;
1359 			}
1360 			case(NetMT_MakeFlechetteExplosion):
1361 			{
1362 				ProcessNetMsg_MakeFlechetteExplosion((NETMESSAGE_MAKEFLECHETTEEXPLOSION *)subMessagePtr);
1363 				subMessagePtr += sizeof(NETMESSAGE_MAKEFLECHETTEEXPLOSION);
1364 				break;
1365 			}
1366 			case(NetMT_MakePlasmaExplosion):
1367 			{
1368 				ProcessNetMsg_MakePlasmaExplosion((NETMESSAGE_MAKEPLASMAEXPLOSION *)subMessagePtr);
1369 				subMessagePtr += sizeof(NETMESSAGE_MAKEPLASMAEXPLOSION);
1370 				break;
1371 			}
1372 			case(NetMT_PredatorSights):
1373 			{
1374 				ProcessNetMsg_PredatorSights((NETMESSAGE_PREDATORSIGHTS *)subMessagePtr, senderId);
1375 				subMessagePtr += sizeof(NETMESSAGE_PREDATORSIGHTS);
1376 				break;
1377 			}
1378 			case(NetMT_LocalObjectOnFire):
1379 			{
1380 				ProcessNetMsg_LocalObjectOnFire((NETMESSAGE_LOBONFIRE *)subMessagePtr, senderId);
1381 				subMessagePtr += sizeof(NETMESSAGE_LOBONFIRE);
1382 				break;
1383 			}
1384 			case(NetMT_RestartNetworkGame):
1385 			{
1386 				RestartNetworkGame(((NETMESSAGE_RESTARTGAME*)subMessagePtr)->seed);
1387 				subMessagePtr += sizeof(NETMESSAGE_RESTARTGAME);
1388 				break;
1389 			}
1390 			case(NetMT_FragmentalObjectsStatus):
1391 			{
1392 				ProcessNetMsg_FragmentalObjectsStatus((NETMESSAGE_FRAGMENTALOBJECTSSTATUS *)subMessagePtr);
1393 				subMessagePtr += sizeof(NETMESSAGE_FRAGMENTALOBJECTSSTATUS);
1394 				break;
1395 			}
1396 			case(NetMT_StrategySynch):
1397 			{
1398 				ProcessNetMsg_StrategySynch((NETMESSAGE_STRATEGYSYNCH *)subMessagePtr);
1399 				subMessagePtr += sizeof(NETMESSAGE_STRATEGYSYNCH);
1400 				break;
1401 			}
1402 			case(NetMT_AlienAIState):
1403 			{
1404 				ProcessNetMsg_AlienAIState((NETMESSAGE_ALIENAISTATE *)subMessagePtr, senderId);
1405 				subMessagePtr += sizeof(NETMESSAGE_ALIENAISTATE);
1406 				break;
1407 			}
1408 			case(NetMT_AlienAISequenceChange):
1409 			{
1410 				ProcessNetMsg_AlienAISequenceChange((NETMESSAGE_ALIENSEQUENCECHANGE *)subMessagePtr, senderId);
1411 				subMessagePtr += sizeof(NETMESSAGE_ALIENSEQUENCECHANGE);
1412 				break;
1413 			}
1414 			case(NetMT_AlienAIKilled):
1415 			{
1416 				ProcessNetMsg_AlienAIKilled((NETMESSAGE_ALIENAIKILLED *)subMessagePtr, senderId);
1417 				subMessagePtr += sizeof(NETMESSAGE_ALIENAIKILLED);
1418 				break;
1419 			}
1420 			case(NetMT_FarAlienPosition):
1421 			{
1422 				ProcessNetMsg_FarAlienPosition((NETMESSAGE_FARALIENPOSITION *)subMessagePtr, senderId);
1423 				subMessagePtr += sizeof(NETMESSAGE_FARALIENPOSITION);
1424 				break;
1425 			}
1426 			case(NetMT_GhostHierarchyDamaged):
1427 			{
1428 				ProcessNetMsg_GhostHierarchyDamaged((char *)subMessagePtr, senderId);
1429 				subMessagePtr += GetSizeOfGhostHierarchyDamagedMessage((char *)subMessagePtr) ;
1430 				break;
1431 			}
1432 			case(NetMT_Gibbing):
1433 			{
1434 				ProcessNetMsg_Gibbing((NETMESSAGE_GIBBING *)subMessagePtr, senderId);
1435 				subMessagePtr += sizeof(NETMESSAGE_GIBBING);
1436 				break;
1437 			}
1438 			case(NetMT_SpotAlienSound):
1439 			{
1440 				ProcessNetMsg_SpotAlienSound((NETMESSAGE_SPOTALIENSOUND *)subMessagePtr, senderId);
1441 				subMessagePtr += sizeof(NETMESSAGE_SPOTALIENSOUND);
1442 				break;
1443 			}
1444 			case(NetMT_SpotOtherSound):
1445 			{
1446 				ProcessNetMsg_SpotOtherSound((NETMESSAGE_SPOTOTHERSOUND *)subMessagePtr, senderId);
1447 				subMessagePtr += sizeof(NETMESSAGE_SPOTOTHERSOUND);
1448 				break;
1449 			}
1450 			case(NetMT_LocalObjectDestroyed_Request):
1451 			{
1452 				ProcessNetMsg_LocalObjectDestroyed_Request((NETMESSAGE_LOBDESTROYED_REQUEST *)subMessagePtr, senderId);
1453 				subMessagePtr += sizeof(NETMESSAGE_LOBDESTROYED_REQUEST);
1454 				break;
1455 			}
1456 
1457 			case(NetMT_LastManStanding_Restart):
1458 			{
1459 				Handle_LastManStanding_Restart(((NETMESSAGE_LMS_RESTART*)subMessagePtr)->playerID,((NETMESSAGE_LMS_RESTART*)subMessagePtr)->seed);
1460 				subMessagePtr += sizeof(NETMESSAGE_LMS_RESTART);
1461 				break;
1462 			}
1463 
1464 			case(NetMT_LastManStanding_RestartInfo):
1465 			{
1466 				Handle_LastManStanding_RestartInfo(((NETMESSAGE_PLAYERID*)subMessagePtr)->playerID);
1467 				subMessagePtr += sizeof(NETMESSAGE_PLAYERID);
1468 				break;
1469 			}
1470 
1471 			case(NetMT_LastManStanding_LastMan):
1472 			{
1473 				Handle_LastManStanding_LastMan(((NETMESSAGE_PLAYERID*)subMessagePtr)->playerID);
1474 				subMessagePtr += sizeof(NETMESSAGE_PLAYERID);
1475 				break;
1476 			}
1477 
1478 			case(NetMT_LastManStanding_RestartCountDown):
1479 			{
1480 				Handle_LastManStanding_RestartTimer(((NETMESSAGE_LMS_RESTARTTIMER*)subMessagePtr)->timer);
1481 				subMessagePtr += sizeof(NETMESSAGE_LMS_RESTARTTIMER);
1482 				break;
1483 			}
1484 
1485 			case(NetMT_PredatorTag_NewPredator):
1486 			{
1487 				Handle_SpeciesTag_NewPersonIt(((NETMESSAGE_PLAYERID*)subMessagePtr)->playerID);
1488 				subMessagePtr += sizeof(NETMESSAGE_PLAYERID);
1489 				break;
1490 			}
1491 
1492 			case(NetMT_CreateWeapon):
1493 			{
1494 				ProcessNetMsg_CreateWeapon((NETMESSAGE_CREATEWEAPON*)subMessagePtr);
1495 				subMessagePtr += sizeof(NETMESSAGE_CREATEWEAPON);
1496 				break;
1497 			}
1498 			case(NetMT_RespawnPickups):
1499 			{
1500 				if(netGameData.myGameState==NGS_Playing ||
1501 				   netGameData.myGameState==NGS_EndGameScreen)
1502 				{
1503 					RespawnAllPickups();
1504 					PrintStringTableEntryInConsole(TEXTSTRING_MULTIPLAYER_WEAPON_RESPAWN);
1505 				}
1506 				break;
1507 			}
1508 
1509 			case(NetMT_ScoreChange):
1510 			{
1511 				ProcessNetMsg_ScoreChange((NETMESSAGE_SCORECHANGE *)subMessagePtr);
1512 				subMessagePtr += sizeof(NETMESSAGE_SCORECHANGE);
1513 				break;
1514 			}
1515 
1516 			case(NetMT_SpeciesScores):
1517 			{
1518 				ProcessNetMsg_SpeciesScores((NETMESSAGE_SPECIESSCORES *)subMessagePtr);
1519 				subMessagePtr += sizeof(NETMESSAGE_SPECIESSCORES);
1520 				break;
1521 			}
1522 
1523 			default:
1524 			{
1525 				LOCALASSERT(1==0);
1526 				break;
1527 			}
1528 		}
1529 	}
1530 	/* if we have read the message correctly, the message pointer should be exactly
1531 	at the end of the message buffer*/
1532 	LOCALASSERT(subMessagePtr==endOfMessage);
1533 
1534 	LogNetInfo("Finished processing a game message \n");
1535 
1536 }
1537 
1538 #if CalculateBytesSentPerSecond
GetBytesPerSecond(int bytesThisFrame)1539 int GetBytesPerSecond(int bytesThisFrame)
1540 {
1541 	static int times[100];
1542 	static int bytes[100];
1543 	static int next_index;
1544 	int i;
1545 	int totalBytes=0;
1546 
1547 	times[next_index]=0;
1548 	bytes[next_index]=bytesThisFrame;
1549 	next_index=(next_index+1)%100;
1550 
1551 	for(i=0;i<100;i++)
1552 	{
1553 		times[i]+=NormalFrameTime;
1554 		totalBytes+=bytes[i];
1555 	}
1556 
1557 	if(!times[next_index]) return 0;
1558 
1559 	return(DIV_FIXED(totalBytes,times[next_index]));
1560 
1561 }
1562 #endif
1563 
1564 /*----------------------------------------------------------------------
1565   Core function for sending messages
1566   ----------------------------------------------------------------------*/
NetSendMessages(void)1567 void NetSendMessages(void)
1568 {
1569 	/* some assertions about our game state */
1570 	//LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Leaving)));
1571 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_GameFull)));
1572 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_GameStarted)));
1573 	LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_HostLost)));
1574 
1575 
1576 	/* only bother sending messages under certain game conditions... */
1577 	if((netGameData.myGameState!=NGS_StartUp)&&(netGameData.myGameState!=NGS_EndGameScreen)&&(netGameData.myGameState!=NGS_Playing)&&(netGameData.myGameState!=NGS_Joining)) return;
1578 
1579 	LogNetInfo("Sending net messages... \n");
1580 
1581 	/* at this point, add player and other object updates... doing this here
1582 	ensures we are sending our most upto date info */
1583 	if(netGameData.myGameState==NGS_Playing ||
1584 	   netGameData.myGameState==NGS_EndGameScreen)
1585 	{
1586 		netGameData.gameDescriptionTimeDelay-=RealFrameTime;
1587 
1588 		GameTimeSinceLastSend+=NormalFrameTime;
1589 		TimeCounterForExtrapolation+=NormalFrameTime;
1590 
1591 		#if EXTRAPOLATION_TEST
1592 		//update muzzle flashes here , since this happens after dynamics
1593 		{
1594 			extern void PostDynamicsExtrapolationUpdate();
1595 			PostDynamicsExtrapolationUpdate();
1596 		}
1597 		#endif
1598 
1599 		if(netGameData.sendFrequency)
1600 		{
1601 			//check to see if messages should be sent this frame
1602 			netGameData.sendTimer-=RealFrameTime;
1603 			if(netGameData.sendTimer>0)
1604 			{
1605 				//don't send messages this frame
1606 				#if CalculateBytesSentPerSecond
1607 				PrintDebuggingText("Bytes/Second: %d\n",GetBytesPerSecond(0));
1608 				#endif
1609 				return;
1610 			}
1611 			netGameData.sendTimer+=netGameData.sendFrequency;
1612 			netGameData.sendTimer=max(0,netGameData.sendTimer);
1613 
1614 		}
1615 
1616 		if(netGameData.myGameState==NGS_EndGameScreen)
1617 		{
1618 			if(AvP.Network==I_Host)
1619 			{
1620 				PeriodicScoreUpdate();
1621 				//send game description once per second
1622 				if(netGameData.gameDescriptionTimeDelay<0)
1623 				{
1624 					netGameData.gameDescriptionTimeDelay+=2*ONE_FIXED;
1625 					AddNetMsg_GameDescription();
1626 
1627 					AddNetMsg_StrategySynch();
1628 
1629 					AddNetMsg_FragmentalObjectsStatus();
1630 				}
1631 			}
1632 		}
1633 		else //game state is NGS_Playing
1634 		{
1635 			AddPlayerAndObjectUpdateMessages();
1636 			if(AvP.Network==I_Host)
1637 			{
1638 				//send game description once per second
1639 				if(netGameData.gameDescriptionTimeDelay<0)
1640 				{
1641 					netGameData.gameDescriptionTimeDelay+=ONE_FIXED;
1642 					AddNetMsg_GameDescription();
1643 
1644 					AddNetMsg_StrategySynch();
1645 
1646 					AddNetMsg_FragmentalObjectsStatus();
1647 				}
1648 
1649 				PeriodicScoreUpdate();
1650 
1651 				if(netGameData.gameType==NGT_LastManStanding)
1652 				{
1653 					CheckLastManStandingState();
1654 				}
1655 				else if(netGameData.gameType==NGT_PredatorTag || netGameData.gameType==NGT_AlienTag)
1656 				{
1657 					CheckSpeciesTagState();
1658 				}
1659 				CheckForPointBasedObjectRespawn();
1660 			}
1661 		}
1662 	}
1663 	else if(netGameData.myGameState==NGS_Leaving ||
1664 			netGameData.myGameState==NGS_Joining ||
1665 			netGameData.myGameState==NGS_StartUp)
1666 	{
1667 		if(AvP.Network==I_Host)
1668 		{
1669 			AddNetMsg_GameDescription();
1670 		}
1671 	}
1672 
1673 	{
1674 		/* send our message buffer...
1675 		NB it should always be non-empty, and always less than the maximum message size */
1676 		HRESULT res;
1677 		int numBytes;
1678 		BOOL clearSendBuffer=TRUE;
1679 		numBytes = (int)(endSendBuffer - &sendBuffer[0]);
1680 
1681 		if(netGameData.myGameState==NGS_EndGameScreen || netGameData.myGameState==NGS_Joining)
1682 		{
1683 			//there may not be any messages while showing the end game screen
1684 			if(numBytes==DPEXT_HEADER_SIZE) return;
1685 		}
1686 
1687 
1688 		LOCALASSERT(numBytes > DPEXT_HEADER_SIZE);
1689 		LOCALASSERT(numBytes <= NET_MESSAGEBUFFERSIZE);
1690 		if(!netGameData.skirmishMode)
1691 		{
1692 			if(glpDP && AVPDPNetID)
1693 			{
1694 				res = DpExtSend(glpDP,AVPDPNetID,DPID_ALLPLAYERS,0,&sendBuffer,numBytes);
1695 				if(res!=DP_OK)
1696 				{
1697 					//we have some problem sending...
1698 					switch(res)
1699 					{
1700 						case DPERR_BUSY :
1701 							/*
1702 							failed to send this frame , try preserving the contents of the send buffer ,
1703 							unless it is getting to full.
1704 							*/
1705 							if(numBytes<NET_MESSAGEBUFFERSIZE/2)
1706 							{
1707 								clearSendBuffer=FALSE;
1708 							}
1709 							break;
1710 
1711 						case DPERR_CONNECTIONLOST :
1712 							NewOnScreenMessage("Connection lost!!");
1713 							break;
1714 
1715 						case DPERR_INVALIDPARAMS  :
1716 							LOCALASSERT(0=="Send - Invalid parameters");
1717 							break;
1718 
1719 						case DPERR_INVALIDPLAYER :
1720 							LOCALASSERT(0=="Send - Invalid player");
1721 							break;
1722 
1723 						case DPERR_NOTLOGGEDIN :
1724 							LOCALASSERT(0=="Send - Not logged in");
1725 							break;
1726 
1727 						case DPERR_SENDTOOBIG :
1728 							LOCALASSERT(0=="Send - Send to big");
1729 							break;
1730 
1731 						default :
1732 							LOCALASSERT(0=="Send - Unknown error");
1733 							break;
1734 
1735 
1736 					}
1737 
1738 				}
1739 
1740 			}
1741 		}
1742 		numMessagesTransmitted++;
1743 		/* re-initialise the send message buffer */
1744 		/*(unless the send failed because it was to busy)*/
1745 		if(clearSendBuffer)
1746 		{
1747 			InitialiseSendMessageBuffer();
1748 		}
1749 
1750 //		PrintDebuggingText("Bytes: %d\n",numBytes);
1751 		#if CalculateBytesSentPerSecond
1752 		PrintDebuggingText("Bytes/Second: %d\n",GetBytesPerSecond(numBytes));
1753 		#endif
1754 
1755 	}
1756 
1757 	LogNetInfo("...Finished sending net message \n");
1758 }
1759 
InitialiseSendMessageBuffer(void)1760 static void InitialiseSendMessageBuffer(void)
1761 {
1762 	/* NB the receive buffer is maintained internally to garry's dp-extension */
1763 	/* reset the end of send buffer pointer */
1764 	endSendBuffer = &sendBuffer[0];
1765 	/* add space for a dpext header to the send buffer */
1766 	endSendBuffer += DPEXT_HEADER_SIZE;
1767 }
1768 
1769 
1770 /*----------------------------------------------------------------------
1771 this function examines the sb-list and adds messages for the player, local
1772 objects, and other such things. NB It would be possible to do this in the
1773 behaviour functions, but would involve a lag
1774   ----------------------------------------------------------------------*/
AddPlayerAndObjectUpdateMessages(void)1775 static void AddPlayerAndObjectUpdateMessages(void)
1776 {
1777 	extern int NumActiveStBlocks;
1778 	extern STRATEGYBLOCK *ActiveStBlockList[];
1779 	int sbIndex = 0;
1780 
1781 	/* don't bother adding these if we're finishing
1782 	(host gets here even if finishing, but doesn't need to send these messages) */
1783 	if(netGameData.myGameState!=NGS_Playing) return;
1784 
1785 	/* NB IF THE LIST OF OBJECT TYPES WHICH ARE UPDATED CHANGES, THERE MUST BE A
1786 	CORESPONDING CHANGE IN THE LIST OF OBJECTS TESTED BY FindObjectFromNetIndex(),
1787 	ELSE PLAYER WILL NOT BE ABLE TO RECEIVE MESSAGES ABOUT OWN OBJECTS OF THAT TYPE! */
1788 
1789 	#if EXTRAPOLATION_TEST
1790 	AddNetMsg_FrameTimer();
1791 	#endif
1792 
1793 	while(sbIndex < NumActiveStBlocks)
1794 	{
1795 		STRATEGYBLOCK *sbPtr = ActiveStBlockList[sbIndex++];
1796 		switch(sbPtr->I_SBtype)
1797 		{
1798 			case(I_BehaviourMarinePlayer):
1799 			case(I_BehaviourAlienPlayer):
1800 			case(I_BehaviourPredatorPlayer):
1801 			{
1802 				/* the player update message */
1803 				AddNetMsg_PlayerState(sbPtr);
1804 				break;
1805 			}
1806 			case(I_BehaviourRocket):
1807 			case(I_BehaviourGrenade):
1808 			case(I_BehaviourProximityGrenade):
1809 			case(I_BehaviourPulseGrenade):
1810 			case(I_BehaviourFragmentationGrenade):
1811 			case(I_BehaviourPredatorEnergyBolt):
1812 			case(I_BehaviourFrisbeeEnergyBolt):
1813 			case(I_BehaviourClusterGrenade):
1814 			case(I_BehaviourNPCPredatorDisc):
1815 			case(I_BehaviourPredatorDisc_SeekTrack):
1816 			case(I_BehaviourAlienSpit):
1817 			case(I_BehaviourNetCorpse):
1818 			case(I_BehaviourPPPlasmaBolt):
1819 			case(I_BehaviourFrisbee):
1820 //			case(I_BehaviourSpeargunBolt): //spear location is sent once , upon creation
1821 			{
1822 
1823  				AddNetMsg_LocalObjectState(sbPtr);
1824 				break;
1825 			}
1826 			case(I_BehaviourFlareGrenade):
1827 			{
1828 			    FLARE_BEHAV_BLOCK *bbPtr = (FLARE_BEHAV_BLOCK * ) sbPtr->SBdataptr;
1829 				DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1830 				//only send messages for flares while they are moving
1831 				if(!dynPtr->IsStatic || bbPtr->becomeStuck)
1832 				{
1833 					AddNetMsg_LocalObjectState(sbPtr);
1834 				}
1835 				break;
1836 			}
1837 			case(I_BehaviourInanimateObject):
1838 			{
1839 				INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->SBdataptr;
1840 
1841 				if (objStatPtr->ghosted_object) {
1842 					AddNetMsg_LocalObjectState(sbPtr);
1843 				}
1844 				break;
1845 			}
1846 			case(I_BehaviourAutoGun):
1847 			{
1848 				/* this MUST be a player placed autogun */
1849 				{
1850 				}
1851 				/* the autogun update message */
1852 				AddNetMsg_PlayerAutoGunState(sbPtr);
1853 				break;
1854 			}
1855 			case(I_BehaviourAlien):
1856 			{
1857 				//only add alien details , if it is near (to someone)
1858 				if(sbPtr->SBdptr)
1859 				{
1860 					AddNetMsg_AlienAIState(sbPtr);
1861 				}
1862 				break;
1863 			}
1864 
1865 			default:
1866 				break;
1867 		}
1868 	}
1869 }
1870 
1871 
1872 
1873 /*----------------------------------------------------------------------
1874   End of network game clean up
1875   ----------------------------------------------------------------------*/
EndAVPNetGame(void)1876 void EndAVPNetGame(void)
1877 {
1878 #if 0
1879 	HRESULT hres;
1880 #endif
1881 
1882 	/* garry's dp extended clean up */
1883 	if(!netGameData.skirmishMode)
1884 	{
1885 		DpExtUnInit();
1886 	}
1887 
1888 
1889 	//netGameData.myGameState=NGS_Leaving;
1890 	RemovePlayerFromGame(AVPDPNetID);
1891 	TransmitPlayerLeavingNetMsg();
1892 
1893 	if(!netGameData.skirmishMode)
1894 	{
1895 		DirectPlay_Disconnect();
1896 	}
1897 
1898 	#if 0
1899 	/* terminate our player */
1900 	if(AVPDPNetID)
1901 	{
1902 		hres = IDirectPlay4_DestroyPlayer(glpDP, AVPDPNetID);
1903 		AVPDPNetID = NULL;
1904 	}
1905 	/* terminate the dp object */
1906 	if(glpDP)
1907 	{
1908 		hres = IDirectPlay4_Close(lpDPlay3AAVP);
1909 		IDirectPlay4_Release(lpDPlay3AAVP);
1910 		lpDPlay3AAVP = NULL;
1911 	}
1912 	#endif
1913 
1914 	/* reset our game mode here */
1915 	AvP.Network = I_No_Network;
1916 	AvP.NetworkAIServer = 0;
1917 	netGameData.skirmishMode=FALSE;
1918 
1919 	TurnOffMultiplayerObserveMode();
1920 
1921 	//reset time scale to default value
1922 	TimeScale=ONE_FIXED;
1923 }
1924 
1925 /*----------------------------------------------------------------------
1926   Functions for adding each message type to the send message buffer
1927   ----------------------------------------------------------------------*/
AddNetMsg_GameDescription(void)1928 void AddNetMsg_GameDescription(void)
1929 {
1930 	NETMESSAGEHEADER *headerPtr;
1931 	NETMESSAGE_GAMEDESCRIPTION *messagePtr;
1932 	int headerSize = sizeof(NETMESSAGEHEADER);
1933 	int messageSize = sizeof(NETMESSAGE_GAMEDESCRIPTION);
1934 
1935 	/* some conditions */
1936 	LOCALASSERT(AvP.Network==I_Host);
1937 
1938 	/* check there's enough room in the send buffer */
1939 	{
1940 		int numBytesReqd = headerSize + messageSize;
1941 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
1942 		if(numBytesReqd > numBytesLeft)
1943 		{
1944 			LOCALASSERT(1==0);
1945 			/* don't add it */
1946 			return;
1947 		}
1948 	}
1949 
1950 	/* set up pointers to header and message structures */
1951 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
1952 	endSendBuffer += headerSize;
1953 	messagePtr = (NETMESSAGE_GAMEDESCRIPTION *)endSendBuffer;
1954 	endSendBuffer += messageSize;
1955 
1956 	/* fill out the header */
1957 	headerPtr->type = (unsigned char)NetMT_GameDescription;
1958 
1959 	/*fill out the message */
1960 	{ 	int i;
1961 		for(i=0;i<NET_MAXPLAYERS;i++)
1962 		{
1963 			messagePtr->players[i].playerId = netGameData.playerData[i].playerId;
1964 			messagePtr->players[i].characterType = (unsigned char)netGameData.playerData[i].characterType;
1965 			messagePtr->players[i].characterSubType = (unsigned char)netGameData.playerData[i].characterSubType;
1966 			messagePtr->players[i].startFlag = netGameData.playerData[i].startFlag;
1967 		}
1968 		messagePtr->gameType = (unsigned char)netGameData.gameType;
1969 		messagePtr->levelNumber = (unsigned char)netGameData.levelNumber;
1970 		messagePtr->scoreLimit = netGameData.scoreLimit;
1971 		messagePtr->timeLimit = (unsigned char)netGameData.timeLimit;
1972 		messagePtr->invulnerableTime = (unsigned char)netGameData.invulnerableTime;
1973 
1974 		for(i=0;i<3;i++)
1975 		{
1976 			messagePtr->characterKillValues[i]=(unsigned char)netGameData.characterKillValues[i];
1977 			messagePtr->aiKillValues[i]=(unsigned char)netGameData.aiKillValues[i];
1978 		}
1979 		messagePtr->baseKillValue=(unsigned char)netGameData.baseKillValue;
1980 		messagePtr->useDynamicScoring=(unsigned char)netGameData.useDynamicScoring;
1981 		messagePtr->useCharacterKillValues=(unsigned char)netGameData.useCharacterKillValues;
1982 
1983 
1984 
1985 		messagePtr->sendDecals=netGameData.sendDecals;
1986 
1987 
1988 		messagePtr->allowSmartgun=netGameData.allowSmartgun;
1989 		messagePtr->allowFlamer=netGameData.allowFlamer;
1990 		messagePtr->allowSadar=netGameData.allowSadar;
1991 		messagePtr->allowGrenadeLauncher=netGameData.allowGrenadeLauncher;
1992 		messagePtr->allowMinigun=netGameData.allowMinigun;
1993 		messagePtr->allowDisc=netGameData.allowDisc;
1994 		messagePtr->allowPistol=netGameData.allowPistol;
1995 		messagePtr->allowPlasmaCaster=netGameData.allowPlasmaCaster;
1996 		messagePtr->allowSpeargun=netGameData.allowSpeargun;
1997 		messagePtr->allowMedicomp=netGameData.allowMedicomp;
1998 		messagePtr->allowSmartDisc=netGameData.allowSmartDisc;
1999 		messagePtr->allowPistols=netGameData.allowPistols;
2000 
2001 		messagePtr->maxPredator=netGameData.maxPredator;
2002 		messagePtr->maxAlien=netGameData.maxAlien;
2003 		messagePtr->maxMarine=netGameData.maxMarine;
2004 
2005 		messagePtr->maxMarineGeneral=netGameData.maxMarineGeneral;
2006 		messagePtr->maxMarinePulseRifle=netGameData.maxMarinePulseRifle;
2007 		messagePtr->maxMarineSmartgun=netGameData.maxMarineSmartgun;
2008 		messagePtr->maxMarineFlamer=netGameData.maxMarineFlamer;
2009 		messagePtr->maxMarineSadar=netGameData.maxMarineSadar;
2010 		messagePtr->maxMarineGrenade=netGameData.maxMarineGrenade;
2011 		messagePtr->maxMarineMinigun=netGameData.maxMarineMinigun;
2012 		messagePtr->maxMarineSmartDisc=netGameData.maxMarineSmartDisc;
2013 		messagePtr->maxMarinePistols=netGameData.maxMarinePistols;
2014 
2015 
2016 		messagePtr->useSharedLives=netGameData.useSharedLives;
2017 		messagePtr->maxLives=netGameData.maxLives;
2018 		messagePtr->numDeaths[0]=(unsigned char) min(netGameData.numDeaths[0],255);
2019 		messagePtr->numDeaths[1]=(unsigned char) min(netGameData.numDeaths[1],255);
2020 		messagePtr->numDeaths[2]=(unsigned char) min(netGameData.numDeaths[2],255);
2021 
2022 		messagePtr->timeForRespawn=(unsigned char)netGameData.timeForRespawn;
2023 		messagePtr->pointsForRespawn=netGameData.pointsForRespawn;
2024 
2025 		messagePtr->GameTimeElapsed=netGameData.GameTimeElapsed>>16;
2026 
2027 		messagePtr->gameSpeed=netGameData.gameSpeed;
2028 
2029 		messagePtr->preDestroyLights=netGameData.preDestroyLights;
2030 		messagePtr->disableFriendlyFire=netGameData.disableFriendlyFire;
2031 		messagePtr->fallingDamage=netGameData.fallingDamage;
2032 		messagePtr->pistolInfiniteAmmo=netGameData.pistolInfiniteAmmo;
2033 		messagePtr->specialistPistols=netGameData.specialistPistols;
2034 
2035 		if(netGameData.myGameState==NGS_EndGameScreen)
2036 			messagePtr->endGame=1;
2037 		else
2038 			messagePtr->endGame=0;
2039 
2040 	}
2041 }
2042 
AddNetMsg_PlayerDescription(void)2043 void AddNetMsg_PlayerDescription(void)
2044 {
2045 	NETMESSAGEHEADER *headerPtr;
2046 	NETMESSAGE_PLAYERDESCRIPTION *messagePtr;
2047 	int headerSize = sizeof(NETMESSAGEHEADER);
2048 	int messageSize = sizeof(NETMESSAGE_PLAYERDESCRIPTION);
2049 
2050 	/* some conditions */
2051 	LOCALASSERT(AvP.Network==I_Peer);
2052 	LOCALASSERT(netGameData.myGameState==NGS_Joining);
2053 
2054 	/* check there's enough room in the send buffer */
2055 	{
2056 		int numBytesReqd = headerSize + messageSize;
2057 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
2058 		if(numBytesReqd > numBytesLeft)
2059 		{
2060 			LOCALASSERT(1==0);
2061 			/* don't add it */
2062 			return;
2063 		}
2064 	}
2065 
2066 	/* set up pointers to header and message structures */
2067 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
2068 	endSendBuffer += headerSize;
2069 	messagePtr = (NETMESSAGE_PLAYERDESCRIPTION *)endSendBuffer;
2070 	endSendBuffer += messageSize;
2071 
2072 	/* fill out the header */
2073 	headerPtr->type = (unsigned char)NetMT_PlayerDescription;
2074 
2075 	/*fill out the message */
2076 	{
2077 		messagePtr->characterType = (unsigned char)netGameData.myCharacterType;
2078 		messagePtr->characterSubType = (unsigned char)netGameData.myCharacterSubType;
2079 		messagePtr->startFlag = (unsigned char)netGameData.myStartFlag;
2080 	}
2081 }
2082 
AddNetMsg_StartGame(void)2083 void AddNetMsg_StartGame(void)
2084 {
2085 	NETMESSAGEHEADER *headerPtr;
2086 	int headerSize = sizeof(NETMESSAGEHEADER);
2087 
2088 	/* some conditions */
2089 	LOCALASSERT(AvP.Network==I_Host);
2090 	LOCALASSERT(netGameData.myGameState==NGS_Joining);
2091 
2092 	/* check there's enough room in the send buffer */
2093 	{
2094 		int numBytesReqd = headerSize;
2095 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
2096 		if(numBytesReqd > numBytesLeft)
2097 		{
2098 			LOCALASSERT(1==0);
2099 			/* don't add it */
2100 			return;
2101 		}
2102 	}
2103 
2104 	/* set up pointers to header and message structures */
2105 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
2106 	endSendBuffer += headerSize;
2107 
2108 	/* fill out the header */
2109 	headerPtr->type = (unsigned char)NetMT_StartGame;
2110 }
2111 
2112 extern int UseExtrapolation;
AddNetMsg_PlayerState(STRATEGYBLOCK * sbPtr)2113 void AddNetMsg_PlayerState(STRATEGYBLOCK *sbPtr)
2114 {
2115 	NETMESSAGEHEADER *headerPtr;
2116 	NETMESSAGE_PLAYERSTATE *messagePtr;
2117 	int headerSize = sizeof(NETMESSAGEHEADER);
2118 	int messageSize = sizeof(NETMESSAGE_PLAYERSTATE);
2119 	int playerIndex;
2120 
2121 
2122 	if(netGameData.myGameState!=NGS_Playing) return;
2123 
2124 	#if EXTRAPOLATION_TEST
2125 	if(UseExtrapolation && netGameData.sendFrequency)
2126 	{
2127 		//see if we can get away with sending reduced information about the player's state
2128 		static VECTORCH previousVelocity;
2129 		static EULER previousOrient;
2130 		static int previousWeapon;
2131 		static unsigned int TimeOfLastPlayerState;
2132 		BOOL sendMinimalState=TRUE;
2133 
2134 		if(TimeCounterForExtrapolation<TimeOfLastPlayerState ||
2135 		   TimeCounterForExtrapolation-TimeOfLastPlayerState>ONE_FIXED/4)
2136 		{
2137 			//It has been over 1/4 second since the last full update , so better do a full update now
2138 			sendMinimalState=FALSE;
2139 		}
2140 
2141 		if(sendMinimalState)
2142 		{
2143 			if(sbPtr->DynPtr->LinImpulse.vx ||
2144 			   sbPtr->DynPtr->LinImpulse.vy ||
2145 			   sbPtr->DynPtr->LinImpulse.vz)
2146 			{
2147 				/*
2148 				The player is probably jumping. This screws up the extrapolation somewhat.
2149 				Therefore better send full player update.
2150 				*/
2151 				sendMinimalState=FALSE;
2152 			}
2153 
2154 		}
2155 
2156 		if(sendMinimalState)
2157 		{
2158 			VECTORCH diff=sbPtr->DynPtr->LinVelocity;
2159 			SubVector(&previousVelocity,&diff);
2160 
2161 			if(Approximate3dMagnitude(&diff)>100)
2162 			{
2163 				//the player's velocity has changed , so need a full update.
2164 				sendMinimalState=FALSE;
2165 			}
2166 		}
2167 
2168 
2169 		if(sendMinimalState)
2170 		{
2171 			PLAYER_WEAPON_DATA *weaponPtr;
2172  			PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr);
2173 			LOCALASSERT(playerStatusPtr);
2174     		weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
2175 
2176 			if(weaponPtr->WeaponIDNumber!=previousWeapon)
2177 			{
2178 				//the player's weapon has changed ,so need a full update
2179 				previousWeapon=weaponPtr->WeaponIDNumber;
2180 				sendMinimalState=FALSE;
2181 			}
2182 		}
2183 
2184 		if(sendMinimalState)
2185 		{
2186 			//don't need to send positional information , but has the player's orientation changed?
2187 			BOOL sendOrient=FALSE;
2188 			if(previousOrient.EulerX!=sbPtr->DynPtr->OrientEuler.EulerX ||
2189 			   previousOrient.EulerY!=sbPtr->DynPtr->OrientEuler.EulerY ||
2190 			   previousOrient.EulerZ!=sbPtr->DynPtr->OrientEuler.EulerZ)
2191 			{
2192 				previousOrient=sbPtr->DynPtr->OrientEuler;
2193 				//we better send the medium sized player state message
2194 				sendOrient=TRUE;
2195 			}
2196 			AddNetMsg_PlayerState_Minimal(sbPtr,sendOrient);
2197 			return;
2198 		}
2199 		else
2200 		{
2201 			previousVelocity=sbPtr->DynPtr->LinVelocity;
2202 			previousOrient=sbPtr->DynPtr->OrientEuler;
2203 			TimeOfLastPlayerState=TimeCounterForExtrapolation;
2204 
2205 		}
2206 	}
2207 	#endif
2208 
2209 	/* check there's enough room in the send buffer */
2210 	{
2211 		int numBytesReqd = headerSize + messageSize;
2212 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
2213 		if(numBytesReqd > numBytesLeft)
2214 		{
2215 			LOCALASSERT(1==0);
2216 			/* don't add it */
2217 			return;
2218 		}
2219 	}
2220 
2221 	/* set up pointers to header and message structures */
2222 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
2223 	endSendBuffer += headerSize;
2224 	messagePtr = (NETMESSAGE_PLAYERSTATE *)endSendBuffer;
2225 	endSendBuffer += messageSize;
2226 
2227 	/* fill out the header */
2228 	headerPtr->type = (unsigned char)NetMT_PlayerState;
2229 
2230 	//check our carrent character type
2231 	{
2232 		switch(AvP.PlayerType)
2233 		{
2234 			case I_Marine :
2235 				netGameData.myCharacterType=NGCT_Marine;
2236 				break;
2237 
2238 			case I_Predator :
2239 				netGameData.myCharacterType=NGCT_Predator;
2240 				break;
2241 
2242 			case I_Alien :
2243 				netGameData.myCharacterType=NGCT_Alien;
2244 				break;
2245 		}
2246 
2247 		playerIndex = PlayerIdInPlayerList(AVPDPNetID);
2248 		GLOBALASSERT(playerIndex!=NET_IDNOTINPLAYERLIST);
2249 
2250 		messagePtr->characterType=netGameData.myCharacterType;
2251 		messagePtr->characterSubType=netGameData.myCharacterSubType;
2252 		messagePtr->nextCharacterType=netGameData.myNextCharacterType;
2253 		netGameData.playerData[playerIndex].characterType=messagePtr->nextCharacterType;
2254 
2255 	}
2256 
2257 	/* fill out our position and orientation */
2258 	{
2259 		DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
2260 
2261 
2262 		LOCALASSERT(dynPtr);
2263 		LOCALASSERT((dynPtr->OrientEuler.EulerX >=0 )&&(dynPtr->OrientEuler.EulerX < 4096));	/* 9 bits of signed data */
2264 		LOCALASSERT((dynPtr->OrientEuler.EulerY >=0 )&&(dynPtr->OrientEuler.EulerY < 4096));	/* 9 bits of signed data */
2265 		LOCALASSERT((dynPtr->OrientEuler.EulerZ >=0 )&&(dynPtr->OrientEuler.EulerZ < 4096));	/* 9 bits of signed data */
2266 
2267 		/* NB we can fit +-4194303 into 23 bits */
2268 		if(dynPtr->Position.vx < -4100000) messagePtr->xPos = -4100000;
2269 		else if(dynPtr->Position.vx > 4100000) messagePtr->xPos = 4100000;
2270 		else messagePtr->xPos = dynPtr->Position.vx;
2271 		messagePtr->xOrient = (dynPtr->OrientEuler.EulerX>>NET_EULERSCALESHIFT);
2272 
2273 		if(dynPtr->Position.vy < -4100000) messagePtr->yPos = -4100000;
2274 		else if(dynPtr->Position.vy > 4100000) messagePtr->yPos = 4100000;
2275 		else messagePtr->yPos = dynPtr->Position.vy;
2276 		messagePtr->yOrient = (dynPtr->OrientEuler.EulerY>>NET_EULERSCALESHIFT);
2277 
2278 		if(dynPtr->Position.vz < -4100000) messagePtr->zPos = -4100000;
2279 		else if(dynPtr->Position.vz > 4100000) messagePtr->zPos = 4100000;
2280 		else messagePtr->zPos = dynPtr->Position.vz;
2281 		messagePtr->zOrient = (dynPtr->OrientEuler.EulerZ>>NET_EULERSCALESHIFT);
2282 
2283 
2284 		#if EXTRAPOLATION_TEST
2285 		messagePtr->velocity_x=dynPtr->LinVelocity.vx/100;
2286 		messagePtr->velocity_y=dynPtr->LinVelocity.vy/100;
2287 		messagePtr->velocity_z=dynPtr->LinVelocity.vz/100;
2288 		messagePtr->standard_gravity=dynPtr->UseStandardGravity;
2289 		#endif
2290 	}
2291 
2292 	/* KJL 17:04:22 26/01/98 - elevation (for weapon, etc.) */
2293 	{
2294 		PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
2295 		messagePtr->Elevation = playerStatusPtr->ViewPanX;
2296 
2297 		switch(AvP.PlayerType)
2298 		{
2299 			case(I_Marine):
2300 			{
2301 				messagePtr->sequence = (unsigned char)GetMyMarineSequence();
2302 				/* Taunt handling. */
2303 				if (playerStatusPtr->tauntTimer==-1) {
2304 					if (messagePtr->sequence!=MSQ_Taunt) {
2305 						/* Taunt overridden. */
2306 						playerStatusPtr->tauntTimer=0;
2307 					} else {
2308 						/* Taunt is go. */
2309 						playerStatusPtr->tauntTimer=TAUNT_LENGTH;
2310 					}
2311 				} else if (playerStatusPtr->tauntTimer!=0) {
2312 					if (messagePtr->sequence!=MSQ_Taunt) {
2313 						/* Taunt cancelled. */
2314 						playerStatusPtr->tauntTimer=0;
2315 					}
2316 				}
2317 				break;
2318 			}
2319 			case(I_Predator):
2320 			{
2321 				messagePtr->sequence = (unsigned char)GetMyPredatorSequence();
2322 				/* Taunt handling. */
2323 				if (playerStatusPtr->tauntTimer==-1) {
2324 					if (messagePtr->sequence!=PredSQ_Taunt) {
2325 						/* Taunt overridden. */
2326 						playerStatusPtr->tauntTimer=0;
2327 					} else {
2328 						/* Taunt is go. */
2329 						playerStatusPtr->tauntTimer=TAUNT_LENGTH;
2330 					}
2331 				} else if (playerStatusPtr->tauntTimer!=0) {
2332 					if (messagePtr->sequence!=PredSQ_Taunt) {
2333 						/* Taunt cancelled. */
2334 						playerStatusPtr->tauntTimer=0;
2335 					}
2336 				}
2337 				break;
2338 			}
2339 			case(I_Alien):
2340 			{
2341 				messagePtr->sequence = (unsigned char)GetMyAlienSequence();
2342 				/* Taunt handling. */
2343 				if (playerStatusPtr->tauntTimer==-1) {
2344 					if (messagePtr->sequence!=ASQ_Taunt) {
2345 						/* Taunt overridden. */
2346 						playerStatusPtr->tauntTimer=0;
2347 					} else {
2348 						/* Taunt is go. */
2349 						playerStatusPtr->tauntTimer=TAUNT_LENGTH;
2350 					}
2351 				} else if (playerStatusPtr->tauntTimer!=0) {
2352 					if (messagePtr->sequence!=ASQ_Taunt) {
2353 						/* Taunt cancelled. */
2354 						playerStatusPtr->tauntTimer=0;
2355 					}
2356 				}
2357 				break;
2358 			}
2359 			default:
2360 			{
2361 				LOCALASSERT(1==0);
2362 				break;
2363 			}
2364 		}
2365 		if(PlayerStatusPtr->ShapeState!=PMph_Standing)
2366 		{
2367 			messagePtr->IAmCrouched = 1;
2368 		}
2369 		else
2370 		{
2371 			messagePtr->IAmCrouched = 0;
2372 		}
2373 	}
2374 
2375 	/* my current weapon id, and whether I am firing it... */
2376 	{
2377 		PLAYER_WEAPON_DATA *weaponPtr;
2378  		PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr);
2379 		LOCALASSERT(playerStatusPtr);
2380     	weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
2381 		messagePtr->currentWeapon = (signed char)(weaponPtr->WeaponIDNumber);
2382 
2383 		if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) {
2384 			if(((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY))
2385 				&&(PlayerStatusPtr->IsAlive)) {
2386 				if (LastHand) {
2387 					messagePtr->IAmFiringPrimary = 0;
2388 					messagePtr->IAmFiringSecondary = 1;
2389 				} else {
2390 					messagePtr->IAmFiringPrimary = 1;
2391 					messagePtr->IAmFiringSecondary = 0;
2392 				}
2393 			} else {
2394 				messagePtr->IAmFiringPrimary = 0;
2395 				messagePtr->IAmFiringSecondary = 0;
2396 			}
2397 			/* Whether in tertiary fire */
2398 			if (AreTwoPistolsInTertiaryFire()) {
2399 				messagePtr->Special=1;
2400 			} else {
2401 				messagePtr->Special=0;
2402 			}
2403 			/* whether or not I'm displaying a gun flash */
2404 			messagePtr->IHaveAMuzzleFlash = MyPlayerHasAMuzzleFlash(sbPtr);
2405 		} else {
2406 
2407 			if ((weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL)
2408 				&&((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY))
2409 				) {
2410 				messagePtr->Special=1;
2411 			} else {
2412 				messagePtr->Special=0;
2413 			}
2414 
2415 			if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(PlayerStatusPtr->IsAlive))
2416 				messagePtr->IAmFiringPrimary = 1;
2417 			else messagePtr->IAmFiringPrimary = 0;
2418 			if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(PlayerStatusPtr->IsAlive))
2419 				messagePtr->IAmFiringSecondary = 1;
2420 			else messagePtr->IAmFiringSecondary = 0;
2421 			/* whether or not I'm displaying a gun flash */
2422 			if(MyPlayerHasAMuzzleFlash(sbPtr)) messagePtr->IHaveAMuzzleFlash = 1;
2423 			else messagePtr->IHaveAMuzzleFlash = 0;
2424 		}
2425 	}
2426 	/* whether or not I'm alive */
2427 	if(PlayerStatusPtr->IsAlive) messagePtr->IAmAlive = 1;
2428 	else messagePtr->IAmAlive = 0;
2429 
2430 	netGameData.playerData[playerIndex].playerAlive=messagePtr->IAmAlive;
2431 
2432 	//Is the player alive or in possesion of extra lives?
2433 	if(messagePtr->IAmAlive)
2434 	{
2435 		messagePtr->IHaveLifeLeft=1;
2436 	}
2437 	else
2438 	{
2439 		messagePtr->IHaveLifeLeft=AreThereAnyLivesLeft();
2440 	}
2441 
2442 	netGameData.playerData[playerIndex].playerHasLives=messagePtr->IHaveLifeLeft;
2443 
2444 	/*Am I currently invulnerable?*/
2445 	if(PlayerStatusPtr->invulnerabilityTimer>0)
2446 		messagePtr->IAmInvulnerable=1;
2447 	else
2448 		messagePtr->IAmInvulnerable=0;
2449 
2450 
2451 	/* whether or not I'm the host */
2452 //	if(AvP.Network==I_Host) messagePtr->IAmHost = 1;
2453 //	else messagePtr->IAmHost = 0;
2454 
2455 	/* whether or not I'm a cloaked predator */
2456 	{
2457  		PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr);
2458 		LOCALASSERT(playerStatusPtr);
2459 
2460 		if(playerStatusPtr->cloakOn)
2461 		{
2462 			LOCALASSERT(AvP.PlayerType==I_Predator);
2463 
2464 			if (playerStatusPtr->CloakingEffectiveness>65535)
2465 			{
2466 				messagePtr->CloakingEffectiveness = 65535;
2467 			}
2468 			else
2469 			{
2470 				messagePtr->CloakingEffectiveness = (unsigned short)(playerStatusPtr->CloakingEffectiveness);
2471 			}
2472 		}
2473 		else messagePtr->CloakingEffectiveness = 0;
2474 	}
2475 
2476 	/* Am I on fire? */
2477 	if (sbPtr->SBDamageBlock.IsOnFire) {
2478 		messagePtr->IAmOnFire=1;
2479 	} else {
2480 		messagePtr->IAmOnFire=0;
2481 	}
2482 	/* Do I have a disk?  Probably not. */
2483 	messagePtr->IHaveADisk=0;
2484 	if (AvP.PlayerType==I_Predator) {
2485 		if (messagePtr->currentWeapon==WEAPON_PRED_DISC) {
2486 			if (PlayersWeapon.HModelControlBlock) {
2487 				SECTION_DATA *disc_section;
2488 				disc_section=GetThisSectionData(PlayersWeapon.HModelControlBlock->section_data,"disk");
2489 				GLOBALASSERT(disc_section);
2490 				if ((disc_section->flags&section_data_notreal)==0) {
2491 					/* We have a disk! */
2492 					messagePtr->IHaveADisk=1;
2493 				}
2494 			}
2495 		}
2496 	}
2497 
2498 	//have we been screaming?
2499 	if(netGameData.myLastScream!=-1)
2500 	{
2501 		messagePtr->scream=netGameData.myLastScream;
2502 	}
2503 	else
2504 	{
2505 		messagePtr->scream=31;
2506 	}
2507 	//reset last scream , so we don't keep sending it
2508 	netGameData.myLastScream=-1;
2509 
2510 	/* CDF 21/4/99 Add landing noise? */
2511 	messagePtr->landingNoise=netGameData.landingNoise;
2512 	//reset that too!
2513 	netGameData.landingNoise=0;
2514 
2515 }
2516 
AddNetMsg_PlayerState_Minimal(STRATEGYBLOCK * sbPtr,BOOL sendOrient)2517 void AddNetMsg_PlayerState_Minimal(STRATEGYBLOCK *sbPtr,BOOL sendOrient)
2518 {
2519 	PLAYER_WEAPON_DATA *weaponPtr=0;
2520 	int playerIndex;
2521 	NETMESSAGEHEADER *headerPtr;
2522 	NETMESSAGE_PLAYERSTATE_MINIMAL *messagePtr;
2523 	int headerSize = sizeof(NETMESSAGEHEADER);
2524 	int messageSize = sizeof(NETMESSAGE_PLAYERSTATE_MINIMAL);
2525 	if(sendOrient)
2526 	{
2527 		messageSize = sizeof(NETMESSAGE_PLAYERSTATE_MEDIUM);
2528 	}
2529 
2530 
2531 
2532 	if(netGameData.myGameState!=NGS_Playing) return;
2533 
2534 	/* check there's enough room in the send buffer */
2535 	{
2536 		int numBytesReqd = headerSize + messageSize;
2537 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
2538 		if(numBytesReqd > numBytesLeft)
2539 		{
2540 			LOCALASSERT(1==0);
2541 			/* don't add it */
2542 			return;
2543 		}
2544 	}
2545 
2546 	/* set up pointers to header and message structures */
2547 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
2548 	endSendBuffer += headerSize;
2549 	messagePtr = (NETMESSAGE_PLAYERSTATE_MINIMAL *)endSendBuffer;
2550 	endSendBuffer += messageSize;
2551 
2552 	/* fill out the header */
2553 	if(sendOrient)
2554 		headerPtr->type = (unsigned char)NetMT_PlayerState_Medium;
2555 	else
2556 		headerPtr->type = (unsigned char)NetMT_PlayerState_Minimal;
2557 
2558 
2559 	playerIndex = PlayerIdInPlayerList(AVPDPNetID);
2560 	GLOBALASSERT(playerIndex!=NET_IDNOTINPLAYERLIST);
2561 
2562 	/* KJL 17:04:22 26/01/98 - elevation (for weapon, etc.) */
2563 	{
2564 		PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
2565 		messagePtr->Elevation = playerStatusPtr->ViewPanX;
2566 	}
2567 
2568 	/* my current weapon id, and whether I am firing it... */
2569 	{
2570  		PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr);
2571 		LOCALASSERT(playerStatusPtr);
2572     	weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
2573 
2574 		if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) {
2575 			if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(PlayerStatusPtr->IsAlive)) {
2576 				if (LastHand) {
2577 					messagePtr->IAmFiringPrimary = 0;
2578 					messagePtr->IAmFiringSecondary = 1;
2579 				} else {
2580 					messagePtr->IAmFiringPrimary = 1;
2581 					messagePtr->IAmFiringSecondary = 0;
2582 				}
2583 			} else {
2584 				messagePtr->IAmFiringPrimary = 0;
2585 				messagePtr->IAmFiringSecondary = 0;
2586 			}
2587 			/* whether or not I'm displaying a gun flash */
2588 			messagePtr->IHaveAMuzzleFlash = MyPlayerHasAMuzzleFlash(sbPtr);
2589 		} else {
2590 			if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(PlayerStatusPtr->IsAlive))
2591 				messagePtr->IAmFiringPrimary = 1;
2592 			else messagePtr->IAmFiringPrimary = 0;
2593 			if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(PlayerStatusPtr->IsAlive))
2594 				messagePtr->IAmFiringSecondary = 1;
2595 			else messagePtr->IAmFiringSecondary = 0;
2596 			/* whether or not I'm displaying a gun flash */
2597 			if(MyPlayerHasAMuzzleFlash(sbPtr)) messagePtr->IHaveAMuzzleFlash = 1;
2598 			else messagePtr->IHaveAMuzzleFlash = 0;
2599 		}
2600 	}
2601 
2602 	/* whether or not I'm alive */
2603 	if(PlayerStatusPtr->IsAlive) messagePtr->IAmAlive = 1;
2604 	else messagePtr->IAmAlive = 0;
2605 
2606 	netGameData.playerData[playerIndex].playerAlive=messagePtr->IAmAlive;
2607 
2608 	//Is the player alive or in possesion of extra lives?
2609 	if(messagePtr->IAmAlive)
2610 	{
2611 		messagePtr->IHaveLifeLeft=1;
2612 	}
2613 	else
2614 	{
2615 		messagePtr->IHaveLifeLeft=AreThereAnyLivesLeft();
2616 	}
2617 
2618 	netGameData.playerData[playerIndex].playerHasLives=messagePtr->IHaveLifeLeft;
2619 
2620 
2621 
2622 
2623 	/* whether or not I'm a cloaked predator */
2624 	{
2625  		PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr);
2626 		LOCALASSERT(playerStatusPtr);
2627 
2628 		if(playerStatusPtr->cloakOn)
2629 		{
2630 			LOCALASSERT(AvP.PlayerType==I_Predator);
2631 
2632 			if (playerStatusPtr->CloakingEffectiveness>65535)
2633 			{
2634 				messagePtr->CloakingEffectiveness = 65535>>8;
2635 			}
2636 			else
2637 			{
2638 				messagePtr->CloakingEffectiveness = (unsigned short)(playerStatusPtr->CloakingEffectiveness>>8);
2639 			}
2640 		}
2641 		else messagePtr->CloakingEffectiveness = 0;
2642 	}
2643 
2644 
2645 	/* Am I on fire? */
2646 	if (sbPtr->SBDamageBlock.IsOnFire) {
2647 		messagePtr->IAmOnFire=1;
2648 	} else {
2649 		messagePtr->IAmOnFire=0;
2650 	}
2651 	/* Do I have a disk?  Probably not. */
2652 	messagePtr->IHaveADisk=0;
2653 	if (AvP.PlayerType==I_Predator) {
2654 		if (weaponPtr->WeaponIDNumber==WEAPON_PRED_DISC) {
2655 			if (PlayersWeapon.HModelControlBlock) {
2656 				SECTION_DATA *disc_section;
2657 				disc_section=GetThisSectionData(PlayersWeapon.HModelControlBlock->section_data,"disk");
2658 				GLOBALASSERT(disc_section);
2659 				if ((disc_section->flags&section_data_notreal)==0) {
2660 					/* We have a disk! */
2661 					messagePtr->IHaveADisk=1;
2662 				}
2663 			}
2664 		}
2665 	}
2666 
2667 	if(sendOrient)
2668 	{
2669 		NETMESSAGE_PLAYERSTATE_MEDIUM* mediumMessage=(NETMESSAGE_PLAYERSTATE_MEDIUM*) messagePtr;
2670 		mediumMessage->xOrient = (sbPtr->DynPtr->OrientEuler.EulerX>>NET_EULERSCALESHIFT);
2671 		mediumMessage->yOrient = (sbPtr->DynPtr->OrientEuler.EulerY>>NET_EULERSCALESHIFT);
2672 		mediumMessage->zOrient = (sbPtr->DynPtr->OrientEuler.EulerZ>>NET_EULERSCALESHIFT);
2673 	}
2674 }
2675 
AddNetMsg_FrameTimer()2676 void AddNetMsg_FrameTimer()
2677 {
2678 	NETMESSAGEHEADER *headerPtr;
2679 	NETMESSAGE_FRAMETIMER *messagePtr;
2680 	int headerSize = sizeof(NETMESSAGEHEADER);
2681 	int messageSize = sizeof(NETMESSAGE_FRAMETIMER);
2682 
2683 	/* only send this if we are playing */
2684 	if(netGameData.myGameState!=NGS_Playing) return;
2685 
2686 	/* check there's enough room in the send buffer */
2687 	{
2688 		int numBytesReqd = headerSize + messageSize;
2689 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
2690 		if(numBytesReqd > numBytesLeft)
2691 		{
2692 			LOCALASSERT(1==0);
2693 			/* don't add it */
2694 			return;
2695 		}
2696 	}
2697 
2698 	/* set up pointers to header and message structures */
2699 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
2700 	endSendBuffer += headerSize;
2701 	messagePtr = (NETMESSAGE_FRAMETIMER *)endSendBuffer;
2702 	endSendBuffer += messageSize;
2703 
2704 	/* fill out the header */
2705 	headerPtr->type = (unsigned char)NetMT_FrameTimer;
2706 
2707 	/* fill out the message */
2708 	messagePtr->frame_time = (unsigned short)GameTimeSinceLastSend;
2709 	GameTimeSinceLastSend=0;
2710 }
2711 
2712 /* support function for addnetmsg_playerstate() */
MyPlayerHasAMuzzleFlash(STRATEGYBLOCK * sbPtr)2713 static int MyPlayerHasAMuzzleFlash(STRATEGYBLOCK *sbPtr)
2714 {
2715 	PLAYER_WEAPON_DATA *weaponPtr;
2716 	TEMPLATE_WEAPON_DATA *twPtr;
2717  	PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr);
2718 	LOCALASSERT(playerStatusPtr);
2719 
2720     weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
2721 	twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber];
2722 
2723 	/* first check if we are displaying a muzle flash ourselves */
2724 	if(twPtr->MuzzleFlashShapeName == NULL) return 0;
2725 	if(twPtr->PrimaryIsMeleeWeapon) return 0;
2726 
2727 	if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) {
2728 		if (weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) {
2729 			if (LastHand) {
2730 				return 2;
2731 			} else {
2732 				return 1;
2733 			}
2734 		} else if (weaponPtr->CurrentState == WEAPONSTATE_FIRING_SECONDARY) {
2735 			if (LastHand) {
2736 				return 2;
2737 			} else {
2738 				return 1;
2739 			}
2740 			return 0;
2741 		}
2742 	}
2743 
2744 	if (weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL) {
2745 		if ((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)
2746 			||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)) {
2747 			//ReleasePrintDebuggingText("Pistol Muzzle Flash 1\n");
2748 			return 1;
2749 		} else {
2750 			//ReleasePrintDebuggingText("Pistol Muzzle Flash 0\n");
2751 			return 0;
2752 		}
2753 	}
2754 
2755 	if (weaponPtr->CurrentState != WEAPONSTATE_FIRING_PRIMARY) {
2756 		return 0;
2757 	}
2758 
2759 	/* even if we are displaying our own muzzle flash, we don't neccessarily want it to
2760 	be visible to other players (because it looks stupid) */
2761 	if((weaponPtr->WeaponIDNumber==WEAPON_PULSERIFLE)||
2762 	   (weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL)||
2763 	   (weaponPtr->WeaponIDNumber==WEAPON_AUTOSHOTGUN)||
2764 	   (weaponPtr->WeaponIDNumber==WEAPON_SMARTGUN)||
2765 	   (weaponPtr->WeaponIDNumber==WEAPON_MINIGUN)||
2766 	   (weaponPtr->WeaponIDNumber==WEAPON_FRISBEE_LAUNCHER)||
2767 	   (weaponPtr->WeaponIDNumber==WEAPON_PRED_PISTOL)||
2768 	   (weaponPtr->WeaponIDNumber==WEAPON_PRED_RIFLE))
2769 	{
2770 		/* if we get this far, we want to display a muzzle flash */
2771 		return 1;
2772 	}
2773 	return 0;
2774 }
2775 
GetWeaponIconFromDamage(DAMAGE_PROFILE * damage)2776 char GetWeaponIconFromDamage(DAMAGE_PROFILE* damage)
2777 {
2778 	#define ICON_CUDGEL 177
2779 	#define ICON_PULSERIFLE 177
2780 	#define ICON_PULSERIFLE_GRENADE 177
2781 	#define ICON_SMARTGUN 138
2782 	#define ICON_FLAMER 137
2783 	#define ICON_SADAR 140
2784 	#define ICON_GRENADE_STANDARD 139
2785 	#define ICON_GRENADE_PROX 139
2786 	#define ICON_GRENADE_FRAG 139
2787 	#define ICON_MINIGUN 141
2788 	#define ICON_SKEETER 143
2789 	#define ICON_MARINE_PISTOL 142
2790 
2791 	#define ICON_CLAW 152
2792 	#define ICON_TAIL 151
2793 	#define ICON_JAWS 176
2794 
2795 	#define ICON_WRISTBLADE 154
2796 	#define ICON_PRED_PISTOL 158
2797 	#define ICON_SHOULDERCANNON 156
2798 	#define ICON_SPEARGUN 155
2799 	#define ICON_DISC 157
2800 
2801 
2802 	if(!damage) return 0;
2803 	switch(damage->Id)
2804 	{
2805 		case AMMO_10MM_CULW :
2806 			return ICON_PULSERIFLE;
2807 
2808 		case AMMO_PULSE_GRENADE :
2809 		case AMMO_PULSE_GRENADE_STRIKE :
2810 			return ICON_PULSERIFLE_GRENADE;
2811 
2812 		case AMMO_SMARTGUN :
2813 			return ICON_SMARTGUN;
2814 
2815 		case AMMO_FLAMETHROWER :
2816 		case AMMO_FIREDAMAGE_POSTMAX :
2817 			return ICON_FLAMER;
2818 
2819 		case AMMO_SADAR_TOW :
2820 		case AMMO_SADAR_BLAST :
2821 			return ICON_SADAR;
2822 
2823 		case AMMO_GRENADE :
2824 			return ICON_GRENADE_STANDARD;
2825 
2826 		case AMMO_FRAGMENTATION_GRENADE :
2827 		case AMMO_FLECHETTE_POSTMAX :
2828 			return ICON_GRENADE_FRAG;
2829 
2830 		case AMMO_PROXIMITY_GRENADE :
2831 			return ICON_GRENADE_PROX;
2832 
2833 		case AMMO_MINIGUN :
2834 			return ICON_MINIGUN ;
2835 
2836 		case AMMO_MARINE_PISTOL :
2837 		case AMMO_MARINE_PISTOL_PC :
2838 			return ICON_MARINE_PISTOL;
2839 
2840 		case AMMO_CUDGEL :
2841 			return ICON_CUDGEL;
2842 
2843 		case AMMO_FRISBEE :
2844 		case AMMO_FRISBEE_BLAST :
2845 		case AMMO_FRISBEE_FIRE :
2846 			return ICON_SKEETER;
2847 
2848 
2849 		case AMMO_PRED_WRISTBLADE :
2850 		case AMMO_HEAVY_PRED_WRISTBLADE :
2851 		case AMMO_PRED_TROPHY_KILLSECTION :
2852 			return ICON_WRISTBLADE;
2853 
2854 		case AMMO_PRED_PISTOL :
2855 			return ICON_PRED_PISTOL;
2856 
2857 		case AMMO_PRED_RIFLE :
2858 			return ICON_SPEARGUN;
2859 
2860 		case AMMO_PRED_ENERGY_BOLT :
2861 		case AMMO_PLASMACASTER_NPCKILL :
2862 		case AMMO_PLASMACASTER_PCKILL :
2863 			return ICON_SHOULDERCANNON;
2864 
2865 		case AMMO_PRED_DISC :
2866 			return ICON_DISC;
2867 
2868 		case AMMO_PREDPISTOL_STRIKE :
2869 			return ICON_PRED_PISTOL;
2870 
2871 
2872 		case AMMO_ALIEN_CLAW :
2873 			return ICON_CLAW;
2874 
2875 		case AMMO_ALIEN_TAIL :
2876 			return ICON_TAIL;
2877 
2878 		case AMMO_ALIEN_BITE_KILLSECTION :
2879 		case AMMO_PC_ALIEN_BITE :
2880 		case AMMO_ALIEN_BITE_KILLSECTION_SUPER :
2881 			return ICON_JAWS;
2882 		default:
2883 			break;
2884 	}
2885 
2886 	return 0;
2887 }
2888 
AddNetMsg_PlayerKilled(int objectId,DAMAGE_PROFILE * damage)2889 void AddNetMsg_PlayerKilled(int objectId,DAMAGE_PROFILE* damage)
2890 {
2891 	NETMESSAGEHEADER *headerPtr;
2892 	NETMESSAGE_PLAYERKILLED *messagePtr;
2893 	int headerSize = sizeof(NETMESSAGEHEADER);
2894 	int messageSize = sizeof(NETMESSAGE_PLAYERKILLED);
2895 
2896 	/* only send this if we are playing */
2897 	if(netGameData.myGameState!=NGS_Playing) return;
2898 
2899 	/* definitely should be actually dead */
2900 	LOCALASSERT(PlayerStatusPtr->IsAlive==0);
2901 
2902 	/* check there's enough room in the send buffer */
2903 	{
2904 		int numBytesReqd = headerSize + messageSize;
2905 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
2906 		if(numBytesReqd > numBytesLeft)
2907 		{
2908 			LOCALASSERT(1==0);
2909 			/* don't add it */
2910 			return;
2911 		}
2912 	}
2913 
2914 	/* set up pointers to header and message structures */
2915 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
2916 	endSendBuffer += headerSize;
2917 	messagePtr = (NETMESSAGE_PLAYERKILLED *)endSendBuffer;
2918 	endSendBuffer += messageSize;
2919 
2920 	/* fill out the header */
2921 	headerPtr->type = (unsigned char)NetMT_PlayerKilled;
2922 
2923 	/* fill out the message: myNetworkkillerId should either be NULL indicating that player
2924 	has killed himself, or the DPID of the killer (which may in fact be the player's DPID)*/
2925 	messagePtr->objectId=objectId; /* ID of the new corpse. */
2926 	messagePtr->killerId = myNetworkKillerId;
2927 	messagePtr->myType=netGameData.myCharacterType;
2928 
2929 	if(myNetworkKillerId)
2930 	{
2931 		int killer_index=PlayerIdInPlayerList(myNetworkKillerId);
2932 		if(killer_index!=NET_IDNOTINPLAYERLIST)
2933 		{
2934 			messagePtr->killerType=netGameData.playerData[killer_index].characterType;
2935 		}
2936 		else
2937 		{
2938 			//the player doing the damage has either left the game , or never existed.
2939 			//call it suicide then.
2940 			myNetworkKillerId=AVPDPNetID;
2941 			messagePtr->killerId=0;
2942 		}
2943 	}
2944 
2945 	if(!myNetworkKillerId || myNetworkKillerId==AVPDPNetID)
2946 	{
2947 		//suicide (or killed by alien , in which case this will be corrected a few lines later)
2948 		messagePtr->killerType=messagePtr->myType;
2949 	}
2950 
2951 	//find the icon for the weapon used
2952 	messagePtr->weaponIcon = GetWeaponIconFromDamage(damage);
2953 
2954 	/*look at the damage type to see if the damage was done by an ai alien*/
2955 	if(damage)
2956 	{
2957 		switch (damage->Id)
2958 		{
2959 			case AMMO_NPC_ALIEN_CLAW :
2960 			case AMMO_NPC_ALIEN_TAIL :
2961 			case AMMO_NPC_ALIEN_BITE :
2962 				messagePtr->killerType=NGCT_AI_Alien;
2963 				break;
2964 
2965 			case AMMO_NPC_PREDALIEN_CLAW :
2966 			case AMMO_NPC_PREDALIEN_BITE :
2967 			case AMMO_NPC_PREDALIEN_TAIL :
2968 				messagePtr->killerType=NGCT_AI_Predalien;
2969 				break;
2970 
2971 			case AMMO_NPC_PRAETORIAN_CLAW :
2972 			case AMMO_NPC_PRAETORIAN_BITE :
2973 			case AMMO_NPC_PRAETORIAN_TAIL :
2974 				messagePtr->killerType=NGCT_AI_Praetorian;
2975 				break;
2976 			default:
2977 				break;
2978 		}
2979 	}
2980 	Inform_PlayerHasDied(myNetworkKillerId,AVPDPNetID,messagePtr->killerType,messagePtr->weaponIcon);
2981 
2982 	if(AvP.Network==I_Host)
2983 	{
2984 		DoNetScoresForHostDeath(messagePtr->myType,messagePtr->killerType);
2985 	}
2986 
2987 }
2988 
AddNetMsg_PlayerDeathAnim(int deathId,int objectId)2989 void AddNetMsg_PlayerDeathAnim(int deathId,int objectId)
2990 {
2991 	NETMESSAGEHEADER *headerPtr;
2992 	NETMESSAGE_CORPSEDEATHANIM *messagePtr;
2993 	int headerSize = sizeof(NETMESSAGEHEADER);
2994 	int messageSize = sizeof(NETMESSAGE_CORPSEDEATHANIM);
2995 
2996 	/* only send this if we are playing */
2997 	if(netGameData.myGameState!=NGS_Playing) return;
2998 
2999 	/* check there's enough room in the send buffer */
3000 	{
3001 		int numBytesReqd = headerSize + messageSize;
3002 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3003 		if(numBytesReqd > numBytesLeft)
3004 		{
3005 			LOCALASSERT(1==0);
3006 			/* don't add it */
3007 			return;
3008 		}
3009 	}
3010 
3011 	/* set up pointers to header and message structures */
3012 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3013 	endSendBuffer += headerSize;
3014 	messagePtr = (NETMESSAGE_CORPSEDEATHANIM *)endSendBuffer;
3015 	endSendBuffer += messageSize;
3016 
3017 	/* fill out the header */
3018 	headerPtr->type = (unsigned char)NetMT_CorpseDeathAnim;
3019 
3020 	messagePtr->objectId=objectId; /* ID of the new corpse. */
3021 	messagePtr->deathId = deathId;
3022 
3023 }
3024 
AddNetMsg_PlayerLeaving(void)3025 void AddNetMsg_PlayerLeaving(void)
3026 {
3027 	NETMESSAGEHEADER *headerPtr;
3028 	int headerSize = sizeof(NETMESSAGEHEADER);
3029 
3030 	/* some conditions */
3031 	//LOCALASSERT(AvP.Network==I_Peer);
3032 	/* yes: need to send this before changing state, as we need to know our previous state,
3033 	and sendMessage requires one of these two states anyway */
3034 	LOCALASSERT((netGameData.myGameState==NGS_StartUp)||(netGameData.myGameState==NGS_Playing)||(netGameData.myGameState==NGS_Joining)||(netGameData.myGameState==NGS_EndGame)||(netGameData.myGameState==NGS_EndGameScreen));
3035 
3036 	/* check there's enough room in the send buffer */
3037 	{
3038 		int numBytesReqd = headerSize;
3039 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3040 		if(numBytesReqd > numBytesLeft)
3041 		{
3042 			LOCALASSERT(1==0);
3043 			/* don't add it */
3044 			return;
3045 		}
3046 	}
3047 
3048 	/* set up pointers to header and message structures */
3049 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3050 	endSendBuffer += headerSize;
3051 
3052 	/* fill out the header */
3053 	headerPtr->type = (unsigned char)NetMT_PlayerLeaving;
3054 }
3055 
AddNetMsg_AllGameScores(void)3056 void AddNetMsg_AllGameScores(void)
3057 {
3058 	NETMESSAGEHEADER *headerPtr;
3059 	NETMESSAGE_ALLGAMESCORES *messagePtr;
3060 	int headerSize = sizeof(NETMESSAGEHEADER);
3061 	int messageSize = sizeof(NETMESSAGE_ALLGAMESCORES);
3062 
3063 	/* should be sent by host only, whilst in end game */
3064 	LOCALASSERT(AvP.Network==I_Host);
3065 	LOCALASSERT((netGameData.myGameState==NGS_Playing)||(netGameData.myGameState==NGS_EndGameScreen));
3066 
3067 	/* check there's enough room in the send buffer */
3068 	{
3069 		int numBytesReqd = headerSize + messageSize;
3070 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3071 		if(numBytesReqd > numBytesLeft)
3072 		{
3073 			LOCALASSERT(1==0);
3074 			/* don't add it */
3075 			return;
3076 		}
3077 	}
3078 
3079 	/* set up pointers to header and message structures */
3080 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3081 	endSendBuffer += headerSize;
3082 	messagePtr = (NETMESSAGE_ALLGAMESCORES *)endSendBuffer;
3083 	endSendBuffer += messageSize;
3084 
3085 	/* fill out the header */
3086 	headerPtr->type = (unsigned char)NetMT_AllGameScores;
3087 
3088 	/*fill out the message */
3089 	{ int i,j;
3090 		for(i=0;i<NET_MAXPLAYERS;i++)
3091 		{
3092 			for(j=0;j<NET_MAXPLAYERS;j++)
3093 			{
3094 				messagePtr->playerFrags[i][j] = netGameData.playerData[i].playerFrags[j];
3095 			}
3096 			messagePtr->playerScores[i] = netGameData.playerData[i].playerScore;
3097 			messagePtr->playerScoresAgainst[i] = netGameData.playerData[i].playerScoreAgainst;
3098 
3099 			for(j=0;j<3;j++)
3100 			{
3101 				messagePtr->aliensKilled[i][j]=netGameData.playerData[i].aliensKilled[j];
3102 			}
3103 
3104 			messagePtr->deathsFromAI[i] = netGameData.playerData[i].deathsFromAI;
3105 		}
3106 	}
3107 }
3108 
AddNetMsg_PlayerScores(int playerId)3109 void AddNetMsg_PlayerScores(int playerId)
3110 {
3111 	NETMESSAGEHEADER *headerPtr;
3112 	NETMESSAGE_PLAYERSCORES *messagePtr;
3113 	int headerSize = sizeof(NETMESSAGEHEADER);
3114 	int messageSize = sizeof(NETMESSAGE_PLAYERSCORES);
3115 
3116 	/* should be sent by host only, whilst playing game */
3117 	LOCALASSERT(AvP.Network==I_Host);
3118 	LOCALASSERT((netGameData.myGameState==NGS_Playing));
3119 
3120 	/* check there's enough room in the send buffer */
3121 	{
3122 		int numBytesReqd = headerSize + messageSize;
3123 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3124 		if(numBytesReqd > numBytesLeft)
3125 		{
3126 			LOCALASSERT(1==0);
3127 			/* don't add it */
3128 			return;
3129 		}
3130 	}
3131 
3132 	/* set up pointers to header and message structures */
3133 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3134 	endSendBuffer += headerSize;
3135 	messagePtr = (NETMESSAGE_PLAYERSCORES *)endSendBuffer;
3136 	endSendBuffer += messageSize;
3137 
3138 	/* fill out the header */
3139 	headerPtr->type = (unsigned char)NetMT_PlayerScores;
3140 
3141 	/*fill out the message */
3142 	messagePtr->playerId = (unsigned char)playerId;
3143 	{ int i;
3144 		for(i=0;i<NET_MAXPLAYERS;i++)
3145 		{
3146 			messagePtr->playerFrags[i] = netGameData.playerData[playerId].playerFrags[i];
3147 		}
3148 		messagePtr->playerScore=netGameData.playerData[playerId].playerScore;
3149 		messagePtr->playerScoreAgainst=netGameData.playerData[playerId].playerScoreAgainst;
3150 
3151 		for(i=0;i<3;i++)
3152 		{
3153 			messagePtr->aliensKilled[i]=netGameData.playerData[playerId].aliensKilled[i];
3154 		}
3155 
3156 		messagePtr->deathsFromAI=netGameData.playerData[playerId].deathsFromAI;
3157 	}
3158 }
3159 
AddNetMsg_ScoreChange(int killerIndex,int victimIndex)3160 void AddNetMsg_ScoreChange(int killerIndex,int victimIndex)
3161 {
3162 	NETMESSAGEHEADER *headerPtr;
3163 	NETMESSAGE_SCORECHANGE *messagePtr;
3164 	int headerSize = sizeof(NETMESSAGEHEADER);
3165 	int messageSize = sizeof(NETMESSAGE_SCORECHANGE);
3166 
3167 	/* check there's enough room in the send buffer */
3168 	{
3169 		int numBytesReqd = headerSize + messageSize;
3170 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3171 		if(numBytesReqd > numBytesLeft)
3172 		{
3173 			LOCALASSERT(1==0);
3174 			/* don't add it */
3175 			return;
3176 		}
3177 	}
3178 
3179 	/* set up pointers to header and message structures */
3180 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3181 	endSendBuffer += headerSize;
3182 	messagePtr = (NETMESSAGE_SCORECHANGE *)endSendBuffer;
3183 	endSendBuffer += messageSize;
3184 
3185 	/* fill out the header */
3186 	headerPtr->type = (unsigned char)NetMT_ScoreChange;
3187 
3188 	/* Fill in message. */
3189 	messagePtr->killerIndex=(unsigned char) killerIndex;
3190 	messagePtr->victimIndex=(unsigned char) victimIndex;
3191 	if(killerIndex==NET_MAXPLAYERS)
3192 	{
3193 		//killed by ai
3194 		messagePtr->fragCount=netGameData.playerData[victimIndex].deathsFromAI;
3195 	}
3196 	else
3197 	{
3198 		//killed by a player
3199 		messagePtr->fragCount=netGameData.playerData[killerIndex].playerFrags[victimIndex];
3200 		messagePtr->killerScoreFor=netGameData.playerData[killerIndex].playerScore;
3201 	}
3202 	messagePtr->victimScoreAgainst=netGameData.playerData[victimIndex].playerScoreAgainst;
3203 
3204 }
3205 
AddNetMsg_SpeciesScores()3206 void AddNetMsg_SpeciesScores()
3207 {
3208 	NETMESSAGEHEADER *headerPtr;
3209 	NETMESSAGE_SPECIESSCORES *messagePtr;
3210 	int headerSize = sizeof(NETMESSAGEHEADER);
3211 	int messageSize = sizeof(NETMESSAGE_SPECIESSCORES);
3212 	int i;
3213 
3214 	/* check there's enough room in the send buffer */
3215 	{
3216 		int numBytesReqd = headerSize + messageSize;
3217 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3218 		if(numBytesReqd > numBytesLeft)
3219 		{
3220 			LOCALASSERT(1==0);
3221 			/* don't add it */
3222 			return;
3223 		}
3224 	}
3225 
3226 	/* set up pointers to header and message structures */
3227 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3228 	endSendBuffer += headerSize;
3229 	messagePtr = (NETMESSAGE_SPECIESSCORES *)endSendBuffer;
3230 	endSendBuffer += messageSize;
3231 
3232 	/* fill out the header */
3233 	headerPtr->type = (unsigned char)NetMT_SpeciesScores;
3234 
3235 	/* Fill in message. */
3236 	for(i=0;i<3;i++)
3237 	{
3238 		messagePtr->teamScores[i]=netGameData.teamScores[i];
3239 	}
3240 }
3241 
3242 /* for sending information about bullet ricochets and plasma impacts */
AddNetMsg_LocalRicochet(AVP_BEHAVIOUR_TYPE behaviourType,VECTORCH * position,VECTORCH * direction)3243 void AddNetMsg_LocalRicochet(AVP_BEHAVIOUR_TYPE behaviourType, VECTORCH *position, VECTORCH *direction)
3244 {
3245 }
3246 
AddNetMsg_LocalObjectState(STRATEGYBLOCK * sbPtr)3247 void AddNetMsg_LocalObjectState(STRATEGYBLOCK *sbPtr)
3248 {
3249 	NETMESSAGEHEADER *headerPtr;
3250 	NETMESSAGE_LOBSTATE *messagePtr;
3251 	int headerSize = sizeof(NETMESSAGEHEADER);
3252 	int messageSize = sizeof(NETMESSAGE_LOBSTATE);
3253 
3254 	/* only send this if we are playing */
3255 	if(netGameData.myGameState!=NGS_Playing) return;
3256 
3257 	/* check there's enough room in the send buffer */
3258 	{
3259 		int numBytesReqd = headerSize + messageSize;
3260 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3261 		if(numBytesReqd > numBytesLeft)
3262 		{
3263 			LOCALASSERT(1==0);
3264 			/* don't add it */
3265 			return;
3266 		}
3267 	}
3268 
3269 	/* set up pointers to header and message structures */
3270 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3271 	endSendBuffer += headerSize;
3272 	messagePtr = (NETMESSAGE_LOBSTATE *)endSendBuffer;
3273 	endSendBuffer += messageSize;
3274 
3275 	/* fill out the header */
3276 	headerPtr->type = (unsigned char)NetMT_LocalObjectState;
3277 
3278 	/* fill out the message */
3279 	{
3280 		DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3281 
3282 		LOCALASSERT(dynPtr);
3283 //		LOCALASSERT((dynPtr->Position.vx < 4194304)&&(dynPtr->Position.vx > -4194304)); /* 23 bits of data */
3284 //		LOCALASSERT((dynPtr->Position.vy < 4194304)&&(dynPtr->Position.vy > -4194304)); /* 23 bits of data */
3285 //		LOCALASSERT((dynPtr->Position.vz < 4194304)&&(dynPtr->Position.vz > -4194304)); /* 23 bits of data */
3286 		LOCALASSERT((dynPtr->OrientEuler.EulerX >=0 )&&(dynPtr->OrientEuler.EulerX < 4096)); /* 9 bits of signed data */
3287 		LOCALASSERT((dynPtr->OrientEuler.EulerY >=0 )&&(dynPtr->OrientEuler.EulerY < 4096)); /* 9 bits of signed data */
3288 		LOCALASSERT((dynPtr->OrientEuler.EulerZ >=0 )&&(dynPtr->OrientEuler.EulerZ < 4096));	/* 9 bits of signed data */
3289 
3290 		/* NB we can fit +-4194303 into 23 bits */
3291 		if(dynPtr->Position.vx < -4100000) messagePtr->xPos = -4100000;
3292 		else if(dynPtr->Position.vx > 4100000) messagePtr->xPos = 4100000;
3293 		else messagePtr->xPos = dynPtr->Position.vx;
3294 		messagePtr->xOrient = (dynPtr->OrientEuler.EulerX>>NET_EULERSCALESHIFT);
3295 
3296 		if(dynPtr->Position.vy < -4100000) messagePtr->yPos = -4100000;
3297 		else if(dynPtr->Position.vy > 4100000) messagePtr->yPos = 4100000;
3298 		else messagePtr->yPos = dynPtr->Position.vy;
3299 		messagePtr->yOrient = (dynPtr->OrientEuler.EulerY>>NET_EULERSCALESHIFT);
3300 
3301 		if(dynPtr->Position.vz < -4100000) messagePtr->zPos = -4100000;
3302 		else if(dynPtr->Position.vz > 4100000) messagePtr->zPos = 4100000;
3303 		else messagePtr->zPos = dynPtr->Position.vz;
3304 		messagePtr->zOrient = (dynPtr->OrientEuler.EulerZ>>NET_EULERSCALESHIFT);
3305 	}
3306 
3307 	{
3308 		int obId = *((int *)(&(sbPtr->SBname[4])));
3309 //		LOCALASSERT((obId >= -NET_MAXOBJECTID)&&(obId <= NET_MAXOBJECTID));
3310 		messagePtr->objectId = obId;
3311 	}
3312 
3313 	messagePtr->event_flag=0;
3314 
3315 	LOCALASSERT((sbPtr->I_SBtype >= 0)&&(sbPtr->I_SBtype < 256));
3316 	messagePtr->type = (unsigned char)sbPtr->I_SBtype;
3317 	LOCALASSERT((sbPtr->I_SBtype == I_BehaviourRocket)||
3318 				(sbPtr->I_SBtype == I_BehaviourPredatorEnergyBolt)||
3319 				(sbPtr->I_SBtype == I_BehaviourFrisbeeEnergyBolt)||
3320 				(sbPtr->I_SBtype == I_BehaviourPPPlasmaBolt)||
3321 				(sbPtr->I_SBtype == I_BehaviourSpeargunBolt)||
3322 				(sbPtr->I_SBtype == I_BehaviourGrenade)||
3323 				(sbPtr->I_SBtype == I_BehaviourPulseGrenade)||
3324 				(sbPtr->I_SBtype == I_BehaviourFlareGrenade)||
3325 				(sbPtr->I_SBtype == I_BehaviourFragmentationGrenade)||
3326 				(sbPtr->I_SBtype == I_BehaviourClusterGrenade)||
3327 				(sbPtr->I_SBtype == I_BehaviourNPCPredatorDisc)||
3328 				(sbPtr->I_SBtype == I_BehaviourPredatorDisc_SeekTrack)||
3329 				(sbPtr->I_SBtype == I_BehaviourAlienSpit)||
3330 				(sbPtr->I_SBtype == I_BehaviourProximityGrenade)||
3331 				(sbPtr->I_SBtype == I_BehaviourInanimateObject)||
3332 				(sbPtr->I_SBtype == I_BehaviourFrisbee)||
3333 				(sbPtr->I_SBtype == I_BehaviourNetCorpse));
3334 
3335 	#if 1
3336 	if (sbPtr->I_SBtype==I_BehaviourInanimateObject) {
3337 		INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->SBdataptr;
3338 
3339 		messagePtr->IOType = (unsigned char)objStatPtr->typeId;
3340 		messagePtr->subtype = (unsigned char)objStatPtr->subType;
3341 	} else {
3342 		messagePtr->IOType = (unsigned char)IOT_Non;
3343 		messagePtr->subtype = (unsigned char)0;
3344 	}
3345 	#endif
3346 
3347 	if (sbPtr->I_SBtype==I_BehaviourPredatorDisc_SeekTrack) {
3348 	    PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) sbPtr->SBdataptr;
3349 
3350 		if (bbPtr->Stuck) {
3351 			/* Signal stuck-ness. */
3352 			messagePtr->event_flag=1;
3353 		}
3354 		else if(bbPtr->Bounced)
3355 		{
3356 			messagePtr->event_flag=2;
3357 			bbPtr->Bounced=0;
3358 		}
3359 	}
3360 	else if (sbPtr->I_SBtype==I_BehaviourFrisbee) {
3361 	    FRISBEE_BEHAV_BLOCK *fbPtr = (FRISBEE_BEHAV_BLOCK * ) sbPtr->SBdataptr;
3362 
3363 		if(fbPtr->Bounced)
3364 		{
3365 			messagePtr->event_flag=2;
3366 			fbPtr->Bounced=0;
3367 		}
3368 	}
3369 	else if(sbPtr->I_SBtype==I_BehaviourFlareGrenade)
3370 	{
3371 	    FLARE_BEHAV_BLOCK *bbPtr = (FLARE_BEHAV_BLOCK * ) sbPtr->SBdataptr;
3372 		if(bbPtr->becomeStuck)
3373 		{
3374 			//set the event flag so that other players will start the flare noise
3375 			messagePtr->event_flag=1;
3376 			bbPtr->becomeStuck=0;
3377 		}
3378 	}
3379 	else if ((sbPtr->I_SBtype==I_BehaviourGrenade)||(sbPtr->I_SBtype==I_BehaviourClusterGrenade))
3380 	{
3381 	    GRENADE_BEHAV_BLOCK *bbPtr = (GRENADE_BEHAV_BLOCK * ) sbPtr->SBdataptr;
3382 		if (bbPtr->bouncelastframe) {
3383 			/* Set event flag to record bounce sound. */
3384 			messagePtr->event_flag=1;
3385 		}
3386 	}
3387 }
3388 
3389 
AddNetMsg_LocalObjectDamaged(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple,int sectionID,int delta_seq,int delta_sub_seq,VECTORCH * incoming)3390 void AddNetMsg_LocalObjectDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int sectionID,int delta_seq,int delta_sub_seq,VECTORCH* incoming)
3391 {
3392 	NETMESSAGEHEADER *headerPtr;
3393 	NETMESSAGE_LOBDAMAGED_HEADER *messageHeader=0;
3394 	NETMESSAGE_DAMAGE_PROFILE *messageProfile=0;
3395 	NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0;
3396 	NETMESSAGE_DAMAGE_SECTION *messageSection=0;
3397 	NETMESSAGE_DAMAGE_DELTA *messageDelta=0;
3398 	NETMESSAGE_DAMAGE_DIRECTION *messageDirection=0;
3399 
3400 	int headerSize = sizeof(NETMESSAGEHEADER);
3401 	int maxMessageSize = sizeof(NETMESSAGE_LOBDAMAGED_HEADER)+
3402 					  sizeof(NETMESSAGE_DAMAGE_PROFILE)+
3403 					  sizeof(NETMESSAGE_DAMAGE_MULTIPLE)+
3404 					  sizeof(NETMESSAGE_DAMAGE_SECTION)+
3405 					  sizeof(NETMESSAGE_DAMAGE_DELTA)+
3406 					  sizeof(NETMESSAGE_DAMAGE_DIRECTION);
3407 
3408 	/* only send this if we are playing */
3409 	if(netGameData.myGameState!=NGS_Playing) return;
3410 
3411 	/* check there's enough room in the send buffer */
3412 	{
3413 		int numBytesReqd = headerSize + maxMessageSize;
3414 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3415 		if(numBytesReqd > numBytesLeft)
3416 		{
3417 			LOCALASSERT(1==0);
3418 			/* don't add it */
3419 			return;
3420 		}
3421 	}
3422 
3423 	/* set up pointers to header and message structures */
3424 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3425 	endSendBuffer += headerSize;
3426 
3427 	/* fill out the header */
3428 	headerPtr->type = (unsigned char)NetMT_LocalObjectDamaged;
3429 
3430 	{
3431 		NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
3432 
3433 		LOCALASSERT(ghostData);
3434 		if(sbPtr->I_SBtype != I_BehaviourNetGhost)
3435 		{
3436 			LOCALASSERT(1==0);
3437 		}
3438 
3439 /*--------------------**
3440 ** 	set up the header **
3441 **--------------------*/
3442 		messageHeader = (NETMESSAGE_LOBDAMAGED_HEADER *)endSendBuffer;
3443 		endSendBuffer += sizeof(NETMESSAGE_LOBDAMAGED_HEADER);
3444 
3445 		messageHeader->playerId=ghostData->playerId;
3446 		messageHeader->objectId = ghostData->playerObjectId;
3447 		messageHeader->ammo_id=damage->Id;
3448 
3449 /*-----------------**
3450 ** 	damage profile **
3451 **-----------------*/
3452 		messageHeader->damageProfile=1;
3453 		if(damage->Id>AMMO_NONE && damage->Id<MAX_NO_OF_AMMO_TEMPLATES)
3454 		{
3455 			if(AreDamageProfilesEqual(damage,&TemplateAmmo[damage->Id].MaxDamage[AvP.Difficulty]))
3456 			{
3457 				messageHeader->damageProfile=0;
3458 			}
3459 		}
3460 		else if(damage->Id==AMMO_FLECHETTE_POSTMAX)
3461 		{
3462 			messageHeader->damageProfile=0;
3463 		}
3464 		if(messageHeader->damageProfile)
3465 		{
3466 			messageProfile = (NETMESSAGE_DAMAGE_PROFILE *)endSendBuffer;
3467 			endSendBuffer += sizeof(NETMESSAGE_DAMAGE_PROFILE);
3468 
3469 			messageProfile->Impact = damage->Impact;
3470 			messageProfile->Cutting = damage->Cutting;
3471 			messageProfile->Penetrative = damage->Penetrative;
3472 			messageProfile->Fire = damage->Fire;
3473 			messageProfile->Electrical = damage->Electrical;
3474 			messageProfile->Acid = damage->Acid;
3475 
3476 			messageProfile->ExplosivePower=damage->ExplosivePower;
3477 			messageProfile->Slicing=damage->Slicing;
3478 			messageProfile->ProduceBlood=damage->ProduceBlood;
3479 			messageProfile->ForceBoom=damage->ForceBoom;
3480 
3481 			messageProfile->BlowUpSections=damage->BlowUpSections;
3482 			messageProfile->Special=damage->Special;
3483 			messageProfile->MakeExitWounds=damage->MakeExitWounds;
3484 
3485 		}
3486 
3487 /*-----------------**
3488 ** damage multiple **
3489 **-----------------*/
3490 		if(multiple!=ONE_FIXED)
3491 		{
3492 			messageHeader->multiple=1;
3493 			messageMultiple = (NETMESSAGE_DAMAGE_MULTIPLE *)endSendBuffer;
3494 			endSendBuffer += sizeof(NETMESSAGE_DAMAGE_MULTIPLE);
3495 
3496 			messageMultiple->multiple=multiple;
3497 
3498 		}
3499 		else
3500 		{
3501 			messageHeader->multiple=0;
3502 		}
3503 /*------------**
3504 ** section id **
3505 **------------*/
3506 		if(sectionID!=-1)
3507 		{
3508 			messageHeader->sectionID=1;
3509 			messageSection = (NETMESSAGE_DAMAGE_SECTION *)endSendBuffer;
3510 			endSendBuffer += sizeof(NETMESSAGE_DAMAGE_SECTION);
3511 
3512 			messageSection->SectionID = (short)sectionID;
3513 		}
3514 		else
3515 		{
3516 			messageHeader->sectionID=0;
3517 		}
3518 
3519 /*----------------**
3520 ** delta sequence **
3521 **----------------*/
3522 		if(delta_seq!=-1)
3523 		{
3524 			messageHeader->delta_seq=1;
3525 			messageDelta = (NETMESSAGE_DAMAGE_DELTA *)endSendBuffer;
3526 			endSendBuffer += sizeof(NETMESSAGE_DAMAGE_DELTA);
3527 
3528 			messageDelta->Delta_Sequence=(char)delta_seq;
3529 			messageDelta->Delta_Sub_Sequence=(char)delta_sub_seq;
3530 		}
3531 		else
3532 		{
3533 			messageHeader->delta_seq=0;
3534 		}
3535 
3536 /*-------------------**
3537 ** direction		 **
3538 **-------------------*/
3539 
3540 		if(incoming && sbPtr->DynPtr)
3541 		{
3542 			VECTORCH direction=*incoming;
3543 
3544 			messageHeader->direction=1;
3545 			messageDirection = (NETMESSAGE_DAMAGE_DIRECTION *)endSendBuffer;
3546 			endSendBuffer += sizeof(NETMESSAGE_DAMAGE_DIRECTION);
3547 
3548 			//need to rotate the vector into world space
3549 			RotateVector(&direction,&sbPtr->DynPtr->OrientMat);
3550 
3551 			//compress vector
3552 			messageDirection->direction_x=direction.vx>>7;
3553 			messageDirection->direction_y=direction.vy>>7;
3554 			messageDirection->direction_z=direction.vz>>7;
3555 		}
3556 		else
3557 		{
3558 			messageHeader->direction=0;
3559 		}
3560 
3561 	}
3562 	//that's it
3563 }
3564 
AddNetMsg_LocalObjectDestroyed_Request(STRATEGYBLOCK * sbPtr)3565 void AddNetMsg_LocalObjectDestroyed_Request(STRATEGYBLOCK *sbPtr)
3566 {
3567 	NETMESSAGEHEADER *headerPtr;
3568 	NETMESSAGE_LOBDESTROYED_REQUEST *messagePtr;
3569 	int headerSize = sizeof(NETMESSAGEHEADER);
3570 	int messageSize = sizeof(NETMESSAGE_LOBDESTROYED_REQUEST);
3571 
3572 	/* only send this if we are playing */
3573 	if(netGameData.myGameState!=NGS_Playing) return;
3574 
3575 	/* check there's enough room in the send buffer */
3576 	{
3577 		int numBytesReqd = headerSize + messageSize;
3578 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3579 		if(numBytesReqd > numBytesLeft)
3580 		{
3581 			LOCALASSERT(1==0);
3582 			/* don't add it */
3583 			return;
3584 		}
3585 	}
3586 
3587 	/* set up pointers to header and message structures */
3588 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3589 	endSendBuffer += headerSize;
3590 	messagePtr = (NETMESSAGE_LOBDESTROYED_REQUEST *)endSendBuffer;
3591 	endSendBuffer += messageSize;
3592 
3593 	/* fill out the header */
3594 	headerPtr->type = (unsigned char)NetMT_LocalObjectDestroyed_Request;
3595 
3596 	/* fill out message */
3597 	{
3598 		NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
3599 
3600 		LOCALASSERT(ghostData);
3601 		if(sbPtr->I_SBtype != I_BehaviourNetGhost)
3602 		{
3603 			LOCALASSERT(1==0);
3604 		}
3605 
3606 		messagePtr->playerId = ghostData->playerId;
3607 /*
3608 		if((ghostData->playerObjectId < -NET_MAXOBJECTID)||(ghostData->playerObjectId > NET_MAXOBJECTID))
3609 		{
3610 			LOCALASSERT(1==0);
3611 		}
3612 */
3613 		messagePtr->objectId = ghostData->playerObjectId;
3614 		/* That's it. */
3615 	}
3616 }
3617 
AddNetMsg_LocalObjectDestroyed(STRATEGYBLOCK * sbPtr)3618 void AddNetMsg_LocalObjectDestroyed(STRATEGYBLOCK *sbPtr)
3619 {
3620 	NETMESSAGEHEADER *headerPtr;
3621 	NETMESSAGE_LOBDESTROYED *messagePtr;
3622 	int headerSize = sizeof(NETMESSAGEHEADER);
3623 	int messageSize = sizeof(NETMESSAGE_LOBDESTROYED);
3624 
3625 	/* only send this if we are playing */
3626 	if(netGameData.myGameState!=NGS_Playing) return;
3627 
3628 	/* check there's enough room in the send buffer */
3629 	{
3630 		int numBytesReqd = headerSize + messageSize;
3631 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3632 		if(numBytesReqd > numBytesLeft)
3633 		{
3634 			LOCALASSERT(1==0);
3635 			/* don't add it */
3636 			return;
3637 		}
3638 	}
3639 
3640 	/* set up pointers to header and message structures */
3641 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3642 	endSendBuffer += headerSize;
3643 	messagePtr = (NETMESSAGE_LOBDESTROYED *)endSendBuffer;
3644 	endSendBuffer += messageSize;
3645 
3646 	/* fill out the header */
3647 	headerPtr->type = (unsigned char)NetMT_LocalObjectDestroyed;
3648 
3649 	/* fill out message */
3650 	{
3651 		int obId = *((int *)(&(sbPtr->SBname[4])));
3652 //		LOCALASSERT((obId >= -NET_MAXOBJECTID)&&(obId <= NET_MAXOBJECTID));
3653 		messagePtr->objectId = obId;
3654 	}
3655 }
3656 
AddNetMsg_InanimateObjectDamaged(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple)3657 void AddNetMsg_InanimateObjectDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple)
3658 {
3659 	NETMESSAGEHEADER *headerPtr;
3660 	NETMESSAGE_INANIMATEDAMAGED_HEADER *messageHeader=0;
3661 	NETMESSAGE_DAMAGE_PROFILE *messageProfile=0;
3662 	NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0;
3663 
3664 	int headerSize = sizeof(NETMESSAGEHEADER);
3665 	int maxMessageSize = sizeof(NETMESSAGE_INANIMATEDAMAGED_HEADER)+
3666 					  sizeof(NETMESSAGE_DAMAGE_PROFILE)+
3667 					  sizeof(NETMESSAGE_DAMAGE_MULTIPLE);
3668 
3669 	/* only send this if we are playing */
3670 	if(netGameData.myGameState!=NGS_Playing) return;
3671 	/* shouldn't be sending this if we are the host */
3672 	LOCALASSERT(AvP.Network!=I_Host);
3673 	/* only send for inanimate objects*/
3674 	LOCALASSERT(sbPtr->I_SBtype==I_BehaviourInanimateObject ||
3675 				sbPtr->I_SBtype==I_BehaviourPlacedLight);
3676 
3677 	/* check there's enough room in the send buffer */
3678 	{
3679 		int numBytesReqd = headerSize + maxMessageSize;
3680 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3681 		if(numBytesReqd > numBytesLeft)
3682 		{
3683 			LOCALASSERT(1==0);
3684 			/* don't add it */
3685 			return;
3686 		}
3687 	}
3688 
3689 	/* set up pointers to header and message structures */
3690 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3691 	endSendBuffer += headerSize;
3692 	/* fill out the header */
3693 	headerPtr->type = (unsigned char)NetMT_InanimateObjectDamaged;
3694 
3695 /*--------------------**
3696 ** 	set up the header **
3697 **--------------------*/
3698 	messageHeader = (NETMESSAGE_INANIMATEDAMAGED_HEADER *)endSendBuffer;
3699 	endSendBuffer += sizeof(NETMESSAGE_INANIMATEDAMAGED_HEADER);
3700 
3701 	COPY_NAME(&(messageHeader->name),&(sbPtr->SBname));
3702 	messageHeader->ammo_id=damage->Id;
3703 
3704 
3705 /*-----------------**
3706 ** 	damage profile **
3707 **-----------------*/
3708 	messageHeader->damageProfile=1;
3709 	if(damage->Id>AMMO_NONE && damage->Id<MAX_NO_OF_AMMO_TEMPLATES)
3710 	{
3711 		if(AreDamageProfilesEqual(damage,&TemplateAmmo[damage->Id].MaxDamage[AvP.Difficulty]))
3712 		{
3713 			messageHeader->damageProfile=0;
3714 		}
3715 	}
3716 	if(messageHeader->damageProfile)
3717 	{
3718 		messageProfile = (NETMESSAGE_DAMAGE_PROFILE *)endSendBuffer;
3719 		endSendBuffer += sizeof(NETMESSAGE_DAMAGE_PROFILE);
3720 
3721 		messageProfile->Impact = damage->Impact;
3722 		messageProfile->Cutting = damage->Cutting;
3723 		messageProfile->Penetrative = damage->Penetrative;
3724 		messageProfile->Fire = damage->Fire;
3725 		messageProfile->Electrical = damage->Electrical;
3726 		messageProfile->Acid = damage->Acid;
3727 
3728 		messageProfile->ExplosivePower=damage->ExplosivePower;
3729 		messageProfile->Slicing=damage->Slicing;
3730 		messageProfile->ProduceBlood=damage->ProduceBlood;
3731 		messageProfile->ForceBoom=damage->ForceBoom;
3732 
3733 		messageProfile->BlowUpSections=damage->BlowUpSections;
3734 		messageProfile->Special=damage->Special;
3735 		messageProfile->MakeExitWounds=damage->MakeExitWounds;
3736 
3737 	}
3738 /*-----------------**
3739 ** damage multiple **
3740 **-----------------*/
3741 	if(multiple!=ONE_FIXED)
3742 	{
3743 		messageHeader->multiple=1;
3744 		messageMultiple = (NETMESSAGE_DAMAGE_MULTIPLE *)endSendBuffer;
3745 		endSendBuffer += sizeof(NETMESSAGE_DAMAGE_MULTIPLE);
3746 
3747 		messageMultiple->multiple=multiple;
3748 
3749 	}
3750 	else
3751 	{
3752 		messageHeader->multiple=0;
3753 	}
3754 
3755 }
3756 
3757 
AddNetMsg_InanimateObjectDestroyed(STRATEGYBLOCK * sbPtr)3758 void AddNetMsg_InanimateObjectDestroyed(STRATEGYBLOCK *sbPtr)
3759 {
3760 	NETMESSAGEHEADER *headerPtr;
3761 	NETMESSAGE_INANIMATEDESTROYED *messagePtr;
3762 	int headerSize = sizeof(NETMESSAGEHEADER);
3763 	int messageSize = sizeof(NETMESSAGE_INANIMATEDESTROYED);
3764 
3765 	/* only send this if we are playing */
3766 	if(netGameData.myGameState!=NGS_Playing) return;
3767 
3768 	/* should only send if we're the host */
3769 	LOCALASSERT(AvP.Network==I_Host);
3770 	LOCALASSERT(sbPtr->I_SBtype==I_BehaviourInanimateObject ||
3771 	            sbPtr->I_SBtype==I_BehaviourPlacedLight);
3772 
3773 	/* check there's enough room in the send buffer */
3774 	{
3775 		int numBytesReqd = headerSize + messageSize;
3776 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3777 		if(numBytesReqd > numBytesLeft)
3778 		{
3779 			LOCALASSERT(1==0);
3780 			/* don't add it */
3781 			return;
3782 		}
3783 	}
3784 
3785 	/* set up pointers to header and message structures */
3786 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3787 	endSendBuffer += headerSize;
3788 	messagePtr = (NETMESSAGE_INANIMATEDESTROYED *)endSendBuffer;
3789 	endSendBuffer += messageSize;
3790 
3791 	/* fill out the header */
3792 	headerPtr->type = (unsigned char)NetMT_InanimateObjectDestroyed;
3793 
3794 	/* fill out message */
3795 	{
3796 		COPY_NAME(&(messagePtr->name),&(sbPtr->SBname));
3797 	}
3798 }
3799 
AddNetMsg_ObjectPickedUp(char * objectName)3800 void AddNetMsg_ObjectPickedUp(char* objectName)
3801 {
3802 	NETMESSAGEHEADER *headerPtr;
3803 	NETMESSAGE_OBJECTPICKEDUP *messagePtr;
3804 	int headerSize = sizeof(NETMESSAGEHEADER);
3805 	int messageSize = sizeof(NETMESSAGE_OBJECTPICKEDUP);
3806 
3807 	/* only send this if we are playing */
3808 	if(netGameData.myGameState!=NGS_Playing) return;
3809 
3810 	/* check there's enough room in the send buffer */
3811 	{
3812 		int numBytesReqd = headerSize + messageSize;
3813 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3814 		if(numBytesReqd > numBytesLeft)
3815 		{
3816 			LOCALASSERT(1==0);
3817 			/* don't add it */
3818 			return;
3819 		}
3820 	}
3821 
3822 	/* set up pointers to header and message structures */
3823 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3824 	endSendBuffer += headerSize;
3825 	messagePtr = (NETMESSAGE_OBJECTPICKEDUP *)endSendBuffer;
3826 	endSendBuffer += messageSize;
3827 
3828 	/* fill out the header */
3829 	headerPtr->type = (unsigned char)NetMT_ObjectPickedUp;
3830 
3831 	/* fill out the message */
3832 	COPY_NAME((&messagePtr->name[0]),objectName);
3833 }
3834 
AddNetMsg_EndGame(void)3835 void AddNetMsg_EndGame(void)
3836 {
3837 	NETMESSAGEHEADER *headerPtr;
3838 	int headerSize = sizeof(NETMESSAGEHEADER);
3839 
3840 	/* should be sent by host only, in endGame state */
3841 	LOCALASSERT(AvP.Network==I_Host);
3842 	/* yes: need to send this before changing state, as we need to know our previous state,
3843 	and sendMessage requires one of these two states anyway */
3844 	LOCALASSERT((netGameData.myGameState==NGS_StartUp)||(netGameData.myGameState==NGS_Playing)||(netGameData.myGameState==NGS_Joining));
3845 
3846 	/* check there's enough room in the send buffer */
3847 	{
3848 		int numBytesReqd = headerSize;
3849 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3850 		if(numBytesReqd > numBytesLeft)
3851 		{
3852 			LOCALASSERT(1==0);
3853 			/* don't add it */
3854 			return;
3855 		}
3856 	}
3857 
3858 	/* set up pointers to header and message structures */
3859 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3860 	endSendBuffer += headerSize;
3861 	/* fill out the header */
3862 	headerPtr->type = (unsigned char)NetMT_EndGame;
3863 }
3864 
AddNetMsg_LOSRequestBinarySwitch(STRATEGYBLOCK * sbPtr)3865 void AddNetMsg_LOSRequestBinarySwitch(STRATEGYBLOCK *sbPtr)
3866 {
3867 	NETMESSAGEHEADER *headerPtr;
3868 	NETMESSAGE_LOSREQUESTBINARYSWITCH *messagePtr;
3869 	int headerSize = sizeof(NETMESSAGEHEADER);
3870 	int messageSize = sizeof(NETMESSAGE_LOSREQUESTBINARYSWITCH);
3871 
3872 	/* only send this if we are playing */
3873 	if(netGameData.myGameState!=NGS_Playing) return;
3874 
3875 	/* also, the object must be a binary switch */
3876 	if(sbPtr->I_SBtype!=I_BehaviourBinarySwitch && sbPtr->I_SBtype!=I_BehaviourLinkSwitch) return;
3877 
3878 	/* check there's enough room in the send buffer */
3879 	{
3880 		int numBytesReqd = headerSize + messageSize;
3881 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3882 		if(numBytesReqd > numBytesLeft)
3883 		{
3884 			LOCALASSERT(1==0);
3885 			/* don't add it */
3886 			return;
3887 		}
3888 	}
3889 
3890 	/* set up pointers to header and message structures */
3891 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3892 	endSendBuffer += headerSize;
3893 	messagePtr = (NETMESSAGE_LOSREQUESTBINARYSWITCH *)endSendBuffer;
3894 	endSendBuffer += messageSize;
3895 
3896 	/* fill out the header */
3897 	headerPtr->type = (unsigned char)NetMT_LOSRequestBinarySwitch;
3898 
3899 	/* fill out the message */
3900 	COPY_NAME((&messagePtr->name[0]),&(sbPtr->SBname));
3901 }
3902 
AddNetMsg_PlatformLiftState(STRATEGYBLOCK * sbPtr)3903 void AddNetMsg_PlatformLiftState(STRATEGYBLOCK *sbPtr)
3904 {
3905 	NETMESSAGEHEADER *headerPtr;
3906 	NETMESSAGE_PLATFORMLIFTSTATE *messagePtr;
3907 	int headerSize = sizeof(NETMESSAGEHEADER);
3908 	int messageSize = sizeof(NETMESSAGE_PLATFORMLIFTSTATE);
3909 	PLATFORMLIFT_BEHAVIOUR_BLOCK *platLiftData;
3910 
3911 	/* only hosts should send this*/
3912 	LOCALASSERT(AvP.Network==I_Host);
3913 
3914 	/* only send this if we are playing */
3915 	if(netGameData.myGameState!=NGS_Playing) return;
3916 
3917 	if(sbPtr->I_SBtype!=I_BehaviourPlatform) return;
3918 	platLiftData = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr;
3919 	LOCALASSERT(platLiftData);
3920 
3921 	/* check there's enough room in the send buffer */
3922 	{
3923 		int numBytesReqd = headerSize + messageSize;
3924 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3925 		if(numBytesReqd > numBytesLeft)
3926 		{
3927 			LOCALASSERT(1==0);
3928 			/* don't add it */
3929 			return;
3930 		}
3931 	}
3932 
3933 	/* set up pointers to header and message structures */
3934 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3935 	endSendBuffer += headerSize;
3936 	messagePtr = (NETMESSAGE_PLATFORMLIFTSTATE *)endSendBuffer;
3937 	endSendBuffer += messageSize;
3938 
3939 	/* fill out the header */
3940 	headerPtr->type = (unsigned char)NetMT_PlatformLiftState;
3941 
3942 	/* fill out the message */
3943 	COPY_NAME((&messagePtr->name[0]),&(sbPtr->SBname));
3944 	messagePtr->state = (char)(platLiftData->state);
3945 }
3946 
AddNetMsg_RequestPlatformLiftActivate(STRATEGYBLOCK * sbPtr)3947 void AddNetMsg_RequestPlatformLiftActivate(STRATEGYBLOCK *sbPtr)
3948 {
3949 	NETMESSAGEHEADER *headerPtr;
3950 	NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE *messagePtr;
3951 	int headerSize = sizeof(NETMESSAGEHEADER);
3952 	int messageSize = sizeof(NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE);
3953 	PLATFORMLIFT_BEHAVIOUR_BLOCK *platLiftData;
3954 
3955 	/* only peers should send this*/
3956 	LOCALASSERT(AvP.Network==I_Peer);
3957 
3958 	/* only send this if we are playing */
3959 	if(netGameData.myGameState!=NGS_Playing) return;
3960 
3961 	if(sbPtr->I_SBtype!=I_BehaviourPlatform) return;
3962 	platLiftData = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr;
3963 	LOCALASSERT(platLiftData);
3964 
3965 	/* check there's enough room in the send buffer */
3966 	{
3967 		int numBytesReqd = headerSize + messageSize;
3968 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
3969 		if(numBytesReqd > numBytesLeft)
3970 		{
3971 			LOCALASSERT(1==0);
3972 			/* don't add it */
3973 			return;
3974 		}
3975 	}
3976 
3977 	/* set up pointers to header and message structures */
3978 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
3979 	endSendBuffer += headerSize;
3980 	messagePtr = (NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE *)endSendBuffer;
3981 	endSendBuffer += messageSize;
3982 
3983 	/* fill out the header */
3984 	headerPtr->type = (unsigned char)NetMT_RequestPlatformLiftActivate;
3985 
3986 	/* fill out the message */
3987 	COPY_NAME((&messagePtr->name[0]),&(sbPtr->SBname));
3988 }
3989 
AddNetMsg_PlayerAutoGunState(STRATEGYBLOCK * sbPtr)3990 void AddNetMsg_PlayerAutoGunState(STRATEGYBLOCK *sbPtr)
3991 {
3992 	NETMESSAGEHEADER *headerPtr;
3993 	NETMESSAGE_AGUNSTATE *messagePtr;
3994 	int headerSize = sizeof(NETMESSAGEHEADER);
3995 	int messageSize = sizeof(NETMESSAGE_AGUNSTATE);
3996 
3997 	/* only send this if we are playing */
3998 	if(netGameData.myGameState!=NGS_Playing) return;
3999 
4000 	/* check there's enough room in the send buffer */
4001 	{
4002 		int numBytesReqd = headerSize + messageSize;
4003 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4004 		if(numBytesReqd > numBytesLeft)
4005 		{
4006 			LOCALASSERT(1==0);
4007 			/* don't add it */
4008 			return;
4009 		}
4010 	}
4011 
4012 	/* set up pointers to header and message structures */
4013 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4014 	endSendBuffer += headerSize;
4015 	messagePtr = (NETMESSAGE_AGUNSTATE *)endSendBuffer;
4016 	endSendBuffer += messageSize;
4017 
4018 	/* fill out the header */
4019 	headerPtr->type = (unsigned char)NetMT_PlayerAutoGunState;
4020 
4021 	/* fill out the message */
4022 	{
4023 		DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
4024 
4025 		LOCALASSERT(dynPtr);
4026 		LOCALASSERT((dynPtr->Position.vx < 4194304)&&(dynPtr->Position.vx > -4194304)); /* 23 bits of data */
4027 		LOCALASSERT((dynPtr->Position.vy < 4194304)&&(dynPtr->Position.vy > -4194304)); /* 23 bits of data */
4028 		LOCALASSERT((dynPtr->Position.vz < 4194304)&&(dynPtr->Position.vz > -4194304)); /* 23 bits of data */
4029 		LOCALASSERT((dynPtr->OrientEuler.EulerX >=0 )&&(dynPtr->OrientEuler.EulerX < 4096)); /* 9 bits of signed data */
4030 		LOCALASSERT((dynPtr->OrientEuler.EulerY >=0 )&&(dynPtr->OrientEuler.EulerY < 4096)); /* 9 bits of signed data */
4031 		LOCALASSERT((dynPtr->OrientEuler.EulerZ >=0 )&&(dynPtr->OrientEuler.EulerZ < 4096));	/* 9 bits of signed data */
4032 
4033 		/* NB we can fit +-4194303 into 23 bits */
4034 		if(dynPtr->Position.vx < -4100000) messagePtr->xPos = -4100000;
4035 		else if(dynPtr->Position.vx > 4100000) messagePtr->xPos = 4100000;
4036 		else messagePtr->xPos = dynPtr->Position.vx;
4037 		messagePtr->xOrient = (dynPtr->OrientEuler.EulerX>>NET_EULERSCALESHIFT);
4038 
4039 		if(dynPtr->Position.vy < -4100000) messagePtr->yPos = -4100000;
4040 		else if(dynPtr->Position.vy > 4100000) messagePtr->yPos = 4100000;
4041 		else messagePtr->yPos = dynPtr->Position.vy;
4042 		messagePtr->yOrient = (dynPtr->OrientEuler.EulerY>>NET_EULERSCALESHIFT);
4043 
4044 		if(dynPtr->Position.vz < -4100000) messagePtr->zPos = -4100000;
4045 		else if(dynPtr->Position.vz > 4100000) messagePtr->zPos = 4100000;
4046 		else messagePtr->zPos = dynPtr->Position.vz;
4047 		messagePtr->zOrient = (dynPtr->OrientEuler.EulerZ>>NET_EULERSCALESHIFT);
4048 	}
4049 
4050 	/* add the object Id */
4051 	{
4052 		int obId = *((int *)(&(sbPtr->SBname[4])));
4053 //		LOCALASSERT((obId >= -NET_MAXOBJECTID)&&(obId <= NET_MAXOBJECTID));
4054 		messagePtr->objectId = obId;
4055 	}
4056 
4057 	/* am I firing?? */
4058 	{
4059 		AUTOGUN_STATUS_BLOCK *agData;
4060 		agData = (AUTOGUN_STATUS_BLOCK*)(sbPtr->SBdataptr);
4061 		LOCALASSERT(agData);
4062 		if(agData->Firing) messagePtr->IAmFiring = 1;
4063 		else messagePtr->IAmFiring = 0;
4064 		if(agData->behaviourState==I_disabled) messagePtr->IAmEnabled = 0;
4065 		else messagePtr->IAmEnabled = 1;
4066 	}
4067 }
4068 
4069 /* KJL 17:49:31 20/01/98 - transmit make decal info */
AddNetMsg_MakeDecal(enum DECAL_ID decalID,VECTORCH * normalPtr,VECTORCH * positionPtr,int moduleIndex)4070 void AddNetMsg_MakeDecal(enum DECAL_ID decalID, VECTORCH *normalPtr, VECTORCH *positionPtr, int moduleIndex)
4071 {
4072 	NETMESSAGEHEADER *headerPtr;
4073 	NETMESSAGE_MAKEDECAL *messagePtr;
4074 	int headerSize = sizeof(NETMESSAGEHEADER);
4075 	int messageSize = sizeof(NETMESSAGE_MAKEDECAL);
4076 
4077 	extern int GlobalFrameCounter;
4078 	static int DecalCountThisFrame=0;
4079 	static int FrameStamp;
4080 
4081 	/* only send this if we are playing */
4082 	if(netGameData.myGameState!=NGS_Playing) return;
4083 
4084 	if(FrameStamp!=GlobalFrameCounter)
4085 	{
4086 		FrameStamp=GlobalFrameCounter;
4087 		DecalCountThisFrame=0;
4088 	}
4089 
4090 	/*Limit the decal count per frame, even in lan games. Otherwise it is easy to get assertions from having tons
4091 	of alien blood particles*/
4092 	if(DecalCountThisFrame>=10)
4093 	{
4094 		return;
4095 	}
4096 	DecalCountThisFrame++;
4097 
4098 	/* check there's enough room in the send buffer */
4099 	{
4100 		int numBytesReqd = headerSize + messageSize;
4101 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4102 		if(numBytesReqd > (numBytesLeft-1000))
4103 		{
4104 		//	LOCALASSERT(1==0);
4105 			/* don't add it */
4106 			return;
4107 		}
4108 	}
4109 
4110 	/* set up pointers to header and message structures */
4111 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4112 	endSendBuffer += headerSize;
4113 	messagePtr = (NETMESSAGE_MAKEDECAL *)endSendBuffer;
4114 	endSendBuffer += messageSize;
4115 
4116 	/* fill out the header */
4117 	headerPtr->type = (unsigned char)NetMT_MakeDecal;
4118 
4119 	/* fill out the message */
4120 	messagePtr->DecalID = decalID;
4121 	messagePtr->Position = *positionPtr;
4122 	messagePtr->Direction = *normalPtr;
4123 	messagePtr->ModuleIndex = moduleIndex;
4124 }
4125 
4126 /* KJL 14:34:45 08/04/98 - broadcast a message to the other players */
AddNetMsg_ChatBroadcast(char * string,BOOL same_species_only)4127 void AddNetMsg_ChatBroadcast(char *string,BOOL same_species_only)
4128 {
4129 	NETMESSAGEHEADER *headerPtr;
4130 	char *messagePtr;
4131 	int headerSize = sizeof(NETMESSAGEHEADER);
4132 	int messageSize;
4133 	unsigned char stringLength = 1;
4134 
4135 	//remove the console (assuming it is on screen)
4136 	if(IOFOCUS_AcceptTyping())
4137 	{
4138 		IOFOCUS_Toggle();
4139 	}
4140 
4141 	/* only send this if we are playing */
4142 	if(netGameData.myGameState!=NGS_Playing) return;
4143 
4144 
4145 	{
4146 		char *ptr = string;
4147 		while(*ptr && stringLength<255)
4148 		{
4149 			stringLength++;
4150 			ptr++;
4151 		}
4152 	}
4153 
4154 	if (stringLength==1 || stringLength>=255) return;
4155 
4156 	messageSize = stringLength+1;
4157 
4158 	/* check there's enough room in the send buffer */
4159 	{
4160 		int numBytesReqd = headerSize + messageSize;
4161 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4162 		if(numBytesReqd > numBytesLeft)
4163 		{
4164 			LOCALASSERT(1==0);
4165 			/* don't add it */
4166 			return;
4167 		}
4168 	}
4169 
4170 	/* set up pointers to header and message structures */
4171 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4172 	endSendBuffer += headerSize;
4173 	messagePtr = endSendBuffer;
4174 	endSendBuffer += messageSize;
4175 
4176 	/* fill out the header */
4177 	headerPtr->type = (unsigned char)NetMT_ChatBroadcast;
4178 
4179 	/* fill out the message */
4180 	{
4181 		char *ptr = string;
4182 		//first byte used to distinguish between SAY and SPECIES_SAY
4183 		*messagePtr++=(char)same_species_only;
4184 
4185 
4186 		do
4187 		{
4188 			*messagePtr++ = *ptr;
4189 		}
4190 		while(*ptr++);
4191 	}
4192 
4193 
4194 	{
4195 		sprintf(OnScreenMessageBuffer,"%s: %s",netGameData.playerData[PlayerIdInPlayerList(AVPDPNetID)].name,string);
4196 		NewOnScreenMessage(OnScreenMessageBuffer);
4197 	}
4198 
4199 }
4200 
4201 /* KJL 11:28:44 27/04/98 - make an explosion (just the sfx; damage is handled separately */
AddNetMsg_MakeExplosion(VECTORCH * positionPtr,enum EXPLOSION_ID explosionID)4202 void AddNetMsg_MakeExplosion(VECTORCH *positionPtr, enum EXPLOSION_ID explosionID)
4203 {
4204 	NETMESSAGEHEADER *headerPtr;
4205 	NETMESSAGE_MAKEEXPLOSION *messagePtr;
4206 	int headerSize = sizeof(NETMESSAGEHEADER);
4207 	int messageSize = sizeof(NETMESSAGE_MAKEEXPLOSION);
4208 
4209 	/* only send this if we are playing */
4210 	if(netGameData.myGameState!=NGS_Playing) return;
4211 
4212 	/* check there's enough room in the send buffer */
4213 	{
4214 		int numBytesReqd = headerSize + messageSize;
4215 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4216 		if(numBytesReqd > numBytesLeft)
4217 		{
4218 			LOCALASSERT(1==0);
4219 			/* don't add it */
4220 			return;
4221 		}
4222 	}
4223 
4224 	/* set up pointers to header and message structures */
4225 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4226 	endSendBuffer += headerSize;
4227 	messagePtr = (NETMESSAGE_MAKEEXPLOSION *)endSendBuffer;
4228 	endSendBuffer += messageSize;
4229 
4230 	/* fill out the header */
4231 	headerPtr->type = (unsigned char)NetMT_MakeExplosion;
4232 
4233 	/* fill out the message */
4234 	messagePtr->Position = *positionPtr;
4235 	messagePtr->ExplosionID = explosionID;
4236 }
AddNetMsg_MakeFlechetteExplosion(VECTORCH * positionPtr,int seed)4237 void AddNetMsg_MakeFlechetteExplosion(VECTORCH *positionPtr, int seed)
4238 {
4239 	NETMESSAGEHEADER *headerPtr;
4240 	NETMESSAGE_MAKEFLECHETTEEXPLOSION *messagePtr;
4241 	int headerSize = sizeof(NETMESSAGEHEADER);
4242 	int messageSize = sizeof(NETMESSAGE_MAKEFLECHETTEEXPLOSION);
4243 
4244 	/* only send this if we are playing */
4245 	if(netGameData.myGameState!=NGS_Playing) return;
4246 
4247 	/* check there's enough room in the send buffer */
4248 	{
4249 		int numBytesReqd = headerSize + messageSize;
4250 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4251 		if(numBytesReqd > numBytesLeft)
4252 		{
4253 			LOCALASSERT(1==0);
4254 			/* don't add it */
4255 			return;
4256 		}
4257 	}
4258 
4259 	/* set up pointers to header and message structures */
4260 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4261 	endSendBuffer += headerSize;
4262 	messagePtr = (NETMESSAGE_MAKEFLECHETTEEXPLOSION *)endSendBuffer;
4263 	endSendBuffer += messageSize;
4264 
4265 	/* fill out the header */
4266 	headerPtr->type = (unsigned char)NetMT_MakeFlechetteExplosion;
4267 
4268 	/* fill out the message */
4269 	messagePtr->Position = *positionPtr;
4270 	messagePtr->Seed = seed;
4271 }
4272 
AddNetMsg_MakePlasmaExplosion(VECTORCH * positionPtr,VECTORCH * fromPositionPtr,enum EXPLOSION_ID explosionID)4273 void AddNetMsg_MakePlasmaExplosion(VECTORCH *positionPtr, VECTORCH *fromPositionPtr, enum EXPLOSION_ID explosionID)
4274 {
4275 	NETMESSAGEHEADER *headerPtr;
4276 	NETMESSAGE_MAKEPLASMAEXPLOSION *messagePtr;
4277 	int headerSize = sizeof(NETMESSAGEHEADER);
4278 	int messageSize = sizeof(NETMESSAGE_MAKEPLASMAEXPLOSION);
4279 
4280 	/* only send this if we are playing */
4281 	if(netGameData.myGameState!=NGS_Playing) return;
4282 
4283 	/* check there's enough room in the send buffer */
4284 	{
4285 		int numBytesReqd = headerSize + messageSize;
4286 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4287 		if(numBytesReqd > numBytesLeft)
4288 		{
4289 			LOCALASSERT(1==0);
4290 			/* don't add it */
4291 			return;
4292 		}
4293 	}
4294 
4295 	/* set up pointers to header and message structures */
4296 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4297 	endSendBuffer += headerSize;
4298 	messagePtr = (NETMESSAGE_MAKEPLASMAEXPLOSION *)endSendBuffer;
4299 	endSendBuffer += messageSize;
4300 
4301 	/* fill out the header */
4302 	headerPtr->type = (unsigned char)NetMT_MakePlasmaExplosion;
4303 
4304 	/* fill out the message */
4305 	messagePtr->Position = *positionPtr;
4306 	messagePtr->FromPosition = *fromPositionPtr;
4307 	messagePtr->ExplosionID = explosionID;
4308 }
4309 
4310 /* KJL 11:27:47 20/05/98 - predator laser sights */
AddNetMsg_PredatorLaserSights(VECTORCH * positionPtr,VECTORCH * normalPtr,DISPLAYBLOCK * dispPtr)4311 void AddNetMsg_PredatorLaserSights(VECTORCH *positionPtr, VECTORCH *normalPtr, DISPLAYBLOCK *dispPtr)
4312 {
4313 	NETMESSAGEHEADER *headerPtr;
4314 	NETMESSAGE_PREDATORSIGHTS *messagePtr;
4315 	int headerSize = sizeof(NETMESSAGEHEADER);
4316 	int messageSize = sizeof(NETMESSAGE_PREDATORSIGHTS);
4317 
4318 	/* only send this if we are playing */
4319 	if(netGameData.myGameState!=NGS_Playing) return;
4320 
4321 	/* check there's enough room in the send buffer */
4322 	{
4323 		int numBytesReqd = headerSize + messageSize;
4324 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4325 		if(numBytesReqd > numBytesLeft)
4326 		{
4327 			LOCALASSERT(1==0);
4328 			/* don't add it */
4329 			return;
4330 		}
4331 	}
4332 
4333 	/* set up pointers to header and message structures */
4334 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4335 	endSendBuffer += headerSize;
4336 	messagePtr = (NETMESSAGE_PREDATORSIGHTS *)endSendBuffer;
4337 	endSendBuffer += messageSize;
4338 
4339 	/* fill out the header */
4340 	headerPtr->type = (unsigned char)NetMT_PredatorSights;
4341 
4342 	/* fill out the message */
4343 	{
4344 		MATRIXCH orientMat;
4345 		EULER orientation;
4346 
4347 		MakeMatrixFromDirection(normalPtr,&orientMat);
4348  		MatrixToEuler(&orientMat, &orientation);
4349 
4350 		/* NB we can fit +-4194303 into 23 bits */
4351 		if(positionPtr->vx < -4100000) messagePtr->xPos = -4100000;
4352 		else if(positionPtr->vx > 4100000) messagePtr->xPos = 4100000;
4353 		else messagePtr->xPos = positionPtr->vx;
4354 		messagePtr->xOrient = (orientation.EulerX>>NET_EULERSCALESHIFT);
4355 
4356 		if(positionPtr->vy < -4100000) messagePtr->yPos = -4100000;
4357 		else if(positionPtr->vy > 4100000) messagePtr->yPos = 4100000;
4358 		else messagePtr->yPos = positionPtr->vy;
4359 		messagePtr->yOrient = (orientation.EulerY>>NET_EULERSCALESHIFT);
4360 
4361 		if(positionPtr->vz < -4100000) messagePtr->zPos = -4100000;
4362 		else if(positionPtr->vz > 4100000) messagePtr->zPos = 4100000;
4363 		else messagePtr->zPos = positionPtr->vz;
4364 		messagePtr->zOrient = (orientation.EulerZ>>NET_EULERSCALESHIFT);
4365 
4366 		messagePtr->TargetID = 0;
4367 		if (dispPtr)
4368 		{
4369 			if (dispPtr->ObStrategyBlock)
4370 			{
4371 				if (dispPtr->ObStrategyBlock->I_SBtype == I_BehaviourNetGhost)
4372 				{
4373 			   		NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)dispPtr->ObStrategyBlock->SBdataptr;
4374 
4375 					if (ghostDataPtr->playerObjectId==GHOST_PLAYEROBJECTID)
4376 					{
4377 						messagePtr->TargetID = ghostDataPtr->playerId;
4378 					}
4379 				}
4380 			}
4381 		}
4382 	}
4383 }
4384 
AddNetMsg_LocalObjectOnFire(STRATEGYBLOCK * sbPtr)4385 void AddNetMsg_LocalObjectOnFire(STRATEGYBLOCK *sbPtr)
4386 {
4387 	NETMESSAGEHEADER *headerPtr;
4388 	NETMESSAGE_LOBONFIRE *messagePtr;
4389 	int headerSize = sizeof(NETMESSAGEHEADER);
4390 	int messageSize = sizeof(NETMESSAGE_LOBONFIRE);
4391 
4392 	/* only send this if we are playing */
4393 	if(netGameData.myGameState!=NGS_Playing) return;
4394 
4395 	/* check there's enough room in the send buffer */
4396 	{
4397 		int numBytesReqd = headerSize + messageSize;
4398 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4399 		if(numBytesReqd > numBytesLeft)
4400 		{
4401 			LOCALASSERT(1==0);
4402 			/* don't add it */
4403 			return;
4404 		}
4405 	}
4406 
4407 	/* set up pointers to header and message structures */
4408 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4409 	endSendBuffer += headerSize;
4410 	messagePtr = (NETMESSAGE_LOBONFIRE *)endSendBuffer;
4411 	endSendBuffer += messageSize;
4412 
4413 	/* fill out the header */
4414 	headerPtr->type = (unsigned char)NetMT_LocalObjectOnFire;
4415 
4416 	/* fill out message */
4417 	{
4418 		NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
4419 
4420 		LOCALASSERT(ghostData);
4421 		if(sbPtr->I_SBtype != I_BehaviourNetGhost)
4422 		{
4423 			LOCALASSERT(1==0);
4424 		}
4425 
4426 		messagePtr->playerId = ghostData->playerId;
4427 		/* LOCALASSERT((ghostData->playerObjectId >= -NET_MAXOBJECTID)&&(ghostData->playerObjectId <= NET_MAXOBJECTID)); */
4428 /*
4429 		if((ghostData->playerObjectId < -NET_MAXOBJECTID)||(ghostData->playerObjectId > NET_MAXOBJECTID))
4430 		{
4431 			LOCALASSERT(1==0);
4432 		}
4433 */
4434 		messagePtr->objectId = ghostData->playerObjectId;
4435 
4436 		/* That's all, folks.  This object is on fire. */
4437 	}
4438 }
4439 
AddNetMsg_RestartNetworkGame(int seed)4440 void AddNetMsg_RestartNetworkGame(int seed)
4441 {
4442 	NETMESSAGEHEADER *headerPtr;
4443 	NETMESSAGE_RESTARTGAME *messagePtr;
4444 	int headerSize = sizeof(NETMESSAGEHEADER);
4445 	int messageSize = sizeof(NETMESSAGE_RESTARTGAME);
4446 
4447 	/* check there's enough room in the send buffer */
4448 	{
4449 		int numBytesReqd = headerSize + messageSize;
4450 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4451 		if(numBytesReqd > numBytesLeft)
4452 		{
4453 			LOCALASSERT(1==0);
4454 			/* don't add it */
4455 			return;
4456 		}
4457 	}
4458 
4459 	/* set up pointers to header and message structures */
4460 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4461 	endSendBuffer += headerSize;
4462 	messagePtr = (NETMESSAGE_RESTARTGAME *)endSendBuffer;
4463 	endSendBuffer += messageSize;
4464 
4465 	/* fill out the header */
4466 	headerPtr->type = NetMT_RestartNetworkGame;
4467 
4468 	/* Fill in message. */
4469 	messagePtr->seed=seed;
4470 
4471 }
4472 
AddNetMsg_FragmentalObjectsStatus(void)4473 void AddNetMsg_FragmentalObjectsStatus(void)
4474 {
4475 	NETMESSAGEHEADER *headerPtr;
4476 	NETMESSAGE_FRAGMENTALOBJECTSSTATUS *messagePtr;
4477 	int headerSize = sizeof(NETMESSAGEHEADER);
4478 	int messageSize = sizeof(NETMESSAGE_FRAGMENTALOBJECTSSTATUS);
4479 	static int object_batch=0;
4480 
4481 	/* only send this if we are playing */
4482 	if(netGameData.myGameState!=NGS_Playing) return;
4483 
4484 	/* only the host should send this */
4485 	LOCALASSERT(AvP.Network==I_Host);
4486 
4487 	/* check there's enough room in the send buffer */
4488 	{
4489 		int numBytesReqd = headerSize + messageSize;
4490 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4491 		if(numBytesReqd > numBytesLeft)
4492 		{
4493 			LOCALASSERT(1==0);
4494 			/* don't add it */
4495 			return;
4496 		}
4497 	}
4498 
4499 	/* set up pointers to header and message structures */
4500 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4501 	endSendBuffer += headerSize;
4502 	messagePtr = (NETMESSAGE_FRAGMENTALOBJECTSSTATUS *)endSendBuffer;
4503 	endSendBuffer += messageSize;
4504 
4505 	/* fill out the header */
4506 	headerPtr->type = (unsigned char)NetMT_FragmentalObjectsStatus;
4507 	messagePtr->BatchNumber=object_batch;
4508 
4509 	/* fill out the message */
4510 	{
4511 		int i;
4512 		int fragNumber=0;
4513 		int objectsToSkip=object_batch*(NUMBER_OF_FRAGMENTAL_OBJECTS<<3);
4514 		int noPlacedLights=0;
4515 
4516 		LOCALASSERT(AvP.Network!=I_No_Network);
4517 
4518 		for (i=0; i<NumActiveStBlocks; i++)
4519 		{
4520 			STRATEGYBLOCK *sbPtr = ActiveStBlockList[i];
4521 
4522 			if(sbPtr->I_SBtype == I_BehaviourInanimateObject)
4523 			{
4524 				INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr = sbPtr->SBdataptr;
4525 				LOCALASSERT(objectStatusPtr);
4526 
4527 				if((objectStatusPtr->typeId == IOT_Static) && (!objectStatusPtr->Indestructable) && (!objectStatusPtr->ghosted_object) && (!objectStatusPtr->lifespanTimer))
4528 				{
4529 					if(objectsToSkip>0)
4530 					{
4531 						objectsToSkip--;
4532 						continue;
4533 					}
4534 					WriteFragmentStatus(fragNumber++,(objectStatusPtr->respawnTimer==0));
4535 				}
4536 			}
4537 			else if (sbPtr->I_SBtype == I_BehaviourPlacedLight)
4538 			{
4539 				PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = sbPtr->SBdataptr;
4540 				LOCALASSERT(pl_bhv);
4541 
4542 				if(!pl_bhv->Indestructable)
4543 				{
4544 					if(objectsToSkip>0)
4545 					{
4546 						objectsToSkip--;
4547 						continue;
4548 					}
4549 					WriteFragmentStatus(fragNumber++,(pl_bhv->state!=Light_State_Broken));
4550 				}
4551 			}
4552 			if(fragNumber>=(NUMBER_OF_FRAGMENTAL_OBJECTS<<3))break;
4553 		}
4554 		if(i==NumActiveStBlocks)
4555 		{
4556 			object_batch=0;
4557 		}
4558 		else
4559 		{
4560 			//there are more objects to look at , so increment batch
4561 			object_batch++;
4562 		}
4563 
4564 
4565 		textprint("noPlacedLights %d\n",noPlacedLights);
4566 		textprint("fragNumber %d\n",fragNumber);
4567 
4568 		for (i=0; i<NUMBER_OF_FRAGMENTAL_OBJECTS; i++)
4569 		{
4570 			messagePtr->StatusBitfield[i] = FragmentalObjectStatus[i];
4571 		}
4572 
4573 
4574 	}
4575 }
4576 
AddNetMsg_StrategySynch(void)4577 void AddNetMsg_StrategySynch(void)
4578 {
4579 /*
4580 	Scan through objects looking for strategies that may need to be synchronized between players.
4581 	Mainly switches and track objects
4582 	Only do 16 objects at a time , so as not to send too much data
4583 */
4584 	NETMESSAGEHEADER *headerPtr;
4585 	NETMESSAGE_STRATEGYSYNCH *messagePtr;
4586 	int headerSize = sizeof(NETMESSAGEHEADER);
4587 	int messageSize = sizeof(NETMESSAGE_STRATEGYSYNCH);
4588 	static int object_batch=0;
4589 
4590 	/* only send this if we are playing */
4591 	if(netGameData.myGameState!=NGS_Playing) return;
4592 
4593 	/* only the host should send this */
4594 	LOCALASSERT(AvP.Network==I_Host);
4595 
4596 	/* check there's enough room in the send buffer */
4597 	{
4598 		int numBytesReqd = headerSize + messageSize;
4599 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4600 		if(numBytesReqd > numBytesLeft)
4601 		{
4602 			LOCALASSERT(1==0);
4603 			/* don't add it */
4604 			return;
4605 		}
4606 	}
4607 
4608 	/* set up pointers to header and message structures */
4609 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4610 	endSendBuffer += headerSize;
4611 	messagePtr = (NETMESSAGE_STRATEGYSYNCH *)endSendBuffer;
4612 	endSendBuffer += messageSize;
4613 
4614 	/* fill out the header */
4615 	headerPtr->type = (unsigned char)NetMT_StrategySynch;
4616 	messagePtr->BatchNumber=object_batch;
4617 
4618 	/* fill out the message */
4619 	{
4620 		int i;
4621 		int objectNumber=0;
4622 		int objectsToSkip=object_batch*(NUMBER_OF_STRATEGIES_TO_SYNCH);
4623 
4624 		LOCALASSERT(AvP.Network!=I_No_Network);
4625 
4626 		for (i=0; i<NumActiveStBlocks; i++)
4627 		{
4628 			STRATEGYBLOCK *sbPtr = ActiveStBlockList[i];
4629 
4630 			if(sbPtr->I_SBtype == I_BehaviourBinarySwitch ||
4631 			   sbPtr->I_SBtype == I_BehaviourLinkSwitch ||
4632 			   sbPtr->I_SBtype == I_BehaviourTrackObject)
4633 			{
4634 
4635 				if(objectsToSkip>0)
4636 				{
4637 					objectsToSkip--;
4638 					continue;
4639 				}
4640 
4641 				switch(sbPtr->I_SBtype)
4642 				{
4643 					case I_BehaviourBinarySwitch :
4644 			 			WriteStrategySynch(objectNumber++,BinarySwitchGetSynchData(sbPtr));
4645 						break;
4646 					case I_BehaviourLinkSwitch :
4647 			 			WriteStrategySynch(objectNumber++,LinkSwitchGetSynchData(sbPtr));
4648 						break;
4649 					case I_BehaviourTrackObject :
4650 			 			WriteStrategySynch(objectNumber++,TrackObjectGetSynchData(sbPtr));
4651 						break;
4652 					default:
4653 						break;
4654 				}
4655 
4656 			}
4657 			if(objectNumber>=(NUMBER_OF_STRATEGIES_TO_SYNCH))break;
4658 		}
4659 		if(i==NumActiveStBlocks)
4660 		{
4661 			object_batch=0;
4662 		}
4663 		else
4664 		{
4665 			//there are more objects to look at , so increment batch
4666 			object_batch++;
4667 		}
4668 
4669 
4670 		for (i=0; i<NUMBER_OF_STRATEGIES_TO_SYNCH>>2; i++)
4671 		{
4672 			messagePtr->StatusBitfield[i] = StrategySynchArray[i];
4673 		}
4674 
4675 
4676 	}
4677 
4678 	if(!netGameData.myStrategyCheckSum) netGameData.myStrategyCheckSum=GetStrategySynchObjectChecksum();
4679 	messagePtr->strategyCheckSum=netGameData.myStrategyCheckSum;
4680 }
4681 
AddNetMsg_CreateWeapon(char * objectName,int type,VECTORCH * location)4682 void AddNetMsg_CreateWeapon(char* objectName,int type,VECTORCH* location)
4683 {
4684 	NETMESSAGEHEADER *headerPtr;
4685 	NETMESSAGE_CREATEWEAPON *messagePtr;
4686 	int headerSize = sizeof(NETMESSAGEHEADER);
4687 	int messageSize = sizeof(NETMESSAGE_CREATEWEAPON);
4688 
4689 	/* only send this if we are playing */
4690 	if(netGameData.myGameState!=NGS_Playing) return;
4691 
4692 	/* check there's enough room in the send buffer */
4693 	{
4694 		int numBytesReqd = headerSize + messageSize;
4695 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4696 		if(numBytesReqd > numBytesLeft)
4697 		{
4698 			LOCALASSERT(1==0);
4699 			/* don't add it */
4700 			return;
4701 		}
4702 	}
4703 
4704 	/* set up pointers to header and message structures */
4705 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4706 	endSendBuffer += headerSize;
4707 	messagePtr = (NETMESSAGE_CREATEWEAPON *)endSendBuffer;
4708 	endSendBuffer += messageSize;
4709 
4710 	/* fill out the header */
4711 	headerPtr->type = (unsigned char)NetMT_CreateWeapon;
4712 
4713 	/* fill out the message */
4714 	COPY_NAME((&messagePtr->name[0]),objectName);
4715 	messagePtr->location=*location;
4716 	messagePtr->type=type;
4717 }
4718 /* KJL 16:32:06 17/06/98 - alien AI network messages */
AddNetMsg_AlienAIState(STRATEGYBLOCK * sbPtr)4719 void AddNetMsg_AlienAIState(STRATEGYBLOCK *sbPtr)
4720 {
4721 	NETMESSAGEHEADER *headerPtr;
4722 	NETMESSAGE_ALIENAISTATE *messagePtr;
4723 	int headerSize = sizeof(NETMESSAGEHEADER);
4724 	int messageSize = sizeof(NETMESSAGE_ALIENAISTATE);
4725 
4726 	DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
4727 	ALIEN_STATUS_BLOCK *alienStatusPtr=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
4728 
4729 	LOCALASSERT(dynPtr);
4730 	GLOBALASSERT(alienStatusPtr);
4731 
4732 	#if EXTRAPOLATION_TEST
4733 	if(UseExtrapolation && netGameData.sendFrequency)
4734 	{
4735 		BOOL updateRequired=FALSE;
4736 		VECTORCH facing;
4737 		//can we get away with not sending an update this frame
4738 
4739 		//has it been a while since the last send
4740 		if(TimeCounterForExtrapolation<alienStatusPtr->timeOfLastSend ||
4741 		   TimeCounterForExtrapolation-alienStatusPtr->timeOfLastSend>ONE_FIXED/4)
4742 		{
4743 			updateRequired=TRUE;
4744 		}
4745 
4746 		if(dynPtr->LinImpulse.vx || dynPtr->LinImpulse.vy || dynPtr->LinImpulse.vz)
4747 		{
4748 			//alien is probably jumping , extrapolation doesn't work in this case
4749 			updateRequired=TRUE;
4750 		}
4751 
4752 		//has the velocity changed
4753 		if(!updateRequired)
4754 		{
4755 			int diff=Magnitude(&dynPtr->LinVelocity)-Magnitude(&alienStatusPtr->lastVelocitySent);
4756 			if(diff>500 || -diff>500)
4757 			{
4758 				updateRequired=TRUE;
4759 			}
4760 		}
4761 		facing.vx=dynPtr->OrientMat.mat31;
4762 		facing.vy=dynPtr->OrientMat.mat32;
4763 		facing.vz=dynPtr->OrientMat.mat33;
4764 
4765 		//has the facing changed
4766 		if(!updateRequired)
4767 		{
4768 			if(DotProduct(&facing,&alienStatusPtr->lastFacingSent)<64000)
4769 			{
4770 				updateRequired=TRUE;
4771 			}
4772 		}
4773 
4774 		if(!updateRequired) return;
4775 
4776 		//okay , we do need to send this frame
4777 		alienStatusPtr->timeOfLastSend=TimeCounterForExtrapolation;
4778 		alienStatusPtr->lastVelocitySent=dynPtr->LinVelocity;
4779 		alienStatusPtr->lastFacingSent=facing;
4780 
4781 	}
4782 	#endif
4783 
4784 	/* check there's enough room in the send buffer */
4785 	{
4786 		int numBytesReqd = headerSize + messageSize;
4787 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4788 		if(numBytesReqd > numBytesLeft)
4789 		{
4790 			LOCALASSERT(1==0);
4791 			/* don't add it */
4792 			return;
4793 		}
4794 	}
4795 
4796 	/* set up pointers to header and message structures */
4797 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4798 	endSendBuffer += headerSize;
4799 	messagePtr = (NETMESSAGE_ALIENAISTATE *)endSendBuffer;
4800 	endSendBuffer += messageSize;
4801 
4802 	/* fill out the header */
4803 	headerPtr->type = (unsigned char)NetMT_AlienAIState;
4804 
4805 	/* fill out our position and orientation */
4806 	{
4807 
4808 		LOCALASSERT((dynPtr->OrientEuler.EulerX >=0 )&&(dynPtr->OrientEuler.EulerX < 4096));	/* 9 bits of signed data */
4809 		LOCALASSERT((dynPtr->OrientEuler.EulerY >=0 )&&(dynPtr->OrientEuler.EulerY < 4096));	/* 9 bits of signed data */
4810 		LOCALASSERT((dynPtr->OrientEuler.EulerZ >=0 )&&(dynPtr->OrientEuler.EulerZ < 4096));	/* 9 bits of signed data */
4811 
4812 		/* NB we can fit +-4194303 into 23 bits */
4813 		if(dynPtr->Position.vx < -4100000) messagePtr->xPos = -4100000;
4814 		else if(dynPtr->Position.vx > 4100000) messagePtr->xPos = 4100000;
4815 		else messagePtr->xPos = dynPtr->Position.vx;
4816 		messagePtr->xOrient = (dynPtr->OrientEuler.EulerX>>NET_EULERSCALESHIFT);
4817 
4818 		if(dynPtr->Position.vy < -4100000) messagePtr->yPos = -4100000;
4819 		else if(dynPtr->Position.vy > 4100000) messagePtr->yPos = 4100000;
4820 		else messagePtr->yPos = dynPtr->Position.vy;
4821 		messagePtr->yOrient = (dynPtr->OrientEuler.EulerY>>NET_EULERSCALESHIFT);
4822 
4823 		if(dynPtr->Position.vz < -4100000) messagePtr->zPos = -4100000;
4824 		else if(dynPtr->Position.vz > 4100000) messagePtr->zPos = 4100000;
4825 		else messagePtr->zPos = dynPtr->Position.vz;
4826 		messagePtr->zOrient = (dynPtr->OrientEuler.EulerZ>>NET_EULERSCALESHIFT);
4827 
4828 		#if EXTRAPOLATION_TEST
4829 		messagePtr->standard_gravity=dynPtr->UseStandardGravity;
4830 		messagePtr->speed=Magnitude(&dynPtr->LinVelocity);
4831 		#endif
4832 	}
4833 
4834 	/* fill out anim sequence */
4835 	{
4836 
4837 
4838 		#if 1
4839 		messagePtr->sequence_type = alienStatusPtr->HModelController.Sequence_Type;
4840 		messagePtr->sub_sequence = alienStatusPtr->HModelController.Sub_Sequence;
4841 
4842 		//send the sequence length in 256ths of a second (instead of 65536ths)
4843 		GLOBALASSERT(alienStatusPtr->HModelController.Seconds_For_Sequence>=0 && alienStatusPtr->HModelController.Seconds_For_Sequence<32*ONE_FIXED);
4844 		messagePtr->sequence_length = alienStatusPtr->HModelController.Seconds_For_Sequence>>8;
4845 
4846 		#else
4847 		if (alienStatusPtr->HModelController.Tweening==Controller_NoTweening) {
4848 			messagePtr->sequence_type = alienStatusPtr->HModelController.Sequence_Type;
4849 			messagePtr->sub_sequence = alienStatusPtr->HModelController.Sub_Sequence;
4850 			messagePtr->sequence_length = alienStatusPtr->HModelController.Seconds_For_Sequence;
4851 		} else {
4852 			/* Might be junk. */
4853 			messagePtr->sequence_type  = -1;
4854 			messagePtr->sub_sequence   = -1;
4855 			messagePtr->sequence_length= -1;
4856 		}
4857 		#endif
4858 		messagePtr->AlienType =	alienStatusPtr->Type;
4859 	}
4860 
4861 	if (sbPtr->SBDamageBlock.IsOnFire) {
4862 		messagePtr->IAmOnFire=1;
4863 	} else {
4864 		messagePtr->IAmOnFire=0;
4865 	}
4866 
4867 	/* fill out guid */
4868 	{
4869 		int guid = *((int *)(&(sbPtr->SBname[4])));
4870 //		LOCALASSERT((guid >= -NET_MAXOBJECTID)&&(guid <= NET_MAXOBJECTID));
4871 		messagePtr->Guid = guid;
4872 	}
4873 
4874 }
4875 
4876 /* CDF 24/8/98 A better message. */
AddNetMsg_AlienAISeqChange(STRATEGYBLOCK * sbPtr,int sequence_type,int sub_sequence,int sequence_length,int tweening_time)4877 void AddNetMsg_AlienAISeqChange(STRATEGYBLOCK *sbPtr,int sequence_type,int sub_sequence,int sequence_length,int tweening_time)
4878 {
4879 	NETMESSAGEHEADER *headerPtr;
4880 	NETMESSAGE_ALIENSEQUENCECHANGE *messagePtr;
4881 	int headerSize = sizeof(NETMESSAGEHEADER);
4882 	int messageSize = sizeof(NETMESSAGE_ALIENSEQUENCECHANGE);
4883 
4884 	/* check there's enough room in the send buffer */
4885 	{
4886 		int numBytesReqd = headerSize + messageSize;
4887 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4888 		if(numBytesReqd > numBytesLeft)
4889 		{
4890 			LOCALASSERT(1==0);
4891 			/* don't add it */
4892 			return;
4893 		}
4894 	}
4895 
4896 	/* set up pointers to header and message structures */
4897 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4898 	endSendBuffer += headerSize;
4899 	messagePtr = (NETMESSAGE_ALIENSEQUENCECHANGE *)endSendBuffer;
4900 	endSendBuffer += messageSize;
4901 
4902 	/* fill out the header */
4903 	headerPtr->type = (unsigned char)NetMT_AlienAISequenceChange;
4904 
4905 	/* fill out anim sequence */
4906 
4907 	messagePtr->sequence_type  =sequence_type  ;
4908 	messagePtr->sub_sequence   =sub_sequence   ;
4909 
4910 	//convert times into 256ths of a second
4911 	if(sequence_length==-1)
4912 		messagePtr->sequence_length=-1;
4913 	else
4914 		messagePtr->sequence_length=sequence_length>>8;
4915 	if(tweening_time==-1)
4916 		messagePtr->tweening_time  =-1  ;
4917 	else
4918 		messagePtr->tweening_time  =tweening_time>>8  ;
4919 
4920 	/* fill out guid */
4921 	{
4922 		int guid = *((int *)(&(sbPtr->SBname[4])));
4923 //		LOCALASSERT((guid >= -NET_MAXOBJECTID)&&(guid <= NET_MAXOBJECTID));
4924 		messagePtr->Guid = guid;
4925 	}
4926 
4927 }
4928 
AddNetMsg_AlienAIKilled(STRATEGYBLOCK * sbPtr,int death_code,int death_time,int GibbFactor,DAMAGE_PROFILE * damage)4929 void AddNetMsg_AlienAIKilled(STRATEGYBLOCK *sbPtr,int death_code,int death_time, int GibbFactor,DAMAGE_PROFILE* damage)
4930 {
4931 	NETMESSAGEHEADER *headerPtr;
4932 	NETMESSAGE_ALIENAIKILLED *messagePtr;
4933 	int headerSize = sizeof(NETMESSAGEHEADER);
4934 	int messageSize = sizeof(NETMESSAGE_ALIENAIKILLED);
4935 
4936 	ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr;
4937 
4938 	//don't do this if we aren't playing (possibly on end game screen)
4939 	if(netGameData.myGameState != NGS_Playing) return;
4940 
4941 	/* check there's enough room in the send buffer */
4942 	{
4943 		int numBytesReqd = headerSize + messageSize;
4944 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
4945 		if(numBytesReqd > numBytesLeft)
4946 		{
4947 			LOCALASSERT(1==0);
4948 			/* don't add it */
4949 			return;
4950 		}
4951 	}
4952 
4953 	/* set up pointers to header and message structures */
4954 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
4955 	endSendBuffer += headerSize;
4956 	messagePtr = (NETMESSAGE_ALIENAIKILLED *)endSendBuffer;
4957 	endSendBuffer += messageSize;
4958 
4959 	/* fill out the header */
4960 	headerPtr->type = (unsigned char)NetMT_AlienAIKilled;
4961 
4962 	/* fill out anim sequence */
4963 
4964 	messagePtr->death_code=death_code;
4965 	messagePtr->death_time=death_time;
4966 	messagePtr->GibbFactor=GibbFactor;
4967 
4968 	messagePtr->killerId=myNetworkKillerId;
4969 
4970 
4971 	{
4972 		int killerIndex=PlayerIdInPlayerList(messagePtr->killerId);
4973 		if(killerIndex!=NET_IDNOTINPLAYERLIST)
4974 		{
4975 			netGameData.playerData[killerIndex].aliensKilled[alienStatus->Type]++;
4976 			messagePtr->killCount=netGameData.playerData[killerIndex].aliensKilled[alienStatus->Type];
4977 
4978 			//record ai's death for purposes of adjusting difficulty.
4979 			//(assuming that optionis being used)
4980 			GeneratorBalance_NoteAIDeath();
4981 		}
4982 		else
4983 		{
4984 			/*
4985 			the player doing the damage has either left the game , or never existed.
4986 			call it suicide then.
4987 			(Could also be 'neutral' damage - flame jets)
4988 			*/
4989 			messagePtr->killerId=0;
4990 			messagePtr->killCount=0;
4991 		}
4992 
4993 	}
4994 
4995 	/* fill out guid */
4996 	{
4997 		int guid = *((int *)(&(sbPtr->SBname[4])));
4998 //		LOCALASSERT((guid >= -NET_MAXOBJECTID)&&(guid <= NET_MAXOBJECTID));
4999 		messagePtr->Guid = guid;
5000 	}
5001 
5002 	messagePtr->AlienType=alienStatus->Type;
5003 
5004 	//find the icon for the weapon used
5005 	messagePtr->weaponIcon = GetWeaponIconFromDamage(damage);
5006 
5007 
5008 	Inform_AiHasDied(messagePtr->killerId,messagePtr->AlienType,messagePtr->weaponIcon);
5009 
5010 }
5011 
AddNetMsg_FarAlienPosition(STRATEGYBLOCK * sbPtr,int targetModuleIndex,int index,BOOL indexIsModuleIndex)5012 void AddNetMsg_FarAlienPosition(STRATEGYBLOCK* sbPtr,int targetModuleIndex,int index,BOOL indexIsModuleIndex)
5013 {
5014 	NETMESSAGEHEADER *headerPtr;
5015 	NETMESSAGE_FARALIENPOSITION *messagePtr;
5016 	int headerSize = sizeof(NETMESSAGEHEADER);
5017 	int messageSize = sizeof(NETMESSAGE_FARALIENPOSITION);
5018 
5019 	ALIEN_STATUS_BLOCK *alienStatusPtr=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
5020 
5021 	/* check there's enough room in the send buffer */
5022 	{
5023 		int numBytesReqd = headerSize + messageSize;
5024 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
5025 		if(numBytesReqd > numBytesLeft)
5026 		{
5027 			LOCALASSERT(1==0);
5028 			/* don't add it */
5029 			return;
5030 		}
5031 	}
5032 
5033 	/* set up pointers to header and message structures */
5034 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
5035 	endSendBuffer += headerSize;
5036 	messagePtr = (NETMESSAGE_FARALIENPOSITION *)endSendBuffer;
5037 	endSendBuffer += messageSize;
5038 
5039 	/* fill out the header */
5040 	headerPtr->type = (unsigned char)NetMT_FarAlienPosition;
5041 
5042 	/* fill out indeces */
5043     messagePtr->targetModuleIndex = targetModuleIndex;
5044 	messagePtr->index = index;
5045 	messagePtr->indexIsModuleIndex = indexIsModuleIndex;
5046 
5047 	messagePtr->alienType =	alienStatusPtr->Type;
5048 
5049 	/* fill out guid */
5050 	{
5051 		int guid = *((int *)(&(sbPtr->SBname[4])));
5052 		messagePtr->Guid = guid;
5053 	}
5054 }
5055 
AddNetMsg_GhostHierarchyDamaged(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple,int sectionID,VECTORCH * incoming)5056 void AddNetMsg_GhostHierarchyDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int sectionID,VECTORCH* incoming)
5057 {
5058 	NETMESSAGEHEADER *headerPtr;
5059 	NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER *messageHeader=0;
5060 	NETMESSAGE_DAMAGE_PROFILE *messageProfile=0;
5061 	NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0;
5062 	NETMESSAGE_DAMAGE_SECTION *messageSection=0;
5063 	NETMESSAGE_DAMAGE_DIRECTION *messageDirection=0;
5064 
5065 	int headerSize = sizeof(NETMESSAGEHEADER);
5066 	int maxMessageSize = sizeof(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER)+
5067 					  sizeof(NETMESSAGE_DAMAGE_PROFILE)+
5068 					  sizeof(NETMESSAGE_DAMAGE_MULTIPLE)+
5069 					  sizeof(NETMESSAGE_DAMAGE_SECTION)+
5070 					  sizeof(NETMESSAGE_DAMAGE_DIRECTION);
5071 
5072 	/* check there's enough room in the send buffer */
5073 	{
5074 		int numBytesReqd = headerSize + maxMessageSize;
5075 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
5076 		if(numBytesReqd > numBytesLeft)
5077 		{
5078 			LOCALASSERT(1==0);
5079 			/* don't add it */
5080 			return;
5081 		}
5082 	}
5083 
5084 	/* set up pointers to header and message structures */
5085 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
5086 	endSendBuffer += headerSize;
5087 	/* fill out the header */
5088 	headerPtr->type = (unsigned char)NetMT_GhostHierarchyDamaged;
5089 
5090 
5091 /*--------------------**
5092 ** 	set up the header **
5093 **--------------------*/
5094 	messageHeader = (NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER *)endSendBuffer;
5095 	endSendBuffer += sizeof(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER);
5096 
5097 	/* fill out guid */
5098 	{
5099 		int guid = *((int *)(&(sbPtr->SBname[4])));
5100 		messageHeader->Guid = guid;
5101 	}
5102 	messageHeader->ammo_id=damage->Id;
5103 
5104 /*-----------------**
5105 ** 	damage profile **
5106 **-----------------*/
5107 	messageHeader->damageProfile=1;
5108 	if(damage->Id>AMMO_NONE && damage->Id<MAX_NO_OF_AMMO_TEMPLATES)
5109 	{
5110 		if(AreDamageProfilesEqual(damage,&TemplateAmmo[damage->Id].MaxDamage[AvP.Difficulty]))
5111 		{
5112 			messageHeader->damageProfile=0;
5113 		}
5114 	}
5115 	if(messageHeader->damageProfile)
5116 	{
5117 		messageProfile = (NETMESSAGE_DAMAGE_PROFILE *)endSendBuffer;
5118 		endSendBuffer += sizeof(NETMESSAGE_DAMAGE_PROFILE);
5119 
5120 		messageProfile->Impact = damage->Impact;
5121 		messageProfile->Cutting = damage->Cutting;
5122 		messageProfile->Penetrative = damage->Penetrative;
5123 		messageProfile->Fire = damage->Fire;
5124 		messageProfile->Electrical = damage->Electrical;
5125 		messageProfile->Acid = damage->Acid;
5126 
5127 		messageProfile->ExplosivePower=damage->ExplosivePower;
5128 		messageProfile->Slicing=damage->Slicing;
5129 		messageProfile->ProduceBlood=damage->ProduceBlood;
5130 		messageProfile->ForceBoom=damage->ForceBoom;
5131 
5132 		messageProfile->BlowUpSections=damage->BlowUpSections;
5133 		messageProfile->Special=damage->Special;
5134 		messageProfile->MakeExitWounds=damage->MakeExitWounds;
5135 
5136 	}
5137 /*-----------------**
5138 ** damage multiple **
5139 **-----------------*/
5140 	if(multiple!=ONE_FIXED)
5141 	{
5142 		messageHeader->multiple=1;
5143 		messageMultiple = (NETMESSAGE_DAMAGE_MULTIPLE *)endSendBuffer;
5144 		endSendBuffer += sizeof(NETMESSAGE_DAMAGE_MULTIPLE);
5145 
5146 		messageMultiple->multiple=multiple;
5147 
5148 	}
5149 	else
5150 	{
5151 		messageHeader->multiple=0;
5152 	}
5153 
5154 /*------------**
5155 ** section id **
5156 **------------*/
5157 	if(sectionID!=-1)
5158 	{
5159 		messageHeader->sectionID=1;
5160 		messageSection = (NETMESSAGE_DAMAGE_SECTION *)endSendBuffer;
5161 		endSendBuffer += sizeof(NETMESSAGE_DAMAGE_SECTION);
5162 
5163 		messageSection->SectionID = (short)sectionID;
5164 	}
5165 	else
5166 	{
5167 		messageHeader->sectionID=0;
5168 	}
5169 
5170 /*-------------------**
5171 ** direction		 **
5172 **-------------------*/
5173 
5174 	if(incoming && sbPtr->DynPtr)
5175 	{
5176 		VECTORCH direction=*incoming;
5177 
5178 		messageHeader->direction=1;
5179 		messageDirection = (NETMESSAGE_DAMAGE_DIRECTION *)endSendBuffer;
5180 		endSendBuffer += sizeof(NETMESSAGE_DAMAGE_DIRECTION);
5181 
5182 		//need to rotate the vector into world space
5183 		RotateVector(&direction,&sbPtr->DynPtr->OrientMat);
5184 
5185 		//compress vector
5186 		messageDirection->direction_x=direction.vx>>7;
5187 		messageDirection->direction_y=direction.vy>>7;
5188 		messageDirection->direction_z=direction.vz>>7;
5189 	}
5190 	else
5191 	{
5192 		messageHeader->direction=0;
5193 	}
5194 }
5195 
5196 
AddNetMsg_Gibbing(STRATEGYBLOCK * sbPtr,int gibbFactor,int seed)5197 void AddNetMsg_Gibbing(STRATEGYBLOCK *sbPtr,int gibbFactor,int seed) {
5198 
5199 	NETMESSAGEHEADER *headerPtr;
5200 	NETMESSAGE_GIBBING *messagePtr;
5201 	int headerSize = sizeof(NETMESSAGEHEADER);
5202 	int messageSize = sizeof(NETMESSAGE_GIBBING);
5203 
5204 	/* check there's enough room in the send buffer */
5205 	{
5206 		int numBytesReqd = headerSize + messageSize;
5207 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
5208 		if(numBytesReqd > numBytesLeft)
5209 		{
5210 			LOCALASSERT(1==0);
5211 			/* don't add it */
5212 			return;
5213 		}
5214 	}
5215 
5216 	/* set up pointers to header and message structures */
5217 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
5218 	endSendBuffer += headerSize;
5219 	messagePtr = (NETMESSAGE_GIBBING *)endSendBuffer;
5220 	endSendBuffer += messageSize;
5221 
5222 	/* fill out the header */
5223 	headerPtr->type = (unsigned char)NetMT_Gibbing;
5224 
5225 	messagePtr->gibbFactor=gibbFactor;
5226 	messagePtr->seed=seed;
5227 
5228 	/* fill out guid */
5229 	{
5230 		int guid = *((int *)(&(sbPtr->SBname[4])));
5231 //		LOCALASSERT((guid >= -NET_MAXOBJECTID)&&(guid <= NET_MAXOBJECTID));
5232 		messagePtr->Guid = guid;
5233 	}
5234 }
5235 
5236 
AddNetMsg_SpotAlienSound(int soundCategory,int alienType,int pitch,VECTORCH * position)5237 void AddNetMsg_SpotAlienSound(int soundCategory,int alienType,int pitch,VECTORCH *position) {
5238 
5239 	NETMESSAGEHEADER *headerPtr;
5240 	NETMESSAGE_SPOTALIENSOUND *messagePtr;
5241 	int headerSize = sizeof(NETMESSAGEHEADER);
5242 	int messageSize = sizeof(NETMESSAGE_SPOTALIENSOUND);
5243 
5244 	/* check there's enough room in the send buffer */
5245 	{
5246 		int numBytesReqd = headerSize + messageSize;
5247 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
5248 		if(numBytesReqd > numBytesLeft)
5249 		{
5250 			LOCALASSERT(1==0);
5251 			/* don't add it */
5252 			return;
5253 		}
5254 	}
5255 
5256 	/* set up pointers to header and message structures */
5257 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
5258 	endSendBuffer += headerSize;
5259 	messagePtr = (NETMESSAGE_SPOTALIENSOUND *)endSendBuffer;
5260 	endSendBuffer += messageSize;
5261 
5262 	/* fill out the header */
5263 	headerPtr->type = (unsigned char)NetMT_SpotAlienSound;
5264 
5265 	/* Fill in message. */
5266 	messagePtr->soundCategory=(unsigned char)soundCategory;
5267 	messagePtr->pitch=pitch;
5268 	messagePtr->alienType=(unsigned char)alienType;
5269 
5270 	messagePtr->vx=position->vx;
5271 	messagePtr->vy=position->vy;
5272 	messagePtr->vz=position->vz;
5273 
5274 }
5275 //for messages that just require a player id
AddNetMsg_PlayerID(DPID playerID,unsigned char message)5276 void AddNetMsg_PlayerID(DPID playerID,unsigned char message)
5277 {
5278 	NETMESSAGEHEADER *headerPtr;
5279 	NETMESSAGE_PLAYERID *messagePtr;
5280 	int headerSize = sizeof(NETMESSAGEHEADER);
5281 	int messageSize = sizeof(NETMESSAGE_PLAYERID);
5282 
5283 	/* check there's enough room in the send buffer */
5284 	{
5285 		int numBytesReqd = headerSize + messageSize;
5286 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
5287 		if(numBytesReqd > numBytesLeft)
5288 		{
5289 			LOCALASSERT(1==0);
5290 			/* don't add it */
5291 			return;
5292 		}
5293 	}
5294 
5295 	/* set up pointers to header and message structures */
5296 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
5297 	endSendBuffer += headerSize;
5298 	messagePtr = (NETMESSAGE_PLAYERID *)endSendBuffer;
5299 	endSendBuffer += messageSize;
5300 
5301 	/* fill out the header */
5302 	headerPtr->type = message;
5303 
5304 	/* Fill in message. */
5305 	messagePtr->playerID=playerID;
5306 
5307 }
5308 
AddNetMsg_LastManStanding_RestartTimer(char time)5309 void AddNetMsg_LastManStanding_RestartTimer(char time)
5310 {
5311 	NETMESSAGEHEADER *headerPtr;
5312 	NETMESSAGE_LMS_RESTARTTIMER *messagePtr;
5313 	int headerSize = sizeof(NETMESSAGEHEADER);
5314 	int messageSize = sizeof(NETMESSAGE_LMS_RESTARTTIMER);
5315 
5316 	/* check there's enough room in the send buffer */
5317 	{
5318 		int numBytesReqd = headerSize + messageSize;
5319 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
5320 		if(numBytesReqd > numBytesLeft)
5321 		{
5322 			LOCALASSERT(1==0);
5323 			/* don't add it */
5324 			return;
5325 		}
5326 	}
5327 
5328 	/* set up pointers to header and message structures */
5329 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
5330 	endSendBuffer += headerSize;
5331 	messagePtr = (NETMESSAGE_LMS_RESTARTTIMER *)endSendBuffer;
5332 	endSendBuffer += messageSize;
5333 
5334 	/* fill out the header */
5335 	headerPtr->type = (unsigned char)NetMT_LastManStanding_RestartCountDown;
5336 
5337 	/* Fill in message. */
5338 	messagePtr->timer=time;
5339 }
5340 
AddNetMsg_LastManStanding_Restart(DPID alienID,int seed)5341 void AddNetMsg_LastManStanding_Restart(DPID alienID,int seed)
5342 {
5343 	NETMESSAGEHEADER *headerPtr;
5344 	NETMESSAGE_LMS_RESTART *messagePtr;
5345 	int headerSize = sizeof(NETMESSAGEHEADER);
5346 	int messageSize = sizeof(NETMESSAGE_LMS_RESTART);
5347 
5348 	/* check there's enough room in the send buffer */
5349 	{
5350 		int numBytesReqd = headerSize + messageSize;
5351 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
5352 		if(numBytesReqd > numBytesLeft)
5353 		{
5354 			LOCALASSERT(1==0);
5355 			/* don't add it */
5356 			return;
5357 		}
5358 	}
5359 
5360 	/* set up pointers to header and message structures */
5361 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
5362 	endSendBuffer += headerSize;
5363 	messagePtr = (NETMESSAGE_LMS_RESTART *)endSendBuffer;
5364 	endSendBuffer += messageSize;
5365 
5366 	/* fill out the header */
5367 	headerPtr->type = NetMT_LastManStanding_Restart;
5368 
5369 	/* Fill in message. */
5370 	messagePtr->playerID=alienID;
5371 	messagePtr->seed=seed;
5372 
5373 }
5374 
5375 
AddNetMsg_RespawnPickups(void)5376 void AddNetMsg_RespawnPickups(void)
5377 {
5378 	NETMESSAGEHEADER *headerPtr;
5379 	int headerSize = sizeof(NETMESSAGEHEADER);
5380 
5381 	/* only send this if we are playing or on the end game screen*/
5382 	if(netGameData.myGameState!=NGS_Playing && netGameData.myGameState!=NGS_EndGameScreen) return;
5383 
5384 	/* check there's enough room in the send buffer */
5385 	{
5386 		int numBytesReqd = headerSize;
5387 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
5388 		if(numBytesReqd > numBytesLeft)
5389 		{
5390 			LOCALASSERT(1==0);
5391 			/* don't add it */
5392 			return;
5393 		}
5394 	}
5395 
5396 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
5397 	endSendBuffer += headerSize;
5398 
5399 	/* fill out the header */
5400 	headerPtr->type = (unsigned char)NetMT_RespawnPickups;
5401 }
5402 
AddNetMsg_SpotOtherSound(enum soundindex SoundIndex,VECTORCH * position,int explosion)5403 void AddNetMsg_SpotOtherSound(enum soundindex SoundIndex,VECTORCH *position,int explosion) {
5404 
5405 	NETMESSAGEHEADER *headerPtr;
5406 	NETMESSAGE_SPOTOTHERSOUND *messagePtr;
5407 	int headerSize = sizeof(NETMESSAGEHEADER);
5408 	int messageSize = sizeof(NETMESSAGE_SPOTOTHERSOUND);
5409 
5410 	/* check there's enough room in the send buffer */
5411 	{
5412 		int numBytesReqd = headerSize + messageSize;
5413 		int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0]));
5414 		if(numBytesReqd > numBytesLeft)
5415 		{
5416 			LOCALASSERT(1==0);
5417 			/* don't add it */
5418 			return;
5419 		}
5420 	}
5421 
5422 	/* set up pointers to header and message structures */
5423 	headerPtr = (NETMESSAGEHEADER *)endSendBuffer;
5424 	endSendBuffer += headerSize;
5425 	messagePtr = (NETMESSAGE_SPOTOTHERSOUND *)endSendBuffer;
5426 	endSendBuffer += messageSize;
5427 
5428 	/* fill out the header */
5429 	headerPtr->type = (unsigned char)NetMT_SpotOtherSound;
5430 
5431 	/* Fill in message. */
5432 	messagePtr->SoundIndex=SoundIndex;
5433 	if (explosion) {
5434 		messagePtr->explosion=1;
5435 	} else {
5436 		messagePtr->explosion=0;
5437    }
5438 
5439 	messagePtr->vx=position->vx;
5440 	messagePtr->vy=position->vy;
5441 	messagePtr->vz=position->vz;
5442 
5443 }
5444 
5445 
5446 
5447 /*----------------------------------------------------------------------
5448   Functions for processing each message type, as retrieved from the read
5449   message buffer...
5450   ----------------------------------------------------------------------*/
ProcessNetMsg_GameDescription(NETMESSAGE_GAMEDESCRIPTION * messagePtr)5451 static void ProcessNetMsg_GameDescription(NETMESSAGE_GAMEDESCRIPTION *messagePtr)
5452 {
5453 	/* should only get this if we're not the host, and we're in start-up state */
5454 	if(AvP.Network!=I_Peer)
5455 	{
5456 		//Vaguely possible that a host could receive a message that is only intended for peers
5457 		//if this computer has only just become the host.
5458 		LOCALASSERT(AvP.Network==I_Host);
5459 		return;
5460 	}
5461 
5462 	//if(netGameData.myGameState!=NGS_Joining) return;
5463 
5464 	/* fill out the game description player list with the new player id's */
5465 	{
5466 		int i;
5467 		for(i=0;i<NET_MAXPLAYERS;i++)
5468 		{
5469 			int playerChanged = 0;
5470 
5471 			if ( (netGameData.playerData[i].playerId != messagePtr->players[i].playerId)
5472 			   ||(netGameData.playerData[i].startFlag != messagePtr->players[i].startFlag) )
5473 				playerChanged=1;
5474 
5475 			if (netGameData.myGameState==NGS_Playing && playerChanged)
5476 			{
5477 				if (messagePtr->players[i].playerId==0)
5478 				{
5479 					Inform_PlayerHasLeft(netGameData.playerData[i].playerId);
5480 				}
5481 				else if (messagePtr->players[i].startFlag)
5482 				{
5483 					Inform_PlayerHasJoined(messagePtr->players[i].playerId);
5484 				}
5485 				else
5486 				{
5487 					Inform_PlayerHasConnected(messagePtr->players[i].playerId);
5488 				}
5489 			}
5490 
5491 			if(netGameData.playerData[i].playerId != messagePtr->players[i].playerId)
5492 			{
5493 				if(messagePtr->players[i].playerId)
5494 				{
5495 					DWORD size=0;
5496 					char* data;
5497 					HRESULT hr;
5498 					//need to find out this player's name
5499 					//first find the size of buffer required
5500   					hr=IDirectPlayX_GetPlayerName(glpDP,messagePtr->players[i].playerId,0,&size);
5501 					if(hr==DP_OK || hr==DPERR_BUFFERTOOSMALL)
5502 					{
5503 						//allocate buffer to recive the name
5504 						data=AllocateMem(size);
5505 						*data=0;
5506 						hr=IDirectPlayX_GetPlayerName(glpDP,messagePtr->players[i].playerId,data,&size);
5507 
5508 						if(hr==DP_OK)
5509 						{
5510 							strncpy(netGameData.playerData[i].name,((DPNAME*)data)->lpszShortNameA,NET_PLAYERNAMELENGTH-1);
5511 							netGameData.playerData[i].name[NET_PLAYERNAMELENGTH-1]='\0';
5512 
5513 						}
5514 						DeallocateMem(data);
5515 					}
5516 
5517 				}
5518 				else
5519 				{
5520 					netGameData.playerData[i].name[0]='\0';
5521 				}
5522 			}
5523 
5524 			netGameData.playerData[i].playerId = messagePtr->players[i].playerId;
5525 			netGameData.playerData[i].characterType = (NETGAME_CHARACTERTYPE)messagePtr->players[i].characterType;
5526 			netGameData.playerData[i].characterSubType = (NETGAME_CHARACTERTYPE)messagePtr->players[i].characterSubType;
5527 			netGameData.playerData[i].startFlag = messagePtr->players[i].startFlag;
5528 		}
5529 		netGameData.gameType = (NETGAME_TYPE)messagePtr->gameType;
5530 		//level number got from the session description instead
5531 		//netGameData.levelNumber = messagePtr->levelNumber;
5532 		netGameData.scoreLimit = messagePtr->scoreLimit;
5533 		netGameData.timeLimit = messagePtr->timeLimit;
5534 		netGameData.invulnerableTime = messagePtr->invulnerableTime;
5535 
5536 		for(i=0;i<3;i++)
5537 		{
5538 			netGameData.characterKillValues[i]=messagePtr->characterKillValues[i];
5539 			netGameData.aiKillValues[i]=messagePtr->aiKillValues[i];
5540 		}
5541 		netGameData.baseKillValue=messagePtr->baseKillValue;
5542 		netGameData.useDynamicScoring=messagePtr->useDynamicScoring;
5543 		netGameData.useCharacterKillValues=messagePtr->useCharacterKillValues;
5544 
5545 		netGameData.sendDecals=messagePtr->sendDecals;
5546 
5547 		netGameData.gameSpeed=messagePtr->gameSpeed;
5548 
5549 		netGameData.disableFriendlyFire=messagePtr->disableFriendlyFire;
5550 		netGameData.fallingDamage=messagePtr->fallingDamage;
5551 		netGameData.pistolInfiniteAmmo=messagePtr->pistolInfiniteAmmo;
5552 		netGameData.specialistPistols=messagePtr->specialistPistols;
5553 
5554 		if(netGameData.needGameDescription)
5555 		{
5556 			/*We were waiting for the game description , best make sure that our player id appears
5557 			int the player list*/
5558 			if(PlayerIdInPlayerList(AVPDPNetID)!=NET_IDNOTINPLAYERLIST)
5559 			{
5560 				/*we now have the game description, so we can stop waiting if we were
5561 				trying to join*/
5562 				netGameData.needGameDescription=0;
5563 				/*
5564 				make sure our time scale is set correctly
5565 				(Only set it the once , so that it can be overridden for debugging purposes)
5566 				*/
5567 				switch(netGameData.gameSpeed)
5568 				{
5569 					case NETGAMESPEED_70PERCENT :
5570 						TimeScale=(ONE_FIXED*70)/100;
5571 						break;
5572 
5573 					case NETGAMESPEED_80PERCENT :
5574 						TimeScale=(ONE_FIXED*80)/100;
5575 						break;
5576 
5577 					case NETGAMESPEED_90PERCENT :
5578 						TimeScale=(ONE_FIXED*90)/100;
5579 						break;
5580 
5581 					case NETGAMESPEED_100PERCENT :
5582 						TimeScale=(ONE_FIXED*100)/100;
5583 						break;
5584 
5585 				}
5586 
5587 			}
5588 		}
5589 
5590 		netGameData.allowSmartgun=messagePtr->allowSmartgun;
5591 		netGameData.allowFlamer=messagePtr->allowFlamer;
5592 		netGameData.allowSadar=messagePtr->allowSadar;
5593 		netGameData.allowGrenadeLauncher=messagePtr->allowGrenadeLauncher;
5594 		netGameData.allowMinigun=messagePtr->allowMinigun;
5595 		netGameData.allowDisc=messagePtr->allowDisc;
5596 		netGameData.allowPistol=messagePtr->allowPistol;
5597 		netGameData.allowPlasmaCaster=messagePtr->allowPlasmaCaster;
5598 		netGameData.allowSpeargun=messagePtr->allowSpeargun;
5599 		netGameData.allowMedicomp=messagePtr->allowMedicomp;
5600 		netGameData.allowSmartDisc=messagePtr->allowSmartDisc;
5601 		netGameData.allowPistols=messagePtr->allowPistols;
5602 
5603 		netGameData.maxPredator=messagePtr->maxPredator;
5604 		netGameData.maxAlien=messagePtr->maxAlien;
5605 		netGameData.maxMarine=messagePtr->maxMarine;
5606 
5607 		netGameData.maxMarineGeneral=messagePtr->maxMarineGeneral;
5608 		netGameData.maxMarinePulseRifle=messagePtr->maxMarinePulseRifle;
5609 		netGameData.maxMarineSmartgun=messagePtr->maxMarineSmartgun;
5610 		netGameData.maxMarineFlamer=messagePtr->maxMarineFlamer;
5611 		netGameData.maxMarineSadar=messagePtr->maxMarineSadar;
5612 		netGameData.maxMarineGrenade=messagePtr->maxMarineGrenade;
5613 		netGameData.maxMarineMinigun=messagePtr->maxMarineMinigun;
5614 		netGameData.maxMarineSmartDisc=messagePtr->maxMarineSmartDisc;
5615 		netGameData.maxMarinePistols=messagePtr->maxMarinePistols;
5616 
5617 		netGameData.useSharedLives=messagePtr->useSharedLives;
5618 		netGameData.maxLives=messagePtr->maxLives;
5619 		netGameData.numDeaths[0]=messagePtr->numDeaths[0];
5620 		netGameData.numDeaths[1]=messagePtr->numDeaths[1];
5621 		netGameData.numDeaths[2]=messagePtr->numDeaths[2];
5622 
5623 
5624 		netGameData.timeForRespawn=messagePtr->timeForRespawn;
5625 		netGameData.pointsForRespawn=messagePtr->pointsForRespawn;
5626 
5627 		{
5628 			//check to if the host's elapsed time is
5629 			//significantly different from our elapsed time value
5630 			int receivedTime=messagePtr->GameTimeElapsed;
5631 			int diff;
5632 			receivedTime<<=16;
5633 
5634 			diff=netGameData.GameTimeElapsed-receivedTime;
5635 
5636 			if(diff<-ONE_FIXED || diff>ONE_FIXED || netGameData.myGameState==NGS_EndGameScreen)
5637 			{
5638 				//best take the host's value
5639 				netGameData.GameTimeElapsed=receivedTime;
5640 			}
5641 
5642 		}
5643 
5644 
5645 	}
5646 
5647 	if(messagePtr->endGame)
5648 	{
5649 		if(netGameData.myGameState==NGS_Playing)
5650 		{
5651 			//we must have missed the end game message
5652 			netGameData.myGameState=NGS_EndGameScreen;
5653 		}
5654 	}
5655 	else
5656 	{
5657 		if(netGameData.myGameState==NGS_EndGameScreen)
5658 		{
5659 			//must have missed message to restart game
5660 			//therefore probably better restart now
5661 			RestartNetworkGame(0);
5662 
5663 		}
5664 	}
5665 }
5666 
ProcessNetMsg_PlayerDescription(NETMESSAGE_PLAYERDESCRIPTION * messagePtr,DPID senderId)5667 static void ProcessNetMsg_PlayerDescription(NETMESSAGE_PLAYERDESCRIPTION *messagePtr, DPID senderId)
5668 {
5669 	/* only act on this if we're the host and in start-up */
5670 	if(AvP.Network!=I_Host) return;
5671 
5672 	/* find the player and fill out their details from the message */
5673 	{
5674 		int id = PlayerIdInPlayerList(senderId);
5675 		if(id==NET_IDNOTINPLAYERLIST)
5676 		{
5677 			/* player does not seem to be in the player list, so ignore it */
5678 			return;
5679 		}
5680 		netGameData.playerData[id].characterType = (NETGAME_CHARACTERTYPE)messagePtr->characterType;
5681 		netGameData.playerData[id].characterSubType = (NETGAME_SPECIALISTCHARACTERTYPE)messagePtr->characterSubType;
5682 
5683 		if (netGameData.myGameState==NGS_Playing)
5684 		{
5685 			if(messagePtr->startFlag && (netGameData.playerData[id].startFlag != messagePtr->startFlag) )
5686 				Inform_PlayerHasJoined(netGameData.playerData[id].playerId);
5687 		}
5688 		netGameData.playerData[id].startFlag = messagePtr->startFlag;
5689 
5690 	}
5691 }
5692 
ProcessNetMsg_StartGame(void)5693 static void ProcessNetMsg_StartGame(void)
5694 {
5695 	/* only act on this if we're a peer and in start-up */
5696 	return;
5697 	if(AvP.Network!=I_Peer) return;
5698 	if(netGameData.myGameState!=NGS_Joining) return;
5699 
5700 	/* switch our game state... if we are in the player list, switch to start, otherwise
5701 	switch to error */
5702 	if(PlayerIdInPlayerList(AVPDPNetID)!=NET_IDNOTINPLAYERLIST)
5703 		netGameData.myGameState=NGS_Playing;
5704 	else
5705 	{
5706 		TransmitPlayerLeavingNetMsg();
5707 		netGameData.myGameState=NGS_Error_HostLost;
5708 		AvP.MainLoopRunning = 0;
5709 	}
5710 }
5711 
ProcessNetMsg_PlayerState(NETMESSAGE_PLAYERSTATE * messagePtr,DPID senderId)5712 static void ProcessNetMsg_PlayerState(NETMESSAGE_PLAYERSTATE *messagePtr, DPID senderId)
5713 {
5714 	VECTORCH position;
5715 	int playerIndex;
5716 	STRATEGYBLOCK *sbPtr;
5717 #if 0
5718 	/* state check: if we're in startup and we've received this message from the host, we
5719 	should go into an error state: */
5720 	if((netGameData.myGameState==NGS_Joining)&&(messagePtr->IAmHost))
5721 	{
5722 		TransmitPlayerLeavingNetMsg();
5723 		netGameData.myGameState=NGS_Error_HostLost;
5724 		AvP.MainLoopRunning = 0;
5725 	}
5726 #endif
5727 
5728 
5729 	position.vx = messagePtr->xPos;
5730 	position.vy = messagePtr->yPos;
5731 	position.vz = messagePtr->zPos;
5732 	{
5733 		//recored the players position , even if we aren't currntly playing
5734 		int playerIndex=PlayerIdInPlayerList(senderId);
5735 		if(playerIndex!=NET_IDNOTINPLAYERLIST)
5736 		{
5737 			netGameData.playerData[playerIndex].lastKnownPosition=position;
5738 		}
5739 	}
5740 
5741 	/* if we're not playing, ignore it */
5742 	if(netGameData.myGameState!=NGS_Playing) return;
5743 
5744 	playerIndex = PlayerIdInPlayerList(senderId);
5745 
5746 	/* KJL 14:47:22 06/04/98 - we don't seem to know about this person yet... ignore them */
5747 	if (playerIndex==NET_IDNOTINPLAYERLIST) return;
5748 
5749 	sbPtr = FindGhost(senderId, GHOST_PLAYEROBJECTID);
5750 
5751 	//record whether the player is in the land of the living
5752 	netGameData.playerData[playerIndex].playerAlive=messagePtr->IAmAlive;
5753 	netGameData.playerData[playerIndex].playerHasLives=messagePtr->IHaveLifeLeft;
5754 
5755 	//check the player type
5756 	//the value in the netgamedata should be set to next character type
5757 	netGameData.playerData[playerIndex].characterType=messagePtr->nextCharacterType;
5758 	netGameData.playerData[playerIndex].characterSubType=messagePtr->characterSubType;
5759 	if(sbPtr)
5760 	{
5761 		NETGHOSTDATABLOCK *ghostData;
5762 		ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
5763 		GLOBALASSERT(ghostData);
5764 
5765 		//here we need to use the current character type
5766 		switch(messagePtr->characterType)
5767 		{
5768 			case NGCT_Marine :
5769 				if(ghostData->type!=I_BehaviourMarinePlayer)
5770 				{
5771 					sbPtr->SBflags.please_destroy_me=1;
5772 					return;
5773 				}
5774 				break;
5775 			case NGCT_Predator :
5776 				if(ghostData->type!=I_BehaviourPredatorPlayer)
5777 				{
5778 					sbPtr->SBflags.please_destroy_me=1;
5779 					return;
5780 				}
5781 				break;
5782 			case NGCT_Alien :
5783 				if(ghostData->type!=I_BehaviourAlienPlayer)
5784 				{
5785 					sbPtr->SBflags.please_destroy_me=1;
5786 					return;
5787 				}
5788 				break;
5789 		}
5790 
5791 	}
5792 
5793 	if(!MultiplayerObservedPlayer)
5794 	{
5795 		if(sbPtr && sbPtr->SBdptr)
5796 		{
5797 			//make sure the model is visivle
5798 			sbPtr->SBdptr->ObFlags&=~ObFlag_NotVis;
5799 		}
5800 	}
5801 
5802 	{
5803 		EULER orientation;
5804 		int sequence;
5805 		int weapon;
5806 		int firingPrimary;
5807 		int firingSecondary;
5808 
5809 		orientation.EulerX = (messagePtr->xOrient<<NET_EULERSCALESHIFT);
5810 		orientation.EulerY = (messagePtr->yOrient<<NET_EULERSCALESHIFT);
5811 		orientation.EulerZ = (messagePtr->zOrient<<NET_EULERSCALESHIFT);
5812 		sequence = (int)messagePtr->sequence;
5813 		weapon = (int)messagePtr->currentWeapon;
5814 		firingPrimary = (int)messagePtr->IAmFiringPrimary;
5815 		firingSecondary = (int)messagePtr->IAmFiringSecondary;
5816 
5817 		//ReleasePrintDebuggingText("Primary %d Secondary %d\n",firingPrimary,firingSecondary);
5818 
5819 		if(!sbPtr)
5820 		{
5821 
5822 			/* If we are not a dead alien then we should have a ghost */
5823   //			if(!(((!(messagePtr->IAmAlive)))&&(netGameData.playerData[playerIndex].characterType==NGCT_Alien)))
5824 			if (messagePtr->IAmAlive)
5825 			{
5826 				{
5827 					AVP_BEHAVIOUR_TYPE type;
5828 					if(messagePtr->characterType==NGCT_Marine) type = I_BehaviourMarinePlayer;
5829 					else if(messagePtr->characterType==NGCT_Alien) type = I_BehaviourAlienPlayer;
5830 					else type = I_BehaviourPredatorPlayer;
5831 					sbPtr = CreateNetGhost(senderId,GHOST_PLAYEROBJECTID,&position,&orientation,type,IOT_Non,0);
5832 					if(sbPtr)
5833 					{
5834 						HandleWeaponElevation(sbPtr,(int)messagePtr->Elevation,weapon);
5835 						//don't draw muzzle flash if observing from this player
5836 						if(MultiplayerObservedPlayer!=senderId) {
5837 							HandleGhostGunFlashEffect(sbPtr, messagePtr->IHaveAMuzzleFlash);
5838 						} else {
5839 							HandleGhostGunFlashEffect(sbPtr, 0);
5840 						}
5841 						HandlePlayerGhostWeaponSound(sbPtr,weapon,firingPrimary,firingSecondary);
5842 						MaintainGhostCloakingStatus(sbPtr,(int)messagePtr->CloakingEffectiveness);
5843 						MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire);
5844 					}
5845 				}
5846 
5847 			}
5848 		}
5849 		else
5850 		{
5851 
5852 			if(!(((!(messagePtr->IAmAlive)))&&(netGameData.playerData[playerIndex].characterType==NGCT_Alien)))
5853 			{
5854 				/* We are not a dead alien */
5855 				HandleWeaponElevation(sbPtr,(int)messagePtr->Elevation,weapon);
5856 				UpdateGhost(sbPtr,&position,&orientation,sequence,messagePtr->Special);
5857 				//don't draw muzzle flash if observing from this player
5858 				if(MultiplayerObservedPlayer!=senderId) {
5859 					HandleGhostGunFlashEffect(sbPtr, messagePtr->IHaveAMuzzleFlash);
5860 				} else {
5861 					HandleGhostGunFlashEffect(sbPtr, 0);
5862 				}
5863 				HandlePlayerGhostWeaponSound(sbPtr,weapon,firingPrimary,firingSecondary);
5864 				MaintainGhostCloakingStatus(sbPtr,(int)messagePtr->CloakingEffectiveness);
5865 				MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire);
5866 				/* Now, more disc. */
5867 
5868 				if (messagePtr->IHaveADisk) {
5869 
5870 					NETGHOSTDATABLOCK *ghostData;
5871 					SECTION_DATA *disc;
5872 					/* Find the thrower's ghost, and add his disc...  */
5873 
5874 					ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
5875 					GLOBALASSERT(ghostData);
5876 					GLOBALASSERT(ghostData->type==I_BehaviourPredatorPlayer);
5877 					disc=GetThisSectionData(ghostData->HModelController.section_data,"disk");
5878 					if (disc) {
5879 						disc->flags&=~section_data_notreal;
5880 					}
5881 				}
5882 			}
5883 			else
5884 			{
5885 				/* We are a dead alien with a ghost */
5886 				RemoveGhost(sbPtr);
5887 				return;
5888 			}
5889 		}
5890 
5891 		if(sbPtr && messagePtr->IAmAlive)
5892 		{
5893 			NETGHOSTDATABLOCK *ghostData;
5894 			ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
5895 
5896 			ghostData->invulnerable=messagePtr->IAmInvulnerable;
5897 
5898 			#if EXTRAPOLATION_TEST
5899 			{
5900 				VECTORCH velocity,diff;
5901 				int playerTimer=netGameData.playerData[playerIndex].timer;
5902 
5903 				velocity.vx=messagePtr->velocity_x*100;
5904 				velocity.vy=messagePtr->velocity_y*100;
5905 				velocity.vz=messagePtr->velocity_z*100;
5906 
5907 				diff=ghostData->velocity;
5908 				SubVector(&velocity,&diff);
5909 
5910 				if(Approximate3dMagnitude(&diff)>1000)
5911 				{
5912 					//change in velocity , so reset extrapolation timer
5913 					ghostData->extrapTimer=-ONE_FIXED;
5914 				}
5915 
5916 				ghostData->velocity=velocity;
5917 				ghostData->extrapTimerLast=0;
5918 				if(playerTimer>=ghostData->lastTimeRead)
5919 				{
5920 					ghostData->extrapTimer-=(playerTimer-ghostData->lastTimeRead);
5921 				}
5922 				else
5923 				{
5924 					ghostData->extrapTimer=-ONE_FIXED;
5925 				}
5926 				ghostData->lastTimeRead=playerTimer;
5927 
5928 			}
5929 
5930 
5931 			if(ghostData->type==I_BehaviourAlienPlayer)
5932 			{
5933 				sbPtr->DynPtr->UseStandardGravity=messagePtr->standard_gravity;
5934 				if(!sbPtr->DynPtr->UseStandardGravity)
5935 				{
5936 					if(sbPtr->DynPtr->GravityDirection.vy==ONE_FIXED)
5937 					{
5938 						MATRIXCH mat;
5939 						//alien is crawling , so we need to get an appropriate gravity direction
5940 						CreateEulerMatrix(&orientation,&mat);
5941 						sbPtr->DynPtr->GravityDirection.vx=mat.mat12;
5942 						sbPtr->DynPtr->GravityDirection.vy=mat.mat22;
5943 						sbPtr->DynPtr->GravityDirection.vz=mat.mat32;
5944 					}
5945 
5946 					sbPtr->DynPtr->LinImpulse.vx=0;
5947 					sbPtr->DynPtr->LinImpulse.vy=0;
5948 					sbPtr->DynPtr->LinImpulse.vz=0;
5949 
5950 					sbPtr->DynPtr->ToppleForce=TOPPLE_FORCE_ALIEN;
5951 				}
5952 			}
5953 			#endif
5954 
5955 
5956 			if(messagePtr->scream!=31)
5957 			{
5958 				//this character is screaming
5959 				switch(messagePtr->characterType)
5960 				{
5961 					case NGCT_Marine :
5962 						PlayMarineScream(0,(SOUND_CATERGORY)messagePtr->scream,0,&ghostData->SoundHandle2,&position);
5963 						break;
5964 
5965 					case NGCT_Alien :
5966 						PlayAlienSound(0,(ALIEN_SOUND_CATEGORY)messagePtr->scream,0,&ghostData->SoundHandle2,&position);
5967 						break;
5968 
5969 					case NGCT_Predator :
5970 						if ((PREDATOR_SOUND_CATEGORY)messagePtr->scream==PSC_Medicomp_Special) {
5971 							Sound_Play(SID_PRED_NEWROAR,"de",&position,&ghostData->SoundHandle2);
5972 						} else {
5973 							PlayPredatorSound(0,(PREDATOR_SOUND_CATEGORY)messagePtr->scream,0,&ghostData->SoundHandle2,&position);
5974 						}
5975 						break;
5976 				}
5977 			}
5978 
5979 			/* Landing noise. */
5980 			if (messagePtr->landingNoise) {
5981 				switch(messagePtr->characterType) {
5982 					case NGCT_Marine :
5983 		   				Sound_Play(SID_MARINE_SMALLLANDING,"d",&position);
5984 						break;
5985 					case NGCT_Alien :
5986 						/* No sound for aliens. */
5987 						break;
5988 					case NGCT_Predator :
5989 		   				Sound_Play(SID_PRED_SMALLLANDING,"d",&position);
5990 						break;
5991 				}
5992 			}
5993 
5994 			//are we currently following this player's movements
5995 			if(MultiplayerObservedPlayer)
5996 			{
5997 				if(MultiplayerObservedPlayer==senderId)
5998 				{
5999 					PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
6000 					playerStatusPtr->ViewPanX=messagePtr->Elevation;
6001 					Player->ObStrategyBlock->DynPtr->Position=position;
6002 					Player->ObStrategyBlock->DynPtr->PrevPosition=position;
6003 
6004 					Player->ObStrategyBlock->DynPtr->OrientEuler = orientation;
6005 					CreateEulerMatrix(&Player->ObStrategyBlock->DynPtr->OrientEuler,&Player->ObStrategyBlock->DynPtr->OrientMat);
6006 					TransposeMatrixCH(&Player->ObStrategyBlock->DynPtr->OrientMat);
6007 
6008 					if(messagePtr->IAmCrouched)
6009 					{
6010 						PlayerStatusPtr->ShapeState=PMph_Crouching;
6011 					}
6012 					else
6013 					{
6014 						PlayerStatusPtr->ShapeState=PMph_Standing;
6015 					}
6016 
6017 					//don't draw the player we're observing
6018 					if(sbPtr && sbPtr->SBdptr)
6019 					{
6020 						sbPtr->SBdptr->ObFlags|=ObFlag_NotVis;
6021 					}
6022 				}
6023 			}
6024 		}
6025 	}
6026 }
ProcessNetMsg_PlayerState_Minimal(NETMESSAGE_PLAYERSTATE_MINIMAL * messagePtr,DPID senderId,BOOL orientation)6027 static void ProcessNetMsg_PlayerState_Minimal(NETMESSAGE_PLAYERSTATE_MINIMAL *messagePtr, DPID senderId,BOOL orientation)
6028 {
6029 	int playerIndex;
6030 	STRATEGYBLOCK *sbPtr;
6031 
6032 	/* if we're not playing, ignore it */
6033 	if(netGameData.myGameState!=NGS_Playing) return;
6034 
6035 	playerIndex = PlayerIdInPlayerList(senderId);
6036 
6037 	/* KJL 14:47:22 06/04/98 - we don't seem to know about this person yet... ignore them */
6038 	if (playerIndex==NET_IDNOTINPLAYERLIST) return;
6039 
6040 	sbPtr = FindGhost(senderId, GHOST_PLAYEROBJECTID);
6041 
6042 
6043 	//record whether the player is in the land of the living
6044 	netGameData.playerData[playerIndex].playerAlive=messagePtr->IAmAlive;
6045 	netGameData.playerData[playerIndex].playerHasLives=messagePtr->IHaveLifeLeft;
6046 
6047 	if(!sbPtr)
6048 	{
6049 		//if we don't have a ghost for this player , wait for a full player state message
6050 		return;
6051 	}
6052 
6053 
6054 	if(!MultiplayerObservedPlayer)
6055 	{
6056 		if(sbPtr && sbPtr->SBdptr)
6057 		{
6058 			//make sure the model is visivle
6059 			sbPtr->SBdptr->ObFlags&=~ObFlag_NotVis;
6060 		}
6061 	}
6062 
6063 	{
6064 		int firingPrimary;
6065 		int firingSecondary;
6066 
6067 		firingPrimary = (int)messagePtr->IAmFiringPrimary;
6068 		firingSecondary = (int)messagePtr->IAmFiringSecondary;
6069 
6070 
6071 
6072 		if(!(((!(messagePtr->IAmAlive)))&&(netGameData.playerData[playerIndex].characterType==NGCT_Alien)))
6073 		{
6074 			NETGHOSTDATABLOCK *ghostData;
6075 			ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
6076 			GLOBALASSERT(ghostData);
6077 
6078 			if(orientation)
6079 			{
6080 				NETMESSAGE_PLAYERSTATE_MEDIUM* mediumMessage=(NETMESSAGE_PLAYERSTATE_MEDIUM*) messagePtr;
6081 				EULER orientation;
6082 				orientation.EulerX = (mediumMessage->xOrient<<NET_EULERSCALESHIFT);
6083 				orientation.EulerY = (mediumMessage->yOrient<<NET_EULERSCALESHIFT);
6084 				orientation.EulerZ = (mediumMessage->zOrient<<NET_EULERSCALESHIFT);
6085 
6086 				UpdateGhost(sbPtr,&sbPtr->DynPtr->Position,&orientation,-1,messagePtr->Special);
6087 
6088 			}
6089 
6090 			/* We are not a dead alien */
6091 			HandleWeaponElevation(sbPtr,(int)messagePtr->Elevation,ghostData->CurrentWeapon);
6092 			//don't draw muzzle flash if observing from this player
6093 			if(MultiplayerObservedPlayer!=senderId)
6094 				HandleGhostGunFlashEffect(sbPtr, messagePtr->IHaveAMuzzleFlash);
6095 			else
6096 				HandleGhostGunFlashEffect(sbPtr, 0);
6097 			MaintainGhostCloakingStatus(sbPtr,(int)messagePtr->CloakingEffectiveness<<8);
6098 			MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire);
6099 			/* Now, more disc. */
6100 
6101 			if (messagePtr->IHaveADisk) {
6102 
6103 				SECTION_DATA *disc;
6104 				/* Find the thrower's ghost, and add his disc...  */
6105 
6106 				GLOBALASSERT(ghostData->type==I_BehaviourPredatorPlayer);
6107 				disc=GetThisSectionData(ghostData->HModelController.section_data,"disk");
6108 				if (disc) {
6109 					disc->flags&=~section_data_notreal;
6110 				}
6111 			}
6112 		}
6113 		else
6114 		{
6115 			/* We are a dead alien with a ghost */
6116 			RemoveGhost(sbPtr);
6117 			return;
6118 		}
6119 
6120 
6121 		if(sbPtr && messagePtr->IAmAlive)
6122 		{
6123 			NETGHOSTDATABLOCK *ghostData;
6124 			ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
6125 
6126 			//are we currently following this player's movements
6127 			if(MultiplayerObservedPlayer)
6128 			{
6129 				if(MultiplayerObservedPlayer==senderId)
6130 				{
6131 					PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
6132 					playerStatusPtr->ViewPanX=messagePtr->Elevation;
6133 
6134 					//don't draw the player we're observing
6135 					if(sbPtr && sbPtr->SBdptr)
6136 					{
6137 						sbPtr->SBdptr->ObFlags|=ObFlag_NotVis;
6138 					}
6139 				}
6140 			}
6141 		}
6142 	}
6143 }
6144 
ProcessNetMsg_FrameTimer(unsigned short frame_time,DPID senderId)6145 static void ProcessNetMsg_FrameTimer(unsigned short frame_time,DPID senderId)
6146 {
6147 	int senderPlayerIndex;
6148 	/* if we're not playing, ignore it */
6149 	if(netGameData.myGameState!=NGS_Playing) return;
6150 
6151 	senderPlayerIndex = PlayerIdInPlayerList(senderId);
6152 	if(senderPlayerIndex==NET_IDNOTINPLAYERLIST) return;
6153 
6154 	netGameData.playerData[senderPlayerIndex].timer+=frame_time;
6155 
6156 
6157 }
6158 
ProcessNetMsg_PlayerKilled(NETMESSAGE_PLAYERKILLED * messagePtr,DPID senderId)6159 static void ProcessNetMsg_PlayerKilled(NETMESSAGE_PLAYERKILLED *messagePtr, DPID senderId)
6160 {
6161 	STRATEGYBLOCK *sbPtr;
6162 	int senderPlayerIndex;
6163 
6164 	/* if we're not playing, ignore it */
6165 	if(netGameData.myGameState!=NGS_Playing) return;
6166 
6167 	/* if this player is not in the play list, messages are probably out of order,
6168 	so just ignore it... */
6169 	senderPlayerIndex = PlayerIdInPlayerList(senderId);
6170 	if(senderPlayerIndex==NET_IDNOTINPLAYERLIST) return;
6171 
6172 	/* find the ghost for this player */
6173 	sbPtr = FindGhost(senderId, GHOST_PLAYEROBJECTID);
6174 	if(!sbPtr)
6175 	{
6176 		/* we don't have a ghost for this player, which is odd, and implies that messages
6177 		have got dis-ordered... best just ignore it then */
6178 		return;
6179 	}
6180 
6181 	/* we have a ghost for this player: remove it if it's an alien */
6182 //	if(netGameData.playerData[senderPlayerIndex].characterType==NGCT_Alien)
6183 	//RemoveGhost(sbPtr);
6184 	KillGhost(sbPtr,messagePtr->objectId);
6185 
6186 	Inform_PlayerHasDied(messagePtr->killerId, senderId,messagePtr->killerType,messagePtr->weaponIcon);
6187 
6188 	/* now attempt to update the scores */
6189 	if(AvP.Network==I_Host)
6190 	{
6191 		UpdateNetworkGameScores(senderId, messagePtr->killerId,messagePtr->myType,messagePtr->killerType);
6192 	}
6193 
6194 
6195 
6196 	/* do some sound... */
6197 	LOCALASSERT(sbPtr->DynPtr);
6198 	switch(netGameData.playerData[senderPlayerIndex].characterType)
6199 	{
6200 		case(NGCT_Alien):
6201 		{
6202 			PlayAlienSound(0,ASC_Scream_Dying,0,NULL,&(sbPtr->DynPtr->Position));
6203 			break;
6204 		}
6205 		case(NGCT_Marine):
6206 		{
6207 			PlayMarineScream(0,SC_Death,0,NULL,&(sbPtr->DynPtr->Position));
6208 			break;
6209 		}
6210 		case(NGCT_Predator):
6211 		{
6212 			PlayPredatorSound(0,PSC_Scream_Dying,0,NULL,&(sbPtr->DynPtr->Position));
6213 			break;
6214 		}
6215 		default:
6216 		{
6217 			LOCALASSERT(1==0);
6218 			break;
6219 		}
6220 	}
6221 }
6222 
ProcessNetMsg_PlayerDeathAnim(NETMESSAGE_CORPSEDEATHANIM * messagePtr,DPID senderId)6223 static void ProcessNetMsg_PlayerDeathAnim(NETMESSAGE_CORPSEDEATHANIM *messagePtr,DPID senderId)
6224 {
6225 	STRATEGYBLOCK *sbPtr;
6226 	/* if we're not playing, ignore it */
6227 	if(netGameData.myGameState!=NGS_Playing) return;
6228 
6229 	/* find the ghost for this player */
6230 	sbPtr = FindGhost(senderId, messagePtr->objectId);
6231 	if(!sbPtr)
6232 	{
6233 		/* we don't have a ghost for this player, which is odd, and implies that messages
6234 		have got dis-ordered... best just ignore it then */
6235 		return;
6236 	}
6237 
6238 	//set the death animation for this player
6239 	ApplyGhostCorpseDeathAnim(sbPtr,messagePtr->deathId);
6240 
6241 }
6242 
ProcessNetMsg_AllGameScores(NETMESSAGE_ALLGAMESCORES * messagePtr)6243 static void ProcessNetMsg_AllGameScores(NETMESSAGE_ALLGAMESCORES *messagePtr)
6244 {
6245 	/* should only get this if we're not the host */
6246 	if(AvP.Network!=I_Peer)
6247 	{
6248 		//Vaguely possible that a host could receive a message that is only intended for peers
6249 		//if this computer has only just become the host.
6250 		LOCALASSERT(AvP.Network==I_Host);
6251 		return;
6252 	}
6253 	/* only do this if we're playing */
6254 	if(netGameData.myGameState!=NGS_Playing) return;
6255 
6256 	/* fill in the game scores from the message */
6257 	{
6258 		int i,j;
6259 
6260 		for(i=0;i<NET_MAXPLAYERS;i++)
6261 		{
6262 			for(j=0;j<NET_MAXPLAYERS;j++)
6263 			{
6264 				netGameData.playerData[i].playerFrags[j] = messagePtr->playerFrags[i][j];
6265 			}
6266 			netGameData.playerData[i].playerScore = messagePtr->playerScores[i];
6267 			netGameData.playerData[i].playerScoreAgainst = messagePtr->playerScoresAgainst[i];
6268 
6269 			for(j=0;j<3;j++)
6270 			{
6271 				netGameData.playerData[i].aliensKilled[j]=messagePtr->aliensKilled[i][j];
6272 			}
6273 
6274 			netGameData.playerData[i].deathsFromAI = messagePtr->deathsFromAI[i];
6275 		}
6276 	}
6277 
6278 	netGameData.myGameState=NGS_EndGameScreen;
6279 }
6280 
ProcessNetMsg_PlayerScores(NETMESSAGE_PLAYERSCORES * messagePtr)6281 static void ProcessNetMsg_PlayerScores(NETMESSAGE_PLAYERSCORES *messagePtr)
6282 {
6283 	int playerId;
6284 	/* should only get this if we're not the host */
6285 	if(AvP.Network!=I_Peer)
6286 	{
6287 		//Vaguely possible that a host could receive a message that is only intended for peers
6288 		//if this computer has only just become the host.
6289 		LOCALASSERT(AvP.Network==I_Host);
6290 		return;
6291 	}
6292 	/* only do this if we're playing */
6293 	if(netGameData.myGameState!=NGS_Playing) return;
6294 
6295 	/* find the player... */
6296 	playerId = (int)messagePtr->playerId;
6297 
6298 	/* fill in the player's scores from the message */
6299 	{
6300 		int i;
6301 
6302 		for(i=0;i<NET_MAXPLAYERS;i++)
6303 		{
6304 			netGameData.playerData[playerId].playerFrags[i] = messagePtr->playerFrags[i];
6305 		}
6306 		netGameData.playerData[playerId].playerScore = messagePtr->playerScore;
6307 		netGameData.playerData[playerId].playerScoreAgainst = messagePtr->playerScoreAgainst;
6308 
6309 		for(i=0;i<3;i++)
6310 		{
6311 			netGameData.playerData[playerId].aliensKilled[i]=messagePtr->aliensKilled[i];
6312 		}
6313 		netGameData.playerData[playerId].deathsFromAI = messagePtr->deathsFromAI;
6314 	}
6315 }
6316 
ProcessNetMsg_ScoreChange(NETMESSAGE_SCORECHANGE * messagePtr)6317 static void ProcessNetMsg_ScoreChange(NETMESSAGE_SCORECHANGE *messagePtr)
6318 {
6319 	/* should only get this if we're not the host */
6320 	if(AvP.Network!=I_Peer)
6321 	{
6322 		//Vaguely possible that a host could receive a message that is only intended for peers
6323 		//if this computer has only just become the host.
6324 		LOCALASSERT(AvP.Network==I_Host);
6325 		return;
6326 	}
6327 	/* only do this if we're playing */
6328 	if(netGameData.myGameState!=NGS_Playing) return;
6329 
6330 	if(messagePtr->killerIndex == NET_MAXPLAYERS)
6331 	{
6332 		//killed by ai
6333 		netGameData.playerData[messagePtr->victimIndex].deathsFromAI=messagePtr->fragCount;
6334 	}
6335 	else
6336 	{
6337 		netGameData.playerData[messagePtr->killerIndex].playerFrags[messagePtr->victimIndex]=messagePtr->fragCount;
6338 		netGameData.playerData[messagePtr->killerIndex].playerScore=messagePtr->killerScoreFor;
6339 	}
6340 	netGameData.playerData[messagePtr->victimIndex].playerScoreAgainst=messagePtr->victimScoreAgainst;
6341 }
6342 
ProcessNetMsg_SpeciesScores(NETMESSAGE_SPECIESSCORES * messagePtr)6343 static void ProcessNetMsg_SpeciesScores(NETMESSAGE_SPECIESSCORES *messagePtr)
6344 {
6345 	int i;
6346 	/* should only get this if we're not the host */
6347 	if(AvP.Network!=I_Peer)
6348 	{
6349 		//Vaguely possible that a host could receive a message that is only intended for peers
6350 		//if this computer has only just become the host.
6351 		LOCALASSERT(AvP.Network==I_Host);
6352 		return;
6353 	}
6354 	/* only do this if we're playing */
6355 	if(netGameData.myGameState!=NGS_Playing) return;
6356 
6357 	for(i=0;i<3;i++)
6358 	{
6359 		netGameData.teamScores[i]=messagePtr->teamScores[i];
6360 	}
6361 
6362 }
6363 
ProcessNetMsg_LocalRicochet(NETMESSAGE_LOCALRICOCHET * messagePtr)6364 static void ProcessNetMsg_LocalRicochet(NETMESSAGE_LOCALRICOCHET *messagePtr)
6365 {
6366 }
6367 
ProcessNetMsg_LocalObjectState(NETMESSAGE_LOBSTATE * messagePtr,DPID senderId)6368 static void ProcessNetMsg_LocalObjectState(NETMESSAGE_LOBSTATE *messagePtr, DPID senderId)
6369 {
6370 	STRATEGYBLOCK *sbPtr;
6371 	int objectId;
6372 
6373 	/* only do this if we're playing */
6374 	if(netGameData.myGameState!=NGS_Playing) return;
6375 
6376 	/* get the object id from the message */
6377 	objectId = (int)messagePtr->objectId;
6378 
6379 	sbPtr = FindGhost(senderId, objectId);
6380 	if(!sbPtr)
6381 	{
6382 		/* we don't seem to have a ghost for this object, so create one */
6383 		VECTORCH position;
6384 		EULER orientation;
6385 		AVP_BEHAVIOUR_TYPE type;
6386 
6387 		position.vx = messagePtr->xPos;
6388 		orientation.EulerX = (messagePtr->xOrient<<NET_EULERSCALESHIFT);
6389 		position.vy = messagePtr->yPos;
6390 		orientation.EulerY = (messagePtr->yOrient<<NET_EULERSCALESHIFT);
6391 		position.vz = messagePtr->zPos;
6392 		orientation.EulerZ = (messagePtr->zOrient<<NET_EULERSCALESHIFT);
6393 		type = (AVP_BEHAVIOUR_TYPE)messagePtr->type;
6394 
6395 		if (type==I_BehaviourNetCorpse) {
6396 			/* This *should* never happen... */
6397 			textprint("IGNORED A CREATE CORPSE COMMAND.\n");
6398 			return;
6399 		}
6400 
6401 		/* NB there is no sequence required for local objects, so just pass zero */
6402 		sbPtr = CreateNetGhost(senderId,objectId,&position,&orientation,type,messagePtr->IOType,messagePtr->subtype);
6403 		if (type==I_BehaviourPredatorDisc_SeekTrack) {
6404 
6405 			NETGHOSTDATABLOCK *ghostData;
6406 			STRATEGYBLOCK *sbPtr2;
6407 			SECTION_DATA *disc;
6408 			int playerIndex;
6409 			/* Find the thrower's ghost, and rip off his disc :-) */
6410 
6411 			playerIndex = PlayerIdInPlayerList(senderId);
6412 			if (playerIndex==NET_IDNOTINPLAYERLIST) {
6413 				return;
6414 			}
6415 			sbPtr2 = FindGhost(senderId, GHOST_PLAYEROBJECTID);
6416 			if (!sbPtr2) {
6417 				return;
6418 			}
6419 			/* Got 'em. */
6420 			ghostData = (NETGHOSTDATABLOCK *)sbPtr2->SBdataptr;
6421 			GLOBALASSERT(ghostData);
6422 			disc=GetThisSectionData(ghostData->HModelController.section_data,"disk");
6423 			if (!disc) {
6424 				return;
6425 			}
6426 			disc->flags|=section_data_notreal;
6427 		}
6428 	}
6429 	else
6430 	{
6431 		/* update the ghost... */
6432 		VECTORCH position;
6433 		EULER orientation;
6434 
6435 		position.vx = messagePtr->xPos;
6436 		orientation.EulerX = (messagePtr->xOrient<<NET_EULERSCALESHIFT);
6437 		position.vy = messagePtr->yPos;
6438 		orientation.EulerY = (messagePtr->yOrient<<NET_EULERSCALESHIFT);
6439 		position.vz = messagePtr->zPos;
6440 		orientation.EulerZ = (messagePtr->zOrient<<NET_EULERSCALESHIFT);
6441 
6442 		/* NB don't need to update the object type */
6443 
6444 		{
6445 			NETGHOSTDATABLOCK *ghostData;
6446 
6447 			ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
6448 
6449 			if(messagePtr->event_flag)
6450 			{
6451 				if (ghostData->type==I_BehaviourPredatorDisc_SeekTrack)
6452 				{
6453 					if (messagePtr->event_flag==1)
6454 					{
6455 						/* Convert! */
6456 						Convert_DiscGhost_To_PickupGhost(sbPtr);
6457 						//return;
6458 					}
6459 					else if(messagePtr->event_flag==2)
6460 					{
6461 						//disc has bounced off a wall , so play appropriate sound
6462 						Sound_Play(SID_PREDATOR_DISK_HITTING_WALL,"dp",&position,((FastRandom()&511)-255));
6463 					}
6464 				}
6465 				else if(ghostData->type==I_BehaviourFrisbee)
6466 				{
6467 					if(messagePtr->event_flag==2)
6468 					{
6469 						//disc has bounced off a wall , so play appropriate sound
6470 						Sound_Play(SID_ED_SKEETERDISC_HITWALL,"dp",&position,((FastRandom()&511)-255));
6471 					}
6472 				}
6473 				else if(ghostData->type==I_BehaviourFlareGrenade)
6474 				{
6475 					//flare has hit wall , so start the flare sound
6476 					if(ghostData->SoundHandle==SOUND_NOACTIVEINDEX)
6477 					{
6478 						Sound_Play(SID_BURNING_FLARE,"dle",&position,&ghostData->SoundHandle);
6479 					}
6480 				}
6481 				else if ((ghostData->type==I_BehaviourGrenade)||(ghostData->type==I_BehaviourClusterGrenade))
6482 				{
6483 					/* Bounce sound. */
6484 					Sound_Play(SID_GRENADE_BOUNCE,"dp",&position,((FastRandom()&511)-255));
6485 				}
6486 			}
6487 			/* NB there is no sequence required for local objects, so just pass zero */
6488 			UpdateGhost(sbPtr,&position,&orientation,0,0);
6489 		}
6490 	}
6491 }
6492 
GetSizeOfLocalObjectDamagedMessage(char * messagePtr)6493 static int GetSizeOfLocalObjectDamagedMessage(char *messagePtr)
6494 {
6495 	int size=sizeof(NETMESSAGE_LOBDAMAGED_HEADER);
6496 	NETMESSAGE_LOBDAMAGED_HEADER *messageHeader = (NETMESSAGE_LOBDAMAGED_HEADER*) messagePtr;
6497 
6498 	if(messageHeader->damageProfile) size+=sizeof(NETMESSAGE_DAMAGE_PROFILE);
6499 	if(messageHeader->multiple) size+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE);
6500 	if(messageHeader->sectionID) size+=sizeof(NETMESSAGE_DAMAGE_SECTION);
6501 	if(messageHeader->delta_seq) size+=sizeof(NETMESSAGE_DAMAGE_DELTA);
6502 	if(messageHeader->direction) size+=sizeof(NETMESSAGE_DAMAGE_DIRECTION);
6503 
6504 	return size;
6505 }
6506 
ProcessNetMsg_LocalObjectDamaged(char * messagePtr,DPID senderId)6507 static void ProcessNetMsg_LocalObjectDamaged(char *messagePtr, DPID senderId)
6508 {
6509 	NETMESSAGE_LOBDAMAGED_HEADER *messageHeader=0;
6510 	NETMESSAGE_DAMAGE_PROFILE *messageProfile=0;
6511 	NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0;
6512 	NETMESSAGE_DAMAGE_SECTION *messageSection=0;
6513 	NETMESSAGE_DAMAGE_DELTA *messageDelta=0;
6514 	NETMESSAGE_DAMAGE_DIRECTION *messageDirection=0;
6515 
6516 	if(netGameData.myGameState!=NGS_Playing) return;
6517 
6518 
6519 	messageHeader=(NETMESSAGE_LOBDAMAGED_HEADER*) messagePtr;
6520 	messagePtr+=sizeof(NETMESSAGE_LOBDAMAGED_HEADER);
6521 
6522 	//find out which elements of the damage message have been sent
6523 	if(messageHeader->damageProfile)
6524 	{
6525 		messageProfile=(NETMESSAGE_DAMAGE_PROFILE*) messagePtr;
6526 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_PROFILE);
6527 	}
6528 	if(messageHeader->multiple)
6529 	{
6530 		messageMultiple=(NETMESSAGE_DAMAGE_MULTIPLE*) messagePtr;
6531 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE);
6532 	}
6533 	if(messageHeader->sectionID)
6534 	{
6535 		messageSection=(NETMESSAGE_DAMAGE_SECTION*) messagePtr;
6536 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_SECTION);
6537 	}
6538 	if(messageHeader->delta_seq)
6539 	{
6540 		messageDelta=(NETMESSAGE_DAMAGE_DELTA*) messagePtr;
6541 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_DELTA);
6542 	}
6543 	if(messageHeader->direction)
6544 	{
6545 		messageDirection=(NETMESSAGE_DAMAGE_DIRECTION*) messagePtr;
6546 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_DIRECTION);
6547 	}
6548 
6549 	/* This message is for the player who owns the object, so first check
6550 	if the message is meant for us */
6551 	if(messageHeader->playerId != AVPDPNetID)
6552 	{
6553 		//however we may need to play a delta sequence on the ghost
6554 		if(messageDelta)
6555 		{
6556 			if(messageDelta->Delta_Sequence>0 && messageDelta->Delta_Sub_Sequence>0)
6557 			{
6558 				STRATEGYBLOCK *sbPtr;
6559 				sbPtr=FindGhost(messageHeader->playerId,(int)messageHeader->objectId);
6560 				if(sbPtr)
6561 				{
6562 					PlayHitDeltaOnGhost(sbPtr,messageDelta->Delta_Sequence,messageDelta->Delta_Sub_Sequence);
6563 				}
6564 			}
6565 		}
6566 		return;
6567 	}
6568 
6569 	/* next we have to find this object in our strategyblock list */
6570 	{
6571 		int objectId;
6572 		STRATEGYBLOCK *sbPtr;
6573 		DAMAGE_PROFILE damage;
6574 		SECTION_DATA *section_data;
6575 		HMODELCONTROLLER *controller;
6576 		int multiple;
6577 		VECTORCH incoming;
6578 		VECTORCH direction;
6579 		VECTORCH* incoming_ptr=0;
6580 
6581 		objectId = (int)messageHeader->objectId;
6582 		sbPtr = FindObjectFromNetIndex(objectId);
6583 
6584 
6585 
6586 
6587 		/* we set this global to remember the id of the player who sent this damage message,
6588 		so that if the player is killed, we know the id of the killer. this is a bit of
6589 		a nasty hack, but means that we don't have to make any changes to the core damage functions */
6590 		LOCALASSERT(myNetworkKillerId==NULL || myNetworkKillerId ==AVPDPNetID);
6591 		/*
6592 		Don't bother setting the killer id for molotov damage. This is because the only source of this damage
6593 		is explosions from flamethrowers. This damage will always come from the net host , and we don't want to credit the
6594 		host for all kills caused by this damage.
6595 
6596 		Similarly all things that cause falling damage should count as suicide (in particular platform lifts)
6597 		*/
6598 		if(messageHeader->ammo_id!=AMMO_MOLOTOV && messageHeader->ammo_id!=AMMO_FALLING_POSTMAX)
6599 		{
6600 			myNetworkKillerId = senderId;
6601 		}
6602 		/* check if we have found an sb: if not the object has probably been
6603 		destroyed already, so just ignore it */
6604 		if(sbPtr)
6605 		{
6606 			//fill out damage profile
6607 			damage.Id=messageHeader->ammo_id;
6608 			if(messageProfile)
6609 			{
6610 				damage.Impact = messageProfile->Impact;
6611 				damage.Cutting = messageProfile->Cutting;
6612 				damage.Penetrative = messageProfile->Penetrative;
6613 				damage.Fire = messageProfile->Fire;
6614 				damage.Electrical = messageProfile->Electrical;
6615 				damage.Acid = messageProfile->Acid;
6616 
6617 				damage.ExplosivePower=messageProfile->ExplosivePower;
6618 				damage.Slicing=messageProfile->Slicing;
6619 				damage.ProduceBlood=messageProfile->ProduceBlood;
6620 				damage.ForceBoom=messageProfile->ForceBoom;
6621 
6622 				damage.BlowUpSections=messageProfile->BlowUpSections;
6623 				damage.Special=messageProfile->Special;
6624 				damage.MakeExitWounds=messageProfile->MakeExitWounds;
6625 			}
6626 			else
6627 			{
6628 				if(damage.Id==AMMO_FLECHETTE_POSTMAX)
6629 				{
6630 					extern DAMAGE_PROFILE FlechetteDamage;
6631 					damage=FlechetteDamage;
6632 				}
6633 				else
6634 				{
6635 					GLOBALASSERT(damage.Id>AMMO_NONE && damage.Id<MAX_NO_OF_AMMO_TEMPLATES);
6636 					damage=TemplateAmmo[damage.Id].MaxDamage[AvP.Difficulty];
6637 				}
6638 			}
6639 
6640 			if(messageMultiple)
6641 			{
6642 				multiple = messageMultiple->multiple;
6643 			}
6644 			else
6645 			{
6646 				multiple = ONE_FIXED;
6647 			}
6648 
6649 			section_data=NULL;
6650 			controller=NULL;
6651 
6652 			//get the direction vector if there is one
6653 			if(sbPtr->DynPtr && messageDirection)
6654 			{
6655 				if(messageDirection->direction_x ||
6656 				   messageDirection->direction_y ||
6657 				   messageDirection->direction_z)
6658 				{
6659 					MATRIXCH mat=sbPtr->DynPtr->OrientMat;
6660 					TransposeMatrixCH(&mat);
6661 
6662 					//extract the direction vector
6663 					incoming.vx=messageDirection->direction_x;
6664 					incoming.vy=messageDirection->direction_y;
6665 					incoming.vz=messageDirection->direction_z;
6666 					//normalise it
6667 					Normalise(&incoming);
6668 					direction=incoming;
6669 
6670 					//and rotate it from world space to the object's local space
6671 					RotateVector(&incoming,&mat);
6672 
6673 					//set the incoming pointer
6674 					incoming_ptr=&incoming;
6675 
6676 				}
6677 
6678 			}
6679 			/*Record the id of the hit body part in a global variable.
6680 			This way , if this blow kill the player , we know which body part has been hit*/
6681 			if(messageSection)
6682 			{
6683 				MyHitBodyPartId=messageSection->SectionID;
6684 			}
6685 			else
6686 			{
6687 				MyHitBodyPartId=-1;
6688 			}
6689 
6690 			if (messageSection && messageSection->SectionID!=-1) {
6691 				/* Hmm. */
6692 				if (sbPtr->I_SBtype==I_BehaviourAlien) {
6693 					/* Only allowed for aliens, right now. */
6694 					ALIEN_STATUS_BLOCK *alienStatusPtr=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
6695 
6696 					GLOBALASSERT(alienStatusPtr);
6697 
6698 					controller=&alienStatusPtr->HModelController;
6699 					section_data=GetThisSectionData_FromID(alienStatusPtr->HModelController.section_data,
6700 						(int)messageSection->SectionID);
6701 				}
6702 				else if (sbPtr->I_SBtype==I_BehaviourNetCorpse)
6703 				{
6704 					NETCORPSEDATABLOCK *corpseData = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr;
6705 
6706 					GLOBALASSERT(corpseData);
6707 
6708 					controller=&corpseData->HModelController;
6709 					section_data=GetThisSectionData_FromID(corpseData->HModelController.section_data,
6710 						(int)messageSection->SectionID);
6711 				}
6712 			}
6713 
6714 			if (section_data)
6715 			{
6716 				DISPLAYBLOCK *fragged_section=0;
6717 				fragged_section=CauseDamageToHModel(controller,sbPtr,(&damage),
6718 									multiple,section_data,incoming_ptr,NULL,0);
6719 
6720 				if(fragged_section && damage.Id==AMMO_PRED_RIFLE && incoming_ptr)
6721 				{
6722 					//a speargun has fragged off a body part , so we need to create a spear
6723 					CreateSpearPossiblyWithFragment(fragged_section,&fragged_section->ObWorld,&direction);
6724 				}
6725 
6726 			}
6727 			else
6728 			{
6729 				CauseDamageToObject(sbPtr, (&damage), multiple,incoming_ptr);
6730 			}
6731 		}
6732 		myNetworkKillerId = AVPDPNetID;
6733 		MyHitBodyPartId=-1;
6734 	}
6735 
6736 
6737 
6738 }
6739 
6740 
ProcessNetMsg_LocalObjectDestroyed_Request(NETMESSAGE_LOBDESTROYED_REQUEST * messagePtr,DPID senderId)6741 static void ProcessNetMsg_LocalObjectDestroyed_Request(NETMESSAGE_LOBDESTROYED_REQUEST *messagePtr, DPID senderId)
6742 {
6743 	/* only do this if we're playing */
6744 	if(netGameData.myGameState!=NGS_Playing) return;
6745 
6746 	/* This message is for the player who owns the object, so first check
6747 	if the message is meant for us */
6748 	if(messagePtr->playerId != AVPDPNetID) return;
6749 
6750 	/* next we have to find this object in our strategyblock list */
6751 	{
6752 		int objectId;
6753 		STRATEGYBLOCK *sbPtr;
6754 
6755 		objectId = (int)messagePtr->objectId;
6756 		sbPtr = FindObjectFromNetIndex(objectId);
6757 
6758 		/* check if we have found an sb: if not the object has probably been
6759 		destroyed already, so just ignore it */
6760 
6761 		if(sbPtr) {
6762 
6763 			/* Er... deal with it, okay? */
6764 			if (sbPtr->I_SBtype==I_BehaviourInanimateObject) {
6765 				RemovePickedUpObject(sbPtr);
6766 			} else {
6767 				GLOBALASSERT(0);
6768 			}
6769 
6770 		}
6771 
6772 	}
6773 }
6774 
ProcessNetMsg_LocalObjectDestroyed(NETMESSAGE_LOBDESTROYED * messagePtr,DPID senderId)6775 static void ProcessNetMsg_LocalObjectDestroyed(NETMESSAGE_LOBDESTROYED *messagePtr, DPID senderId)
6776 {
6777 	STRATEGYBLOCK *sbPtr;
6778 	int objectId;
6779 
6780 	/* only do this if we're playing */
6781 	if(netGameData.myGameState!=NGS_Playing) return;
6782 
6783 	/* this message is a cue to destroy a ghost... except for the player which has
6784 	a seperate 'playerkilled' message... */
6785 
6786 	/* start by finding the ghost for this object */
6787 	objectId = (int)messagePtr->objectId;
6788 	sbPtr = FindGhost(senderId, objectId);
6789 	if(!sbPtr)
6790 	{
6791 		/* if we haven't got a ghost for this object things have gone wrong: eg, we haven't
6792 		yet received the object creation message. Just ignore it then... */
6793 		return;
6794 	}
6795 	RemoveGhost(sbPtr);
6796 }
6797 
6798 
GetSizeOfInanimateDamagedMessage(char * messagePtr)6799 static int GetSizeOfInanimateDamagedMessage(char *messagePtr)
6800 {
6801 	int size=sizeof(NETMESSAGE_INANIMATEDAMAGED_HEADER);
6802 	NETMESSAGE_INANIMATEDAMAGED_HEADER *messageHeader =(NETMESSAGE_INANIMATEDAMAGED_HEADER*) messagePtr;
6803 
6804 	if(messageHeader->damageProfile) size+=sizeof(NETMESSAGE_DAMAGE_PROFILE);
6805 	if(messageHeader->multiple) size+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE);
6806 
6807 	return size;
6808 }
6809 
ProcessNetMsg_InanimateObjectDamaged(char * messagePtr)6810 static void ProcessNetMsg_InanimateObjectDamaged(char *messagePtr)
6811 {
6812 	NETMESSAGE_INANIMATEDAMAGED_HEADER *messageHeader=0;
6813 	NETMESSAGE_DAMAGE_PROFILE *messageProfile=0;
6814 	NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0;
6815 
6816 	STRATEGYBLOCK *sbPtr;
6817 
6818 	/* only do this if we're playing */
6819 	if(netGameData.myGameState!=NGS_Playing) return;
6820 
6821 	/* only process this if we're the host*/
6822 	if(AvP.Network!=I_Host) return;
6823 
6824 	messageHeader=(NETMESSAGE_INANIMATEDAMAGED_HEADER*) messagePtr;
6825 	messagePtr+=sizeof(NETMESSAGE_INANIMATEDAMAGED_HEADER);
6826 
6827 	//find out which elements of the damage message have been sent
6828 	if(messageHeader->damageProfile)
6829 	{
6830 		messageProfile=(NETMESSAGE_DAMAGE_PROFILE*) messagePtr;
6831 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_PROFILE);
6832 	}
6833 	if(messageHeader->multiple)
6834 	{
6835 		messageMultiple=(NETMESSAGE_DAMAGE_MULTIPLE*) messagePtr;
6836 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE);
6837 	}
6838 
6839 	/* start by finding the object */
6840 	sbPtr = FindEnvironmentObjectFromName(messageHeader->name);
6841 	if(!sbPtr)
6842 	{
6843 		/* if we haven't got a ghost for this object things have gone wrong: eg, we haven't
6844 		yet received the object creation message. Just ignore it then... */
6845 		return;
6846 	}
6847 
6848 	/* ok: cause the damage */
6849 	{
6850 		STRATEGYBLOCK *objectPtr = FindEnvironmentObjectFromName(messageHeader->name);
6851 		DAMAGE_PROFILE damage;
6852 		int multiple;
6853 
6854 		if(!objectPtr) return; /* couldn't find it */
6855 
6856 		//fill out damage profile
6857 		damage.Id=messageHeader->ammo_id;
6858 		if(messageProfile)
6859 		{
6860 			damage.Impact = messageProfile->Impact;
6861 			damage.Cutting = messageProfile->Cutting;
6862 			damage.Penetrative = messageProfile->Penetrative;
6863 			damage.Fire = messageProfile->Fire;
6864 			damage.Electrical = messageProfile->Electrical;
6865 			damage.Acid = messageProfile->Acid;
6866 
6867 			damage.ExplosivePower=messageProfile->ExplosivePower;
6868 			damage.Slicing=messageProfile->Slicing;
6869 			damage.ProduceBlood=messageProfile->ProduceBlood;
6870 			damage.ForceBoom=messageProfile->ForceBoom;
6871 
6872 			damage.BlowUpSections=messageProfile->BlowUpSections;
6873 			damage.Special=messageProfile->Special;
6874 			damage.MakeExitWounds=messageProfile->MakeExitWounds;
6875 		}
6876 		else
6877 		{
6878 			GLOBALASSERT(damage.Id>AMMO_NONE && damage.Id<MAX_NO_OF_AMMO_TEMPLATES);
6879 			damage=TemplateAmmo[damage.Id].MaxDamage[AvP.Difficulty];
6880 		}
6881 
6882 		//get damage multiple
6883 		if(messageMultiple)
6884 		{
6885 			multiple = messageMultiple->multiple;
6886 		}
6887 		else
6888 		{
6889 			multiple = ONE_FIXED;
6890 		}
6891 
6892 		CauseDamageToObject(sbPtr, (&damage), multiple,NULL);
6893 	}
6894 }
6895 
ProcessNetMsg_InanimateObjectDestroyed(NETMESSAGE_INANIMATEDESTROYED * messagePtr)6896 static void ProcessNetMsg_InanimateObjectDestroyed(NETMESSAGE_INANIMATEDESTROYED *messagePtr)
6897 {
6898 	STRATEGYBLOCK *sbPtr;
6899 
6900 	/* only do this if we're playing */
6901 	if(netGameData.myGameState!=NGS_Playing) return;
6902 	/* only peers should get this */
6903 	LOCALASSERT(AvP.Network!=I_Host);
6904 
6905 	/* start by finding the object */
6906 	sbPtr = FindEnvironmentObjectFromName(messagePtr->name);
6907 	if(!sbPtr)
6908 	{
6909 		/* if we haven't got a ghost for this object things have gone wrong: eg, we haven't
6910 		yet received the object creation message. Just ignore it then... */
6911 		return;
6912 	}
6913 
6914 
6915 	/* ok: drop a nuke on it */
6916 	{
6917 		extern int InanimateDamageFromNetHost;
6918 
6919 		InanimateDamageFromNetHost = 1;
6920 		CauseDamageToObject(sbPtr, &certainDeath, ONE_FIXED,NULL);
6921 		InanimateDamageFromNetHost = 0;
6922 	}
6923 }
6924 
ProcessNetMsg_ObjectPickedUp(NETMESSAGE_OBJECTPICKEDUP * messagePtr)6925 static void ProcessNetMsg_ObjectPickedUp(NETMESSAGE_OBJECTPICKEDUP *messagePtr)
6926 {
6927 	/* only do this if we're playing */
6928 	if(netGameData.myGameState!=NGS_Playing) return;
6929 
6930 	{
6931 		STRATEGYBLOCK *objectPtr = FindEnvironmentObjectFromName(messagePtr->name);
6932 		if(!objectPtr) return; /* couldn't find it */
6933 
6934 		LOCALASSERT(objectPtr->I_SBtype == I_BehaviourInanimateObject);
6935 
6936 		/* Play an appropriate sound? */
6937 		{
6938 			INANIMATEOBJECT_STATUSBLOCK* objStatPtr = objectPtr->SBdataptr;
6939 
6940 			/* patrick, for e3- add a sound effect to explosions */
6941 			if(objectPtr->DynPtr)
6942 			{
6943 				switch(objStatPtr->typeId)
6944 				{
6945 					case(IOT_Weapon):
6946 						/* Ignore predator case for now! */
6947 						Sound_Play(SID_MARINE_PICKUP_WEAPON,"%d",&objectPtr->DynPtr->Position);
6948 						break;
6949 					case(IOT_Ammo):
6950 						Sound_Play(SID_MARINE_PICKUP_AMMO,"%d",&objectPtr->DynPtr->Position);
6951 						break;
6952 					case(IOT_Armour):
6953 						Sound_Play(SID_MARINE_PICKUP_ARMOUR,"%d",&objectPtr->DynPtr->Position);
6954 						break;
6955 					case(IOT_FieldCharge):
6956 						Sound_Play(SID_PREDATOR_PICKUP_FIELDCHARGE,"%d",&objectPtr->DynPtr->Position);
6957 						break;
6958 					default:
6959 						Sound_Play(SID_PICKUP,"%d",&objectPtr->DynPtr->Position);
6960 						break;
6961 				}
6962 			}
6963 		}
6964 
6965 		KillInanimateObjectForRespawn(objectPtr);
6966 	}
6967 }
6968 
ProcessNetMsg_EndGame(void)6969 static void ProcessNetMsg_EndGame(void)
6970 {
6971 	/* should only get this if we're not the host */
6972 	if(AvP.Network!=I_Peer)
6973 	{
6974 		//Vaguely possible that a host could receive a message that is only intended for peers
6975 		//if this computer has only just become the host.
6976 		LOCALASSERT(AvP.Network==I_Host);
6977 	}
6978 
6979 	/* only do this if we're playing or in startup */
6980 			/* check start flags on all players (including ourselves) */
6981 			{
6982 				if(netGameData.playerData[PlayerIdInPlayerList(AVPDPNetID)].startFlag)
6983 				{
6984 					netGameData.myGameState = NGS_Playing;
6985 				}
6986 			}
6987 	if((netGameData.myGameState!=NGS_Playing)&&(netGameData.myGameState!=NGS_StartUp)&&(netGameData.myGameState!=NGS_Joining)) return;
6988 
6989 	netGameData.myGameState = NGS_EndGame;
6990 	AvP.MainLoopRunning = 0;
6991 }
6992 
ProcessNetMsg_PlayerLeaving(DPID senderId)6993 static void ProcessNetMsg_PlayerLeaving(DPID senderId)
6994 {
6995 	/* only do this if we're playing or in startup */
6996 	if(netGameData.myGameState==NGS_Playing || netGameData.myGameState==NGS_EndGameScreen)
6997 	{
6998 		RemovePlayersGhosts(senderId);
6999 	}
7000 
7001 	Inform_PlayerHasLeft(senderId);
7002 
7003 	RemovePlayerFromGame(senderId);
7004 
7005 }
7006 
ProcessNetMsg_LOSRequestBinarySwitch(NETMESSAGE_LOSREQUESTBINARYSWITCH * msgPtr)7007 static void ProcessNetMsg_LOSRequestBinarySwitch(NETMESSAGE_LOSREQUESTBINARYSWITCH *msgPtr)
7008 {
7009 	STRATEGYBLOCK *objectPtr;
7010 
7011 	/* only do this if we're playing */
7012 	if(netGameData.myGameState!=NGS_Playing) return;
7013 
7014 	objectPtr = FindEnvironmentObjectFromName(msgPtr->name);
7015 	if(!objectPtr) return; /* no object */
7016 	if(objectPtr->I_SBtype!=I_BehaviourBinarySwitch && objectPtr->I_SBtype!=I_BehaviourLinkSwitch) return;/* we only do switches */
7017 
7018 	/* change the state of this object, then, via request state */
7019 	RequestState(objectPtr,1,NULL);
7020 }
7021 
ProcessNetMsg_PlatformLiftState(NETMESSAGE_PLATFORMLIFTSTATE * msgPtr)7022 static void ProcessNetMsg_PlatformLiftState(NETMESSAGE_PLATFORMLIFTSTATE *msgPtr)
7023 {
7024 	STRATEGYBLOCK *objectPtr;
7025 
7026 	/* only peers should get this */
7027 	if(AvP.Network!=I_Peer)
7028 	{
7029 		//Vaguely possible that a host could receive a message that is only intended for peers
7030 		//if this computer has only just become the host.
7031 		LOCALASSERT(AvP.Network==I_Host);
7032 		return;
7033 	}
7034 
7035 	/* only do this if we're playing */
7036 	if(netGameData.myGameState!=NGS_Playing) return;
7037 
7038 	objectPtr = FindEnvironmentObjectFromName(msgPtr->name);
7039 	if(!objectPtr) return; /* no object */
7040 	if(objectPtr->I_SBtype!=I_BehaviourPlatform) return;/* we only do binary switches */
7041 
7042 	/* update the lift state */
7043 	{
7044 		extern void NetworkPeerChangePlatformLiftState(STRATEGYBLOCK* sbPtr,PLATFORMLIFT_STATES new_state);
7045 		NetworkPeerChangePlatformLiftState(objectPtr,(PLATFORMLIFT_STATES)(msgPtr->state));
7046 	}
7047 }
7048 
ProcessNetMsg_RequestPlatformLiftActivate(NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE * msgPtr)7049 static void ProcessNetMsg_RequestPlatformLiftActivate(NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE *msgPtr)
7050 {
7051 	STRATEGYBLOCK *objectPtr;
7052 
7053 	/* only host should process this */
7054 	if(AvP.Network!=I_Host) return;
7055 
7056 	/* only do this if we're playing */
7057 	if(netGameData.myGameState!=NGS_Playing) return;
7058 
7059 	objectPtr = FindEnvironmentObjectFromName(msgPtr->name);
7060 	if(!objectPtr) return; /* no object */
7061 	if(objectPtr->I_SBtype!=I_BehaviourPlatform) return;/* we only do platform lifts */
7062 
7063 	/* update the lift state */
7064 	{
7065 		PLATFORMLIFT_BEHAVIOUR_BLOCK *platLiftData = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)objectPtr->SBdataptr;
7066 		LOCALASSERT(platLiftData);
7067 		if(platLiftData->state == PLBS_AtRest && platLiftData->Enabled) ActivatePlatformLift(objectPtr);
7068 	}
7069 }
7070 
ProcessNetMsg_PlayerAutoGunState(NETMESSAGE_AGUNSTATE * messagePtr,DPID senderId)7071 static void ProcessNetMsg_PlayerAutoGunState(NETMESSAGE_AGUNSTATE *messagePtr, DPID senderId)
7072 {
7073 	STRATEGYBLOCK *sbPtr;
7074 	int objectId;
7075 
7076 	/* only do this if we're playing */
7077 	if(netGameData.myGameState!=NGS_Playing) return;
7078 
7079 	/* get the object id from the message */
7080 	objectId = (int)messagePtr->objectId;
7081 
7082 	sbPtr = FindGhost(senderId, objectId);
7083 	if(!sbPtr)
7084 	{
7085 		/* we don't seem to have a ghost for this autoGun, so create one */
7086 		VECTORCH position;
7087 		EULER orientation;
7088 
7089 		position.vx = messagePtr->xPos;
7090 		orientation.EulerX = (messagePtr->xOrient<<NET_EULERSCALESHIFT);
7091 		position.vy = messagePtr->yPos;
7092 		orientation.EulerY = (messagePtr->yOrient<<NET_EULERSCALESHIFT);
7093 		position.vz = messagePtr->zPos;
7094 		orientation.EulerZ = (messagePtr->zOrient<<NET_EULERSCALESHIFT);
7095 
7096 		/* NB there is no sequence required for autoguns, so just pass zero */
7097 		sbPtr = CreateNetGhost(senderId,objectId,&position,&orientation,I_BehaviourAutoGun,IOT_Non,0);
7098 		if(sbPtr)
7099 		{
7100 			HandleGhostAutoGunMuzzleFlash(sbPtr, (int)messagePtr->IAmFiring);
7101 			HandleGhostAutoGunSound(sbPtr, (int)messagePtr->IAmFiring);
7102 		}
7103 
7104 	}
7105 	else
7106 	{
7107 		/* update the autogun ghost... */
7108 		VECTORCH position;
7109 		EULER orientation;
7110 
7111 		position.vx = messagePtr->xPos;
7112 		orientation.EulerX = (messagePtr->xOrient<<NET_EULERSCALESHIFT);
7113 		position.vy = messagePtr->yPos;
7114 		orientation.EulerY = (messagePtr->yOrient<<NET_EULERSCALESHIFT);
7115 		position.vz = messagePtr->zPos;
7116 		orientation.EulerZ = (messagePtr->zOrient<<NET_EULERSCALESHIFT);
7117 
7118 		UpdateGhost(sbPtr,&position,&orientation,0,0);
7119 		HandleGhostAutoGunMuzzleFlash(sbPtr, (int)messagePtr->IAmFiring);
7120 		HandleGhostAutoGunSound(sbPtr,(int)messagePtr->IAmFiring);
7121 	}
7122 }
7123 
7124 
ProcessNetMsg_MakeDecal(NETMESSAGE_MAKEDECAL * messagePtr)7125 static void ProcessNetMsg_MakeDecal(NETMESSAGE_MAKEDECAL *messagePtr)
7126 {
7127 	if(netGameData.myGameState!=NGS_Playing) return;
7128 
7129 	AddDecal(messagePtr->DecalID,&(messagePtr->Direction),&(messagePtr->Position),messagePtr->ModuleIndex);
7130 }
7131 
7132 
ProcessNetMsg_ChatBroadcast(char * subMessagePtr,DPID senderId)7133 static char *ProcessNetMsg_ChatBroadcast(char *subMessagePtr, DPID senderId)
7134 {
7135 
7136 	BOOL same_species_only;
7137 	/* get player index from dpid */
7138 	char *ptr = subMessagePtr;
7139 	int stringLength=1;
7140 
7141 	int playerIndex = PlayerIdInPlayerList(senderId);
7142 
7143 	//get same_species flag
7144 	same_species_only=*ptr++;
7145 
7146 	while(*ptr++ && stringLength<255)
7147 	{
7148 		stringLength++;
7149 	}
7150 
7151 	if (stringLength==1 || stringLength>=255)
7152 	{
7153 		LOCALASSERT(0);
7154 		return ptr;
7155 	}
7156 	if(playerIndex==NET_IDNOTINPLAYERLIST)
7157 	{
7158 		return ptr;
7159 	}
7160 
7161 
7162 	if(netGameData.myGameState==NGS_Playing)
7163 	{
7164 		if(same_species_only)
7165 		{
7166 			//was a species say message , check to see if we are the correct species
7167 			if(netGameData.playerData[playerIndex].characterType != netGameData.myCharacterType ) return ptr;
7168 		}
7169 
7170 		sprintf(OnScreenMessageBuffer,"%s: %s",netGameData.playerData[playerIndex].name,subMessagePtr+1);
7171 		NewOnScreenMessage(OnScreenMessageBuffer);
7172 
7173 		/* KJL 99/2/5 - play 'incoming message' sound */
7174 		switch(netGameData.playerData[playerIndex].characterType)
7175 		{
7176 			case NGCT_Marine:
7177 			{
7178 				Sound_Play(SID_CONSOLE_MARINEMESSAGE,NULL);
7179 				break;
7180 			}
7181     	   	case NGCT_Predator:
7182 			{
7183 				Sound_Play(SID_CONSOLE_PREDATORMESSAGE,NULL);
7184 				break;
7185 			}
7186 			case NGCT_Alien:
7187 			{
7188 				Sound_Play(SID_CONSOLE_ALIENMESSAGE,NULL);
7189 				break;
7190 			}
7191 			default:
7192 				break;
7193 		}
7194 	}
7195 	return ptr;
7196 
7197 }
7198 
ProcessNetMsg_MakeExplosion(NETMESSAGE_MAKEEXPLOSION * messagePtr)7199 static void ProcessNetMsg_MakeExplosion(NETMESSAGE_MAKEEXPLOSION *messagePtr)
7200 {
7201 	if(netGameData.myGameState!=NGS_Playing) return;
7202 	MakeVolumetricExplosionAt(&(messagePtr->Position),messagePtr->ExplosionID);
7203 }
7204 
ProcessNetMsg_MakeFlechetteExplosion(NETMESSAGE_MAKEFLECHETTEEXPLOSION * messagePtr)7205 static void ProcessNetMsg_MakeFlechetteExplosion(NETMESSAGE_MAKEFLECHETTEEXPLOSION *messagePtr)
7206 {
7207 	extern void MakeFlechetteExplosionAt(VECTORCH *positionPtr,int seed);
7208 	if(netGameData.myGameState!=NGS_Playing) return;
7209 	MakeFlechetteExplosionAt(&(messagePtr->Position),messagePtr->Seed);
7210 }
7211 
ProcessNetMsg_MakePlasmaExplosion(NETMESSAGE_MAKEPLASMAEXPLOSION * messagePtr)7212 static void ProcessNetMsg_MakePlasmaExplosion(NETMESSAGE_MAKEPLASMAEXPLOSION *messagePtr)
7213 {
7214 	if(netGameData.myGameState!=NGS_Playing) return;
7215 	MakePlasmaExplosion(&(messagePtr->Position),&(messagePtr->FromPosition),messagePtr->ExplosionID);
7216 }
7217 
ProcessNetMsg_PredatorSights(NETMESSAGE_PREDATORSIGHTS * messagePtr,DPID senderId)7218 static void ProcessNetMsg_PredatorSights(NETMESSAGE_PREDATORSIGHTS *messagePtr, DPID senderId)
7219 {
7220 	extern THREE_LASER_DOT_DESC PredatorLaserSights[];
7221 	int playerIndex = PlayerIdInPlayerList(senderId);
7222 
7223 	if(netGameData.myGameState!=NGS_Playing) return;
7224 
7225 	if(playerIndex==NET_IDNOTINPLAYERLIST)
7226 	{
7227 		return;
7228 	}
7229 
7230 	{
7231 		int i=2;
7232 
7233 		VECTORCH offset[3] =
7234 		{
7235 			{0,-50,0},
7236 			{43,25,0},
7237 			{-43,25,0},
7238 		};
7239 		MATRIXCH matrix;
7240 		VECTORCH centre;
7241 		EULER orientation;
7242 
7243 
7244 		centre.vx = messagePtr->xPos;
7245 		orientation.EulerX = (messagePtr->xOrient<<NET_EULERSCALESHIFT);
7246 		centre.vy = messagePtr->yPos;
7247 		orientation.EulerY = (messagePtr->yOrient<<NET_EULERSCALESHIFT);
7248 		centre.vz = messagePtr->zPos;
7249 		orientation.EulerZ = (messagePtr->zOrient<<NET_EULERSCALESHIFT);
7250 
7251 		CreateEulerMatrix(&orientation,&matrix);
7252 		TransposeMatrixCH(&matrix);
7253 		do
7254 		{
7255 			VECTORCH position = offset[i];
7256 
7257 		  	RotateVector(&position,&matrix);
7258 
7259 			PredatorLaserSights[playerIndex].Position[i].vx = centre.vx + position.vx;
7260 			PredatorLaserSights[playerIndex].Position[i].vy = centre.vy + position.vy;
7261 			PredatorLaserSights[playerIndex].Position[i].vz = centre.vz + position.vz;
7262 			PredatorLaserSights[playerIndex].Normal[i].vx = matrix.mat31;
7263 			PredatorLaserSights[playerIndex].Normal[i].vy = matrix.mat32;
7264 			PredatorLaserSights[playerIndex].Normal[i].vz = matrix.mat33;
7265 		}
7266 		while(i--);
7267 
7268 		PredatorLaserSights[playerIndex].TargetID = messagePtr->TargetID;
7269   	}
7270 
7271 
7272 }
7273 
ProcessNetMsg_FragmentalObjectsStatus(NETMESSAGE_FRAGMENTALOBJECTSSTATUS * messagePtr)7274 static void ProcessNetMsg_FragmentalObjectsStatus(NETMESSAGE_FRAGMENTALOBJECTSSTATUS *messagePtr)
7275 {
7276 	int i;
7277 	int fragNumber=0;
7278 	int objectsToSkip=messagePtr->BatchNumber*(NUMBER_OF_FRAGMENTAL_OBJECTS<<3);
7279 
7280 	if(netGameData.myGameState!=NGS_Playing) return;
7281 	LOCALASSERT(AvP.Network!=I_No_Network);
7282 
7283 	for (i=0; i<NUMBER_OF_FRAGMENTAL_OBJECTS; i++)
7284 	{
7285 		FragmentalObjectStatus[i] = messagePtr->StatusBitfield[i];
7286 	}
7287 
7288 	for (i=0; i<NumActiveStBlocks; i++)
7289 	{
7290 		STRATEGYBLOCK *sbPtr = ActiveStBlockList[i];
7291 		int status;
7292 
7293 		if(sbPtr->I_SBtype == I_BehaviourInanimateObject)
7294 		{
7295 			INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr = sbPtr->SBdataptr;
7296 			LOCALASSERT(objectStatusPtr);
7297 
7298 			if((objectStatusPtr->typeId == IOT_Static) && (!objectStatusPtr->Indestructable) && (!objectStatusPtr->lifespanTimer))
7299 			{
7300 				if(objectsToSkip>0)
7301 				{
7302 					objectsToSkip--;
7303 					continue;
7304 				}
7305 				status = ReadFragmentStatus(fragNumber++);
7306 
7307 				if (status) /* should exist */
7308 				{
7309 					#if 0
7310 					/* so if it doesn't exist, respawn it */
7311 					if(objectStatusPtr->respawnTimer!=0)
7312 					{
7313 						RespawnInanimateObject(sbPtr);
7314 						objectStatusPtr->respawnTimer=0;
7315 					}
7316 					#endif
7317 				}
7318 				else /* shouldn't exist */
7319 				{
7320 					if(objectStatusPtr->respawnTimer==0)
7321 					{
7322 						extern void KillFragmentalObjectForRespawn(STRATEGYBLOCK *sbPtr);
7323 						KillFragmentalObjectForRespawn(sbPtr);
7324 					}
7325 				}
7326 			}
7327 		}
7328 		else if(sbPtr->I_SBtype == I_BehaviourPlacedLight)
7329 		{
7330 			PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = sbPtr->SBdataptr;
7331 			LOCALASSERT(pl_bhv);
7332 
7333 			if(!pl_bhv->Indestructable)
7334 			{
7335 				if(objectsToSkip>0)
7336 				{
7337 					objectsToSkip--;
7338 					continue;
7339 				}
7340 				status = ReadFragmentStatus(fragNumber++);
7341 
7342 				if (status) /* should exist */
7343 				{
7344 					#if 0
7345 					/* so if it doesn't exist, respawn it */
7346 					if(pl_bhv->state==Light_State_Broken)
7347 					{
7348 						RespawnInanimateObject(sbPtr);
7349 						objectStatusPtr->respawnTimer=0;
7350 					}
7351 					#endif
7352 				}
7353 				else /* shouldn't exist */
7354 				{
7355 					if(pl_bhv->state!=Light_State_Broken)
7356 					{
7357 						KillLightForRespawn(sbPtr);
7358 					}
7359 				}
7360 			}
7361 
7362 		}
7363 
7364 		if(fragNumber>=(NUMBER_OF_FRAGMENTAL_OBJECTS<<3))break;
7365 
7366 	}
7367 }
7368 
ProcessNetMsg_StrategySynch(NETMESSAGE_STRATEGYSYNCH * messagePtr)7369 static void ProcessNetMsg_StrategySynch(NETMESSAGE_STRATEGYSYNCH *messagePtr)
7370 {
7371 	int i;
7372 	int objectNumber=0;
7373 	int objectsToSkip=messagePtr->BatchNumber*(NUMBER_OF_STRATEGIES_TO_SYNCH);
7374 
7375 	if(netGameData.myGameState!=NGS_Playing) return;
7376 	LOCALASSERT(AvP.Network!=I_No_Network);
7377 
7378 	if(!netGameData.myStrategyCheckSum) netGameData.myStrategyCheckSum=GetStrategySynchObjectChecksum();
7379 	if(messagePtr->strategyCheckSum!=netGameData.myStrategyCheckSum)
7380 	{
7381 		//strategies are obviously different from those on the host's machine
7382 		textprint("Strategy checksums don't match");
7383 		return;
7384 	}
7385 
7386 	for (i=0; i<NUMBER_OF_STRATEGIES_TO_SYNCH>>2; i++)
7387 	{
7388 		StrategySynchArray[i] = messagePtr->StatusBitfield[i];
7389 	}
7390 
7391 	for (i=0; i<NumActiveStBlocks; i++)
7392 	{
7393 		STRATEGYBLOCK *sbPtr = ActiveStBlockList[i];
7394 
7395 		if(sbPtr->I_SBtype == I_BehaviourBinarySwitch ||
7396 		   sbPtr->I_SBtype == I_BehaviourLinkSwitch ||
7397 		   sbPtr->I_SBtype == I_BehaviourTrackObject)
7398 		{
7399 
7400 			if(objectsToSkip>0)
7401 			{
7402 				objectsToSkip--;
7403 				continue;
7404 			}
7405 
7406 			switch(sbPtr->I_SBtype)
7407 			{
7408 				case I_BehaviourBinarySwitch :
7409 		 			BinarySwitchSetSynchData(sbPtr,ReadStrategySynch(objectNumber++));
7410 					break;
7411 				case I_BehaviourLinkSwitch :
7412 		 			LinkSwitchSetSynchData(sbPtr,ReadStrategySynch(objectNumber++));
7413 					break;
7414 				case I_BehaviourTrackObject :
7415 		 			TrackObjectSetSynchData(sbPtr,ReadStrategySynch(objectNumber++));
7416 					break;
7417 				default:
7418 					break;
7419 			}
7420 
7421 		}
7422 
7423 		if(objectNumber>=(NUMBER_OF_STRATEGIES_TO_SYNCH))break;
7424 
7425 	}
7426 }
7427 
ProcessNetMsg_LocalObjectOnFire(NETMESSAGE_LOBONFIRE * messagePtr,DPID senderId)7428 static void ProcessNetMsg_LocalObjectOnFire(NETMESSAGE_LOBONFIRE *messagePtr, DPID senderId)
7429 {
7430 	/* only do this if we're playing */
7431 	if(netGameData.myGameState!=NGS_Playing) return;
7432 
7433 	/* This message is for the player who owns the object, so first check
7434 	if the message is meant for us */
7435 	if(messagePtr->playerId != AVPDPNetID) return;
7436 
7437 	/* next we have to find this object in our strategyblock list */
7438 	{
7439 		int objectId;
7440 		STRATEGYBLOCK *sbPtr;
7441 
7442 		objectId = (int)messagePtr->objectId;
7443 		sbPtr = FindObjectFromNetIndex(objectId);
7444 
7445 		/* check if we have found an sb: if not the object has probably been
7446 		destroyed already, so just ignore it */
7447 		if(sbPtr)
7448 		{
7449 			sbPtr->SBDamageBlock.IsOnFire=1;
7450 			if (sbPtr == Player->ObStrategyBlock)
7451 			{
7452 				myIgniterId=senderId;
7453 				PlayerStatusPtr->fireTimer=PLAYER_ON_FIRE_TIME;
7454 			}
7455 			else if(sbPtr->I_SBtype==I_BehaviourAlien)
7456 			{
7457 				//need to note who burnt this alien
7458 				ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr;
7459 				alienStatus->aliensIgniterId=senderId;
7460 			}
7461 		}
7462 	}
7463 }
7464 
ProcessNetMsg_AlienAIState(NETMESSAGE_ALIENAISTATE * messagePtr,DPID senderId)7465 static void ProcessNetMsg_AlienAIState(NETMESSAGE_ALIENAISTATE *messagePtr, DPID senderId)
7466 {
7467 	STRATEGYBLOCK *sbPtr;
7468 	int objectId;
7469 	VECTORCH position;
7470 	EULER orientation;
7471 
7472 	/* only do this if we're playing */
7473 	if(netGameData.myGameState!=NGS_Playing) return;
7474 
7475 	/* get the object id from the message */
7476 	objectId = (int)messagePtr->Guid;
7477 
7478 	sbPtr = FindGhost(senderId, objectId);
7479 
7480 	position.vx = messagePtr->xPos;
7481 	orientation.EulerX = (messagePtr->xOrient<<NET_EULERSCALESHIFT);
7482 	position.vy = messagePtr->yPos;
7483 	orientation.EulerY = (messagePtr->yOrient<<NET_EULERSCALESHIFT);
7484 	position.vz = messagePtr->zPos;
7485 	orientation.EulerZ = (messagePtr->zOrient<<NET_EULERSCALESHIFT);
7486 
7487 	if(!sbPtr)
7488 	{
7489 		/* we don't seem to have a ghost for this object, so create one */
7490 		sbPtr = CreateNetGhost(senderId,objectId,&position,&orientation,I_BehaviourAlien, IOT_Non,messagePtr->AlienType);
7491 	}
7492 	else
7493 	{
7494 		/* update the ghost... */
7495 		MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire);
7496 		/* NB don't need to update the object type */
7497 		UpdateAlienAIGhost(sbPtr,&position,&orientation,messagePtr->sequence_type,messagePtr->sub_sequence,messagePtr->sequence_length<<8);
7498 	}
7499 
7500 	#if EXTRAPOLATION_TEST
7501 	if(sbPtr)
7502 	{
7503 		NETGHOSTDATABLOCK *ghostData;
7504 		VECTORCH velocity;
7505 		int diff;
7506 		int playerTimer;
7507 		int playerIndex = PlayerIdInPlayerList(senderId);
7508 		if (playerIndex==NET_IDNOTINPLAYERLIST) return;
7509 
7510 		ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
7511 		GLOBALASSERT(ghostData);
7512 
7513 		playerTimer=netGameData.playerData[playerIndex].timer;
7514 
7515 		velocity.vx=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat31,messagePtr->speed);
7516 		velocity.vy=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat32,messagePtr->speed);
7517 		velocity.vz=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat33,messagePtr->speed);
7518 
7519 		diff=Approximate3dMagnitude(&ghostData->velocity)-Approximate3dMagnitude(&velocity);
7520 
7521 		if(diff>1500 || -diff>1500)
7522 		{
7523 			//change in velocity , so reset extrapolation timer
7524 			ghostData->extrapTimer=-ONE_FIXED;
7525 		}
7526 
7527 		ghostData->velocity=velocity;
7528 		ghostData->extrapTimerLast=0;
7529 		if(playerTimer>=ghostData->lastTimeRead)
7530 		{
7531 			ghostData->extrapTimer-=(playerTimer-ghostData->lastTimeRead);
7532 		}
7533 		else
7534 		{
7535 			ghostData->extrapTimer=-ONE_FIXED;
7536 		}
7537 		ghostData->lastTimeRead=playerTimer;
7538 
7539 		sbPtr->DynPtr->UseStandardGravity=messagePtr->standard_gravity;
7540 		if(!sbPtr->DynPtr->UseStandardGravity)
7541 		{
7542 			if(sbPtr->DynPtr->GravityDirection.vy==ONE_FIXED)
7543 			{
7544 				MATRIXCH mat;
7545 				//alien is crawling , so we need to get an appropriate gravity direction
7546 				CreateEulerMatrix(&orientation,&mat);
7547 				sbPtr->DynPtr->GravityDirection.vx=mat.mat12;
7548 				sbPtr->DynPtr->GravityDirection.vy=mat.mat22;
7549 				sbPtr->DynPtr->GravityDirection.vz=mat.mat32;
7550 			}
7551 
7552 			sbPtr->DynPtr->LinImpulse.vx=0;
7553 			sbPtr->DynPtr->LinImpulse.vy=0;
7554 			sbPtr->DynPtr->LinImpulse.vz=0;
7555 
7556 			sbPtr->DynPtr->ToppleForce=TOPPLE_FORCE_ALIEN;
7557 		}
7558 
7559 	}
7560 	#endif
7561 
7562 }
7563 
7564 /* CDF 24/8/98 A better message. */
ProcessNetMsg_AlienAISequenceChange(NETMESSAGE_ALIENSEQUENCECHANGE * messagePtr,DPID senderId)7565 static void ProcessNetMsg_AlienAISequenceChange(NETMESSAGE_ALIENSEQUENCECHANGE *messagePtr, DPID senderId)
7566 {
7567 	STRATEGYBLOCK *sbPtr;
7568 	int objectId;
7569 
7570 	/* only do this if we're playing */
7571 	if(netGameData.myGameState!=NGS_Playing) return;
7572 
7573 	/* get the object id from the message */
7574 	objectId = (int)messagePtr->Guid;
7575 
7576 	sbPtr = FindGhost(senderId, objectId);
7577 	if(!sbPtr)
7578 	{
7579 		/* Gordon Bennet.  Return, then. */
7580 		return;
7581 	}
7582 	else
7583 	{
7584 		int sequence_length,tweening_time;
7585 		/* update the ghost... */
7586 
7587 		if(messagePtr->sequence_length==-1)
7588 			sequence_length=-1;
7589 		else
7590 			sequence_length=messagePtr->sequence_length<<8;
7591 
7592 		if(messagePtr->tweening_time==-1)
7593 			tweening_time=-1;
7594 		else
7595 			tweening_time=messagePtr->tweening_time<<8;
7596 
7597 		UpdateAlienAIGhostAnimSequence(sbPtr,messagePtr->sequence_type,messagePtr->sub_sequence,sequence_length,tweening_time);
7598 	}
7599 }
7600 
ProcessNetMsg_AlienAIKilled(NETMESSAGE_ALIENAIKILLED * messagePtr,DPID senderId)7601 static void ProcessNetMsg_AlienAIKilled(NETMESSAGE_ALIENAIKILLED *messagePtr, DPID senderId)
7602 {
7603 	STRATEGYBLOCK *sbPtr;
7604 	int objectId;
7605 
7606 	/* only do this if we're playing */
7607 	if(netGameData.myGameState!=NGS_Playing) return;
7608 
7609 	Inform_AiHasDied(messagePtr->killerId,messagePtr->AlienType,messagePtr->weaponIcon);
7610 
7611 	{
7612 		int killerIndex=PlayerIdInPlayerList(messagePtr->killerId);
7613 		if(killerIndex!=NET_IDNOTINPLAYERLIST)
7614 		{
7615 			netGameData.playerData[killerIndex].aliensKilled[messagePtr->AlienType]=messagePtr->killCount;
7616 		}
7617 	}
7618 
7619 	/* get the object id from the message */
7620 	objectId = (int)messagePtr->Guid;
7621 
7622 	sbPtr = FindGhost(senderId, objectId);
7623 	if(!sbPtr)
7624 	{
7625 		/* Gordon Bennet.  Return, then. It's not that important. */
7626 		return;
7627 	}
7628 	else
7629 	{
7630 		/* 'update' the ghost... */
7631 		KillAlienAIGhost(sbPtr,messagePtr->death_code,messagePtr->death_time,messagePtr->GibbFactor);
7632 	}
7633 }
7634 
ProcessNetMsg_FarAlienPosition(NETMESSAGE_FARALIENPOSITION * messagePtr,DPID senderId)7635 static void ProcessNetMsg_FarAlienPosition(NETMESSAGE_FARALIENPOSITION *messagePtr, DPID senderId)
7636 {
7637 	STRATEGYBLOCK* sbPtr;
7638 	EULER orientation={0,0,0};
7639 	VECTORCH position;
7640 	AIMODULE* targetModule=0;
7641 
7642 	/* only do this if we're playing */
7643 	if(netGameData.myGameState!=NGS_Playing) return;
7644 
7645 	//make sure the target module index is in range
7646 	if(messagePtr->targetModuleIndex>=AIModuleArraySize) return;
7647 	targetModule = &AIModuleArray[messagePtr->targetModuleIndex];
7648 
7649 	if(messagePtr->indexIsModuleIndex)
7650 	{
7651 		FARENTRYPOINT *targetEntryPoint;
7652 		AIMODULE *startModule=0;
7653 		//The alien is located at an entry point , the second index is the source module index
7654 		//Make sure it is a valid module index
7655 		if(messagePtr->index>=AIModuleArraySize) return;
7656 		startModule = &AIModuleArray[messagePtr->index];
7657 
7658 		//find the appropriate entry point
7659 		targetEntryPoint = GetAIModuleEP(targetModule,startModule);
7660 
7661 		if(!targetEntryPoint) return; //forget it then
7662 
7663 		//found the alien's location (relative to module)
7664 		position=targetEntryPoint->position;
7665 
7666 	}
7667 	else
7668 	{
7669 		//The alien is at one of the modules auxilary locations
7670 		int noOfAuxLocs = FALLP_AuxLocs[messagePtr->targetModuleIndex].numLocations;
7671 		VECTORCH *auxLocsList = FALLP_AuxLocs[messagePtr->targetModuleIndex].locationsList;
7672 
7673 		//make sure we have a valid index
7674 		if(messagePtr->index>=noOfAuxLocs) return;
7675 
7676 		//found the alien's location (relative to module)
7677 		position=auxLocsList[messagePtr->index];
7678 	}
7679 	//convert the position into a world position
7680 	position.vx += targetModule->m_world.vx;
7681 	position.vy += targetModule->m_world.vy;
7682 	position.vz += targetModule->m_world.vz;
7683 
7684 
7685 	//find the alien
7686 	sbPtr = FindGhost(senderId, messagePtr->Guid);
7687 
7688 	if(!sbPtr)
7689 	{
7690 		//need to create a new ghost then
7691 		sbPtr = CreateNetGhost(senderId,messagePtr->Guid,&position,&orientation,I_BehaviourAlien, IOT_Non,messagePtr->alienType);
7692 	}
7693 
7694 	if(sbPtr)
7695 	{
7696 		NETGHOSTDATABLOCK *ghostData;
7697 		ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
7698 		GLOBALASSERT(ghostData);
7699 		//make sure this is a ghost of an alien
7700 		if(ghostData->type!=I_BehaviourAlien) return;
7701 
7702 		//update the position , and mark it as valid for far use only
7703 		ghostData->onlyValidFar=1;
7704 
7705 		sbPtr->DynPtr->Position=position;
7706 		sbPtr->DynPtr->PrevPosition=position;
7707 
7708 		sbPtr->DynPtr->LinVelocity.vx=0;
7709 		sbPtr->DynPtr->LinVelocity.vy=0;
7710 		sbPtr->DynPtr->LinVelocity.vz=0;
7711 
7712 		sbPtr->DynPtr->LinImpulse.vx=0;
7713 		sbPtr->DynPtr->LinImpulse.vy=0;
7714 		sbPtr->DynPtr->LinImpulse.vz=0;
7715 
7716 		//make sure the alien is far
7717 		if(sbPtr->SBdptr) MakeGhostFar(sbPtr);
7718 
7719 	}
7720 }
7721 
GetSizeOfGhostHierarchyDamagedMessage(char * messagePtr)7722 static int GetSizeOfGhostHierarchyDamagedMessage(char *messagePtr)
7723 {
7724 	int size=sizeof(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER);
7725 	NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER *messageHeader =(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER*) messagePtr;
7726 
7727 	if(messageHeader->damageProfile) size+=sizeof(NETMESSAGE_DAMAGE_PROFILE);
7728 	if(messageHeader->multiple) size+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE);
7729 	if(messageHeader->sectionID) size+=sizeof(NETMESSAGE_DAMAGE_SECTION);
7730 	if(messageHeader->direction) size+=sizeof(NETMESSAGE_DAMAGE_DIRECTION);
7731 
7732 	return size;
7733 }
7734 
ProcessNetMsg_GhostHierarchyDamaged(char * messagePtr,DPID senderId)7735 static void ProcessNetMsg_GhostHierarchyDamaged(char *messagePtr, DPID senderId)
7736 {
7737 	NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER *messageHeader=0;
7738 	NETMESSAGE_DAMAGE_PROFILE *messageProfile=0;
7739 	NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0;
7740 	NETMESSAGE_DAMAGE_SECTION *messageSection=0;
7741 	NETMESSAGE_DAMAGE_DIRECTION *messageDirection=0;
7742 
7743 	STRATEGYBLOCK *sbPtr;
7744 	int objectId;
7745 	NETGHOSTDATABLOCK *ghostData;
7746 	VECTORCH direction;
7747 	VECTORCH incoming;
7748 	VECTORCH* incoming_ptr=0;
7749 
7750 	/* only do this if we're playing */
7751 	if(netGameData.myGameState!=NGS_Playing) return;
7752 
7753 	messageHeader=(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER*) messagePtr;
7754 	messagePtr+=sizeof(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER);
7755 
7756 	//find out which elements of the damage message have been sent
7757 	if(messageHeader->damageProfile)
7758 	{
7759 		messageProfile=(NETMESSAGE_DAMAGE_PROFILE*) messagePtr;
7760 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_PROFILE);
7761 	}
7762 	if(messageHeader->multiple)
7763 	{
7764 		messageMultiple=(NETMESSAGE_DAMAGE_MULTIPLE*) messagePtr;
7765 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE);
7766 	}
7767 	if(messageHeader->sectionID)
7768 	{
7769 		messageSection=(NETMESSAGE_DAMAGE_SECTION*) messagePtr;
7770 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_SECTION);
7771 	}
7772 	if(messageHeader->direction)
7773 	{
7774 		messageDirection=(NETMESSAGE_DAMAGE_DIRECTION*) messagePtr;
7775 		messagePtr+=sizeof(NETMESSAGE_DAMAGE_DIRECTION);
7776 	}
7777 
7778 	/* get the object id from the message */
7779 	objectId = (int)messageHeader->Guid;
7780 
7781 	sbPtr = FindGhost(senderId, objectId);
7782 	if(!sbPtr)
7783 	{
7784 		/* Gordon Bennet.  Return, then. It's not that important. */
7785 		return;
7786 	}
7787 	else
7788 	{
7789 		DAMAGE_PROFILE damage;
7790 		int multiple;
7791 
7792 		/* damage the ghost... */
7793 		SECTION_DATA *section_data=NULL;
7794 		HMODELCONTROLLER *controller=NULL;
7795 
7796 		ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
7797 
7798 		//fill out damage profile
7799 		damage.Id=messageHeader->ammo_id;
7800 		if(messageProfile)
7801 		{
7802 			damage.Impact = messageProfile->Impact;
7803 			damage.Cutting = messageProfile->Cutting;
7804 			damage.Penetrative = messageProfile->Penetrative;
7805 			damage.Fire = messageProfile->Fire;
7806 			damage.Electrical = messageProfile->Electrical;
7807 			damage.Acid = messageProfile->Acid;
7808 
7809 			damage.ExplosivePower=messageProfile->ExplosivePower;
7810 			damage.Slicing=messageProfile->Slicing;
7811 			damage.ProduceBlood=messageProfile->ProduceBlood;
7812 			damage.ForceBoom=messageProfile->ForceBoom;
7813 
7814 			damage.BlowUpSections=messageProfile->BlowUpSections;
7815 			damage.Special=messageProfile->Special;
7816 			damage.MakeExitWounds=messageProfile->MakeExitWounds;
7817 		}
7818 		else
7819 		{
7820 			GLOBALASSERT(damage.Id>AMMO_NONE && damage.Id<MAX_NO_OF_AMMO_TEMPLATES);
7821 			damage=TemplateAmmo[damage.Id].MaxDamage[AvP.Difficulty];
7822 		}
7823 
7824 		if(messageMultiple)
7825 		{
7826 			multiple = messageMultiple->multiple;
7827 		}
7828 		else
7829 		{
7830 			multiple = ONE_FIXED;
7831 		}
7832 
7833 		if(sbPtr->DynPtr && messageDirection)
7834 		{
7835 
7836 
7837 			if(messageDirection->direction_x ||
7838 			   messageDirection->direction_y ||
7839 			   messageDirection->direction_z)
7840 			{
7841 				MATRIXCH mat=sbPtr->DynPtr->OrientMat;
7842 				TransposeMatrixCH(&mat);
7843 
7844 				//extract the direction vector
7845 				incoming.vx=messageDirection->direction_x;
7846 				incoming.vy=messageDirection->direction_y;
7847 				incoming.vz=messageDirection->direction_z;
7848 				//normalise it
7849 				Normalise(&incoming);
7850 				direction=incoming;
7851 
7852 				//and rotate it from world space to the object's local space
7853 				RotateVector(&incoming,&mat);
7854 
7855 				//set the incoming pointer
7856 				incoming_ptr=&incoming;
7857 
7858 			}
7859 
7860 		}
7861 
7862 
7863 		if (messageSection && messageSection->SectionID!=-1) {
7864 			/* Hmm. */
7865 
7866 			controller=&ghostData->HModelController;
7867 			section_data=GetThisSectionData_FromID(ghostData->HModelController.section_data,
7868 				messageSection->SectionID);
7869 		}
7870 
7871 		if (section_data)
7872 		{
7873 			DISPLAYBLOCK *fragged_section=0;
7874 
7875 			fragged_section=CauseDamageToHModel(controller,sbPtr,(&damage),
7876 								multiple,section_data,incoming_ptr,NULL,1);
7877 
7878 			if(fragged_section && damage.Id==AMMO_PRED_RIFLE && incoming_ptr)
7879 			{
7880 				//a speargun has fragged off a body part , so we need to create a spear
7881 				CreateSpearPossiblyWithFragment(fragged_section,&fragged_section->ObWorld,&direction);
7882 			}
7883 		}
7884 	}
7885 }
7886 
7887 
ProcessNetMsg_Gibbing(NETMESSAGE_GIBBING * messagePtr,DPID senderId)7888 static void ProcessNetMsg_Gibbing(NETMESSAGE_GIBBING *messagePtr,DPID senderId)
7889 {
7890 	STRATEGYBLOCK *sbPtr;
7891 	int objectId;
7892 	NETGHOSTDATABLOCK *ghostData;
7893 
7894 	/* only do this if we're playing */
7895 	if(netGameData.myGameState!=NGS_Playing) return;
7896 
7897 	/* get the object id from the message */
7898 	objectId = (int)messagePtr->Guid;
7899 
7900 	sbPtr = FindGhost(senderId, objectId);
7901 	if(!sbPtr)
7902 	{
7903 		/* Gordon Bennet.  Return, then. It's not that important. */
7904 		return;
7905 	}
7906 	else
7907 	{
7908 		ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
7909 
7910 		//only interested in gibbing corpses
7911 		if(ghostData->type!=I_BehaviourNetCorpse) return;
7912 
7913 		//use the random number seed
7914 		SetSeededFastRandom(messagePtr->seed);
7915 		//now do the gibbing
7916 		if (messagePtr->gibbFactor>0)
7917 		{
7918 			Extreme_Gibbing(sbPtr,ghostData->HModelController.section_data,messagePtr->gibbFactor);
7919 		}
7920 		else if (messagePtr->gibbFactor<0)
7921 		{
7922 			KillRandomSections(ghostData->HModelController.section_data,-(messagePtr->gibbFactor));
7923 		}
7924 
7925 	}
7926 }
7927 
ProcessNetMsg_SpotAlienSound(NETMESSAGE_SPOTALIENSOUND * messagePtr,DPID senderId)7928 static void ProcessNetMsg_SpotAlienSound(NETMESSAGE_SPOTALIENSOUND *messagePtr, DPID senderId)
7929 {
7930 	VECTORCH position;
7931 
7932 	/* only do this if we're playing */
7933 	if(netGameData.myGameState!=NGS_Playing) return;
7934 
7935 	/* Just play the thing. */
7936 
7937 
7938 
7939 	position.vx=messagePtr->vx;
7940 	position.vy=messagePtr->vy;
7941 	position.vz=messagePtr->vz;
7942 
7943 	PlayAlienSound((int)messagePtr->alienType,(int)messagePtr->soundCategory,messagePtr->pitch,NULL,&position);
7944 }
7945 
ProcessNetMsg_CreateWeapon(NETMESSAGE_CREATEWEAPON * messagePtr)7946 static void ProcessNetMsg_CreateWeapon(NETMESSAGE_CREATEWEAPON * messagePtr)
7947 {
7948 	/* if we're not playing, ignore it */
7949 	if(netGameData.myGameState!=NGS_Playing) return;
7950 
7951 	//create the weapon
7952 	CreateMultiplayerWeaponPickup(&messagePtr->location,messagePtr->type,&messagePtr->name[0]);
7953 }
7954 
ProcessNetMsg_SpotOtherSound(NETMESSAGE_SPOTOTHERSOUND * messagePtr,DPID senderId)7955 static void ProcessNetMsg_SpotOtherSound(NETMESSAGE_SPOTOTHERSOUND *messagePtr, DPID senderId)
7956 {
7957 	VECTORCH position;
7958 
7959 	/* only do this if we're playing */
7960 	if(netGameData.myGameState!=NGS_Playing) return;
7961 
7962 	/* Just play the thing. */
7963 
7964 	position.vx=messagePtr->vx;
7965 	position.vy=messagePtr->vy;
7966 	position.vz=messagePtr->vz;
7967 
7968 	PlayOtherSound(messagePtr->SoundIndex,&position,messagePtr->explosion);
7969 }
7970 
7971 /*----------------------------------------------------------------------
7972   These support functions are used to examine the current game state
7973   ----------------------------------------------------------------------*/
7974 
7975 /* returns index if the given DPID is in the player list */
PlayerIdInPlayerList(DPID Id)7976 int PlayerIdInPlayerList(DPID Id)
7977 {
7978 	int i;
7979 	/* check first, if we've been passed a null id */
7980 	if(Id==0) return NET_IDNOTINPLAYERLIST;
7981 
7982 	/* check player list */
7983 	for(i=0;i<NET_MAXPLAYERS;i++)
7984 	{
7985 		if(netGameData.playerData[i].playerId == Id) return i;
7986 	}
7987 
7988 	/* failed to find Id */
7989 	return NET_IDNOTINPLAYERLIST;
7990 }
7991 
7992 /* returns true if there are any empty slots */
EmptySlotInPlayerList(void)7993 int EmptySlotInPlayerList(void)
7994 {
7995 	int i;
7996 
7997 	for(i=0;i<NET_MAXPLAYERS;i++)
7998 	{
7999 		if(netGameData.playerData[i].playerId == 0) return i;
8000 	}
8001 	return NET_NOEMPTYSLOTINPLAYERLIST;
8002 }
8003 
8004 /* Finds the local strategy block who's network object id is that passed */
FindObjectFromNetIndex(int obIndex)8005 static STRATEGYBLOCK *FindObjectFromNetIndex(int obIndex)
8006 {
8007 	extern int NumActiveStBlocks;
8008 	extern STRATEGYBLOCK *ActiveStBlockList[];
8009 	int sbIndex = 0;
8010 	/* first of all, check for index "GHOST_PLAYEROBJECTID": that's the player */
8011 	if(obIndex==GHOST_PLAYEROBJECTID)
8012 	{
8013 		return (Player->ObStrategyBlock);
8014 	}
8015 
8016 	while(sbIndex < NumActiveStBlocks)
8017 	{
8018 		STRATEGYBLOCK *sbPtr = ActiveStBlockList[sbIndex++];
8019 		/* need to be careful here: netIndexes maybe the same as pre-assigned names
8020 		for global objects, therefore we must check the type of the object */
8021 		if((sbPtr->I_SBtype == I_BehaviourRocket)||
8022 		   (sbPtr->I_SBtype == I_BehaviourGrenade)||
8023 		   (sbPtr->I_SBtype == I_BehaviourPulseGrenade)||
8024 		   (sbPtr->I_SBtype == I_BehaviourFragmentationGrenade)||
8025 		   (sbPtr->I_SBtype == I_BehaviourFlareGrenade)||
8026 		   (sbPtr->I_SBtype == I_BehaviourPredatorEnergyBolt)||
8027 		   (sbPtr->I_SBtype == I_BehaviourFrisbeeEnergyBolt)||
8028 		   (sbPtr->I_SBtype == I_BehaviourPPPlasmaBolt)||
8029 		   (sbPtr->I_SBtype == I_BehaviourSpeargunBolt)||
8030 		   (sbPtr->I_SBtype == I_BehaviourClusterGrenade)||
8031 		   (sbPtr->I_SBtype == I_BehaviourNPCPredatorDisc)||
8032 		   (sbPtr->I_SBtype == I_BehaviourPredatorDisc_SeekTrack)||
8033 		   (sbPtr->I_SBtype == I_BehaviourAlienSpit)||
8034 		   (sbPtr->I_SBtype == I_BehaviourAutoGun)||
8035 		   (sbPtr->I_SBtype == I_BehaviourAlien)||
8036 		   (sbPtr->I_SBtype == I_BehaviourNetCorpse)||
8037 		   (sbPtr->I_SBtype == I_BehaviourInanimateObject)||
8038 		   (sbPtr->I_SBtype == I_BehaviourProximityGrenade))
8039 		{
8040 			int *sbIdPtr = (int *)(&(sbPtr->SBname[4]));
8041 			if(*sbIdPtr == obIndex) return sbPtr;
8042 		}
8043 	}
8044 	return (STRATEGYBLOCK *)0;
8045 }
8046 
8047 /* Finds the inanimate objects strategy block who's name is passed */
8048 /* NB must be careful finding obejcts from their name: local and global objects may end up
8049 with the same name, so we must make sure we differentiate between them... */
FindEnvironmentObjectFromName(char * name)8050 static STRATEGYBLOCK *FindEnvironmentObjectFromName(char *name)
8051 {
8052 	extern int NumActiveStBlocks;
8053 	extern STRATEGYBLOCK *ActiveStBlockList[];
8054 	int sbIndex = 0;
8055 
8056 	while(sbIndex < NumActiveStBlocks)
8057 	{
8058 		STRATEGYBLOCK *sbPtr = ActiveStBlockList[sbIndex++];
8059 
8060 		if((sbPtr->I_SBtype==I_BehaviourInanimateObject)||
8061 			(sbPtr->I_SBtype==I_BehaviourPlatform)||
8062 			(sbPtr->I_SBtype==I_BehaviourPlacedLight)||
8063 			(sbPtr->I_SBtype==I_BehaviourBinarySwitch))
8064 		{
8065 		   if(NAME_ISEQUAL((&(sbPtr->SBname[0])),(name))) return sbPtr;
8066 		}
8067 	}
8068 	return (STRATEGYBLOCK *)0;
8069 }
8070 
8071 
8072 /* asigns an object id to a strategyblock, such as a projectile */
8073 #if 0
8074 void AddNetGameObjectID(STRATEGYBLOCK *sbPtr)
8075 {
8076 	int *sbIdPtr = (int *)(&(sbPtr->SBname[0]));
8077 
8078 	*sbIdPtr = netNextLocalObjectId++;
8079 }
8080 #endif
8081 
8082 
8083 /* called by host only: updates the scores for a described kill, and sends a
8084 game score update message */
8085 
UpdateNetworkGameScores(DPID playerKilledId,DPID killerId,NETGAME_CHARACTERTYPE playerKilledType,NETGAME_CHARACTERTYPE killerType)8086 static void UpdateNetworkGameScores(DPID playerKilledId, DPID killerId,NETGAME_CHARACTERTYPE playerKilledType,NETGAME_CHARACTERTYPE killerType)
8087 {
8088 	int playerKilledIndex;
8089 	int killerIndex;
8090 	int scoreForKill;
8091 	int i;
8092 
8093 	LOCALASSERT(AvP.Network==I_Host);
8094 	if(netGameData.myGameState != NGS_Playing) return;
8095 
8096 
8097 	/* get the index of the player who has been killed. If they're not in
8098 	the player list, can't have been killed ! */
8099 	playerKilledIndex = PlayerIdInPlayerList(playerKilledId);
8100 	if(playerKilledIndex==NET_IDNOTINPLAYERLIST) return;
8101 
8102 	if(killerId==0 || killerId == playerKilledId || killerType>=NGCT_AI_Alien)
8103 	{
8104 		//suicide
8105 		killerIndex=playerKilledIndex;
8106 
8107 		//record player's death for purposes of adjusting difficulty.
8108 		//(assuming that optionis being used)
8109 		GeneratorBalance_NotePlayerDeath();
8110 
8111 	}
8112 	else
8113 	{
8114 		killerIndex = PlayerIdInPlayerList(killerId);
8115 		if(killerIndex==NET_IDNOTINPLAYERLIST) return;
8116 	}
8117 
8118 	if(killerType>=NGCT_AI_Alien)
8119 	{
8120 		//update deaths from AI;
8121 		netGameData.playerData[playerKilledIndex].deathsFromAI++;
8122 
8123 	}
8124 	else
8125 	{
8126 	//update frag count;
8127 		netGameData.playerData[killerIndex].playerFrags[playerKilledIndex]++;
8128 	}
8129 
8130 	//update overall number of kills
8131 	netGameData.numDeaths[playerKilledType]++;
8132 
8133 
8134 	if(netGameData.gameType==NGT_LastManStanding)
8135 	{
8136 		if(killerType==NGCT_Alien || killerIndex==playerKilledIndex)
8137 		{
8138 			if(playerKilledType!=NGCT_Alien)
8139 			{
8140 				int marineCount=0;
8141 				int marineIndex;
8142 
8143 				//give a point to the alien for killing a marine
8144 				if(killerType==NGCT_Alien)
8145 				{
8146 					netGameData.playerData[killerIndex].playerScore+=1;
8147 				}
8148 
8149 				//also give a point to every surviving marine
8150 				for(i=0;i<NET_MAXPLAYERS;i++)
8151 				{
8152 					if(i==playerKilledIndex) continue;
8153 					if(netGameData.playerData[i].playerId)
8154 					{
8155 						if(netGameData.playerData[i].characterType!=NGCT_Alien)
8156 						{
8157 							marineCount++;
8158 							marineIndex=i;
8159 
8160 							netGameData.playerData[i].playerScore+=1;
8161 							AddNetMsg_ScoreChange(i,i);
8162 						}
8163 					}
8164 				}
8165 				if(marineCount==1)
8166 				{
8167 					//only one marine left , tell everyone
8168 					AddNetMsg_PlayerID(netGameData.playerData[marineIndex].playerId,NetMT_LastManStanding_LastMan);
8169 					Handle_LastManStanding_LastMan(netGameData.playerData[marineIndex].playerId);
8170 
8171 				}
8172 
8173 			}
8174 		}
8175 		else
8176 		{
8177 
8178 
8179 			if(playerKilledType!=NGCT_Alien)
8180 			{
8181 				//lose a point for killing a marine
8182 				netGameData.playerData[killerIndex].playerScore-=1;
8183 
8184 			}
8185 			else
8186 			{
8187 				//if we're the last marine gain a point for killing an alien
8188 				for(i=0;i<NET_MAXPLAYERS;i++)
8189 				{
8190 					if(i==killerIndex) continue;
8191 					if(netGameData.playerData[i].playerId)
8192 					{
8193 						if(netGameData.playerData[i].characterType!=NGCT_Alien)
8194 						{
8195 							break;
8196 						}
8197 					}
8198 				}
8199 				if(i==NET_MAXPLAYERS)
8200 				{
8201 					netGameData.playerData[killerIndex].playerScore+=1;
8202 				}
8203 
8204 
8205 			}
8206 		}
8207 	}
8208 	else if(netGameData.gameType==NGT_Coop)
8209 	{
8210 		//do nothing
8211 	}
8212 	else
8213 	{
8214 		NETGAME_CHARACTERTYPE playerKilledCopy=netGameData.playerData[playerKilledIndex].characterType;
8215 		NETGAME_CHARACTERTYPE killerCopy=netGameData.playerData[killerIndex].characterType;
8216 
8217 		//temporarily set the character types to what they were at the time of death
8218 		netGameData.playerData[playerKilledIndex].characterType=playerKilledType;
8219 		netGameData.playerData[killerIndex].characterType=killerType;
8220 
8221 		//get score for this kill
8222 		scoreForKill=GetNetScoreForKill(playerKilledIndex,killerIndex);
8223 
8224 		//restore character types
8225 		netGameData.playerData[playerKilledIndex].characterType=playerKilledCopy;
8226 		netGameData.playerData[killerIndex].characterType=killerCopy;
8227 
8228 		//update score
8229 		netGameData.playerData[killerIndex].playerScore+=scoreForKill;
8230 		if(scoreForKill>0)
8231 		{
8232 			//note score against person being killed
8233 			netGameData.playerData[playerKilledIndex].playerScoreAgainst+=scoreForKill;
8234 		}
8235 		else
8236 		{
8237 			netGameData.playerData[killerIndex].playerScoreAgainst+=scoreForKill;
8238 		}
8239 
8240 		if(netGameData.gameType==NGT_CoopDeathmatch)
8241 		{
8242 			//need to adjust the species scores as well
8243 			netGameData.teamScores[killerType]+=scoreForKill;
8244 			AddNetMsg_SpeciesScores();
8245 		}
8246 	}
8247 
8248 	if(killerType>=NGCT_AI_Alien)
8249 	{
8250 		//killed by alien ai
8251 		AddNetMsg_ScoreChange(NET_MAXPLAYERS,playerKilledIndex);
8252 	}
8253 	else
8254 	{
8255 		AddNetMsg_ScoreChange(killerIndex,playerKilledIndex);
8256 	}
8257 
8258 	//AddNetMsg_PlayerScores(killerIndex);
8259 
8260 	if(netGameData.gameType==NGT_PredatorTag || netGameData.gameType==NGT_AlienTag)
8261 	{
8262 		NETGAME_CHARACTERTYPE tagSpecies = NGCT_Predator;
8263 		if(netGameData.gameType==NGT_AlienTag) tagSpecies = NGCT_Alien;
8264 
8265 
8266 		//was the predator killed?
8267 		if(playerKilledType==tagSpecies)
8268 		{
8269 			if(CountPlayersOfType(tagSpecies)==1)
8270 			{
8271 				//select new predator
8272 				//if it wasn't suicide , choose killer
8273 				if(playerKilledIndex!=killerIndex)
8274 				{
8275 					AddNetMsg_PlayerID(killerId,NetMT_PredatorTag_NewPredator);
8276 					Handle_SpeciesTag_NewPersonIt(killerId);
8277 				}
8278 				else
8279 				{
8280 					//choose next player
8281 					for(i=playerKilledIndex+1;;i++)
8282 					{
8283 						i=i%NET_MAXPLAYERS;
8284 						if(netGameData.playerData[i].playerId)
8285 						{
8286 							/*
8287 							don't choose player if he was the previous predator
8288 							(In fact this should only happen if someone is silly enough to player single player
8289 							predator tag).
8290 							*/
8291 							if(i!=playerKilledIndex)
8292 							{
8293 								AddNetMsg_PlayerID(netGameData.playerData[i].playerId,NetMT_PredatorTag_NewPredator);
8294 								Handle_SpeciesTag_NewPersonIt(netGameData.playerData[i].playerId);
8295 							}
8296 							break;
8297 						}
8298 					}
8299 
8300 				}
8301 			}
8302 		}
8303 	}
8304 }
8305 
8306 
8307 /* This function is a hook for the playerdead() function in player.c:
8308 if we're the host, we need to update the scores seperately in the event that we have
8309 been killed during a netgame. For other players, scores are updated (by the host) in
8310 response to a 'playerKilled' message.  However, the host will not receive it's own
8311 playerKilled message, and must therefore do it seperately... */
DoNetScoresForHostDeath(NETGAME_CHARACTERTYPE myType,NETGAME_CHARACTERTYPE killerType)8312 void DoNetScoresForHostDeath(NETGAME_CHARACTERTYPE myType,NETGAME_CHARACTERTYPE killerType)
8313 {
8314 	LOCALASSERT(AvP.Network==I_Host);
8315 	if(myNetworkKillerId)
8316 	{
8317 		int killer_index=PlayerIdInPlayerList(myNetworkKillerId);
8318 		if(killer_index==NET_IDNOTINPLAYERLIST)
8319 		{
8320 			//the player doing the damage has either left the game , or never existed.
8321 			//call it suicide then.
8322 			myNetworkKillerId=AVPDPNetID;
8323 		}
8324 
8325 	}
8326 	UpdateNetworkGameScores(AVPDPNetID,myNetworkKillerId,myType,killerType);
8327 }
8328 
AddUpPlayerFrags(int playerId)8329 int AddUpPlayerFrags(int playerId)
8330 {
8331 	int score = 0;
8332 	int j;
8333 	LOCALASSERT(netGameData.playerData[playerId].playerId!=NULL);
8334 	for(j=0;j<(NET_MAXPLAYERS);j++) score+=netGameData.playerData[playerId].playerFrags[j];
8335 	return score;
8336 }
8337 
8338 #if 0
8339 static void ConvertNetNameToUpperCase(char *strPtr)
8340 {
8341 	int count = 0;
8342 	while((count<(NET_PLAYERNAMELENGTH-1))&&(strPtr[count]!='\0'))
8343 	{
8344 		strPtr[count] = toupper(strPtr[count]);
8345 		count++;
8346 	}
8347 
8348 }
8349 #endif
8350 
8351 
8352 /* Patrick 11/7/97 ----------------------------------------------
8353 Functions for determining our sequence for player update messages
8354 -----------------------------------------------------------------*/
8355 
GetMyMarineSequence(void)8356 static MARINE_SEQUENCE GetMyMarineSequence(void)
8357 {
8358 	int playerIsMoving = 0;
8359 	int playerIsFiring = 0;
8360 	int playerIsCrouching = 0;
8361 	int playerIsAlive = 0;
8362 	int playerIsJumping = 0;
8363 	int usingCloseAttackWeapon;
8364 	extern int StaffAttack;
8365 
8366 	/* sort out what state we're in */
8367 	if(PlayerStatusPtr->IsAlive) playerIsAlive = 1;
8368 	else playerIsAlive = 0;
8369 
8370 	if (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Backward) {
8371 		playerIsMoving=-1;
8372 	} else if((PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Forward)||
8373 	   (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft)||
8374 	   (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight)) {
8375 	   playerIsMoving = 1;
8376 	} else {
8377 		playerIsMoving = 0;
8378 	}
8379 
8380 	if ( (Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx)
8381 		&& (Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy)
8382 		&& (Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz) ) {
8383 		/* Actually not moving - overruled! */
8384 		playerIsMoving=0;
8385 	}
8386 
8387 	if(PlayerStatusPtr->ShapeState!=PMph_Standing)
8388 	{
8389 		playerIsCrouching = 1;
8390 	}
8391 	else
8392 	{
8393 		playerIsCrouching = 0;
8394 	}
8395 
8396 	if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)||
8397 	   (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_PRIMARY)) {
8398 			playerIsFiring = 1;
8399 	} else {
8400 		if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_MARINE_PISTOL) {
8401 			if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_SECONDARY)||
8402 			   (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_SECONDARY)) {
8403 				playerIsFiring = 1;
8404 			} else {
8405 				playerIsFiring = 0;
8406 			}
8407 		} else {
8408 			playerIsFiring = 0;
8409 		}
8410 	}
8411 
8412 	if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL)
8413 		usingCloseAttackWeapon = 1;
8414 	else usingCloseAttackWeapon = 0;
8415 
8416 	/* Fix cudgel. */
8417 	if (usingCloseAttackWeapon) {
8418 		if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_SECONDARY)||
8419 		   (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_SECONDARY)) {
8420 			playerIsFiring = 1;
8421 		}
8422 	}
8423 
8424 	/* KJL 14:27:14 10/29/97 - deal with jumping & falling */
8425 	{
8426 		DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr;
8427 		if (!dynPtr->IsInContactWithFloor && (dynPtr->TimeNotInContactWithFloor==0))
8428 			playerIsJumping=1;
8429 	}
8430 
8431 	/* and deduce the sequence */
8432 	if(playerIsAlive==0)
8433 	{
8434 		if(playerIsCrouching) {
8435 			return MSQ_CrouchDie;
8436 		} else {
8437 			return MSQ_StandDieFront;
8438 		}
8439 	}
8440 
8441 	if(playerIsJumping) {
8442 		return MSQ_Jump;
8443 	}
8444 
8445 	/* Put this in here... no running cudgel attacks yet. */
8446 	if(playerIsFiring&&usingCloseAttackWeapon) {
8447 		/* Deal with cudgel case! */
8448 		if (StaffAttack>=0) {
8449 			return(MSQ_BaseOfCudgelAttacks+StaffAttack);
8450 		}
8451 	}
8452 
8453 	if(playerIsCrouching)
8454 	{
8455 		if(playerIsMoving>0) {
8456 			return MSQ_Crawl;
8457 		} else if (playerIsMoving<0) {
8458 			return MSQ_Crawl_Backwards;
8459 		} else {
8460 			return MSQ_Crouch;
8461 		}
8462 	}
8463 
8464 	if(playerIsMoving>0)
8465 	{
8466 		if(playerIsFiring) {
8467 			if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS)
8468 				&&(LastHand)) {
8469 				return MSQ_RunningFireSecondary;
8470 			} else {
8471 				return MSQ_RunningFire;
8472 			}
8473 		} else {
8474 			return MSQ_Walk;
8475 		}
8476 	} else if (playerIsMoving<0) {
8477 		if(playerIsFiring) {
8478 			if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS)
8479 				&&(LastHand)) {
8480 				return MSQ_RunningFireSecondary_Backwards;
8481 			} else {
8482 				return MSQ_RunningFire_Backwards;
8483 			}
8484 		} else {
8485 			return MSQ_Walk_Backwards;
8486 		}
8487 	}
8488 
8489 	if(playerIsFiring) {
8490 		if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS)
8491 			&&(LastHand)) {
8492 			return MSQ_StandingFireSecondary;
8493 		} else {
8494 			return MSQ_StandingFire;
8495 		}
8496 	} else {
8497 		if (PlayerStatusPtr->tauntTimer!=0) {
8498 			return MSQ_Taunt;
8499 		} else {
8500 			return MSQ_Stand;
8501 		}
8502 	}
8503 }
8504 
GetMyAlienSequence(void)8505 static ALIEN_SEQUENCE GetMyAlienSequence(void)
8506 {
8507 	extern STRATEGYBLOCK *Biting;
8508 	int playerIsMoving = 0;
8509 	int playerIsFiring = 0;
8510 	int playerIsCrouching = 0;
8511 	int playerIsAlive = 0;
8512 	int playerIsJumping = 0;
8513 
8514 	/* sort out what state we're in */
8515 	if(PlayerStatusPtr->IsAlive) playerIsAlive = 1;
8516 	else playerIsAlive = 0;
8517 
8518 	if (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Backward) {
8519 		playerIsMoving =-1;
8520 	} else if ((PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Forward)||
8521 	   (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft)||
8522 	   (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight)) {
8523 	   	playerIsMoving = 1;
8524 	} else {
8525 		playerIsMoving = 0;
8526 	}
8527 
8528 	if ( (Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx)
8529 		&& (Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy)
8530 		&& (Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz) ) {
8531 		/* Actually not moving - overruled! */
8532 		playerIsMoving=0;
8533 	}
8534 
8535 	if(PlayerStatusPtr->ShapeState!=PMph_Standing) playerIsCrouching = 1;
8536 	else playerIsCrouching = 0;
8537 
8538 	/* ChrisF 20/4/98: playerIsFiring now specifies alien weapon behaviour. */
8539 	//if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)||
8540 	//   (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_PRIMARY))
8541 	//		playerIsFiring = 1;
8542 	//else playerIsFiring = 0;
8543 	//
8544 	//if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber!=WEAPON_ALIEN_SPIT) {
8545 	//	usingCloseAttackWeapon = 1;
8546 	//} else {
8547 	//	usingCloseAttackWeapon = 0;
8548 	//}
8549 
8550 	switch(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState) {
8551 		case (WEAPONSTATE_FIRING_PRIMARY):
8552 			if(Biting) {
8553 				playerIsFiring=4; //Eat.
8554 			} else {
8555 				playerIsFiring=1; //Claw.
8556 			}
8557 			break;
8558 		case (WEAPONSTATE_FIRING_SECONDARY):
8559 			playerIsFiring=2; //Tail Poise.
8560 			break;
8561 		case (WEAPONSTATE_RECOIL_SECONDARY):
8562 			playerIsFiring=3; //Tail Strike.
8563 			break;
8564 		default:
8565 			playerIsFiring=0; //Nothing.
8566 			break;
8567 	}
8568 
8569 
8570 	/* KJL 14:27:14 10/29/97 - deal with jumping & falling */
8571 	{
8572 		DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr;
8573 		if (!dynPtr->IsInContactWithFloor && (dynPtr->TimeNotInContactWithFloor==0))
8574 			playerIsJumping=1;
8575 	}
8576 
8577 	/* and deduce the sequence */
8578 	if(playerIsAlive==0)
8579 	{
8580 		return ASQ_Stand; /* kind of irrelevant really */
8581 	}
8582 
8583 	if(playerIsJumping) /* TODO: consider jump & crouch */
8584 	{
8585 		switch(playerIsFiring) {
8586 			case 1:
8587 				return ASQ_Pounce;
8588 				break;
8589 			case 2:
8590 				return ASQ_JumpingTailPoise;
8591 				break;
8592 			case 3:
8593 				return ASQ_JumpingTailStrike;
8594 				break;
8595 			case 4:
8596 				/* What the hell? */
8597 				return ASQ_Eat;
8598 				break;
8599 			default:
8600 				return ASQ_Jump;
8601 				break;
8602 		}
8603 	}
8604 
8605 	if(playerIsCrouching)
8606 	{
8607 		if(playerIsMoving>0)
8608 		{
8609 			switch(playerIsFiring) {
8610 				case 1:
8611 					return ASQ_CrawlingAttack_Claw;
8612 					break;
8613 				case 2:
8614 					return ASQ_CrawlingTailPoise;
8615 					break;
8616 				case 3:
8617 					return ASQ_CrawlingTailStrike;
8618 					break;
8619 				case 4:
8620 					/* What the hell? */
8621 					return ASQ_CrouchEat;
8622 					break;
8623 				default:
8624 					if(Player->ObStrategyBlock->DynPtr->OrientMat.mat22>50000)
8625 						return ASQ_Scamper;
8626 					else
8627 						return ASQ_Crawl;
8628 					break;
8629 			}
8630 		} else if(playerIsMoving<0)	{
8631 			switch(playerIsFiring) {
8632 				case 1:
8633 					return ASQ_CrawlingAttack_Claw_Backwards;
8634 					break;
8635 				case 2:
8636 					return ASQ_CrawlingTailPoise_Backwards;
8637 					break;
8638 				case 3:
8639 					return ASQ_CrawlingTailStrike_Backwards;
8640 					break;
8641 				case 4:
8642 					/* What the hell? */
8643 					return ASQ_CrouchEat;
8644 					break;
8645 				default:
8646 					if(Player->ObStrategyBlock->DynPtr->OrientMat.mat22>50000)
8647 						return ASQ_Scamper_Backwards;
8648 					else
8649 						return ASQ_Crawl_Backwards;
8650 					break;
8651 			}
8652 		}
8653 
8654 		switch(playerIsFiring) {
8655 			case 1:
8656 				return ASQ_CrouchedAttack_Claw;
8657 				break;
8658 			case 2:
8659 				return ASQ_CrouchedTailPoise;
8660 				break;
8661 			case 3:
8662 				return ASQ_CrouchedTailStrike;
8663 				break;
8664 			case 4:
8665 				return ASQ_Eat;
8666 				break;
8667 			default:
8668 				return ASQ_Crouch;
8669 				break;
8670 		}
8671 	}
8672 
8673 	if(playerIsMoving>0)
8674 	{
8675 		switch(playerIsFiring) {
8676 			case 1:
8677 				return ASQ_RunningAttack_Claw;
8678 				break;
8679 			case 2:
8680 				return ASQ_RunningTailPoise;
8681 				break;
8682 			case 3:
8683 				return ASQ_RunningTailStrike;
8684 				break;
8685 			case 4:
8686 				/* What the hell? */
8687 				return ASQ_Eat;
8688 				break;
8689 			default:
8690 				return ASQ_Run;
8691 				break;
8692 		}
8693 	} else if(playerIsMoving<0) {
8694 		switch(playerIsFiring) {
8695 			case 1:
8696 				return ASQ_RunningAttack_Claw_Backwards;
8697 				break;
8698 			case 2:
8699 				return ASQ_RunningTailPoise_Backwards;
8700 				break;
8701 			case 3:
8702 				return ASQ_RunningTailStrike_Backwards;
8703 				break;
8704 			case 4:
8705 				/* What the hell? */
8706 				return ASQ_Eat;
8707 				break;
8708 			default:
8709 				return ASQ_Run_Backwards;
8710 				break;
8711 		}
8712 	}
8713 
8714 	switch(playerIsFiring) {
8715 		case 1:
8716 			return ASQ_StandingAttack_Claw;
8717 			break;
8718 		case 2:
8719 			return ASQ_StandingTailPoise;
8720 			break;
8721 		case 3:
8722 			return ASQ_StandingTailStrike;
8723 			break;
8724 		case 4:
8725 			return ASQ_Eat;
8726 			break;
8727 		default:
8728 			if (PlayerStatusPtr->tauntTimer!=0) {
8729 				/* Second lowest priority ever. */
8730 				return ASQ_Taunt;
8731 			} else {
8732 				return ASQ_Stand;
8733 			}
8734 			break;
8735 	}
8736 
8737 }
8738 
GetMyPredatorSequence(void)8739 static PREDATOR_SEQUENCE GetMyPredatorSequence(void)
8740 {
8741 	int playerIsMoving = 0;
8742 	int playerIsFiring = 0;
8743 	int playerIsCrouching = 0;
8744 	int playerIsAlive = 0;
8745 	int playerIsJumping = 0;
8746 	int usingCloseAttackWeapon;
8747 	extern int StaffAttack;
8748 
8749 	/* sort out what state we're in */
8750 	if(PlayerStatusPtr->IsAlive) playerIsAlive = 1;
8751 	else playerIsAlive = 0;
8752 
8753 	if (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Backward) {
8754 		playerIsMoving=-1;
8755 	} else if((PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Forward)||
8756 	   (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft)||
8757 	   (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight)) {
8758 	   	playerIsMoving = 1;
8759 	} else {
8760 		playerIsMoving = 0;
8761 	}
8762 
8763 	if ( (Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx)
8764 		&& (Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy)
8765 		&& (Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz) ) {
8766 		/* Actually not moving - overruled! */
8767 		playerIsMoving=0;
8768 	}
8769 
8770 	if(PlayerStatusPtr->ShapeState!=PMph_Standing) playerIsCrouching = 1;
8771 	else playerIsCrouching = 0;
8772 
8773 	playerIsFiring = 0;
8774 
8775 	if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON)
8776 	{
8777 		//the shoulder cannon is fired during recoil (I think)
8778 		if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_PRIMARY)
8779 		{
8780 			playerIsFiring = 1;
8781 		}
8782 	}
8783 	else if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_PRED_WRISTBLADE)
8784 	{
8785 		if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)||
8786 		   (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_PRIMARY) ||
8787 		   (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_SECONDARY))
8788 		{
8789 			if(StaffAttack!=-1)
8790 			{
8791 				playerIsFiring = 1;
8792 			}
8793 		}
8794 	}
8795 	else
8796 	{
8797 		if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)||
8798 		   (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_PRIMARY))
8799 		{
8800 				playerIsFiring = 1;
8801 		}
8802 	}
8803 
8804 	if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_PRED_WRISTBLADE)
8805 		usingCloseAttackWeapon = 3;
8806 	else if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_PRED_DISC)
8807 		usingCloseAttackWeapon = 1;
8808 	else if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_PRED_STAFF)
8809 		usingCloseAttackWeapon = 2;
8810 	else usingCloseAttackWeapon = 0;
8811 
8812 	/* KJL 14:27:14 10/29/97 - deal with jumping & falling */
8813 	{
8814 		DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr;
8815 		if (!dynPtr->IsInContactWithFloor && (dynPtr->TimeNotInContactWithFloor==0))
8816 			playerIsJumping=1;
8817 	}
8818 
8819 	/* and deduce the sequence */
8820 	if(playerIsAlive==0)
8821 	{
8822 		if(playerIsCrouching) {
8823 			return PredSQ_CrouchDie;
8824 		} else {
8825 			return PredSQ_StandDie;
8826 		}
8827 	}
8828 
8829 	if(playerIsJumping) {
8830 		return(PredSQ_Jump);
8831 	}
8832 
8833 	if(playerIsCrouching)
8834 	{
8835 		if(playerIsMoving>0)
8836 		{
8837 			if(playerIsFiring&&usingCloseAttackWeapon) {
8838 				/* Deal with staff case! */
8839 				if (usingCloseAttackWeapon==2) {
8840 					if (StaffAttack>=0) {
8841 						return(PredSQ_BaseOfStaffAttacks+StaffAttack);
8842 					}
8843 				} else if (usingCloseAttackWeapon==3) {
8844 					if (StaffAttack>=0) {
8845 						return(PredSQ_BaseOfWristbladeAttacks+StaffAttack);
8846 					}
8847 				}
8848 				return PredSQ_CrawlingSwipe;
8849 			} else {
8850 				return PredSQ_Crawl;
8851 			}
8852 		} else if (playerIsMoving<0) {
8853 			if(playerIsFiring&&usingCloseAttackWeapon) {
8854 				/* Deal with staff case! */
8855 				if (usingCloseAttackWeapon==2) {
8856 					if (StaffAttack>=0) {
8857 						return(PredSQ_BaseOfStaffAttacks+StaffAttack);
8858 					}
8859 				} else if (usingCloseAttackWeapon==3) {
8860 					if (StaffAttack>=0) {
8861 						return(PredSQ_BaseOfWristbladeAttacks+StaffAttack);
8862 					}
8863 				}
8864 				return PredSQ_CrawlingSwipe_Backwards;
8865 			} else {
8866 				return PredSQ_Crawl_Backwards;
8867 			}
8868 		}
8869 		if(playerIsFiring&&usingCloseAttackWeapon) {
8870 			/* Deal with staff case! */
8871 			if (usingCloseAttackWeapon==2) {
8872 				if (StaffAttack>=0) {
8873 					return(PredSQ_BaseOfStaffAttacks+StaffAttack);
8874 				}
8875 			} else if (usingCloseAttackWeapon==3) {
8876 				if (StaffAttack>=0) {
8877 					return(PredSQ_BaseOfWristbladeAttacks+StaffAttack);
8878 				}
8879 			}
8880 			return PredSQ_CrouchedSwipe;
8881 		} else {
8882 			return PredSQ_Crouch;
8883 		}
8884 	}
8885 
8886 	if(playerIsMoving>0)
8887 	{
8888 		if(playerIsFiring&&usingCloseAttackWeapon) {
8889 			/* Deal with staff case! */
8890 			if (usingCloseAttackWeapon==2) {
8891 				if (StaffAttack>=0) {
8892 					return(PredSQ_BaseOfStaffAttacks+StaffAttack);
8893 				}
8894 			} else if (usingCloseAttackWeapon==3) {
8895 				if (StaffAttack>=0) {
8896 					return(PredSQ_BaseOfWristbladeAttacks+StaffAttack);
8897 				}
8898 			}
8899 			return PredSQ_RunningSwipe;
8900 		} else {
8901 			return PredSQ_Run;
8902 		}
8903 	} else if (playerIsMoving<0) {
8904 		if(playerIsFiring&&usingCloseAttackWeapon) {
8905 			/* Deal with staff case! */
8906 			if (usingCloseAttackWeapon==2) {
8907 				if (StaffAttack>=0) {
8908 					return(PredSQ_BaseOfStaffAttacks+StaffAttack);
8909 				}
8910 			} else if (usingCloseAttackWeapon==3) {
8911 				if (StaffAttack>=0) {
8912 					return(PredSQ_BaseOfWristbladeAttacks+StaffAttack);
8913 				}
8914 			}
8915 			return PredSQ_RunningSwipe_Backwards;
8916 		} else {
8917 			return PredSQ_Run_Backwards;
8918 		}
8919 	}
8920 
8921 	if(playerIsFiring&&usingCloseAttackWeapon) {
8922 		/* Deal with staff case! */
8923 		if (usingCloseAttackWeapon==2) {
8924 			if (StaffAttack>=0) {
8925 				return(PredSQ_BaseOfStaffAttacks+StaffAttack);
8926 			}
8927 		} else if (usingCloseAttackWeapon==3) {
8928 			if (StaffAttack>=0) {
8929 				return(PredSQ_BaseOfWristbladeAttacks+StaffAttack);
8930 			}
8931 		}
8932 		return PredSQ_StandingSwipe;
8933 	} else {
8934 		if (PlayerStatusPtr->tauntTimer!=0) {
8935 			return PredSQ_Taunt;
8936 		} else {
8937 			return PredSQ_Stand;
8938 		}
8939 	}
8940 }
8941 
8942 /* Patrick 11/7/97 ----------------------------------------------
8943 Functions for transmitting state changes
8944 -----------------------------------------------------------------*/
TransmitEndOfGameNetMsg(void)8945 void TransmitEndOfGameNetMsg(void)
8946 {
8947 	int i;
8948 	/* first of, initialise the send buffer: this means that we may loose some stacked
8949 	messages, but this should be ok.*/
8950 	InitialiseSendMessageBuffer();
8951 
8952 	netGameData.myGameState=NGS_EndGameScreen;
8953 	for(i=0;i<NET_MESSAGEITERATIONS;i++)
8954 	{
8955 		AddNetMsg_AllGameScores();
8956 	 //	AddNetMsg_EndGame();
8957 		NetSendMessages();
8958 	}
8959 	netGameData.stateCheckTimeDelay=3*ONE_FIXED;
8960 }
8961 
TransmitPlayerLeavingNetMsg(void)8962 void TransmitPlayerLeavingNetMsg(void)
8963 {
8964 	int i;
8965 	/* first of, initialise the send buffer: this means that we may loose some stacked
8966 	messages, but this should be ok.*/
8967 	InitialiseSendMessageBuffer();
8968 
8969 	for(i=0;i<NET_MESSAGEITERATIONS;i++)
8970 	{
8971 		AddNetMsg_PlayerLeaving();
8972 		NetSendMessages();
8973 	}
8974 }
8975 
TransmitStartGameNetMsg(void)8976 void TransmitStartGameNetMsg(void)
8977 {
8978 	int i;
8979 	/* first of, initialise the send buffer: this means that we may loose some stacked
8980 	messages, but this should be ok.*/
8981 	InitialiseSendMessageBuffer();
8982 
8983 	for(i=0;i<NET_MESSAGEITERATIONS;i++)
8984 	{
8985 		AddNetMsg_StartGame();
8986 		NetSendMessages();
8987 	}
8988 }
8989 
8990 /* Patrick 29/7/97 --------------------------------------------------
8991 Stuff for assigning starting positions to network players
8992 ---------------------------------------------------------------------*/
8993 #if 0
8994 void TeleportNetPlayerToAStartingPosition(STRATEGYBLOCK *playerSbPtr, int startOfGame)
8995 {
8996 	extern int NumActiveStBlocks;
8997 	extern STRATEGYBLOCK *ActiveStBlockList[];
8998 	int numStartPositions;
8999 	VECTORCH* startPositions;
9000 
9001 	int sbIndex = 0;
9002 	int numReadThro,numConsidered;
9003 	int start_index=0;
9004 	int found = 0;
9005 
9006 	PLAYER_STATUS *psPtr=(PLAYER_STATUS*)playerSbPtr->SBdataptr;
9007 
9008 	/* some basic checks */
9009 	if(playerSbPtr==NULL) return;
9010 	if(playerSbPtr->DynPtr==NULL) return;
9011 	if(!ActiveStBlockList) return;
9012 	if(NumActiveStBlocks<=0) return;
9013 
9014 	//set the players invulnerability timer
9015 	GLOBALASSERT(psPtr);
9016 	psPtr->invulnerabilityTimer=netGameData.invulnerableTime*ONE_FIXED;
9017 
9018 
9019 	//select the start positions for this character type
9020 	switch(AvP.PlayerType)
9021 	{
9022 		case I_Marine :
9023 			numStartPositions=numMarineStartPos;
9024 			startPositions=marineStartPositions;
9025 			break;
9026 
9027 		case I_Predator :
9028 			numStartPositions=numPredatorStartPos;
9029 			startPositions=predatorStartPositions;
9030 			break;
9031 
9032 		case I_Alien :
9033 			numStartPositions=numAlienStartPos;
9034 			startPositions=alienStartPositions;
9035 			break;
9036 	}
9037 
9038 
9039 	if(!numStartPositions) return;
9040 
9041 	/* pick a starting point*/
9042 	if(startOfGame)
9043 	{
9044 		numReadThro = (PlayerIdInPlayerList(AVPDPNetID))%8;
9045 		while(numReadThro<0)
9046 		{
9047 			//Probably haven't received the details of all the players yet
9048 			MinimalNetCollectMessages();
9049 			numReadThro = (PlayerIdInPlayerList(AVPDPNetID))%8;
9050 		}
9051 	}
9052 	else numReadThro = FastRandom()%numStartPositions;
9053 	numConsidered = 0;
9054 
9055 	/* and go through the list */
9056 	for(start_index=numReadThro;!found;start_index++)
9057 	{
9058 		start_index%=numStartPositions;
9059 
9060 		/* we are going to try this one: see if it's clear */
9061 		{
9062 			int sbIndex2 = 0;
9063 			STRATEGYBLOCK *sbPtr2;
9064 			int obstructed = 0;
9065 
9066 			while((sbIndex2 < NumActiveStBlocks)&&(!obstructed))
9067 			{
9068 				sbPtr2 = ActiveStBlockList[sbIndex2++];
9069 				if(sbPtr2->I_SBtype==I_BehaviourNetGhost)
9070 				{
9071 					NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr2->SBdataptr;
9072 					LOCALASSERT(ghostData);
9073 					if((ghostData->type==I_BehaviourMarinePlayer)||
9074 				   	   (ghostData->type==I_BehaviourPredatorPlayer)||
9075 				   	   (ghostData->type==I_BehaviourAlienPlayer))
9076 					{
9077 						VECTORCH seperationVec;
9078 						LOCALASSERT(sbPtr2->DynPtr);
9079 						seperationVec = sbPtr2->DynPtr->Position;
9080 						seperationVec.vx -= startPositions[start_index].vx;
9081 						seperationVec.vy -= startPositions[start_index].vy;
9082 						seperationVec.vz -= startPositions[start_index].vz;
9083 						if((Magnitude(&seperationVec)<2000)&&(numConsidered<8)) obstructed = 1;
9084 					}
9085 				}
9086 			}
9087 
9088 			numConsidered++;
9089 			if(!obstructed)
9090 			{
9091 				/* found a clear start position */
9092 				playerSbPtr->DynPtr->Position = playerSbPtr->DynPtr->PrevPosition = startPositions[start_index];
9093 				found = 1;
9094 
9095 			}
9096 		}
9097 	}
9098 }
9099 #else
TeleportNetPlayerToAStartingPosition(STRATEGYBLOCK * playerSbPtr,int startOfGame)9100 void TeleportNetPlayerToAStartingPosition(STRATEGYBLOCK *playerSbPtr, int startOfGame)
9101 {
9102 	int numStartPositions;
9103 	MULTIPLAYER_START* startPositions;
9104 	int start_index;
9105 	int numChecked=0;
9106 	int bestDistance=-1;
9107 	int bestIndex=-1;
9108 
9109 	PLAYER_STATUS *psPtr=(PLAYER_STATUS*)playerSbPtr->SBdataptr;
9110 
9111 	if(MultiplayerRestartSeed)
9112 	{
9113 		StartOfGame_PlayerPlacement(playerSbPtr,MultiplayerRestartSeed);
9114 		MultiplayerRestartSeed=0;
9115 		return;
9116 	}
9117 
9118 	/* some basic checks */
9119 	if(playerSbPtr==NULL) return;
9120 	if(playerSbPtr->DynPtr==NULL) return;
9121 
9122 	//set the players invulnerability timer
9123 	GLOBALASSERT(psPtr);
9124 	psPtr->invulnerabilityTimer=netGameData.invulnerableTime*ONE_FIXED;
9125 
9126 
9127 	//select the start positions for this character type
9128 	switch(AvP.PlayerType)
9129 	{
9130 		case I_Marine :
9131 			numStartPositions=numMarineStartPos;
9132 			startPositions=marineStartPositions;
9133 			break;
9134 
9135 		case I_Predator :
9136 			numStartPositions=numPredatorStartPos;
9137 			startPositions=predatorStartPositions;
9138 			break;
9139 
9140 		case I_Alien :
9141 			numStartPositions=numAlienStartPos;
9142 			startPositions=alienStartPositions;
9143 			break;
9144 	}
9145 
9146 
9147 	if(!numStartPositions) return;
9148 
9149 	for(start_index=FastRandom()%numStartPositions;numChecked<numStartPositions;start_index++,numChecked++)
9150 	{
9151 		int closestDistance=0x7fffffff;
9152 		int playerIndex;
9153 
9154 		if(start_index>=numStartPositions) start_index=0;
9155 
9156 		//find the closest player to this start position
9157 		for(playerIndex=0;playerIndex<NET_MAXPLAYERS;playerIndex++)
9158 		{
9159 			if(netGameData.playerData[playerIndex].playerId &&
9160 			   netGameData.playerData[playerIndex].playerId!=AVPDPNetID &&
9161 			   netGameData.playerData[playerIndex].playerAlive)
9162 			{
9163 				VECTORCH seperationVec;
9164 				int distance;
9165 
9166 				seperationVec = netGameData.playerData[playerIndex].lastKnownPosition;
9167 				seperationVec.vx -= startPositions[start_index].location.vx;
9168 				seperationVec.vy -= startPositions[start_index].location.vy;
9169 				seperationVec.vz -= startPositions[start_index].location.vz;
9170 
9171 				distance=Approximate3dMagnitude(&seperationVec);
9172 				if(distance<closestDistance)
9173 				{
9174 					closestDistance=distance;
9175 				}
9176 			}
9177 
9178 		}
9179 
9180 
9181 		if(closestDistance>20000)
9182 		{
9183 			//no player near this start position, so it will do
9184 			bestIndex=start_index;
9185 			break;
9186 		}
9187 		else if(closestDistance>bestDistance)
9188 		{
9189 			bestDistance=closestDistance;
9190 			bestIndex=start_index;
9191 		}
9192 	}
9193 
9194 	if(bestIndex!=-1)
9195 	{
9196 		extern MODULE * playerPherModule;
9197 		DYNAMICSBLOCK *dynPtr = playerSbPtr->DynPtr;
9198 		//found a start postion
9199 		Player->ObWorld=dynPtr->Position = dynPtr->PrevPosition = startPositions[bestIndex].location;
9200 		dynPtr->OrientEuler = startPositions[bestIndex].orientation;
9201 		CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
9202 		TransposeMatrixCH(&dynPtr->OrientMat);
9203 
9204 		playerSbPtr->containingModule=ModuleFromPosition(&Player->ObWorld, (MODULE*)0);
9205 		playerPherModule=playerSbPtr->containingModule;
9206 
9207 
9208 		/*
9209 		After teleportation we need to update the visibilities , to ensure that
9210 		dynamics will work properly this frame.
9211 		*/
9212 		{
9213 			extern VIEWDESCRIPTORBLOCK* Global_VDB_Ptr;
9214 			Global_VDB_Ptr->VDB_World = Player->ObWorld;
9215 			AllNewModuleHandler();
9216 			DoObjectVisibilities();
9217 		}
9218 
9219 	}
9220 
9221 }
9222 #endif
9223 
9224 /*Works out everyone's starting positions . Use a shared random numer seed
9225 in order to avoid having several players appearing at the same place*/
StartOfGame_PlayerPlacement(STRATEGYBLOCK * playerSbPtr,int seed)9226 void StartOfGame_PlayerPlacement(STRATEGYBLOCK *playerSbPtr,int seed)
9227 {
9228 	int numStartPositions;
9229 	MULTIPLAYER_START* startPositions;
9230 	PLAYER_STATUS *psPtr=(PLAYER_STATUS*)playerSbPtr->SBdataptr;
9231 
9232 	VECTORCH ChosenPositions[NET_MAXPLAYERS];
9233 	int NumChosen=0;
9234 	int i;
9235 
9236 	//set the players invulnerability timer
9237 	GLOBALASSERT(psPtr);
9238 	psPtr->invulnerabilityTimer=netGameData.invulnerableTime*ONE_FIXED;
9239 
9240 	SetSeededFastRandom(seed);
9241 
9242 	for(i=0;i<NET_MAXPLAYERS;i++)
9243 	{
9244 		int index;
9245 		int numChecked=0;
9246 		if(!netGameData.playerData[i].playerId) continue;
9247 
9248 		switch(netGameData.playerData[i].characterType)
9249 		{
9250 			case NGCT_Marine :
9251 				numStartPositions=numMarineStartPos;
9252 				startPositions=marineStartPositions;
9253 				break;
9254 
9255 			case NGCT_Alien :
9256 				numStartPositions=numAlienStartPos;
9257 				startPositions=alienStartPositions;
9258 				break;
9259 
9260 			case NGCT_Predator :
9261 				numStartPositions=numPredatorStartPos;
9262 				startPositions=predatorStartPositions;
9263 				break;
9264 
9265 			default :
9266 				continue;//hmm
9267 				break;
9268 		}
9269 
9270 		if(!numStartPositions) continue;
9271 
9272 		for(index=SeededFastRandom()%numStartPositions;numChecked<numStartPositions;index++,numChecked++)
9273 		{
9274 			int j;
9275 			if(index>=numStartPositions) index=0;
9276 
9277 			//see if anyone is at this position
9278 			for(j=0;j<NumChosen;j++)
9279 			{
9280 				if(ChosenPositions[j].vx==startPositions[index].location.vx &&
9281 				   ChosenPositions[j].vy==startPositions[index].location.vy &&
9282 				   ChosenPositions[j].vz==startPositions[index].location.vz)
9283 				{
9284 					break;
9285 				}
9286 			}
9287 
9288 			if(j==NumChosen)
9289 			{
9290 				//found a clear start position
9291 				break;
9292 			}
9293 		}
9294 
9295 		if(index>=numStartPositions) index=0;
9296 
9297 		//we've either found a clear start position , or gone through the entire list
9298 		//without finding one.Either way take the starting position index that we reached
9299 
9300 		ChosenPositions[NumChosen]=startPositions[index].location;
9301 		NumChosen++;
9302 
9303 		if(netGameData.playerData[i].playerId==AVPDPNetID)
9304 		{
9305 			extern MODULE * playerPherModule;
9306 			//this was our new start position
9307 			DYNAMICSBLOCK *dynPtr = playerSbPtr->DynPtr;
9308 			//found a start postion
9309 			Player->ObWorld=dynPtr->Position = dynPtr->PrevPosition = startPositions[index].location;
9310 			dynPtr->OrientEuler = startPositions[index].orientation;
9311 			CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
9312 			TransposeMatrixCH(&dynPtr->OrientMat);
9313 
9314 			playerSbPtr->containingModule=ModuleFromPosition(&Player->ObWorld, (MODULE*)0);
9315 			playerPherModule=playerSbPtr->containingModule;
9316 
9317 			/*
9318 			After teleportation we need to update the visibilities , to ensure that
9319 			dynamics will work properly this frame.
9320 			*/
9321 			{
9322 				extern VIEWDESCRIPTORBLOCK* Global_VDB_Ptr;
9323 				Global_VDB_Ptr->VDB_World = Player->ObWorld;
9324 				AllNewModuleHandler();
9325 				DoObjectVisibilities();
9326 			}
9327 			//don't care about the positioning of anyone further on in the list
9328 			return;
9329 
9330 		}
9331 
9332 
9333 	}
9334 }
9335 
9336 /* Patrick 4/8/97-------------------------------------
9337    For testing purposes...
9338    ---------------------------------------------------*/
9339 #define logNetGameProcesses 0
9340 #if logNetGameProcesses
9341 static FILE *netLogfile;
9342 #endif
InitNetLog(void)9343 void InitNetLog(void)
9344 {
9345 #if logNetGameProcesses
9346 		netLogfile = fopen("NETINFO.TXT","w");
9347 		fprintf(netLogfile, "NETGAME DEBUGGING LOG \n \n");
9348 		fclose(netLogfile);
9349 #endif
9350 }
9351 
LogNetInfo(char * msg)9352 void LogNetInfo(char *msg)
9353 {
9354 #if logNetGameProcesses
9355 		if(!msg) return;
9356 		netLogfile = fopen("NETINFO.TXT","a");
9357 		fprintf(netLogfile, msg);
9358 		fclose(netLogfile);
9359 #endif
9360 }
9361 
9362 
9363 
9364 DISPLAYBLOCK PlayersMirrorImage;
9365 STRATEGYBLOCK PlayersMirrorImageSB;
9366 NETGHOSTDATABLOCK PlayersMirrorGhost;
9367 DYNAMICSBLOCK PlayersMirrorDynBlock;
9368 
Current_Level_Requires_Mirror_Image()9369 BOOL Current_Level_Requires_Mirror_Image()
9370 {
9371 	extern char LevelName[];
9372 	if ( (!stricmp(LevelName,"e3demo")) || (!stricmp(LevelName,"e3demosp")) || (!stricmp(LevelName,"derelict")) )
9373 	{
9374  		return TRUE;
9375 	}
9376 	return FALSE;
9377 }
9378 
9379 
CreatePlayersImageInMirror(void)9380 void CreatePlayersImageInMirror(void)
9381 {
9382 	AVP_BEHAVIOUR_TYPE type;
9383 	STRATEGYBLOCK *sbPtr = &PlayersMirrorImageSB;
9384 	NETGHOSTDATABLOCK *ghostData = &PlayersMirrorGhost;
9385 	PlayersMirrorImage.ObStrategyBlock = sbPtr;
9386 
9387 	sbPtr->SBdptr = &PlayersMirrorImage;
9388 
9389 	sbPtr->SBdataptr = (void *)ghostData;
9390 	sbPtr->DynPtr = &PlayersMirrorDynBlock;
9391 
9392 	switch(AvP.PlayerType)
9393 	{
9394 		case(I_Marine):
9395 		{
9396 			type = I_BehaviourMarinePlayer;
9397 			break;
9398 		}
9399 		case(I_Predator):
9400 		{
9401 			type = I_BehaviourPredatorPlayer;
9402 			break;
9403 		}
9404 		case(I_Alien):
9405 		{
9406 			type = I_BehaviourAlienPlayer;
9407 			break;
9408 		}
9409 	}
9410 	ghostData->type = type;
9411 	ghostData->IOType=IOT_Non;
9412 	ghostData->subtype=0;
9413 	ghostData->myGunFlash = NULL;
9414 	ghostData->SoundHandle = SOUND_NOACTIVEINDEX;
9415 	ghostData->currentAnimSequence = 0;
9416 	ghostData->CloakingEffectiveness = 0;
9417 	ghostData->IgnitionHandshaking = 0;
9418 	ghostData->soundStartFlag = 0;
9419 
9420 	if(AvP.Network == I_No_Network)
9421 	{
9422 		ghostData->playerId=0;
9423 	}
9424 	else
9425 	{
9426 		ghostData->playerId=AVPDPNetID;
9427 	}
9428 
9429 	/* set the shape */
9430 
9431 	switch(type)
9432 	{
9433 		case(I_BehaviourMarinePlayer):
9434 		{
9435 			CreateMarineHModel(ghostData,WEAPON_PULSERIFLE);
9436 			break;
9437 		}
9438 		case(I_BehaviourAlienPlayer):
9439 		{
9440 			CreateAlienHModel(ghostData,AT_Standard);
9441 			break;
9442 		}
9443 		case(I_BehaviourPredatorPlayer):
9444 		{
9445 			CreatePredatorHModel(ghostData,WEAPON_PRED_WRISTBLADE);
9446 			break;
9447 		}
9448 		default:
9449 			break;
9450 	}
9451 		sbPtr->SBdptr->HModelControlBlock=&ghostData->HModelController;
9452 		ProveHModel(sbPtr->SBdptr->HModelControlBlock,sbPtr->SBdptr);
9453 
9454 }
9455 
DeallocatePlayersMirrorImage()9456 void DeallocatePlayersMirrorImage()
9457 {
9458 	#if MIRRORING_ON
9459 	if(Current_Level_Requires_Mirror_Image())
9460 	{
9461 		Dispel_HModel(&PlayersMirrorGhost.HModelController);
9462 	}
9463 	#endif
9464 }
9465 
9466 
RenderPlayersImageInMirror(void)9467 void RenderPlayersImageInMirror(void)
9468 {
9469 	STRATEGYBLOCK *sbPtr = &PlayersMirrorImageSB;
9470 	NETGHOSTDATABLOCK *ghostData = &PlayersMirrorGhost;
9471 
9472 	int sequence;
9473 	int weapon;
9474 	int firingPrimary;
9475 	int firingSecondary;
9476 
9477 	switch(AvP.PlayerType)
9478 	{
9479 		case(I_Marine):
9480 		{
9481 			sequence = (unsigned char)GetMyMarineSequence();
9482 			//check for change of charcter type
9483 			if(ghostData->type!=I_BehaviourMarinePlayer)
9484 			{
9485 				ghostData->type=I_BehaviourMarinePlayer;
9486 				//settings currentweapon to -1 will forec the hmodel to be updated
9487 				ghostData->CurrentWeapon=-1;
9488 			}
9489 
9490 			break;
9491 		}
9492 		case(I_Predator):
9493 		{
9494 			sequence = (unsigned char)GetMyPredatorSequence();
9495 			//check for change of charcter type
9496 			if(ghostData->type!=I_BehaviourPredatorPlayer)
9497 			{
9498 				ghostData->type=I_BehaviourPredatorPlayer;
9499 				//settings currentweapon to -1 will forec the hmodel to be updated
9500 				ghostData->CurrentWeapon=-1;
9501 			}
9502 			break;
9503 		}
9504 		case(I_Alien):
9505 		{
9506 			sequence = (unsigned char)GetMyAlienSequence();
9507 			//check for change of charcter type
9508 			if(ghostData->type!=I_BehaviourAlienPlayer)
9509 			{
9510 				ghostData->type=I_BehaviourAlienPlayer;
9511 				//setting currentweapon to -1 will force the hmodel to be updated
9512 				ghostData->CurrentWeapon=-1;
9513 			}
9514 			break;
9515 		}
9516 		default:
9517 		{
9518 			LOCALASSERT(1==0);
9519 			break;
9520 		}
9521 	}
9522 		/* my current weapon id, and whether I am firing it... */
9523 	{
9524 		PLAYER_WEAPON_DATA *weaponPtr;
9525  		PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr);
9526 		LOCALASSERT(playerStatusPtr);
9527     	weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]);
9528 		weapon = (signed char)(weaponPtr->WeaponIDNumber);
9529 
9530 		if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(playerStatusPtr->IsAlive))
9531 			firingPrimary = 1;
9532 		else firingPrimary = 0;
9533 		if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(playerStatusPtr->IsAlive))
9534 			firingSecondary = 1;
9535 		else firingSecondary = 0;
9536 	}
9537 
9538 //		if(!(((!(messagePtr->IAmAlive)))&&(netGameData.playerData[playerIndex].characterType==NGCT_Alien)))
9539 	{
9540 		{
9541 			PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
9542 			HandleWeaponElevation(sbPtr,playerStatusPtr->ViewPanX,weapon);
9543 
9544 			UpdateGhost(sbPtr,&(Player->ObStrategyBlock->DynPtr->Position),&(Player->ObStrategyBlock->DynPtr->OrientEuler),sequence,AreTwoPistolsInTertiaryFire());
9545 
9546 
9547 			MaintainGhostCloakingStatus(sbPtr,(int)playerStatusPtr->cloakOn);
9548 		}
9549 	}
9550 	{
9551 		extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr;
9552 		DISPLAYBLOCK *dPtr = &PlayersMirrorImage;
9553 		dPtr->ObWorld = PlayersMirrorDynBlock.Position;
9554 		dPtr->ObMat = PlayersMirrorDynBlock.OrientMat;
9555 		ReflectObject(dPtr);
9556 
9557 		PlayersMirrorImage.ObStrategyBlock = 0;
9558 
9559 		AddShape(dPtr,Global_VDB_Ptr);
9560 		PlayersMirrorImage.ObStrategyBlock = &PlayersMirrorImageSB;
9561 
9562 	}
9563 	HandleGhostGunFlashEffect(sbPtr,MyPlayerHasAMuzzleFlash(sbPtr));
9564 }
9565 
9566 
9567 /* KJL 15:32:17 24/05/98 - respawn all game objects that have been destroyed */
RestartNetworkGame(int seed)9568 void RestartNetworkGame(int seed)
9569 {
9570 	int i,j;
9571 	if(netGameData.myGameState!=NGS_Playing && netGameData.myGameState!=NGS_EndGameScreen) return;
9572 
9573 	//reset all the scores
9574 
9575 	for(i=0;i<(NET_MAXPLAYERS);i++)
9576 	{
9577 		for(j=0;j<(NET_MAXPLAYERS);j++) netGameData.playerData[i].playerFrags[j] = 0;
9578 		netGameData.playerData[i].playerScore = 0;
9579 		netGameData.playerData[i].playerScoreAgainst = 0;
9580 		netGameData.playerData[i].aliensKilled[0]=0;
9581 		netGameData.playerData[i].aliensKilled[1]=0;
9582 		netGameData.playerData[i].aliensKilled[2]=0;
9583 		netGameData.playerData[i].deathsFromAI=0;
9584 		netGameData.playerData[i].startFlag = 0;
9585 		netGameData.playerData[i].playerAlive = 1;
9586 		netGameData.playerData[i].playerHasLives = 1;
9587 	}
9588 	for(j=0;j<3;j++) netGameData.teamScores[j] = 0;
9589 
9590    	netGameData.stateCheckTimeDelay=0;
9591 	netGameData.GameTimeElapsed = 0;
9592 	netGameData.LMS_AlienIndex=-1;
9593 	netGameData.LMS_RestartTimer=0;
9594 	netGameData.numDeaths[0]=0;
9595 	netGameData.numDeaths[1]=0;
9596 	netGameData.numDeaths[2]=0;
9597 
9598 
9599 	netGameData.lastPointsBasedRespawn=0;
9600 
9601 	AvP.RestartLevel=1;
9602 
9603 
9604 
9605 	if(netGameData.gameType==NGT_LastManStanding)
9606 	{
9607 		int i;
9608 		//in a last man standing game , turn everyone in marines to start with
9609 		extern void ChangeToMarine();
9610 		ChangeToMarine();
9611 
9612 		for(i=0;i<NET_MAXPLAYERS;i++)
9613 		{
9614 			netGameData.playerData[i].characterType=NGCT_Marine;
9615 		}
9616 	}
9617 	TurnOffMultiplayerObserveMode();
9618 
9619 	//go to a new start position
9620 //	StartOfGame_PlayerPlacement(Player->ObStrategyBlock, seed);
9621 
9622 	netGameData.myGameState=NGS_Playing;
9623 
9624 	//record seed for later (used during restart level process)
9625 	MultiplayerRestartSeed=seed;
9626 	if(!MultiplayerRestartSeed) MultiplayerRestartSeed=1;
9627 
9628 }
9629 
9630 
9631 
9632 
9633 /* KJL 15:46:19 09/04/98 - processing info pertaining to multiplayer games */
9634 
Inform_PlayerHasDied(DPID killer,DPID victim,NETGAME_CHARACTERTYPE killerType,char weaponIcon)9635 static void Inform_PlayerHasDied(DPID killer, DPID victim,NETGAME_CHARACTERTYPE killerType,char weaponIcon)
9636 {
9637 	int victimIndex = PlayerIdInPlayerList(victim);
9638 
9639 	/* KJL 15:35:38 09/04/98 - not knowing who the victim is what make things a bit awkward... */
9640 	if(victimIndex==NET_IDNOTINPLAYERLIST) return;
9641 
9642 
9643 	switch(killerType)
9644 	{
9645 		case NGCT_AI_Alien :
9646 		{
9647 			NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY_ALIEN,netGameData.playerData[victimIndex].name,0);
9648 			break;
9649 		}
9650 
9651 		case NGCT_AI_Predalien :
9652 		{
9653 			NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY_PREDALIEN,netGameData.playerData[victimIndex].name,0);
9654 			break;
9655 		}
9656 
9657 		case NGCT_AI_Praetorian :
9658 		{
9659 			NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY_PRAETORIAN,netGameData.playerData[victimIndex].name,0);
9660 			break;
9661 		}
9662 
9663 		default :
9664 		{
9665 			/* KJL 15:36:03 09/04/98 - killer should be set to null if it's a suicide */
9666 			/*killer==vitim means suicide now ,as well*/
9667 			if (killer && killer!=victim)
9668 			{
9669 				int killerIndex = PlayerIdInPlayerList(killer);
9670 
9671 				if(killerIndex!=NET_IDNOTINPLAYERLIST)
9672 				{
9673 					char weaponSymbol[5]="";
9674 					if(weaponIcon)
9675 					{
9676 						sprintf(weaponSymbol," %c",weaponIcon);
9677 					}
9678 					NetworkGameConsoleMessageWithWeaponIcon(TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY,netGameData.playerData[victimIndex].name,netGameData.playerData[killerIndex].name,weaponSymbol);
9679 				}
9680 			}
9681 			else
9682 			{
9683 				NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_SUICIDE,netGameData.playerData[victimIndex].name,0);
9684 			}
9685 			break;
9686 		}
9687 	}
9688 }
9689 
Inform_AiHasDied(DPID killer,ALIEN_TYPE type,char weaponIcon)9690 static void Inform_AiHasDied(DPID killer,ALIEN_TYPE type,char weaponIcon)
9691 {
9692 	int killerIndex = PlayerIdInPlayerList(killer);
9693 
9694 	if(killerIndex!=NET_IDNOTINPLAYERLIST)
9695 	{
9696 		char weaponSymbol[5]="";
9697 		if(weaponIcon)
9698 		{
9699 			sprintf(weaponSymbol," %c",weaponIcon);
9700 		}
9701 		switch(type)
9702 		{
9703 			case AT_Standard :
9704 			{
9705 				NetworkGameConsoleMessageWithWeaponIcon(TEXTSTRING_MULTIPLAYERCONSOLE_ALIEN_KILLED,netGameData.playerData[killerIndex].name,0,weaponSymbol);
9706 	  			break;
9707 			}
9708 
9709 			case AT_Predalien :
9710 			{
9711 				NetworkGameConsoleMessageWithWeaponIcon(TEXTSTRING_MULTIPLAYERCONSOLE_PREDALIEN_KILLED,netGameData.playerData[killerIndex].name,0,weaponSymbol);
9712 				break;
9713 			}
9714 
9715 			case AT_Praetorian :
9716 			{
9717 				NetworkGameConsoleMessageWithWeaponIcon(TEXTSTRING_MULTIPLAYERCONSOLE_PRAETORIAN_KILLED,netGameData.playerData[killerIndex].name,0,weaponSymbol);
9718 				break;
9719 			}
9720 		}
9721 	}
9722 }
9723 
Inform_PlayerHasLeft(DPID player)9724 static void Inform_PlayerHasLeft(DPID player)
9725 {
9726 	int playerIndex = PlayerIdInPlayerList(player);
9727 
9728 	/* KJL 15:35:38 09/04/98 - not knowing who the player is what make things a bit awkward... */
9729 	if(playerIndex==NET_IDNOTINPLAYERLIST) return;
9730 
9731 	NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_LEAVEGAME,netGameData.playerData[playerIndex].name,0);
9732 
9733 }
Inform_PlayerHasJoined(DPID player)9734 static void Inform_PlayerHasJoined(DPID player)
9735 {
9736 	int playerIndex = PlayerIdInPlayerList(player);
9737 
9738 	/* KJL 15:35:38 09/04/98 - not knowing who the player is what make things a bit awkward... */
9739 	if(playerIndex==NET_IDNOTINPLAYERLIST) return;
9740 
9741 	NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_JOINGAME,netGameData.playerData[playerIndex].name,0);
9742 }
Inform_PlayerHasConnected(DPID player)9743 static void Inform_PlayerHasConnected(DPID player)
9744 {
9745 	int playerIndex = PlayerIdInPlayerList(player);
9746 
9747 	/* KJL 15:35:38 09/04/98 - not knowing who the player is what make things a bit awkward... */
9748 	if(playerIndex==NET_IDNOTINPLAYERLIST) return;
9749 
9750 	NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_CONNECTGAME,netGameData.playerData[playerIndex].name,0);
9751 }
9752 
Inform_NewHost(void)9753 static void Inform_NewHost(void)
9754 {
9755 	NewOnScreenMessage(GetTextString(TEXTSTRING_MULTIPLAYERCONSOLE_NEWHOST));
9756 }
9757 
9758 
9759 
9760 
WriteFragmentStatus(int fragmentNumber,int status)9761 static void WriteFragmentStatus(int fragmentNumber, int status)
9762 {
9763 	int n = fragmentNumber>>3;
9764 	int r = fragmentNumber - (n<<3);
9765 	unsigned char *ptr = &FragmentalObjectStatus[n];
9766 	unsigned char mask = 1<<r;
9767 
9768 	if (status)
9769 	{
9770 		*ptr |= mask;
9771 	}
9772 	else
9773 	{
9774 		*ptr &= ~mask;
9775 	}
9776 }
ReadFragmentStatus(int fragmentNumber)9777 static int ReadFragmentStatus(int fragmentNumber)
9778 {
9779 	int n = fragmentNumber>>3;
9780 	int r = fragmentNumber - (n<<3);
9781 	unsigned char *ptr = &FragmentalObjectStatus[n];
9782 	unsigned char mask = 1<<r;
9783 
9784 	return((*ptr)&mask);
9785 }
9786 
WriteStrategySynch(int objectNumber,int status)9787 static void WriteStrategySynch(int objectNumber, int status)
9788 {
9789 	int n = objectNumber>>2;
9790 	int shift = (objectNumber - (n<<2))*2;
9791 	unsigned char *ptr = &StrategySynchArray[n];
9792 	unsigned char mask = 3<<shift;
9793 
9794 	*ptr &=~ mask;
9795 	*ptr |= (status & 3)<<shift;
9796 
9797 }
ReadStrategySynch(int objectNumber)9798 static int ReadStrategySynch(int objectNumber)
9799 {
9800 	int n = objectNumber>>2;
9801 	int shift = (objectNumber - (n<<2))*2;
9802 	unsigned char *ptr = &StrategySynchArray[n];
9803 	unsigned char mask = 3<<shift;
9804 
9805 	return(((*ptr)&mask)>>shift);
9806 }
9807 
9808 
9809 
9810 #if 1
GetDynamicScoreMultiplier(int playerKilledIndex,int killerIndex)9811 static int GetDynamicScoreMultiplier(int playerKilledIndex,int killerIndex)
9812 {
9813 	int scoreFor;
9814 	int scoreAgainst;
9815 	int mult;
9816 	int playerCount=0;
9817 	int i;
9818 
9819 
9820 	GLOBALASSERT(playerKilledIndex!=killerIndex);
9821 
9822 	scoreFor=netGameData.playerData[playerKilledIndex].playerScore;
9823 	scoreAgainst=netGameData.playerData[playerKilledIndex].playerScoreAgainst;
9824 
9825 	scoreFor=max(500,scoreFor+500);
9826 	scoreAgainst=max(500,scoreAgainst+500);
9827 
9828 	//count players
9829 	for(i=0;i<NET_MAXPLAYERS;i++)
9830 	{
9831 		if(netGameData.playerData[i].playerId==0) continue;
9832 		playerCount++;
9833 	}
9834 	//only bother if there are at least 3 players
9835 	if(playerCount<3) return ONE_FIXED;
9836 
9837 
9838 	//value of player depends on comparing player's score with the number of points scored against that player
9839 	if(scoreFor>scoreAgainst)
9840 	{
9841 		int ratio=DIV_FIXED(scoreFor,scoreAgainst);
9842 		mult=DIV_FIXED(10*ratio,9*ONE_FIXED+ratio);
9843 		if(mult<ONE_FIXED) mult=ONE_FIXED;
9844 	}
9845 	else
9846 	{
9847 		int ratio=DIV_FIXED(scoreAgainst,scoreFor);
9848 		mult=DIV_FIXED(9*ONE_FIXED+ratio,10*ratio);
9849 		if(mult>ONE_FIXED) mult=ONE_FIXED;
9850 	}
9851 
9852 
9853 	return mult;
9854 
9855 }
9856 #else
GetDynamicScoreMultiplier(int playerKilledIndex,int killerIndex)9857 static int GetDynamicScoreMultiplier(int playerKilledIndex,int killerIndex)
9858 {
9859 	int i;
9860 	int scoreTotal=0;
9861 	int playerCount=0;
9862 	int playerKilledScore;
9863 	int mult;
9864 
9865 	GLOBALASSERT(playerKilledIndex!=killerIndex);
9866 
9867 	//add up score of all players
9868 	for(i=0;i<NET_MAXPLAYERS;i++)
9869 	{
9870 		if(netGameData.playerData[i].playerId==NULL) continue;
9871 
9872 
9873 
9874 		playerCount++;
9875 		//give everyone a minimum score of 500 for the purpose of this calculation
9876 		scoreTotal+=max(500,netGameData.playerData[i].playerScore+500);
9877 	}
9878 	if(playerCount<3 || !scoreTotal) return ONE_FIXED;
9879 
9880 	playerKilledScore=max(500,netGameData.playerData[playerKilledIndex].playerScore+500);
9881 
9882 	//get average score of all players other than killed player
9883 	playerCount--;
9884 	scoreTotal=(scoreTotal-playerKilledScore)/playerCount;
9885 
9886 	if(playerKilledScore>scoreTotal)
9887 	{
9888 		int ratio=DIV_FIXED(playerKilledScore,scoreTotal);
9889 		mult=DIV_FIXED(10*ratio,10*ONE_FIXED+ratio);
9890 		if(mult<ONE_FIXED) mult=ONE_FIXED;
9891 	}
9892 	else
9893 	{
9894 		int ratio=DIV_FIXED(scoreTotal,playerKilledScore);
9895 		mult=DIV_FIXED(10*ONE_FIXED+ratio,10*ratio);
9896 		if(mult>ONE_FIXED) mult=ONE_FIXED;
9897 	}
9898 
9899 
9900 	return mult;
9901 
9902 }
9903 #endif
GetNetScoreForKill(int playerKilledIndex,int killerIndex)9904 static int GetNetScoreForKill(int playerKilledIndex,int killerIndex)
9905 {
9906 	NETGAME_CHARACTERTYPE killerType=netGameData.playerData[killerIndex].characterType;
9907 	NETGAME_CHARACTERTYPE playerKilledType=netGameData.playerData[playerKilledIndex].characterType;
9908 
9909 	int score=netGameData.baseKillValue;
9910 
9911 	if(playerKilledIndex==killerIndex)
9912 	{
9913 		//suicide
9914 		return -netGameData.baseKillValue;
9915 	}
9916 
9917 	if(netGameData.gameType==NGT_PredatorTag)
9918 	{
9919 		//only the predator can score
9920 		if(killerType!=NGCT_Predator) return 0;
9921 	}
9922 	else if(netGameData.gameType==NGT_AlienTag)
9923 	{
9924 		//only the alien can score
9925 		if(killerType!=NGCT_Alien) return 0;
9926 	}
9927 	else if(netGameData.gameType==NGT_CoopDeathmatch)
9928 	{
9929 		//have we killed someone on the same team
9930 		if(killerType==playerKilledType)
9931 		{
9932 			return -netGameData.baseKillValue;
9933 		}
9934 	}
9935 
9936 	if(netGameData.useCharacterKillValues)
9937 	{
9938 		score=netGameData.characterKillValues[playerKilledType];
9939 	}
9940 
9941 	if(netGameData.useDynamicScoring && score>0)
9942 	{
9943 		int dynamicScoreMult=GetDynamicScoreMultiplier(playerKilledIndex,killerIndex);
9944 		score=MUL_FIXED(score,dynamicScoreMult);
9945    		//make sure player gets at least one point
9946 		if(score<1) score=1;
9947 	}
9948 
9949 
9950 	return score;
9951 
9952 }
9953 
9954 
CheckLastManStandingState()9955 static void CheckLastManStandingState()
9956 {
9957 	//make sure that ther is at least 1 alien and 1 non-alien
9958 	int alienCount=0;
9959 	int nonAlienCount=0;
9960 	int alienIndex;
9961 	int i;
9962 
9963 	if(netGameData.stateCheckTimeDelay>0)
9964 	{
9965 		//still too soon after last restart to check again
9966 		netGameData.stateCheckTimeDelay-=RealFrameTime;
9967 		return;
9968 	}
9969 
9970 	for(i=0;i<NET_MAXPLAYERS;i++)
9971 	{
9972 		if(netGameData.playerData[i].playerId)
9973 		{
9974 			if(netGameData.playerData[i].characterType==NGCT_Alien)
9975 			{
9976 				alienCount++;
9977 			}
9978 			else
9979 			{
9980 				nonAlienCount++;
9981 			}
9982 		}
9983 	}
9984 
9985 	//if there is only one player forget it
9986 	if((alienCount+nonAlienCount)<2) return;
9987 
9988 	if(alienCount && nonAlienCount)
9989 	{
9990 		//the game is still going
9991 		//make sure the restarttimer is 0
9992 		netGameData.LMS_RestartTimer=0;
9993 		return;
9994 	}
9995 
9996 
9997 
9998 	//find out who the next alien will be
9999 	for(alienIndex=netGameData.LMS_AlienIndex+1;;alienIndex++)
10000 	{
10001 		if(alienIndex>=NET_MAXPLAYERS)
10002 		{
10003 			//everyone has had a turn as an alien
10004 			TransmitEndOfGameNetMsg();
10005 			netGameData.myGameState = NGS_EndGameScreen;
10006 			return;
10007 		}
10008 
10009 		if(netGameData.playerData[alienIndex].playerId)
10010 		{
10011 			//this player will be our new alien
10012 			break;
10013 		}
10014 	}
10015 
10016 	//game needs to be restarted.
10017 	//has the countdown started?
10018 	if(netGameData.LMS_RestartTimer>0)
10019 	{
10020 		int secondsBefore,secondsAfter;
10021 		secondsBefore=(netGameData.LMS_RestartTimer+ONE_FIXED-1)/ONE_FIXED;
10022 		netGameData.LMS_RestartTimer-=RealFrameTime;
10023 		secondsAfter=(netGameData.LMS_RestartTimer+ONE_FIXED-1)/ONE_FIXED;
10024 
10025 		//has the timer reached 0?
10026 		if(netGameData.LMS_RestartTimer<0)
10027 		{
10028 			//get a random number seed for starting position
10029 			int seed=FastRandom();
10030 			netGameData.LMS_RestartTimer=0;
10031 
10032 			netGameData.LMS_AlienIndex=alienIndex;
10033 
10034 			AddNetMsg_LastManStanding_Restart(netGameData.playerData[alienIndex].playerId,seed);
10035 			Handle_LastManStanding_Restart(netGameData.playerData[alienIndex].playerId,seed);
10036 
10037 			//set time delay until we next check for need to restart
10038 			//this gives time for the other players to get their messages
10039 			netGameData.stateCheckTimeDelay=5*ONE_FIXED;
10040 		}
10041 		else
10042 		{
10043 			//if the timer has gone down another second , tell everyone
10044 			if(secondsAfter<secondsBefore)
10045 			{
10046 				AddNetMsg_LastManStanding_RestartTimer((char)secondsAfter);
10047 				Handle_LastManStanding_RestartTimer((char)secondsAfter);
10048 			}
10049 		}
10050 
10051 	}
10052 	else
10053 	{
10054 		static int ReminderTimer=0;
10055 
10056 		if(netGameData.LMS_RestartTimer==-1)
10057 		{
10058 			ReminderTimer -= RealFrameTime;
10059 			if(ReminderTimer<0)
10060 			{
10061 				//give a reminder (forced by setting reset timer to 0)
10062 				ReminderTimer=0;
10063 				netGameData.LMS_RestartTimer=0;
10064 			}
10065 		}
10066 
10067 		if(netGameData.LMS_RestartTimer!=-1)
10068 		{
10069 
10070 			//tell host to press operate
10071 			PrintStringTableEntryInConsole(TEXTSTRING_MULTIPLAYER_LMS_ALLMARINESDEAD);
10072 			PrintStringTableEntryInConsole(TEXTSTRING_MULTIPLAYER_LMS_HOSTPRESSOPERATE);
10073 			AddNetMsg_LastManStanding_RestartTimer(255);
10074 			netGameData.LMS_RestartTimer=-1;
10075 			ReminderTimer = 6*ONE_FIXED;
10076 		}
10077 
10078 		//wait for host to press operate
10079 
10080 		{
10081 			PLAYER_STATUS *psPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
10082 			if(psPtr->Mvt_InputRequests.Flags.Rqst_Operate)
10083 			{
10084 
10085 				//say who the next alien will be
10086 				AddNetMsg_PlayerID(netGameData.playerData[alienIndex].playerId,NetMT_LastManStanding_RestartInfo);
10087 				Handle_LastManStanding_RestartInfo(netGameData.playerData[alienIndex].playerId);
10088 
10089 				//start the restart timer
10090 				netGameData.LMS_RestartTimer=4*ONE_FIXED;
10091 			}
10092 		}
10093 
10094 	}
10095 
10096 }
10097 
Handle_LastManStanding_Restart(DPID alienID,int seed)10098 static void Handle_LastManStanding_Restart(DPID alienID,int seed)
10099 {
10100 	int i;
10101 	/* if we're not playing, ignore it */
10102 	if(netGameData.myGameState!=NGS_Playing) return;
10103 	if(AVPDPNetID==alienID)
10104 	{
10105 		//become an alien
10106 		extern void ChangeToAlien();
10107 		ChangeToAlien();
10108 	}
10109 	else
10110 	{
10111 		//become a marine
10112 		extern void ChangeToMarine();
10113 		ChangeToMarine();
10114 	}
10115 
10116 	for(i=0;i<NET_MAXPLAYERS;i++)
10117 	{
10118 		if(netGameData.playerData[i].playerId==alienID)
10119 		{
10120 			netGameData.playerData[i].characterType=NGCT_Alien;
10121 		}
10122 		else
10123 		{
10124 			netGameData.playerData[i].characterType=NGCT_Marine;
10125 		}
10126 	}
10127 	/*
10128 	//go to an new start position
10129 	StartOfGame_PlayerPlacement(Player->ObStrategyBlock,seed);
10130 
10131 	//restore all the destroyed objects.
10132 	RespawnAllObjects();
10133 	*/
10134 
10135 	MultiplayerRestartSeed=seed;
10136 	AvP.RestartLevel=1;
10137 
10138 	PrintStringTableEntryInConsole(TEXTSTRING_MULTIPLAYER_LMS_GO);
10139 }
10140 
Handle_LastManStanding_RestartInfo(DPID alienID)10141 static void Handle_LastManStanding_RestartInfo(DPID alienID)
10142 {
10143 	int i;
10144 	/* if we're not playing, ignore it */
10145 	if(netGameData.myGameState!=NGS_Playing) return;
10146 
10147 	//find the alien's name
10148 	for(i=0;i<NET_MAXPLAYERS;i++)
10149 	{
10150 		if(netGameData.playerData[i].playerId==alienID)
10151 		{
10152 			NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYER_LMS_WILLBEALIEN,netGameData.playerData[i].name,0);
10153 		}
10154 	}
10155 }
10156 
Handle_LastManStanding_LastMan(DPID marineID)10157 static void Handle_LastManStanding_LastMan(DPID marineID)
10158 {
10159 	int i;
10160 	/* if we're not playing, ignore it */
10161 	if(netGameData.myGameState!=NGS_Playing) return;
10162 
10163 	//find the marine's name
10164 	for(i=0;i<NET_MAXPLAYERS;i++)
10165 	{
10166 		if(netGameData.playerData[i].playerId==marineID)
10167 		{
10168 			NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYER_LMS_LASTMANSTANDING,netGameData.playerData[i].name,0);
10169 		}
10170 	}
10171 }
10172 
Handle_LastManStanding_RestartTimer(unsigned char time)10173 static void Handle_LastManStanding_RestartTimer(unsigned char time)
10174 {
10175 	/* if we're not playing, ignore it */
10176 	if(netGameData.myGameState!=NGS_Playing) return;
10177 	if((int)time==255)
10178 	{
10179 		//tell player to wait
10180 		PrintStringTableEntryInConsole(TEXTSTRING_MULTIPLAYER_LMS_ALLMARINESDEAD);
10181 		PrintStringTableEntryInConsole(TEXTSTRING_MULTIPLAYER_LMS_WAITFORHOST);
10182 	}
10183 	else
10184 	{
10185 		//show countdown
10186 		sprintf(OnScreenMessageBuffer,"%d...",time );
10187 		NewOnScreenMessage(OnScreenMessageBuffer);
10188 	}
10189 
10190 }
10191 
10192 
10193 
10194 
10195 
CountPlayersOfType(NETGAME_CHARACTERTYPE species)10196 static int CountPlayersOfType(NETGAME_CHARACTERTYPE species)
10197 {
10198 	int i;
10199 	int numPredators=0;
10200 
10201 	for(i=0;i<(NET_MAXPLAYERS);i++)
10202 	{
10203 		if(netGameData.playerData[i].playerId)
10204 		{
10205 			if(netGameData.playerData[i].characterType==species)
10206 			{
10207 				numPredators++;
10208 			}
10209 		}
10210 	}
10211 
10212 	return numPredators;
10213 }
10214 
CheckSpeciesTagState()10215 static void CheckSpeciesTagState()
10216 {
10217 	int i;
10218 	NETGAME_CHARACTERTYPE tagSpecies=NGCT_Predator;
10219 	if(netGameData.gameType==NGT_AlienTag) tagSpecies=NGCT_Alien;
10220 
10221 	//make sure that there is at least one predator in the game
10222 	if(netGameData.stateCheckTimeDelay>0)
10223 	{
10224 		netGameData.stateCheckTimeDelay-=RealFrameTime;
10225 		return;
10226 	}
10227 
10228 	if(CountPlayersOfType(tagSpecies)) return;
10229 
10230 	//we need to choose a predator player
10231 	//make it the person with the lowest score
10232 	{
10233 		DPID predID=0;
10234 		int lowScore=1000000000;
10235 		for(i=0;i<(NET_MAXPLAYERS);i++)
10236 		{
10237 			if(netGameData.playerData[i].playerId)
10238 			{
10239 				if(netGameData.playerData[i].playerScore<lowScore)
10240 				{
10241 					lowScore=netGameData.playerData[i].playerScore;
10242 					predID=netGameData.playerData[i].playerId;
10243 				}
10244 			}
10245 
10246 		}
10247 		AddNetMsg_PlayerID(predID,NetMT_PredatorTag_NewPredator);
10248 		Handle_SpeciesTag_NewPersonIt(predID);
10249 
10250 
10251 	}
10252 
10253 }
10254 
10255 
Handle_SpeciesTag_NewPersonIt(DPID predatorID)10256 static void Handle_SpeciesTag_NewPersonIt(DPID predatorID)
10257 {
10258 	/* if we're not playing, ignore it */
10259 	if(netGameData.myGameState!=NGS_Playing) return;
10260 
10261 	if(AVPDPNetID==predatorID)
10262 	{
10263 		//become aa predator or alien
10264 		if(netGameData.gameType==NGT_PredatorTag)
10265 		{
10266 			extern void ChangeToPredator();
10267 			ChangeToPredator();
10268 		}
10269 		else if(netGameData.gameType==NGT_AlienTag)
10270 		{
10271 			extern void ChangeToAlien();
10272 			ChangeToAlien();
10273 		}
10274 	}
10275 
10276 	netGameData.stateCheckTimeDelay=5*ONE_FIXED;
10277 }
10278 
ChangeNetGameType_Individual()10279 void ChangeNetGameType_Individual()
10280 {
10281 	if(AvP.Network==I_No_Network) return;
10282 	netGameData.gameType=NGT_Individual;
10283 }
10284 
ChangeNetGameType_Coop()10285 void ChangeNetGameType_Coop()
10286 {
10287 	if(AvP.Network==I_No_Network) return;
10288 	netGameData.gameType=NGT_CoopDeathmatch;
10289 }
10290 
ChangeNetGameType_LastManStanding()10291 void ChangeNetGameType_LastManStanding()
10292 {
10293 	if(AvP.Network==I_No_Network) return;
10294 	netGameData.gameType=NGT_LastManStanding;
10295 	netGameData.LMS_AlienIndex=0;
10296 	netGameData.stateCheckTimeDelay=0;
10297 }
10298 
ChangeNetGameType_PredatorTag()10299 void ChangeNetGameType_PredatorTag()
10300 {
10301 	if(AvP.Network==I_No_Network) return;
10302 	netGameData.gameType=NGT_PredatorTag;
10303 }
10304 
10305 
10306 /*
10307 	This function takes a string from the list of language localised strings, and replaces
10308 	instances of %1 and %2 with the appropriate names.
10309 	It then displays the message in the console.
10310 */
NetworkGameConsoleMessage(enum TEXTSTRING_ID stringID,const char * name1,const char * name2)10311 static void NetworkGameConsoleMessage(enum TEXTSTRING_ID stringID,const char* name1,const char* name2)
10312 {
10313 	char* string;
10314 	char* messageptr=&OnScreenMessageBuffer[0];
10315 
10316 	string=GetTextString(stringID);
10317 	if(!string) return;
10318 
10319 	while(*string)
10320 	{
10321 		if(string[0]=='%')
10322 		{
10323 			if(string[1]>='1' && string[1]<='9')
10324 			{
10325 				if(string[1]=='1' && name1)
10326 				{
10327 					strcpy(messageptr,name1);
10328 					messageptr+=strlen(name1);
10329 				}
10330 				if(string[1]=='2' && name2)
10331 				{
10332 					strcpy(messageptr,name2);
10333 					messageptr+=strlen(name2);
10334 				}
10335 
10336 				string+=2;
10337 				continue;
10338 			}
10339 		}
10340 		*messageptr++=*string++;
10341 	}
10342 	*messageptr=0;
10343 
10344 	NewOnScreenMessage(OnScreenMessageBuffer);
10345 }
10346 
NetworkGameConsoleMessageWithWeaponIcon(enum TEXTSTRING_ID stringID,const char * name1,const char * name2,const char * weaponSymbol)10347 static void NetworkGameConsoleMessageWithWeaponIcon(enum TEXTSTRING_ID stringID,const char* name1,const char* name2,const char* weaponSymbol)
10348 {
10349 	char* string;
10350 	char* messageptr=&OnScreenMessageBuffer[0];
10351 
10352 	string=GetTextString(stringID);
10353 	if(!string) return;
10354 
10355 	while(*string)
10356 	{
10357 		if(string[0]=='%')
10358 		{
10359 			if(string[1]>='1' && string[1]<='9')
10360 			{
10361 				if(string[1]=='1' && name1)
10362 				{
10363 					strcpy(messageptr,name1);
10364 					messageptr+=strlen(name1);
10365 				}
10366 				if(string[1]=='2' && name2)
10367 				{
10368 					strcpy(messageptr,name2);
10369 					messageptr+=strlen(name2);
10370 				}
10371 
10372 
10373 				string+=2;
10374 				continue;
10375 			}
10376 		}
10377 		*messageptr++=*string++;
10378 	}
10379 	*messageptr=0;
10380 
10381 	if(weaponSymbol)
10382 	{
10383 		strcat(OnScreenMessageBuffer,weaponSymbol);
10384 	}
10385 
10386 	NewOnScreenMessage(OnScreenMessageBuffer);
10387 }
10388 
10389 static int CharacterTypesAvailable[NUM_PC_TYPES];
10390 static int CharacterSubTypesAvailable[NUM_PC_SUBTYPES];
10391 
DetermineAvailableCharacterTypes(BOOL ConsiderUsedCharacters)10392 int DetermineAvailableCharacterTypes(BOOL ConsiderUsedCharacters)
10393 {
10394 	int i;
10395 	int maxMarines=0;
10396 
10397 	//set limits for disallowed marine types to zero
10398 	if(!netGameData.allowSmartgun) netGameData.maxMarineSmartgun=0;
10399 	if(!netGameData.allowFlamer) netGameData.maxMarineFlamer=0;
10400 	if(!netGameData.allowMinigun) netGameData.maxMarineMinigun=0;
10401 	if(!netGameData.allowSadar) netGameData.maxMarineSadar=0;
10402 	if(!netGameData.allowGrenadeLauncher) netGameData.maxMarineGrenade=0;
10403 	if(!netGameData.allowSmartDisc) netGameData.maxMarineSmartDisc=0;
10404 	if(!netGameData.allowPistols) netGameData.maxMarinePistols=0;
10405 
10406 	if(netGameData.gameType==NGT_PredatorTag)
10407 	{
10408 		//force limit of one predator
10409 		netGameData.maxPredator=1;
10410 	}
10411 	else if(netGameData.gameType==NGT_AlienTag)
10412 	{
10413 		//force limit of one alien
10414 		netGameData.maxAlien=1;
10415 	}
10416 	else if(netGameData.gameType==NGT_LastManStanding)
10417 	{
10418 		//no predators are allowed
10419 		netGameData.maxPredator=0;
10420 		//the host will be the first alien (and so is the only person that can select alien on the starting screen)
10421 		netGameData.maxAlien=1;
10422 	}
10423 	else if(netGameData.gameType==NGT_Coop)
10424 	{
10425 		//no pc aliens allowed in coop games
10426 		netGameData.maxAlien=0;
10427 	}
10428 
10429 	if(netGameData.skirmishMode)
10430 	{
10431 		//Skirmish mode - player can be anything except an alien
10432 		netGameData.maxAlien = 0;
10433 		netGameData.maxPredator=8;
10434 		netGameData.maxMarine=8;
10435 
10436 		netGameData.maxMarineGeneral=8;
10437 		netGameData.maxMarinePulseRifle=8;
10438 		netGameData.maxMarineSmartgun=8;
10439 		netGameData.maxMarineFlamer=8;
10440 		netGameData.maxMarineSadar=8;
10441 		netGameData.maxMarineGrenade=8;
10442 		netGameData.maxMarineMinigun=8;
10443 		netGameData.maxMarineSmartDisc=8;
10444 		netGameData.maxMarinePistols=8;
10445 	}
10446 
10447 	CharacterTypesAvailable[NGCT_Marine]=netGameData.maxMarine;
10448 	CharacterTypesAvailable[NGCT_Alien]=netGameData.maxAlien;
10449 	CharacterTypesAvailable[NGCT_Predator]=netGameData.maxPredator;
10450 
10451 	CharacterSubTypesAvailable[NGSCT_General]=netGameData.maxMarineGeneral;
10452 	CharacterSubTypesAvailable[NGSCT_PulseRifle]=netGameData.maxMarinePulseRifle;
10453 	CharacterSubTypesAvailable[NGSCT_Smartgun]=netGameData.maxMarineSmartgun;
10454 	CharacterSubTypesAvailable[NGSCT_Flamer]=netGameData.maxMarineFlamer;
10455 	CharacterSubTypesAvailable[NGSCT_Sadar]=netGameData.maxMarineSadar;
10456 	CharacterSubTypesAvailable[NGSCT_GrenadeLauncher]=netGameData.maxMarineGrenade;
10457 	CharacterSubTypesAvailable[NGSCT_Minigun]=netGameData.maxMarineMinigun;
10458 	CharacterSubTypesAvailable[NGSCT_Frisbee]=netGameData.maxMarineSmartDisc;
10459 	CharacterSubTypesAvailable[NGSCT_Pistols]=netGameData.maxMarinePistols;
10460 
10461 
10462 	//go through all the other players to see which character types are being used
10463 	if(ConsiderUsedCharacters)
10464 	{
10465 		if(AvP.Network!=I_No_Network)
10466 		{
10467 			//(it will still be I_No_Network while the host is setting things up)
10468 			for(i=0;i<NET_MAXPLAYERS;i++)
10469 			{
10470 				if(netGameData.playerData[i].playerId && netGameData.playerData[i].playerId!=AVPDPNetID)
10471 				{
10472 					switch(netGameData.playerData[i].characterType)
10473 					{
10474 						case NGCT_Marine :
10475 							CharacterTypesAvailable[NGCT_Marine]--;
10476 							switch(netGameData.playerData[i].characterSubType)
10477 							{
10478 								case NGSCT_General :
10479 									CharacterSubTypesAvailable[NGSCT_General]--;
10480 									break;
10481 
10482 								case NGSCT_PulseRifle :
10483 									CharacterSubTypesAvailable[NGSCT_PulseRifle]--;
10484 									break;
10485 
10486 								case NGSCT_Smartgun :
10487 									CharacterSubTypesAvailable[NGSCT_Smartgun]--;
10488 									break;
10489 
10490 								case NGSCT_Flamer :
10491 									CharacterSubTypesAvailable[NGSCT_Flamer]--;
10492 									break;
10493 
10494 								case NGSCT_Sadar :
10495 									CharacterSubTypesAvailable[NGSCT_Sadar]--;
10496 									break;
10497 
10498 								case NGSCT_GrenadeLauncher :
10499 									CharacterSubTypesAvailable[NGSCT_GrenadeLauncher]--;
10500 									break;
10501 
10502 								case NGSCT_Minigun :
10503 									CharacterSubTypesAvailable[NGSCT_Minigun]--;
10504 									break;
10505 
10506 								case NGSCT_Frisbee :
10507 									CharacterSubTypesAvailable[NGSCT_Frisbee]--;
10508 									break;
10509 
10510 								case NGSCT_Pistols :
10511 									CharacterSubTypesAvailable[NGSCT_Pistols]--;
10512 									break;
10513 
10514 							}
10515 							break;
10516 
10517 						case NGCT_Predator :
10518 							CharacterTypesAvailable[NGCT_Predator]--;
10519 							break;
10520 
10521 						case NGCT_Alien :
10522 							CharacterTypesAvailable[NGCT_Alien]--;
10523 							break;
10524 
10525 						default:
10526 							break;
10527 					}
10528 				}
10529 			}
10530 
10531 		}
10532 	}
10533 	//make sure all the limits are at least 0
10534 	for(i=0;i<NUM_PC_TYPES;i++)
10535 	{
10536 		CharacterTypesAvailable[i]=max(0,CharacterTypesAvailable[i]);
10537 	}
10538 	for(i=0;i<NUM_PC_SUBTYPES;i++)
10539 	{
10540 		CharacterSubTypesAvailable[i]=max(0,CharacterSubTypesAvailable[i]);
10541 	}
10542 
10543 
10544 
10545 	//adjust the marine limits to take into account that there must be both sufficent marine slots ,
10546 	// and also sufficient subtype slots
10547 	maxMarines=0;
10548 	for(i=0;i<NUM_PC_SUBTYPES;i++)
10549 	{
10550 		CharacterSubTypesAvailable[i]=min(CharacterSubTypesAvailable[i],CharacterTypesAvailable[NGCT_Marine]);
10551 		maxMarines+=CharacterSubTypesAvailable[i];
10552 	}
10553 	CharacterTypesAvailable[NGCT_Marine]=min(CharacterTypesAvailable[NGCT_Marine],maxMarines);
10554 
10555 	//return the total number of players available
10556 	return CharacterTypesAvailable[NGCT_Marine]+
10557 		   CharacterTypesAvailable[NGCT_Alien]+
10558 		   CharacterTypesAvailable[NGCT_Predator];
10559 
10560 }
10561 
GetNextAllowedSpecies(int * species,BOOL search_forwards)10562 void GetNextAllowedSpecies(int* species,BOOL search_forwards)
10563 {
10564 	int count =0;
10565 
10566 	if(AvP.Network==I_No_Network)
10567 	{
10568 		if(netGameData.gameType==NGT_PredatorTag)
10569 		{
10570 			//this computer is the host setting up a predator tag game
10571 			//therefore must be a predator
10572 			*species=1;
10573 			return;
10574 		}
10575 		else if(netGameData.gameType==NGT_AlienTag || netGameData.gameType==NGT_LastManStanding)
10576 		{
10577 			//this computer is the host setting up an alien tag or last man standing game
10578 			//therefore must be a alien
10579 			*species=2;
10580 			return;
10581 		}
10582 	}
10583 
10584 	DetermineAvailableCharacterTypes(TRUE);
10585 	do
10586 	{
10587 		switch(*species)
10588 		{
10589 			case 0:	//marine (general)
10590 				if(CharacterSubTypesAvailable[NGSCT_General]>0) return;
10591 				break;
10592 
10593 			case 1:	//predator
10594 				if(CharacterTypesAvailable[NGCT_Predator]>0) return;
10595 				break;
10596 
10597 			case 2:	//alien
10598 				if(CharacterTypesAvailable[NGCT_Alien]>0) return;
10599 				break;
10600 
10601 			case 3: //marine (pulse rifle)
10602 				if(CharacterSubTypesAvailable[NGSCT_PulseRifle]) return;
10603 				break;
10604 
10605 			case 4: //marine (smartgun)
10606 				if(CharacterSubTypesAvailable[NGSCT_Smartgun]) return;
10607 				break;
10608 
10609 			case 5: //marine (flamer)
10610 				if(CharacterSubTypesAvailable[NGSCT_Flamer]) return;
10611 				break;
10612 
10613 			case 6: //marine (sadar)
10614 				if(CharacterSubTypesAvailable[NGSCT_Sadar]) return;
10615 				break;
10616 
10617 			case 7: //marine (grenade)
10618 				if(CharacterSubTypesAvailable[NGSCT_GrenadeLauncher]) return;
10619 				break;
10620 
10621 			case 8: //marine (minigun)
10622 				if(CharacterSubTypesAvailable[NGSCT_Minigun]) return;
10623 				break;
10624 
10625 			case 9: //marine (frisbee)
10626 				if(CharacterSubTypesAvailable[NGSCT_Frisbee]) return;
10627 				break;
10628 
10629 			case 10: //marine (pistols)
10630 				if(CharacterSubTypesAvailable[NGSCT_Pistols]) return;
10631 				break;
10632 
10633 		}
10634 
10635 		if(search_forwards)
10636 		{
10637 			(*species)++;
10638 			if(*species>10) *species=0;
10639 		}
10640 		else
10641 		{
10642 			(*species)--;
10643 			if(*species<0) *species=10;
10644 		}
10645 		count++;
10646 
10647 	}while(count<9);
10648 
10649 	//oh dear no allowable species
10650 	*species=0;
10651 
10652 }
10653 
SpeciesTag_DetermineMyNextCharacterType()10654 void SpeciesTag_DetermineMyNextCharacterType()
10655 {
10656 	NETGAME_CHARACTERTYPE tagSpecies;
10657 	NETGAME_CHARACTERTYPE otherSpecies;
10658 	if(netGameData.gameType==NGT_PredatorTag)
10659 	{
10660 		if(AvP.PlayerType!=I_Predator) return;
10661 		tagSpecies=NGCT_Predator;
10662 		otherSpecies=NGCT_Alien;
10663 	}
10664 	else
10665 	{
10666 		if(AvP.PlayerType!=I_Alien) return;
10667 		tagSpecies=NGCT_Alien;
10668 		otherSpecies=NGCT_Predator;
10669 	}
10670 
10671 
10672 
10673 	if(myNetworkKillerId && myNetworkKillerId!=AVPDPNetID && CountPlayersOfType(tagSpecies)==1)
10674 	{
10675 		//become the character that killed me
10676 		int killer_index=PlayerIdInPlayerList(myNetworkKillerId);
10677 		if(killer_index!=NET_IDNOTINPLAYERLIST)
10678 		{
10679 			netGameData.myNextCharacterType=netGameData.playerData[killer_index].characterType;
10680 			netGameData.myCharacterSubType=netGameData.playerData[killer_index].characterSubType;
10681 		}
10682 		else
10683 		{
10684 			//the player doing the damage has either left the game , or never existed.
10685 			//call it suicide then.
10686 			myNetworkKillerId=0;
10687 		}
10688 
10689 	}
10690 
10691 	if(!(myNetworkKillerId && myNetworkKillerId!=AVPDPNetID && CountPlayersOfType(tagSpecies)==1))
10692 	{
10693 		int total=0;
10694 		//either suicide , or we have too many predators for some reason
10695 		//pick marine/alien at random
10696 
10697 		//first determine available character types
10698 		DetermineAvailableCharacterTypes(TRUE);
10699 
10700 		total=CharacterTypesAvailable[NGCT_Marine]+
10701 			  CharacterTypesAvailable[otherSpecies];
10702 
10703 		if(total==0)
10704 		{
10705 			//hmm , no available character types
10706 			//in that case look at the character types that are allowed in the first place
10707 			DetermineAvailableCharacterTypes(FALSE);
10708 
10709 			total=CharacterTypesAvailable[NGCT_Marine]+
10710 				  CharacterTypesAvailable[otherSpecies];
10711 		}
10712 
10713 		if(total>0)
10714 		{
10715 			int dieroll=(FastRandom() % total);
10716 
10717 			if(dieroll<CharacterTypesAvailable[NGCT_Marine])
10718 			{
10719 				int i;
10720 				//become a marine
10721 				netGameData.myNextCharacterType=NGCT_Marine;
10722 
10723 				//but what type of marine ?
10724 				total=0;
10725 				for(i=0;i<NUM_PC_SUBTYPES;i++)
10726 				{
10727 					total+=CharacterSubTypesAvailable[i];
10728 				}
10729 
10730 				//since there were available marine slots , there must be at least some
10731 				//marine subtype slots
10732 				GLOBALASSERT(total>0);
10733 
10734 				dieroll=(FastRandom() % total);
10735 
10736 				for(i=0;i<NUM_PC_SUBTYPES;i++)
10737 				{
10738 					dieroll-=CharacterSubTypesAvailable[i];
10739 					if(dieroll<0)
10740 					{
10741 						netGameData.myCharacterSubType=i;
10742 						return;
10743 					}
10744 				}
10745 
10746 				GLOBALASSERT(0=="Shouldn't be possible to reach this line");
10747 
10748 			}
10749 			else
10750 			{
10751 				//become an alien
10752 				netGameData.myNextCharacterType=otherSpecies;
10753 
10754 			}
10755 		}
10756 		else
10757 		{
10758 			//no marines or aliens allowed?
10759 			//tough, the player can become a standard marine
10760 			netGameData.myNextCharacterType=NGCT_Marine;
10761 			netGameData.myCharacterSubType=NGSCT_General;
10762 
10763 		}
10764 	}
10765 }
10766 
10767 
10768 /*----------------------------------------------------------------**
10769 ** Identify the network player closest to the centre of the screen **
10770 **----------------------------------------------------------------*/
ShowNearestPlayersName()10771 void ShowNearestPlayersName()
10772 {
10773 	extern int NumOnScreenBlocks;
10774 	extern DISPLAYBLOCK *OnScreenBlockList[];
10775 	extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr;
10776 	int numberOfObjects = NumOnScreenBlocks;
10777 
10778 	DPID nearestID=0;
10779 	int nearestDist=0x7fffffff;
10780 
10781 	//search through all the nearby objects for players
10782 	while (numberOfObjects--)
10783 	{
10784 		DISPLAYBLOCK* objectPtr = OnScreenBlockList[numberOfObjects];
10785 		STRATEGYBLOCK* sbPtr = objectPtr->ObStrategyBlock;
10786 
10787 		if (sbPtr && sbPtr->I_SBtype==I_BehaviourNetGhost)
10788 		{
10789 			NETGHOSTDATABLOCK *ghostData;
10790 			ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr;
10791 
10792 			//we're only interested in player netghosts
10793 			if(ghostData)
10794 			{
10795 				if(ghostData->type==I_BehaviourMarinePlayer ||
10796 				   ghostData->type==I_BehaviourPredatorPlayer ||
10797 				   ghostData->type==I_BehaviourAlienPlayer)
10798 				{
10799 					VECTORCH targetView;
10800 					SmartTarget_GetCofM(objectPtr,&targetView);
10801 					//get the players screen coordinates
10802 					if(targetView.vz>0)
10803 					{
10804 						int screenX = WideMulNarrowDiv
10805 								(
10806 									targetView.vx,
10807 									Global_VDB_Ptr->VDB_ProjX,
10808 									targetView.vz
10809 								);
10810 
10811 						int screenY = WideMulNarrowDiv
10812 								(
10813 									targetView.vy,
10814 									Global_VDB_Ptr->VDB_ProjY,
10815 									targetView.vz
10816 								);
10817 
10818 						if(screenX<0) screenX=-screenX;
10819 						if(screenY<0) screenY=-screenY;
10820 
10821 						//make sure the player is in fact on screen
10822 						if(screenX<ScreenDescriptorBlock.SDB_Width/2 && screenY<ScreenDescriptorBlock.SDB_Height/2)
10823 						{
10824 							int dist=screenX*screenX + screenY*screenY;
10825 							//is this player closer to the centre of the screen than any before?
10826 							if(dist<nearestDist)
10827 							{
10828 								//the player must be visible
10829 								if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr,Player,&(Global_VDB_Ptr->VDB_World),1000000) )
10830 								{
10831 									{
10832 										nearestDist=dist;
10833 										nearestID=ghostData->playerId;
10834 									}
10835 								}
10836 							}
10837 						}
10838 
10839 					}
10840 				}
10841 			}
10842 		}
10843 	}
10844 
10845 	{
10846 		int	nearestIndex=PlayerIdInPlayerList(nearestID);
10847 
10848 		if(nearestIndex!=NET_IDNOTINPLAYERLIST)
10849 		{
10850 			//we've found the nearest on screen player, so show the name in the console
10851 			NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_PLAYERSEEN,netGameData.playerData[nearestIndex].name,0);
10852 		}
10853 	}
10854 
10855 }
10856 
10857 
CheckForPointBasedObjectRespawn()10858 static void CheckForPointBasedObjectRespawn()
10859 {
10860 	int score=0;
10861 	int i;
10862 	if(netGameData.pointsForRespawn==0) return;
10863 
10864 
10865 
10866 	for(i=0;i<NET_MAXPLAYERS;i++)
10867 	{
10868 		if(netGameData.gameType==NGT_Coop)
10869 		{
10870 			int j;
10871 			for(j=0;j<3;j++)
10872 			{
10873 				score+=netGameData.playerData[i].aliensKilled[j]*netGameData.aiKillValues[j];
10874 			}
10875 		}
10876 		else
10877 		{
10878 			score+=netGameData.playerData[i].playerScore;
10879 		}
10880 	}
10881 
10882 	if(score>=(netGameData.lastPointsBasedRespawn + netGameData.pointsForRespawn))
10883 	{
10884 		//time for pickups to respawn
10885 		AddNetMsg_RespawnPickups();
10886 
10887 		netGameData.lastPointsBasedRespawn=score-(score%netGameData.pointsForRespawn);
10888 		RespawnAllPickups();
10889 
10890 		PrintStringTableEntryInConsole(TEXTSTRING_MULTIPLAYER_WEAPON_RESPAWN);
10891 
10892 	}
10893 
10894 }
10895 
10896 
CountMultiplayerLivesLeft()10897 static int CountMultiplayerLivesLeft()
10898 {
10899 	int i;
10900 	int livesUsed=0;
10901 
10902 
10903 	//count the lives used
10904 	if(netGameData.useSharedLives)
10905 	{
10906 		//lives used is equal to number of deaths + number of currently living players
10907 		if(netGameData.gameType==NGT_CoopDeathmatch)
10908 		{
10909 			//shared lives , are shared between team members
10910 			livesUsed=netGameData.numDeaths[netGameData.myCharacterType];
10911 		}
10912 		else
10913 		{
10914 			livesUsed=netGameData.numDeaths[0]+netGameData.numDeaths[1]+netGameData.numDeaths[2];
10915 		}
10916 
10917 
10918 
10919 		for(i=0;i<NET_MAXPLAYERS;i++)
10920 		{
10921 			if(netGameData.playerData[i].playerId)
10922 			{
10923 				//add an extra life if this player is currently alive
10924 				if(netGameData.gameType==NGT_CoopDeathmatch)
10925 				{
10926 					if(netGameData.playerData[i].characterType!=netGameData.myCharacterType)
10927 					{
10928 						//don't count this player , since he isn't on the same team
10929 						continue;
10930 					}
10931 				}
10932 				livesUsed+=netGameData.playerData[i].playerAlive;
10933 			}
10934 		}
10935 	}
10936 	else
10937 	{
10938 		int index=PlayerIdInPlayerList(AVPDPNetID);
10939 		if(index==NET_IDNOTINPLAYERLIST) return FALSE;
10940 
10941 		for(i=0;i<NET_MAXPLAYERS;i++)
10942 		{
10943 			livesUsed+=netGameData.playerData[i].playerFrags[index];
10944 		}
10945 		livesUsed+=netGameData.playerData[index].deathsFromAI;
10946 		livesUsed+=netGameData.playerData[index].playerAlive;
10947 	}
10948 
10949 	if(livesUsed>netGameData.maxLives)
10950 	{
10951 		return 0;
10952 	}
10953 
10954 	return (netGameData.maxLives-livesUsed);
10955 }
10956 
AreThereAnyLivesLeft()10957 BOOL AreThereAnyLivesLeft()
10958 {
10959 
10960 	if(netGameData.maxLives==0) return TRUE; //infinite lives
10961 
10962 	if(netGameData.gameType!=NGT_Individual &&
10963 	   netGameData.gameType!=NGT_Coop &&
10964 	   netGameData.gameType!=NGT_CoopDeathmatch)
10965 		return TRUE; //lives only affect some game types
10966 
10967 	return (CountMultiplayerLivesLeft()>0);
10968 }
10969 
10970 #define FONT_ALIENSYMBOL 176
10971 #define FONT_MARINESYMBOL 177
10972 #define FONT_PREDATORSYMBOL 178
DoMultiplayerEndGameScreen(void)10973 void DoMultiplayerEndGameScreen(void)
10974 {
10975 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
10976 	int i,j;
10977 	int x,y;
10978 	char text[100];
10979 
10980 	if(netGameData.myGameState==NGS_EndGameScreen)
10981 	{
10982 		D3D_FadeDownScreen(16384,0);
10983 	}
10984 	else
10985 	{
10986 		ShowMultiplayerScoreTimer-=RealFrameTime;
10987 		if(ShowMultiplayerScoreTimer<=0)ShowMultiplayerScoreTimer=0;
10988 	}
10989 
10990 //   RenderStringCentred("Test Endgame Screen",ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height/2,0xffffffff);
10991 
10992 
10993 	//draw headings
10994 	y=150;
10995 	x=120;
10996 
10997 	for(i=0;i<NET_MAXPLAYERS;i++)
10998 	{
10999 		if(netGameData.playerData[i].playerId)
11000 		{
11001 			RenderStringVertically(netGameData.playerData[i].name,x,y,0xffffffff);
11002 			x+=20;
11003 		}
11004 	}
11005 	x+=30;
11006 	if(netGameData.gameType==NGT_Coop)
11007 	{
11008 		if(NPCHive.AliensCanBeGenerated)
11009 		{
11010 			RenderStringVertically(GetTextString(TEXTSTRING_MULTIPLAYER_ALIENS),x,y,0xffffffff);
11011 			x+=20;
11012 		}
11013 		if(NPCHive.PredAliensCanBeGenerated)
11014 		{
11015 			RenderStringVertically(GetTextString(TEXTSTRING_MULTIPLAYER_PREDALIENS),x,y,0xffffffff);
11016 			x+=20;
11017 		}
11018 		if(NPCHive.PraetoriansCanBeGenerated)
11019 		{
11020 			RenderStringVertically(GetTextString(TEXTSTRING_MULTIPLAYER_PRAETORIANS),x,y,0xffffffff);
11021 			x+=20;
11022 		}
11023 		x+=20;
11024 		RenderStringVertically(GetTextString(TEXTSTRING_MULTIPLAYER_SCORE),x,y,0xffffffff);
11025 		x+=20;
11026 	}
11027 	else
11028 	{
11029 		RenderStringVertically(GetTextString(TEXTSTRING_MULTIPLAYER_SCOREFOR),x,y,0xffffffff);
11030 		x+=30;
11031 		RenderStringVertically(GetTextString(TEXTSTRING_MULTIPLAYER_SCOREAGAINST),x,y,0xffffffff);
11032 		x+=30;
11033 	}
11034 
11035 
11036 
11037 
11038 	y+=10;
11039 
11040 	for(i=0;i<NET_MAXPLAYERS;i++)
11041 	{
11042 		if(netGameData.playerData[i].playerId)
11043 		{
11044 			RenderStringCentred(netGameData.playerData[i].name,50,y,0xffffffff);
11045 
11046 			//draw the player's species symbol
11047 			{
11048 				char symbol[2]={0,0};
11049 				switch(netGameData.playerData[i].characterType)
11050 				{
11051 					case NGCT_Marine :
11052 						symbol[0]=FONT_MARINESYMBOL;
11053 						RenderStringCentred(symbol,100,y,0xffffffff);
11054 						break;
11055 
11056 					case NGCT_Alien :
11057 						symbol[0]=FONT_ALIENSYMBOL;
11058 						RenderStringCentred(symbol,100,y,0xffffffff);
11059 						break;
11060 
11061 					case NGCT_Predator :
11062 						symbol[0]=FONT_PREDATORSYMBOL;
11063 						RenderStringCentred(symbol,100,y,0xffffffff);
11064 						break;
11065 
11066 					default:
11067 						break;
11068 				}
11069 			}
11070 
11071 
11072 			x=120;
11073 			for(j=0;j<NET_MAXPLAYERS;j++)
11074 			{
11075 				if(netGameData.playerData[j].playerId)
11076 				{
11077 					sprintf(text,"%d",netGameData.playerData[i].playerFrags[j]);
11078 					if(i==j)
11079 						RenderStringCentred(text,x,y,0xffff0000);
11080 					else
11081 						RenderStringCentred(text,x,y,0xff00ff00);
11082 
11083 					x+=20;
11084 				}
11085 			}
11086 
11087 
11088 			x+=30;
11089 			if(netGameData.gameType==NGT_Coop)
11090 			{
11091 				int score=0;
11092 
11093 				if(NPCHive.AliensCanBeGenerated)
11094 				{
11095 					sprintf(text,"%d",netGameData.playerData[i].aliensKilled[0]);
11096 					RenderStringCentred(text,x,y,0xff00ff00);
11097 					x+=20;
11098 				}
11099 				if(NPCHive.PredAliensCanBeGenerated)
11100 				{
11101 					sprintf(text,"%d",netGameData.playerData[i].aliensKilled[1]);
11102 					RenderStringCentred(text,x,y,0xff00ff00);
11103 					x+=20;
11104 				}
11105 				if(NPCHive.PraetoriansCanBeGenerated)
11106 				{
11107 					sprintf(text,"%d",netGameData.playerData[i].aliensKilled[2]);
11108 					RenderStringCentred(text,x,y,0xff00ff00);
11109 					x+=20;
11110 				}
11111 
11112 				for(j=0;j<3;j++)
11113 				{
11114 
11115 					score+=netGameData.playerData[i].aliensKilled[j]*netGameData.aiKillValues[j];
11116 				}
11117 				x+=20;
11118 				sprintf(text,"%d",score);
11119 				RenderStringCentred(text,x,y,0xff00ff00);
11120 
11121 			}
11122 			else
11123 			{
11124 				sprintf(text,"%d",netGameData.playerData[i].playerScore);
11125 				RenderStringCentred(text,x,y,0xff00ff00);
11126 				x+=30;
11127 
11128 				sprintf(text,"%d",netGameData.playerData[i].playerScoreAgainst);
11129 				RenderStringCentred(text,x,y,0xffff0000);
11130 				x+=30;
11131 			}
11132 			y+=20;
11133 		}
11134 
11135 	}
11136 
11137 	if(netGameData.gameType==NGT_Coop)
11138 	{
11139 		//show kills by ai aliens
11140 		RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_ALIENS),50,y,0xffffffff);
11141 
11142 
11143 		x=120;
11144 		for(j=0;j<NET_MAXPLAYERS;j++)
11145 		{
11146 			if(netGameData.playerData[j].playerId)
11147 			{
11148 				sprintf(text,"%d",netGameData.playerData[j].deathsFromAI);
11149 				RenderStringCentred(text,x,y,0xff00ff00);
11150 				x+=20;
11151 			}
11152 		}
11153 
11154 		y+=20;
11155 	}
11156 
11157 	if(netGameData.maxLives!=0)
11158 	{
11159 		if(netGameData.gameType==NGT_Individual ||
11160 		   netGameData.gameType==NGT_Coop ||
11161 		   netGameData.gameType==NGT_CoopDeathmatch)
11162 		{
11163 			y+=20;
11164 
11165 			if(y<240)
11166 			{
11167 				//make sure the text appears far enough down the screen , so we don't
11168 				//overlap with the species score stuff
11169 				y=240;
11170 			}
11171 			//display remaining lives
11172 			sprintf(text,"%s: %d",GetTextString(TEXTSTRING_MULTIPLAYER_LIVES_LEFT),CountMultiplayerLivesLeft());
11173 			RenderStringCentred(text,ScreenDescriptorBlock.SDB_Width/2,y,0xffffffff);
11174 
11175 		}
11176 	}
11177 
11178 	if(netGameData.gameType==NGT_CoopDeathmatch)
11179 	{
11180 		//show species scores
11181 		x+=50;
11182 		//titles
11183 		RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_ALIEN),x,160,0xffffffff);
11184 		RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_MARINE),x,180,0xffffffff);
11185 		RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_PREDATOR),x,200,0xffffffff);
11186 
11187 		//scores
11188 		x+=50;
11189 
11190 		RenderStringVertically(GetTextString(TEXTSTRING_MULTIPLAYER_SPECIESSCORE),x,150,0xffffffff);
11191 
11192 		sprintf(text,"%d",netGameData.teamScores[NGCT_Alien]);
11193 		RenderStringCentred(text,x,160,0xffffffff);
11194 		sprintf(text,"%d",netGameData.teamScores[NGCT_Marine]);
11195 		RenderStringCentred(text,x,180,0xffffffff);
11196 		sprintf(text,"%d",netGameData.teamScores[NGCT_Predator]);
11197 		RenderStringCentred(text,x,200,0xffffffff);
11198 
11199 	}
11200 
11201 
11202 	if(netGameData.myGameState==NGS_EndGameScreen)
11203 	{
11204 		if(AvP.Network==I_Host)
11205 		{
11206 
11207 			//pause before the host can restart
11208 			if(netGameData.stateCheckTimeDelay>0)
11209 			{
11210 				netGameData.stateCheckTimeDelay-=RealFrameTime;
11211 				return;
11212 			}
11213 			netGameData.stateCheckTimeDelay=0;
11214 
11215   			RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_PRESSKEYTORESTARTGAME),ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height-20,0xffffffff);
11216 			if (DebouncedGotAnyKey)
11217 			{
11218 				int seed=FastRandom();
11219 				RestartNetworkGame(seed);
11220 				AddNetMsg_RestartNetworkGame(seed);
11221 			}
11222 		}
11223 		else
11224 		{
11225  			RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_WAITFORRESTARTGAME),ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height-20,0xffffffff);
11226 		}
11227 	}
11228 	else if(!playerStatusPtr->IsAlive)
11229 	{
11230 		if(AreThereAnyLivesLeft())
11231 		{
11232  			RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_OPERATETORESPAWN),ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height-20,0xffffffff);
11233 		}
11234 		else
11235 		{
11236  			RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_OPERATETOOBSERVE),ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height-20,0xffffffff);
11237 		}
11238 	}
11239 }
11240 
IsItPossibleToScore()11241 static BOOL IsItPossibleToScore()
11242 {
11243 
11244 	if(CalculateMyScore()) return TRUE;
11245 
11246 	if(netGameData.gameType==NGT_LastManStanding) return TRUE;
11247 	if(netGameData.gameType==NGT_Coop)
11248 	{
11249 		if(netGameData.aiKillValues[0]) return TRUE;
11250 		if(netGameData.aiKillValues[1]) return TRUE;
11251 		if(netGameData.aiKillValues[2]) return TRUE;
11252 		return FALSE;
11253 	}
11254 	else
11255 	{
11256 		if(netGameData.baseKillValue == 0) return FALSE;
11257 		if(netGameData.useCharacterKillValues && !netGameData.useDynamicScoring)
11258 		{
11259 			if(netGameData.characterKillValues[0]) return TRUE;
11260 			if(netGameData.characterKillValues[1]) return TRUE;
11261 			if(netGameData.characterKillValues[2]) return TRUE;
11262 			return FALSE;
11263 		}
11264 	}
11265 	return TRUE;
11266 
11267 }
11268 
DoMultiplayerSpecificHud()11269 void DoMultiplayerSpecificHud()
11270 {
11271 
11272 	PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
11273 	char text[200];
11274 
11275 	//Show score table if either
11276 	//1. Player has asked to
11277 	//2. Game is over
11278 	//3. Player is dead and not observing anyone
11279 	if(ShowMultiplayerScoreTimer>0 ||
11280 		netGameData.myGameState==NGS_EndGameScreen ||
11281 		(!playerStatusPtr->IsAlive && !MultiplayerObservedPlayer))
11282 	{
11283 		DoMultiplayerEndGameScreen();
11284 	}
11285 	else
11286 	{
11287 
11288 		if(MultiplayerObservedPlayer)
11289 		{
11290 			//show the name of the observed player
11291 			int index=PlayerIdInPlayerList(MultiplayerObservedPlayer);
11292 			if(index!=NET_IDNOTINPLAYERLIST)
11293 			{
11294 		    	RenderStringCentred(netGameData.playerData[index].name,ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height/2,0xff0000ff);
11295 			}
11296 		}
11297 
11298 
11299 		/*
11300 		{
11301 			int i;
11302 			int myIndex = PlayerIdInPlayerList(AVPDPNetID);
11303 			LOCALASSERT(myIndex!=NET_IDNOTINPLAYERLIST);
11304 			for(i=0;i<NET_MAXPLAYERS;i++)
11305 			{
11306 				if(netGameData.playerData[i].playerId)
11307 				{
11308 					if(netGameData.gameType==NGT_LastManStanding)
11309 					{
11310 						switch(netGameData.playerData[i].characterType)
11311 						{
11312 							case NGCT_Marine :
11313 								PrintDebuggingText("%s : %d   (Marine)\n",netGameData.playerData[i].name,netGameData.playerData[i].playerScore);
11314 								break;
11315 							case NGCT_Alien :
11316 								PrintDebuggingText("%s : %d   (Alien)\n",netGameData.playerData[i].name,netGameData.playerData[i].playerScore);
11317 								break;
11318 							case NGCT_Predator :
11319 								PrintDebuggingText("%s : %d   (Predator)\n",netGameData.playerData[i].name,netGameData.playerData[i].playerScore);
11320 								break;
11321 						}
11322 					}
11323 					else if(netGameData.gameType==NGT_Coop)
11324 					{
11325 						//show kills / deaths
11326 						int totalKills=netGameData.playerData[i].aliensKilled[0]+netGameData.playerData[i].aliensKilled[1]+netGameData.playerData[i].aliensKilled[2];
11327 						PrintDebuggingText("%s : %d/%d\n",netGameData.playerData[i].name,totalKills,netGameData.playerData[i].playerFrags[i]);
11328 					}
11329 					else
11330 					{
11331 						switch(netGameData.playerData[i].characterType)
11332 						{
11333 							case NGCT_Marine :
11334 								PrintDebuggingText("%s : %d   (%d)(Marine)\n",netGameData.playerData[i].name,netGameData.playerData[i].playerScore,GetNetScoreForKill(i,myIndex));
11335 								break;
11336 							case NGCT_Alien :
11337 								PrintDebuggingText("%s : %d   (%d)(Alien)\n",netGameData.playerData[i].name,netGameData.playerData[i].playerScore,GetNetScoreForKill(i,myIndex));
11338 								break;
11339 							case NGCT_Predator :
11340 								PrintDebuggingText("%s : %d   (%d)(Predator)\n",netGameData.playerData[i].name,netGameData.playerData[i].playerScore,GetNetScoreForKill(i,myIndex));
11341 								break;
11342 						}
11343 					}
11344 				}
11345 			}
11346 		}
11347 		*/
11348 	}
11349 
11350 	//show the player's score
11351 	{
11352 		int score = CalculateMyScore();
11353 		if(score || IsItPossibleToScore())
11354 		{
11355 			sprintf(text,"%s : %d",GetTextString(TEXTSTRING_MULTIPLAYER_SCORE),score);
11356 			RenderString(text,5,0,0xffffffff);
11357 		}
11358 	}
11359 
11360 	//show time left
11361 	if(netGameData.timeLimit>0)
11362 	{
11363 		int hoursLeft;
11364 		int minutesLeft;
11365 		int secondsLeft=(netGameData.timeLimit*60)-(netGameData.GameTimeElapsed>>16);
11366 		if(secondsLeft<0) secondsLeft=0;
11367 
11368 		hoursLeft=secondsLeft/3600;
11369 		minutesLeft=(secondsLeft/60)%60;
11370 		secondsLeft%=60;
11371 
11372 		//display time left as hh:mm:ss
11373 		sprintf(text,"%s : %02d:%02d:%02d",GetTextString(TEXTSTRING_MULTIPLAYER_TIME),hoursLeft,minutesLeft,secondsLeft);
11374 
11375 		RenderString(text,5,20,0xffffffff);
11376 
11377 	}
11378 
11379 }
11380 
11381 
GetNextMultiplayerObservedPlayer()11382 void GetNextMultiplayerObservedPlayer()
11383 {
11384 	extern int GlobalFrameCounter;
11385 	static int LastFrameTried;
11386 
11387 	//Use the frame counter to debounce changing player to observe
11388 	if(LastFrameTried==GlobalFrameCounter || LastFrameTried+1==GlobalFrameCounter)
11389 	{
11390 		//obviously tried last frame , so don't bother trying to find a player to watch
11391 		LastFrameTried=GlobalFrameCounter;
11392 		return;
11393 	}
11394 	else
11395 	{
11396 		int cur_index=PlayerIdInPlayerList(MultiplayerObservedPlayer);
11397 		int next_index;
11398 		int count=0;
11399 
11400 		LastFrameTried=GlobalFrameCounter;
11401 
11402 		for(next_index=cur_index+1;count<NET_MAXPLAYERS;next_index++,count++)
11403 		{
11404 			if(next_index==NET_MAXPLAYERS) next_index=0;
11405 			if(netGameData.playerData[next_index].playerId)
11406 			{
11407 				if(netGameData.playerData[next_index].playerAlive)
11408 				{
11409 					DYNAMICSBLOCK* dynPtr=Player->ObStrategyBlock->DynPtr;
11410 					MultiplayerObservedPlayer=netGameData.playerData[next_index].playerId;
11411 					//need to disable gravity , and make sure the playher isn't moving
11412 					//of his own accord
11413 					dynPtr->GravityOn=0;
11414 
11415 					dynPtr->LinImpulse.vx=0;
11416 					dynPtr->LinImpulse.vy=0;
11417 					dynPtr->LinImpulse.vz=0;
11418 
11419 					dynPtr->LinVelocity.vx=0;
11420 					dynPtr->LinVelocity.vy=0;
11421 					dynPtr->LinVelocity.vz=0;
11422 
11423 
11424 					return;
11425 				}
11426 			}
11427 		}
11428 
11429 		//oh well , no one available to observe
11430 		TurnOffMultiplayerObserveMode();
11431 	}
11432 }
11433 
TurnOffMultiplayerObserveMode()11434 void TurnOffMultiplayerObserveMode()
11435 {
11436 	if(MultiplayerObservedPlayer)
11437 	{
11438 		DYNAMICSBLOCK* dynPtr=Player->ObStrategyBlock->DynPtr;
11439 
11440 		MultiplayerObservedPlayer=0;
11441 
11442 		//need to turn gravity and collisions back on
11443 		dynPtr->GravityOn=1;
11444 	}
11445 }
11446 
CheckStateOfObservedPlayer()11447 void CheckStateOfObservedPlayer()
11448 {
11449 	int index=PlayerIdInPlayerList(MultiplayerObservedPlayer);
11450 	if(!MultiplayerObservedPlayer) return;
11451 
11452 	//our observed player must exist
11453 	if(index==NET_IDNOTINPLAYERLIST)
11454 	{
11455 		TurnOffMultiplayerObserveMode();
11456 		return;
11457 	}
11458 
11459 	//he must also be alive
11460 	if(!netGameData.playerData[index].playerAlive)
11461 	{
11462 		TurnOffMultiplayerObserveMode();
11463 		return;
11464 	}
11465 }
11466 
11467 
11468 
CalculateMyScore()11469 static int CalculateMyScore()
11470 {
11471 	int myIndex=PlayerIdInPlayerList(AVPDPNetID);
11472 	if(myIndex==NET_IDNOTINPLAYERLIST) return 0;
11473 
11474 	if(netGameData.gameType==NGT_Coop)
11475 	{
11476 		int score=0;
11477 		int i;
11478 		for(i=0;i<3;i++)
11479 		{
11480 			score+=netGameData.playerData[myIndex].aliensKilled[i]*netGameData.aiKillValues[i];
11481 		}
11482 		return score;
11483 
11484 	}
11485 	else
11486 	{
11487 		return netGameData.playerData[myIndex].playerScore;
11488 	}
11489 }
11490 
11491 
11492 
11493 
PeriodicScoreUpdate()11494 static void PeriodicScoreUpdate()
11495 {
11496 	static unsigned int timer=0;
11497 	static int playerIndex=0;
11498 	int count=0;
11499 
11500 	//cycle through the players , sending scores every 2 seconds
11501 	timer+=RealFrameTime;
11502 	if(timer<2*ONE_FIXED) return;
11503 	timer=0;
11504 
11505 	if(netGameData.myGameState!=NGS_Playing) return;
11506 	for(playerIndex++;count<NET_MAXPLAYERS;count++,playerIndex++)
11507 	{
11508 		if(playerIndex>=NET_MAXPLAYERS && netGameData.gameType==NGT_CoopDeathmatch)
11509 		{
11510 			//for species deathmatch games also update team scores occasionly
11511 			AddNetMsg_SpeciesScores();
11512 		}
11513 
11514 		playerIndex%=NET_MAXPLAYERS;
11515 		if(netGameData.playerData[playerIndex].playerId)
11516 		{
11517 			AddNetMsg_PlayerScores(playerIndex);
11518 			return;
11519 		}
11520 	}
11521 }
11522 
11523 
11524 
GetStrategySynchObjectChecksum()11525 static int GetStrategySynchObjectChecksum()
11526 {
11527 	/*
11528 	Generate a number from the sbnames of all the strategies that need to be synched
11529 	*/
11530 	int sum=0;
11531 	int position=0;
11532 	int i;
11533 	for (i=0; i<NumActiveStBlocks; i++)
11534 	{
11535 		STRATEGYBLOCK *sbPtr = ActiveStBlockList[i];
11536 
11537 		if(sbPtr->I_SBtype == I_BehaviourBinarySwitch ||
11538 		   sbPtr->I_SBtype == I_BehaviourLinkSwitch ||
11539 		   sbPtr->I_SBtype == I_BehaviourTrackObject)
11540 		{
11541 			position++;
11542 			sum+=(*(int*)&sbPtr->SBname[0])*position;
11543 		}
11544 	}
11545 	if(sum==0) sum=1;
11546 	return sum;
11547 }
11548 
11549 
11550