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