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§ion_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§ion_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