| | 1 | #include "system.h" |
| | 2 | #include "prototyp.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 "scream.h" |
| | 23 | #include "targeting.h" |
| | 24 | |
| | 25 | extern int GetLoadedShapeMSL(char const * shapename); |
| | 26 | extern void RespawnInanimateObject(STRATEGYBLOCK *sbPtr); |
| | 27 | extern void EnableBehaviourType(STRATEGYBLOCK* sbptr, void *bhdata); |
| | 28 | extern void KillInanimateObjectForRespawn(STRATEGYBLOCK *sbPtr); |
| | 29 | extern char * mission_messages; |
| | 30 | extern unsigned int mission_messages_timer; |
| | 31 | |
| | 32 | struct netgame_gamedata netGameData; |
| | 33 | |
| | 34 | struct DPNAME |
| | 35 | { |
| | 36 | char *name; |
| | 37 | int dwSize; |
| | 38 | }; |
| | 39 | |
| | 40 | char sendBuffer[NET_MESSAGEBUFFERSIZE]; |
| | 41 | char *endSendBuffer; |
| | 42 | |
| | 43 | int netNextLocalObjectId = 1; |
| | 44 | int myNetworkKillerId = 0; |
| | 45 | int myIgniterId = 0; |
| | 46 | int MyHitBodyPartId = -1; |
| | 47 | int MultiplayerObservedPlayer = 0; |
| | 48 | int numMarineStartPos = 0; |
| | 49 | int numAlienStartPos = 0; |
| | 50 | int numPredatorStartPos = 0; |
| | 51 | int MultiplayerRestartSeed = 0; |
| | 52 | int GameTimeSinceLastSend = 0; |
| | 53 | int AVPDPNetID; |
| | 54 | |
| | 55 | static int CharacterTypesAvailable[NUM_PC_TYPES]; |
| | 56 | static int CharacterSubTypesAvailable[NUM_PC_SUBTYPES]; |
| | 57 | |
| | 58 | unsigned int TimeCounterForExtrapolation=0; |
| | 59 | |
| | 60 | char OnScreenMessageBuffer[300]; |
| | 61 | uint8_t FragmentalObjectStatus[NUMBER_OF_FRAGMENTAL_OBJECTS]; |
| | 62 | uint8_t StrategySynchArray[NUMBER_OF_STRATEGIES_TO_SYNCH>>2]; |
| | 63 | |
| | 64 | MULTIPLAYER_START* marineStartPositions = NULL; |
| | 65 | MULTIPLAYER_START* alienStartPositions = NULL; |
| | 66 | MULTIPLAYER_START* predatorStartPositions = NULL; |
| | 67 | |
| | 68 | extern int RealFrameTime; |
| | 69 | extern int TimeScale; |
| | 70 | extern int got_any_key(); |
| | 71 | extern int RightHand; // For alien claws and two pistols |
| | 72 | extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; |
| | 73 | |
| | 74 | extern void RemovePickedUpObject(STRATEGYBLOCK *objectPtr); |
| | 75 | |
| | 76 | extern void SetSeededFastRandom(int seed); |
| | 77 | extern int SeededFastRandom(); |
| | 78 | extern void RenderStringVertically(char *stringPtr, int centreX, int bottomY, int colour); |
| | 79 | extern void RenderStringCentred(char *stringPtr, int centreX, int y, int colour); |
| | 80 | extern void RenderHUDString(char *stringPtr, int x, int y, int colour); |
| | 81 | |
| | 82 | #define DPEXT_HEADER_SIZE 10 |
| | 83 | |
| | 84 | void InitialiseSendMessageBuffer() |
| | 85 | { |
| | 86 | /* NB the receive buffer is maintained internally to garry's dp-extension */ |
| | 87 | /* reset the end of send buffer pointer */ |
| | 88 | endSendBuffer = &sendBuffer[0]; |
| | 89 | /* add space for a dpext header to the send buffer */ |
| | 90 | endSendBuffer += DPEXT_HEADER_SIZE; |
| | 91 | } |
| | 92 | |
| | 93 | #include <stdio.h> |
| | 94 | #include <stdlib.h> |
| | 95 | int number_of_connected_players = 0; |
| | 96 | |
| | 97 | #if _NOT_ONLY_SINGLEPLAYER_ |
| | 98 | #include <SDL/SDL_net.h> |
| | 99 | TCPsocket server,connected_players[6]; |
| | 100 | IPaddress server_ip,*remoteip; |
| | 101 | |
| | 102 | int init_server() |
| | 103 | { |
| | 104 | Uint16 port = 1234; |
| | 105 | |
| | 106 | if(SDLNet_Init() == -1) |
| | 107 | { |
| | 108 | printf("SDLNet_Init: %s\n",SDLNet_GetError()); |
| | 109 | return 0; |
| | 110 | } |
| | 111 | |
| | 112 | if(SDLNet_ResolveHost(&server_ip, NULL, port) == -1) |
| | 113 | { |
| | 114 | printf("SDLNet_ResolveHost: %s\n",SDLNet_GetError()); |
| | 115 | return 0; |
| | 116 | } |
| | 117 | |
| | 118 | server = SDLNet_TCP_Open(&server_ip); |
| | 119 | |
| | 120 | if(!server) |
| | 121 | { |
| | 122 | printf("SDLNet_TCP_Open: %s\n",SDLNet_GetError()); |
| | 123 | return 0; |
| | 124 | } |
| | 125 | |
| | 126 | return 1; |
| | 127 | } |
| | 128 | |
| | 129 | void shutdown_network() |
| | 130 | { |
| | 131 | int i = 0; |
| | 132 | |
| | 133 | SDLNet_TCP_Close(server); |
| | 134 | |
| | 135 | for (; i <= number_of_connected_players; i++) |
| | 136 | SDLNet_TCP_Close(connected_players[number_of_connected_players]); |
| | 137 | |
| | 138 | SDLNet_Quit(); |
| | 139 | } |
| | 140 | |
| | 141 | void host_add_players() |
| | 142 | { |
| | 143 | if (number_of_connected_players < 7) |
| | 144 | { |
| | 145 | connected_players[number_of_connected_players] = SDLNet_TCP_Accept(server); |
| | 146 | |
| | 147 | if(connected_players[number_of_connected_players]) |
| | 148 | { |
| | 149 | //printf("SDLNet_TCP_Accept: %s\n",SDLNet_GetError()); |
| | 150 | remoteip = SDLNet_TCP_GetPeerAddress(connected_players[number_of_connected_players]); |
| | 151 | |
| | 152 | if(remoteip) |
| | 153 | { |
| | 154 | char message[1024]; |
| | 155 | Uint32 ipaddr = SDL_SwapBE32(remoteip->host); |
| | 156 | printf("Accepted a connection from %d.%d.%d.%d port %hu\n", ipaddr>>24, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff,
ipaddr&0xff, remoteip->port); |
| | 157 | |
| | 158 | int len = SDLNet_TCP_Recv(connected_players[number_of_connected_players], message,1024); |
| | 159 | |
| | 160 | if(!len) |
| | 161 | printf("SDLNet_TCP_Recv: %s\n",SDLNet_GetError()); |
| | 162 | } |
| | 163 | } |
| | 164 | |
| | 165 | number_of_connected_players++; |
| | 166 | } |
| | 167 | } |
| | 168 | |
| | 169 | int player_connect(const char* server) |
| | 170 | { |
| | 171 | IPaddress ip; |
| | 172 | TCPsocket sock; |
| | 173 | char message[1024]; |
| | 174 | int len; |
| | 175 | Uint16 port = 1234; |
| | 176 | |
| | 177 | if(SDLNet_Init()==-1) |
| | 178 | { |
| | 179 | printf("SDLNet_Init: %s\n",SDLNet_GetError()); |
| | 180 | return 0; |
| | 181 | } |
| | 182 | |
| | 183 | if(SDLNet_ResolveHost(&ip, server, port)==-1) |
| | 184 | { |
| | 185 | printf("SDLNet_ResolveHost: %s\n",SDLNet_GetError()); |
| | 186 | return 0; |
| | 187 | } |
| | 188 | |
| | 189 | sock = SDLNet_TCP_Open(&ip); |
| | 190 | |
| | 191 | if(!sock) |
| | 192 | { |
| | 193 | printf("SDLNet_TCP_Open: %s\n",SDLNet_GetError()); |
| | 194 | return 0; |
| | 195 | } |
| | 196 | |
| | 197 | /* |
| | 198 | printf("Enter Message, or Q to make the server quit:\n"); |
| | 199 | fgets(message,1024,stdin); |
| | 200 | len = strlen(message); |
| | 201 | message[len-1]='\0'; |
| | 202 | |
| | 203 | if(len) |
| | 204 | { |
| | 205 | int result; |
| | 206 | |
| | 207 | // print out the message |
| | 208 | printf("Sending: %.*s\n",len,message); |
| | 209 | |
| | 210 | result=SDLNet_TCP_Send(sock,message,len); // add 1 for the NULL |
| | 211 | if(result<len) |
| | 212 | printf("SDLNet_TCP_Send: %s\n",SDLNet_GetError()); |
| | 213 | } |
| | 214 | */ |
| | 215 | |
| | 216 | return 1; |
| | 217 | } |
| | 218 | |
| | 219 | #else |
| | 220 | void shutdown_network() {} |
| | 221 | int init_server() { return 1; } |
| | 222 | int player_connect(const char* server) { return 1; } |
| | 223 | #endif |
| | 224 | |
| | 225 | int client_player_send() |
| | 226 | { |
| | 227 | return 0; |
| | 228 | } |
| | 229 | int client_player_read() |
| | 230 | { |
| | 231 | return 0; |
| | 232 | } |
| | 233 | |
| | 234 | int DetermineAvailableCharacterTypes(int ConsiderUsedCharacters) |
| | 235 | { |
| | 236 | int i; |
| | 237 | int maxMarines = 0; |
| | 238 | |
| | 239 | //set limits for disallowed marine types to zero |
| | 240 | netGameData.maxMarineSmartgun = netGameData.allowSmartgun; |
| | 241 | netGameData.maxMarineFlamer = netGameData.allowFlamer; |
| | 242 | netGameData.maxMarineMinigun = netGameData.allowMinigun; |
| | 243 | netGameData.maxMarineSadar = netGameData.allowSadar; |
| | 244 | netGameData.maxMarineGrenade = netGameData.allowGrenadeLauncher; |
| | 245 | netGameData.maxMarineSmartDisc = netGameData.allowSmartDisc; |
| | 246 | netGameData.maxMarinePistols = netGameData.allowPistols; |
| | 247 | |
| | 248 | switch(netGameData.gameType) |
| | 249 | { |
| | 250 | case NGT_PredatorTag: |
| | 251 | { |
| | 252 | //force limit of one predator |
| | 253 | netGameData.maxPredator = 1; |
| | 254 | } |
| | 255 | break; |
| | 256 | case NGT_AlienTag: |
| | 257 | { |
| | 258 | //force limit of one alien |
| | 259 | netGameData.maxAlien = 1; |
| | 260 | } |
| | 261 | break; |
| | 262 | case NGT_LastManStanding: |
| | 263 | { |
| | 264 | //no predators are allowed |
| | 265 | netGameData.maxPredator = 0; |
| | 266 | //the host will be the first alien (and so is the only person that can select alien on the starting screen) |
| | 267 | netGameData.maxAlien = 1; |
| | 268 | } |
| | 269 | case NGT_Coop: |
| | 270 | { |
| | 271 | //no pc aliens allowed in coop games |
| | 272 | netGameData.maxAlien = 0; |
| | 273 | } |
| | 274 | default: |
| | 275 | break; |
| | 276 | } |
| | 277 | |
| | 278 | if(Skirmish == AvP.PlayMode) |
| | 279 | { |
| | 280 | //Skirmish mode - player can be anything except an alien |
| | 281 | netGameData.maxAlien = 0; |
| | 282 | netGameData.maxPredator = 8; |
| | 283 | netGameData.maxMarine = 8; |
| | 284 | netGameData.maxMarineGeneral = 8; |
| | 285 | netGameData.maxMarinePulseRifle = 8; |
| | 286 | netGameData.maxMarineSmartgun = 8; |
| | 287 | netGameData.maxMarineFlamer = 8; |
| | 288 | netGameData.maxMarineSadar = 8; |
| | 289 | netGameData.maxMarineGrenade = 8; |
| | 290 | netGameData.maxMarineMinigun = 8; |
| | 291 | netGameData.maxMarineSmartDisc = 8; |
| | 292 | netGameData.maxMarinePistols = 8; |
| | 293 | } |
| | 294 | |
| | 295 | CharacterTypesAvailable[NGCT_Marine] = netGameData.maxMarine; |
| | 296 | CharacterTypesAvailable[NGCT_Alien] = netGameData.maxAlien; |
| | 297 | CharacterTypesAvailable[NGCT_Predator] = netGameData.maxPredator; |
| | 298 | CharacterSubTypesAvailable[NGSCT_General] = netGameData.maxMarineGeneral; |
| | 299 | CharacterSubTypesAvailable[NGSCT_PulseRifle] = netGameData.maxMarinePulseRifle; |
| | 300 | CharacterSubTypesAvailable[NGSCT_Smartgun] = netGameData.maxMarineSmartgun; |
| | 301 | CharacterSubTypesAvailable[NGSCT_Flamer] = netGameData.maxMarineFlamer; |
| | 302 | CharacterSubTypesAvailable[NGSCT_Sadar] = netGameData.maxMarineSadar; |
| | 303 | CharacterSubTypesAvailable[NGSCT_GrenadeLauncher] = netGameData.maxMarineGrenade; |
| | 304 | CharacterSubTypesAvailable[NGSCT_Minigun] = netGameData.maxMarineMinigun; |
| | 305 | CharacterSubTypesAvailable[NGSCT_Frisbee] = netGameData.maxMarineSmartDisc; |
| | 306 | CharacterSubTypesAvailable[NGSCT_Pistols] = netGameData.maxMarinePistols; |
| | 307 | |
| | 308 | //go through all the other players to see which character types are being used |
| | 309 | if(ConsiderUsedCharacters) |
| | 310 | { |
| | 311 | //if(AvP.Network != I_No_Network) |
| | 312 | { |
| | 313 | //(it will still be I_No_Network while the host is setting things up) |
| | 314 | for(i=0; i < NET_MAXPLAYERS; i++) |
| | 315 | { |
| | 316 | if(netGameData.playerData[i].playerId && netGameData.playerData[i].playerId != AVPDPNetID) |
| | 317 | { |
| | 318 | switch(netGameData.playerData[i].characterType) |
| | 319 | { |
| | 320 | case NGCT_Marine : |
| | 321 | CharacterTypesAvailable[NGCT_Marine]--; |
| | 322 | |
| | 323 | switch(netGameData.playerData[i].characterSubType) |
| | 324 | { |
| | 325 | case NGSCT_General : |
| | 326 | CharacterSubTypesAvailable[NGSCT_General]--; |
| | 327 | break; |
| | 328 | case NGSCT_PulseRifle : |
| | 329 | CharacterSubTypesAvailable[NGSCT_PulseRifle]--; |
| | 330 | break; |
| | 331 | case NGSCT_Smartgun : |
| | 332 | CharacterSubTypesAvailable[NGSCT_Smartgun]--; |
| | 333 | break; |
| | 334 | case NGSCT_Flamer : |
| | 335 | CharacterSubTypesAvailable[NGSCT_Flamer]--; |
| | 336 | break; |
| | 337 | case NGSCT_Sadar : |
| | 338 | CharacterSubTypesAvailable[NGSCT_Sadar]--; |
| | 339 | break; |
| | 340 | case NGSCT_GrenadeLauncher : |
| | 341 | CharacterSubTypesAvailable[NGSCT_GrenadeLauncher]--; |
| | 342 | break; |
| | 343 | case NGSCT_Minigun : |
| | 344 | CharacterSubTypesAvailable[NGSCT_Minigun]--; |
| | 345 | break; |
| | 346 | case NGSCT_Frisbee : |
| | 347 | CharacterSubTypesAvailable[NGSCT_Frisbee]--; |
| | 348 | break; |
| | 349 | case NGSCT_Pistols : |
| | 350 | CharacterSubTypesAvailable[NGSCT_Pistols]--; |
| | 351 | } |
| | 352 | break; |
| | 353 | case NGCT_Predator : |
| | 354 | CharacterTypesAvailable[NGCT_Predator]--; |
| | 355 | break; |
| | 356 | case NGCT_Alien : |
| | 357 | CharacterTypesAvailable[NGCT_Alien]--; |
| | 358 | default: |
| | 359 | break; |
| | 360 | } |
| | 361 | } |
| | 362 | } |
| | 363 | |
| | 364 | } |
| | 365 | } |
| | 366 | |
| | 367 | //make sure all the limits are at least 0 |
| | 368 | for(i=0; i < NUM_PC_TYPES; i++) |
| | 369 | CharacterTypesAvailable[i] = max(0, CharacterTypesAvailable[i]); |
| | 370 | |
| | 371 | for(i=0; i < NUM_PC_SUBTYPES; i++) |
| | 372 | CharacterSubTypesAvailable[i] = max(0, CharacterSubTypesAvailable[i]); |
| | 373 | |
| | 374 | //adjust the marine limits to take into account that there must be both sufficent marine slots , |
| | 375 | // and also sufficient subtype slots |
| | 376 | |
| | 377 | for(i=0; i < NUM_PC_SUBTYPES; i++) |
| | 378 | { |
| | 379 | CharacterSubTypesAvailable[i] = min(CharacterSubTypesAvailable[i],CharacterTypesAvailable[NGCT_Marine]); |
| | 380 | maxMarines += CharacterSubTypesAvailable[i]; |
| | 381 | } |
| | 382 | |
| | 383 | CharacterTypesAvailable[NGCT_Marine] = min(CharacterTypesAvailable[NGCT_Marine], maxMarines); |
| | 384 | |
| | 385 | //return the total number of players available |
| | 386 | return CharacterTypesAvailable[NGCT_Marine] + CharacterTypesAvailable[NGCT_Alien] + CharacterTypesAvailable[NGCT_Predator]; |
| | 387 | } |
| | 388 | |
| | 389 | /*---------------------------------------------------------------------- |
| | 390 | These support functions are used to examine the current game state |
| | 391 | ----------------------------------------------------------------------*/ |
| | 392 | |
| | 393 | /* returns index if the given int is in the player list */ |
| | 394 | int PlayerIdInPlayerList(int Id) |
| | 395 | { |
| | 396 | int i=0; |
| | 397 | /* check first, if we've been passed a null id */ |
| | 398 | if(Id == 0) |
| | 399 | return NET_IDNOTINPLAYERLIST; |
| | 400 | |
| | 401 | /* check player list */ |
| | 402 | for(; i < NET_MAXPLAYERS; i++) |
| | 403 | { |
| | 404 | if(netGameData.playerData[i].playerId == Id) |
| | 405 | return i; |
| | 406 | } |
| | 407 | |
| | 408 | /* failed to find Id */ |
| | 409 | return NET_IDNOTINPLAYERLIST; |
| | 410 | } |
| | 411 | |
| | 412 | int InitAVPNetGameForHost(const char *playerName, int species, int gamestyle, int level) |
| | 413 | { |
| | 414 | int maxPlayers = DetermineAvailableCharacterTypes(0); |
| | 415 | |
| | 416 | if(maxPlayers < 1) |
| | 417 | maxPlayers = 1; |
| | 418 | else if(maxPlayers > 8) |
| | 419 | maxPlayers = 8; |
| | 420 | |
| | 421 | AVPDPNetID = 100; |
| | 422 | InitialiseSendMessageBuffer(); |
| | 423 | |
| | 424 | netGameData.myGameState = NGS_Joining; |
| | 425 | /* base initialisation of game description */ |
| | 426 | switch (species) |
| | 427 | { |
| | 428 | default: |
| | 429 | case 0: |
| | 430 | netGameData.myCharacterType = NGCT_Marine; |
| | 431 | netGameData.myNextCharacterType = NGCT_Marine; |
| | 432 | AvP.PlayerType = I_Marine; |
| | 433 | break; |
| | 434 | case 1: |
| | 435 | netGameData.myCharacterType = NGCT_Predator; |
| | 436 | netGameData.myNextCharacterType = NGCT_Predator; |
| | 437 | AvP.PlayerType = I_Predator; |
| | 438 | break; |
| | 439 | case 2: |
| | 440 | netGameData.myCharacterType = NGCT_Alien; |
| | 441 | netGameData.myNextCharacterType = NGCT_Alien; |
| | 442 | AvP.PlayerType = I_Alien; |
| | 443 | break; |
| | 444 | case 3: //various marine subtypes |
| | 445 | case 4: |
| | 446 | case 5: |
| | 447 | case 6: |
| | 448 | case 7: |
| | 449 | case 8: |
| | 450 | case 9: |
| | 451 | case 10: |
| | 452 | netGameData.myCharacterType = NGCT_Marine; |
| | 453 | netGameData.myNextCharacterType = NGCT_Marine; |
| | 454 | netGameData.myCharacterSubType = (NETGAME_SPECIALISTCHARACTERTYPE) (species-2); |
| | 455 | AvP.PlayerType = I_Marine; |
| | 456 | } |
| | 457 | |
| | 458 | netGameData.gameType = gamestyle; |
| | 459 | netGameData.levelNumber = level; |
| | 460 | |
| | 461 | myNetworkKillerId = AVPDPNetID; /* init global id of player who killed me last */ |
| | 462 | netNextLocalObjectId = 1; /* init local object network id */ |
| | 463 | |
| | 464 | /* If I'm the host, add myself to the game data */ |
| | 465 | netGameData.playerData[0].playerId = AVPDPNetID; |
| | 466 | strncpy(netGameData.playerData[0].name, playerName, NET_PLAYERNAMELENGTH-1); |
| | 467 | netGameData.playerData[0].name[NET_PLAYERNAMELENGTH-1] = '\0'; |
| | 468 | netGameData.playerData[0].characterType = netGameData.myCharacterType; |
| | 469 | netGameData.playerData[0].characterSubType = netGameData.myCharacterSubType; |
| | 470 | |
| | 471 | //make sure our time scale is set correctly |
| | 472 | switch(netGameData.gameSpeed) |
| | 473 | { |
| | 474 | case NETGAMESPEED_70PERCENT : |
| | 475 | TimeScale = (ONE_FIXED*70)/100; |
| | 476 | break; |
| | 477 | case NETGAMESPEED_80PERCENT : |
| | 478 | TimeScale = (ONE_FIXED*80)/100; |
| | 479 | break; |
| | 480 | case NETGAMESPEED_90PERCENT : |
| | 481 | TimeScale = (ONE_FIXED*90)/100; |
| | 482 | break; |
| | 483 | case NETGAMESPEED_100PERCENT : |
| | 484 | TimeScale = (ONE_FIXED*100)/100; |
| | 485 | } |
| | 486 | |
| | 487 | fprintf(stderr, "InitAVPNetGameForHost(%s, %d, %d, %d)\n", playerName, species, gamestyle, level); |
| | 488 | |
| | 489 | if(Skirmish != AvP.PlayMode) |
| | 490 | return init_server(); |
| | 491 | |
| | 492 | return 1; |
| | 493 | } |
| | 494 | |
| | 495 | /* |
| | 496 | This function takes a string from the list of language localised strings, and replaces |
| | 497 | instances of %1 and %2 with the appropriate names. |
| | 498 | It then displays the message in the console. |
| | 499 | */ |
| | 500 | static void NetworkGameConsoleMessage(const char * mesg, const char* name1, const char* name2) |
| | 501 | { |
| | 502 | const char* string = mesg; |
| | 503 | char* messageptr = &OnScreenMessageBuffer[0]; |
| | 504 | |
| | 505 | if(!string) |
| | 506 | return; |
| | 507 | |
| | 508 | while(*string) |
| | 509 | { |
| | 510 | if(string[0] == '%') |
| | 511 | { |
| | 512 | if(string[1] >= '1' && string[1] <= '9') |
| | 513 | { |
| | 514 | if(string[1] =='1' && name1) |
| | 515 | { |
| | 516 | strcpy(messageptr,name1); |
| | 517 | messageptr += strlen(name1); |
| | 518 | } |
| | 519 | |
| | 520 | if(string[1] =='2' && name2) |
| | 521 | { |
| | 522 | strcpy(messageptr,name2); |
| | 523 | messageptr += strlen(name2); |
| | 524 | } |
| | 525 | |
| | 526 | string += 2; |
| | 527 | continue; |
| | 528 | } |
| | 529 | } |
| | 530 | *messageptr++=*string++; |
| | 531 | } |
| | 532 | *messageptr = 0; |
| | 533 | |
| | 534 | mission_messages = OnScreenMessageBuffer; |
| | 535 | mission_messages_timer = timeGetTime() + strlen(mission_messages) * 80; |
| | 536 | } |
| | 537 | |
| | 538 | static void Inform_PlayerHasConnected(int player) |
| | 539 | { |
| | 540 | int playerIndex = PlayerIdInPlayerList(player); |
| | 541 | |
| | 542 | /* KJL 15:35:38 09/04/98 - not knowing who the player is what make things a bit awkward... */ |
| | 543 | if(playerIndex == NET_IDNOTINPLAYERLIST) |
| | 544 | return; |
| | 545 | |
| | 546 | NetworkGameConsoleMessage("%1 has connected to the game", netGameData.playerData[playerIndex].name, 0); |
| | 547 | printf("%s with id %d has connected to the game", netGameData.playerData[playerIndex].name, netGameData.playerData[playerIndex].playerId ); |
| | 548 | } |
| | 549 | |
| | 550 | /* returns true if there are any empty slots */ |
| | 551 | int EmptySlotInPlayerList() |
| | 552 | { |
| | 553 | int i=1; |
| | 554 | for(; i < NET_MAXPLAYERS; i++) |
| | 555 | { |
| | 556 | if(!netGameData.playerData[i].playerId) |
| | 557 | return i; |
| | 558 | } |
| | 559 | |
| | 560 | return 0; |
| | 561 | } |
| | 562 | |
| | 563 | static int AddPlayerToGame(int id, char* name) |
| | 564 | { |
| | 565 | /* find a free slot for the player */ |
| | 566 | int freePlayerIndex = EmptySlotInPlayerList(); |
| | 567 | |
| | 568 | if(!freePlayerIndex) |
| | 569 | return 0; |
| | 570 | |
| | 571 | /* initialise the slot */ |
| | 572 | netGameData.playerData[freePlayerIndex].playerId = id; |
| | 573 | |
| | 574 | strncpy(netGameData.playerData[freePlayerIndex].name, name, NET_PLAYERNAMELENGTH-1); |
| | 575 | netGameData.playerData[freePlayerIndex].name[NET_PLAYERNAMELENGTH-1] = '\0'; |
| | 576 | |
| | 577 | netGameData.playerData[freePlayerIndex].characterType = NGCT_Marine; |
| | 578 | netGameData.playerData[freePlayerIndex].characterSubType = NGSCT_General; |
| | 579 | netGameData.playerData[freePlayerIndex].startFlag = 0; |
| | 580 | |
| | 581 | { |
| | 582 | int i = 0; |
| | 583 | for(; i < NET_MAXPLAYERS; i++) |
| | 584 | netGameData.playerData[freePlayerIndex].playerFrags[i] = 0; |
| | 585 | |
| | 586 | netGameData.playerData[freePlayerIndex].playerScore = 0; |
| | 587 | netGameData.playerData[freePlayerIndex].playerScoreAgainst = 0; |
| | 588 | netGameData.playerData[freePlayerIndex].aliensKilled[0] = 0; |
| | 589 | netGameData.playerData[freePlayerIndex].aliensKilled[1] = 0; |
| | 590 | netGameData.playerData[freePlayerIndex].aliensKilled[2] = 0; |
| | 591 | netGameData.playerData[freePlayerIndex].deathsFromAI=0; |
| | 592 | netGameData.playerData[freePlayerIndex].playerAlive = 1; |
| | 593 | netGameData.playerData[freePlayerIndex].playerHasLives = 1; |
| | 594 | netGameData.playerData[freePlayerIndex].lastKnownPosition.vx=0; |
| | 595 | netGameData.playerData[freePlayerIndex].lastKnownPosition.vy=100000000; |
| | 596 | netGameData.playerData[freePlayerIndex].lastKnownPosition.vz=0; |
| | 597 | } |
| | 598 | |
| | 599 | Inform_PlayerHasConnected(id); |
| | 600 | |
| | 601 | return freePlayerIndex; |
| | 602 | } |
| | 603 | |
| | 604 | void GetNextAllowedSpecies(int* species, int search_forwards) |
| | 605 | { |
| | 606 | int count = 0; |
| | 607 | |
| | 608 | if(SinglePlayer == AvP.PlayMode) |
| | 609 | { |
| | 610 | switch(netGameData.gameType) |
| | 611 | { |
| | 612 | case NGT_PredatorTag: |
| | 613 | { |
| | 614 | //this computer is the host setting up a predator tag game |
| | 615 | //therefore must be a predator |
| | 616 | *species = 1; |
| | 617 | return; |
| | 618 | } |
| | 619 | case NGT_AlienTag: |
| | 620 | case NGT_LastManStanding: |
| | 621 | { |
| | 622 | //this computer is the host setting up an alien tag or last man standing game |
| | 623 | //therefore must be a alien |
| | 624 | *species = 2; |
| | 625 | return; |
| | 626 | } |
| | 627 | default: |
| | 628 | break; |
| | 629 | } |
| | 630 | } |
| | 631 | |
| | 632 | DetermineAvailableCharacterTypes(1); |
| | 633 | |
| | 634 | do |
| | 635 | { |
| | 636 | switch(*species) |
| | 637 | { |
| | 638 | case 0: //marine (general) |
| | 639 | if(CharacterSubTypesAvailable[NGSCT_General] > 0) |
| | 640 | return; |
| | 641 | break; |
| | 642 | case 1: //predator |
| | 643 | if(CharacterTypesAvailable[NGCT_Predator] > 0) |
| | 644 | return; |
| | 645 | break; |
| | 646 | case 2: //alien |
| | 647 | if(CharacterTypesAvailable[NGCT_Alien] > 0) |
| | 648 | return; |
| | 649 | break; |
| | 650 | case 3: //marine (pulse rifle) |
| | 651 | if(CharacterSubTypesAvailable[NGSCT_PulseRifle]) |
| | 652 | return; |
| | 653 | break; |
| | 654 | case 4: //marine (smartgun) |
| | 655 | if(CharacterSubTypesAvailable[NGSCT_Smartgun]) |
| | 656 | return; |
| | 657 | break; |
| | 658 | case 5: //marine (flamer) |
| | 659 | if(CharacterSubTypesAvailable[NGSCT_Flamer]) |
| | 660 | return; |
| | 661 | break; |
| | 662 | case 6: //marine (sadar) |
| | 663 | if(CharacterSubTypesAvailable[NGSCT_Sadar]) |
| | 664 | return; |
| | 665 | break; |
| | 666 | case 7: //marine (grenade) |
| | 667 | if(CharacterSubTypesAvailable[NGSCT_GrenadeLauncher]) |
| | 668 | return; |
| | 669 | break; |
| | 670 | case 8: //marine (minigun) |
| | 671 | if(CharacterSubTypesAvailable[NGSCT_Minigun]) |
| | 672 | return; |
| | 673 | break; |
| | 674 | case 9: //marine (frisbee) |
| | 675 | if(CharacterSubTypesAvailable[NGSCT_Frisbee]) |
| | 676 | return; |
| | 677 | break; |
| | 678 | case 10: //marine (pistols) |
| | 679 | if(CharacterSubTypesAvailable[NGSCT_Pistols]) |
| | 680 | return; |
| | 681 | break; |
| | 682 | } |
| | 683 | |
| | 684 | if(search_forwards) |
| | 685 | { |
| | 686 | (*species)++; |
| | 687 | |
| | 688 | if(*species > 10) |
| | 689 | *species = 0; |
| | 690 | } |
| | 691 | else |
| | 692 | { |
| | 693 | (*species)--; |
| | 694 | |
| | 695 | if(*species < 0) |
| | 696 | *species = 10; |
| | 697 | } |
| | 698 | |
| | 699 | count++; |
| | 700 | |
| | 701 | } while(count < 9); |
| | 702 | |
| | 703 | //oh dear no allowable species |
| | 704 | *species = 0; |
| | 705 | } |
| | 706 | |
| | 707 | int InitAVPNetGameForJoin(const char* player_name, const char* server) |
| | 708 | { |
| | 709 | AvP.PlayMode = NetworkPeer; |
| | 710 | InitialiseSendMessageBuffer(); |
| | 711 | netGameData.myGameState = NGS_Joining; |
| | 712 | netGameData.needGameDescription = 1; |
| | 713 | myNetworkKillerId = 0; /* init global id of player who killed me last */ |
| | 714 | netNextLocalObjectId = 1; /* init local object network id */ |
| | 715 | |
| | 716 | return player_connect(server); |
| | 717 | |
| | 718 | //if (AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYER_SPECIES_JOIN) |
| | 719 | { |
| | 720 | //MinimalNetCollectMessages(); |
| | 721 | extern int MP_Species; |
| | 722 | |
| | 723 | GetNextAllowedSpecies(&MP_Species, 1); |
| | 724 | netGameData.myCharacterSubType = NGSCT_General; |
| | 725 | |
| | 726 | switch (MP_Species) |
| | 727 | { |
| | 728 | default: |
| | 729 | case 0: |
| | 730 | netGameData.myCharacterType = NGCT_Marine; |
| | 731 | netGameData.myNextCharacterType = NGCT_Marine; |
| | 732 | AvP.PlayerType = I_Marine; |
| | 733 | break; |
| | 734 | case 1: |
| | 735 | netGameData.myCharacterType = NGCT_Predator; |
| | 736 | netGameData.myNextCharacterType = NGCT_Predator; |
| | 737 | AvP.PlayerType = I_Predator; |
| | 738 | break; |
| | 739 | case 2: |
| | 740 | netGameData.myCharacterType = NGCT_Alien; |
| | 741 | netGameData.myNextCharacterType = NGCT_Alien; |
| | 742 | AvP.PlayerType = I_Alien; |
| | 743 | break; |
| | 744 | case 3: //various marine subtypes |
| | 745 | case 4: |
| | 746 | case 5: |
| | 747 | case 6: |
| | 748 | case 7: |
| | 749 | case 8: |
| | 750 | case 9: |
| | 751 | case 10: |
| | 752 | netGameData.myCharacterType = NGCT_Marine; |
| | 753 | netGameData.myNextCharacterType = NGCT_Marine; |
| | 754 | AvP.PlayerType = I_Marine; |
| | 755 | netGameData.myCharacterSubType =(NETGAME_SPECIALISTCHARACTERTYPE) (MP_Species-2); |
| | 756 | } |
| | 757 | |
| | 758 | AddNetMsg_PlayerDescription(); |
| | 759 | NetSendMessages(); |
| | 760 | } |
| | 761 | /* |
| | 762 | { |
| | 763 | netGameData.playerData[1].playerId = random(); |
| | 764 | netGameData.playerData[1].name[NET_PLAYERNAMELENGTH-1] = '\0'; |
| | 765 | } |
| | 766 | */ |
| | 767 | |
| | 768 | return 1; |
| | 769 | } |
| | 770 | |
| | 771 | void RemovePlayerFromGame(int id) |
| | 772 | { |
| | 773 | /* get player index from dpid */ |
| | 774 | int playerIndex = PlayerIdInPlayerList(id); |
| | 775 | |
| | 776 | if(playerIndex == NET_IDNOTINPLAYERLIST) |
| | 777 | { |
| | 778 | /* the player is not actually in the game, so do nothing. This might occur, for |
| | 779 | example if a player tries to join when the game is full */ |
| | 780 | return; |
| | 781 | } |
| | 782 | |
| | 783 | /* free the slot */ |
| | 784 | netGameData.playerData[playerIndex].playerId = 0; |
| | 785 | |
| | 786 | int j = 0; |
| | 787 | for(; j < NET_PLAYERNAMELENGTH; j++) |
| | 788 | netGameData.playerData[playerIndex].name[j] = '\0'; |
| | 789 | |
| | 790 | netGameData.playerData[playerIndex].characterType = NGCT_Marine; |
| | 791 | netGameData.playerData[playerIndex].characterSubType = NGSCT_General; |
| | 792 | |
| | 793 | netGameData.playerData[playerIndex].startFlag = 0; |
| | 794 | |
| | 795 | { |
| | 796 | int i = 0; |
| | 797 | for(; i < NET_MAXPLAYERS; i++) |
| | 798 | { |
| | 799 | netGameData.playerData[playerIndex].playerFrags[i] = 0; |
| | 800 | netGameData.playerData[i].playerFrags[playerIndex] = 0; |
| | 801 | } |
| | 802 | |
| | 803 | netGameData.playerData[playerIndex].playerScore = 0; |
| | 804 | netGameData.playerData[playerIndex].playerScoreAgainst = 0; |
| | 805 | netGameData.playerData[playerIndex].aliensKilled[0] = 0; |
| | 806 | netGameData.playerData[playerIndex].aliensKilled[1] = 0; |
| | 807 | netGameData.playerData[playerIndex].aliensKilled[2] = 0; |
| | 808 | netGameData.playerData[playerIndex].deathsFromAI=0; |
| | 809 | netGameData.playerData[playerIndex].playerAlive = 1; |
| | 810 | netGameData.playerData[playerIndex].playerHasLives = 1; |
| | 811 | netGameData.playerData[playerIndex].lastKnownPosition.vx=0; |
| | 812 | netGameData.playerData[playerIndex].lastKnownPosition.vy=100000000; |
| | 813 | netGameData.playerData[playerIndex].lastKnownPosition.vz=0; |
| | 814 | } |
| | 815 | } |
| | 816 | |
| | 817 | #define DPSYS_ADDPLAYERTOGROUP 2 |
| | 818 | #define DPSYS_CREATEPLAYERORGROUP 3 |
| | 819 | #define DPPLAYERTYPE_PLAYER 4 |
| | 820 | #define DPSYS_DELETEPLAYERFROMGROUP 5 |
| | 821 | #define DPSYS_HOST 6 |
| | 822 | #define DPSYS_SESSIONLOST 7 |
| | 823 | #define DPSYS_SETPLAYERORGROUPDATA 8 |
| | 824 | #define DPSYS_SETPLAYERORGROUPNAME 9 |
| | 825 | #define DPERR_BUSY 11 |
| | 826 | #define DPERR_CONNECTIONLOST 12 |
| | 827 | #define DPERR_INVALIDPARAMS 13 |
| | 828 | #define DPERR_INVALIDPLAYER 14 |
| | 829 | #define DPERR_NOTLOGGEDIN 15 |
| | 830 | #define DPERR_SENDTOOBIG 16 |
| | 831 | #define DPERR_BUFFERTOOSMALL 17 |
| | 832 | #define DPID_SYSMSG 18 |
| | 833 | #define DPSYS_DESTROYPLAYERORGROUP 19 |
| | 834 | |
| | 835 | static void ProcessSystemMessage(char *msgP, unsigned int msgSize) |
| | 836 | { |
| | 837 | |
| | 838 | struct DPMSG_GENERIC |
| | 839 | { |
| | 840 | int dwType; |
| | 841 | |
| | 842 | } * systemMessage = (struct DPMSG_GENERIC *)msgP; |
| | 843 | |
| | 844 | /* currently, only the host deals with system mesages */ |
| | 845 | /* check for invalid parameters */ |
| | 846 | if(!msgSize || (msgP == NULL)) |
| | 847 | return; |
| | 848 | |
| | 849 | switch(systemMessage->dwType) |
| | 850 | { |
| | 851 | case DPSYS_CREATEPLAYERORGROUP: |
| | 852 | { |
| | 853 | /* only useful during startup: during main game, connecting player should |
| | 854 | detect game state and exit immediately */ |
| | 855 | if(NetworkHost == AvP.PlayMode) |
| | 856 | { |
| | 857 | struct DPMSG_CREATEPLAYERORGROUP |
| | 858 | { |
| | 859 | int dwType; |
| | 860 | int dpId; |
| | 861 | int dwPlayerType; |
| | 862 | struct DPNAME dpnName; |
| | 863 | }; |
| | 864 | |
| | 865 | struct DPMSG_CREATEPLAYERORGROUP * createMessage = (struct DPMSG_CREATEPLAYERORGROUP *)systemMessage; |
| | 866 | |
| | 867 | if(createMessage->dwPlayerType == DPPLAYERTYPE_PLAYER) |
| | 868 | { |
| | 869 | int id = createMessage->dpId; |
| | 870 | char *name = &(createMessage->dpnName.name[0]); |
| | 871 | AddPlayerToGame(id, name); |
| | 872 | } |
| | 873 | } |
| | 874 | printf("system message: DPSYS_CREATEPLAYERORGROUP \n"); |
| | 875 | break; |
| | 876 | } |
| | 877 | case DPSYS_DESTROYPLAYERORGROUP: |
| | 878 | { |
| | 879 | /* Aha. Either a player has left (should have sent a leaving message) |
| | 880 | or s/he has exited abnormally. In either case, only need to act on |
| | 881 | this during start-up. During the main game, the ghosts will time-out |
| | 882 | anyway */ |
| | 883 | |
| | 884 | if(NetworkHost == AvP.PlayMode) |
| | 885 | { |
| | 886 | struct DPMSG_DESTROYPLAYERORGROUP |
| | 887 | { |
| | 888 | int dwType; |
| | 889 | int dpId; |
| | 890 | int dwPlayerType; |
| | 891 | }; |
| | 892 | |
| | 893 | struct DPMSG_DESTROYPLAYERORGROUP * destroyMessage = (struct DPMSG_DESTROYPLAYERORGROUP *)systemMessage; |
| | 894 | |
| | 895 | if(destroyMessage->dwPlayerType == DPPLAYERTYPE_PLAYER) |
| | 896 | { |
| | 897 | int id = destroyMessage->dpId; |
| | 898 | RemovePlayerFromGame(id); |
| | 899 | } |
| | 900 | } |
| | 901 | printf("system message: DPSYS_DESTROYPLAYERORGROUP \n"); |
| | 902 | break; |
| | 903 | } |
| | 904 | case DPSYS_HOST: |
| | 905 | { |
| | 906 | /* Aha... the host has died, then. This is a terminal game state, |
| | 907 | as the host was managing the game. Thefore, temporarily adopt host |
| | 908 | duties for the purpose of ending the game... |
| | 909 | This is most important during the playing state, but also happens in |
| | 910 | startup. In startup, peers keep a host timeout which should fire before |
| | 911 | this message arrives anyway. */ |
| | 912 | //assert(AvP.Network==I_Peer); |
| | 913 | |
| | 914 | if((netGameData.myGameState==NGS_StartUp) |
| | 915 | ||(netGameData.myGameState==NGS_Playing) |
| | 916 | ||(netGameData.myGameState==NGS_Joining) |
| | 917 | ||(netGameData.myGameState==NGS_EndGameScreen)) |
| | 918 | { |
| | 919 | AvP.PlayMode = NetworkHost; |
| | 920 | /* Eek, I guess the old AIs bite the dust? */ |
| | 921 | //but the new host can create some more |
| | 922 | //AvP.NetworkAIServer = (netGameData.gameType == NGT_Coop); |
| | 923 | GADGET_NewOnScreenMessage("This machine is not host"); |
| | 924 | } |
| | 925 | printf("system message: DPSYS_HOST \n"); |
| | 926 | break; |
| | 927 | } |
| | 928 | case DPSYS_SESSIONLOST: |
| | 929 | { |
| | 930 | /* Aha. I have lost my connection. Time to exit the game gracefully.*/ |
| | 931 | printf("Session lost!!\n"); |
| | 932 | break; |
| | 933 | } |
| | 934 | default: |
| | 935 | { |
| | 936 | /* invalid system message type: ignore */ |
| | 937 | break; |
| | 938 | } |
| | 939 | } |
| | 940 | } |
| | 941 | |
| | 942 | static void Inform_PlayerHasJoined(int player) |
| | 943 | { |
| | 944 | int playerIndex = PlayerIdInPlayerList(player); |
| | 945 | |
| | 946 | /* KJL 15:35:38 09/04/98 - not knowing who the player is what make things a bit awkward... */ |
| | 947 | if(playerIndex == NET_IDNOTINPLAYERLIST) |
| | 948 | return; |
| | 949 | |
| | 950 | NetworkGameConsoleMessage("%1 has joined the game", netGameData.playerData[playerIndex].name, 0); |
| | 951 | } |
| | 952 | |
| | 953 | static void Inform_PlayerHasLeft(int player) |
| | 954 | { |
| | 955 | int playerIndex = PlayerIdInPlayerList(player); |
| | 956 | |
| | 957 | /* KJL 15:35:38 09/04/98 - not knowing who the player is what make things a bit awkward... */ |
| | 958 | if(playerIndex == NET_IDNOTINPLAYERLIST) |
| | 959 | return; |
| | 960 | |
| | 961 | NetworkGameConsoleMessage("%1 has left the game", netGameData.playerData[playerIndex].name, 0); |
| | 962 | } |
| | 963 | |
| | 964 | static void ProcessNetMsg_GameDescription(NETMESSAGE_GAMEDESCRIPTION *messagePtr) |
| | 965 | { |
| | 966 | /* should only get this if we're not the host, and we're in start-up state */ |
| | 967 | if(NetworkPeer != AvP.PlayMode) |
| | 968 | { |
| | 969 | //Vaguely possible that a host could receive a message that is only intended for peers |
| | 970 | //if this computer has only just become the host. |
| | 971 | assert(NetworkHost == AvP.PlayMode); |
| | 972 | return; |
| | 973 | } |
| | 974 | |
| | 975 | //if(netGameData.myGameState!=NGS_Joining) return; |
| | 976 | |
| | 977 | /* fill out the game description player list with the new player id's */ |
| | 978 | { |
| | 979 | int i = 0; |
| | 980 | for(; i < NET_MAXPLAYERS; i++) |
| | 981 | { |
| | 982 | int playerChanged = 0; |
| | 983 | |
| | 984 | if ( (netGameData.playerData[i].playerId != messagePtr->players[i].playerId) |
| | 985 | ||(netGameData.playerData[i].startFlag != messagePtr->players[i].startFlag) ) |
| | 986 | playerChanged = 1; |
| | 987 | |
| | 988 | if (netGameData.myGameState == NGS_Playing && playerChanged) |
| | 989 | { |
| | 990 | if (messagePtr->players[i].playerId == 0) |
| | 991 | { |
| | 992 | Inform_PlayerHasLeft(netGameData.playerData[i].playerId); |
| | 993 | } |
| | 994 | else if (messagePtr->players[i].startFlag) |
| | 995 | { |
| | 996 | Inform_PlayerHasJoined(messagePtr->players[i].playerId); |
| | 997 | } |
| | 998 | else |
| | 999 | { |
| | 1000 | Inform_PlayerHasConnected(messagePtr->players[i].playerId); |
| | 1001 | } |
| | 1002 | } |
| | 1003 | |
| | 1004 | if(netGameData.playerData[i].playerId != messagePtr->players[i].playerId) |
| | 1005 | { |
| | 1006 | if(messagePtr->players[i].playerId) |
| | 1007 | { |
| | 1008 | unsigned int size=0; |
| | 1009 | char* data; |
| | 1010 | int hr = 1; |
| | 1011 | //need to find out this player's name |
| | 1012 | //first find the size of buffer required |
| | 1013 | |
| | 1014 | if(hr == 0 || hr == DPERR_BUFFERTOOSMALL) |
| | 1015 | { |
| | 1016 | //allocate buffer to recive the name |
| | 1017 | data = malloc(size); |
| | 1018 | *data = 0; |
| | 1019 | hr = 1; |
| | 1020 | |
| | 1021 | if(hr == 0) |
| | 1022 | { |
| | 1023 | strncpy(netGameData.playerData[i].name,((struct DPNAME*)data)->name,NET_PLAYERNAMELENGTH-1); |
| | 1024 | netGameData.playerData[i].name[NET_PLAYERNAMELENGTH-1]='\0'; |
| | 1025 | } |
| | 1026 | |
| | 1027 | free(data); |
| | 1028 | } |
| | 1029 | |
| | 1030 | } |
| | 1031 | else |
| | 1032 | { |
| | 1033 | netGameData.playerData[i].name[0] = '\0'; |
| | 1034 | } |
| | 1035 | } |
| | 1036 | |
| | 1037 | netGameData.playerData[i].playerId = messagePtr->players[i].playerId; |
| | 1038 | netGameData.playerData[i].characterType = (NETGAME_CHARACTERTYPE)messagePtr->players[i].characterType; |
| | 1039 | netGameData.playerData[i].characterSubType = (NETGAME_CHARACTERTYPE)messagePtr->players[i].characterSubType; |
| | 1040 | netGameData.playerData[i].startFlag = messagePtr->players[i].startFlag; |
| | 1041 | } |
| | 1042 | |
| | 1043 | netGameData.gameType = (NETGAME_TYPE)messagePtr->gameType; |
| | 1044 | //level number got from the session description instead |
| | 1045 | //netGameData.levelNumber = messagePtr->levelNumber; |
| | 1046 | netGameData.scoreLimit = messagePtr->scoreLimit; |
| | 1047 | netGameData.timeLimit = messagePtr->timeLimit; |
| | 1048 | netGameData.invulnerableTime = messagePtr->invulnerableTime; |
| | 1049 | |
| | 1050 | for(i=0; i < 3; i++) |
| | 1051 | { |
| | 1052 | netGameData.characterKillValues[i]=messagePtr->characterKillValues[i]; |
| | 1053 | netGameData.aiKillValues[i]=messagePtr->aiKillValues[i]; |
| | 1054 | } |
| | 1055 | |
| | 1056 | netGameData.baseKillValue=messagePtr->baseKillValue; |
| | 1057 | netGameData.useDynamicScoring=messagePtr->useDynamicScoring; |
| | 1058 | netGameData.useCharacterKillValues=messagePtr->useCharacterKillValues; |
| | 1059 | netGameData.sendDecals=messagePtr->sendDecals; |
| | 1060 | netGameData.gameSpeed=messagePtr->gameSpeed; |
| | 1061 | netGameData.disableFriendlyFire=messagePtr->disableFriendlyFire; |
| | 1062 | netGameData.fallingDamage=messagePtr->fallingDamage; |
| | 1063 | netGameData.pistolInfiniteAmmo=messagePtr->pistolInfiniteAmmo; |
| | 1064 | netGameData.specialistPistols=messagePtr->specialistPistols; |
| | 1065 | |
| | 1066 | if(netGameData.needGameDescription) |
| | 1067 | { |
| | 1068 | /*We were waiting for the game description , best make sure that our player id appears |
| | 1069 | int the player list*/ |
| | 1070 | if(PlayerIdInPlayerList(AVPDPNetID) != NET_IDNOTINPLAYERLIST) |
| | 1071 | { |
| | 1072 | /*we now have the game description, so we can stop waiting if we were |
| | 1073 | trying to join*/ |
| | 1074 | netGameData.needGameDescription = 0; |
| | 1075 | /* |
| | 1076 | make sure our time scale is set correctly |
| | 1077 | (Only set it the once , so that it can be overridden for debugging purposes) |
| | 1078 | */ |
| | 1079 | switch(netGameData.gameSpeed) |
| | 1080 | { |
| | 1081 | case NETGAMESPEED_70PERCENT : |
| | 1082 | TimeScale=(ONE_FIXED*70)/100; |
| | 1083 | break; |
| | 1084 | |
| | 1085 | case NETGAMESPEED_80PERCENT : |
| | 1086 | TimeScale=(ONE_FIXED*80)/100; |
| | 1087 | break; |
| | 1088 | |
| | 1089 | case NETGAMESPEED_90PERCENT : |
| | 1090 | TimeScale=(ONE_FIXED*90)/100; |
| | 1091 | break; |
| | 1092 | |
| | 1093 | case NETGAMESPEED_100PERCENT : |
| | 1094 | TimeScale=(ONE_FIXED*100)/100; |
| | 1095 | break; |
| | 1096 | } |
| | 1097 | } |
| | 1098 | } |
| | 1099 | |
| | 1100 | netGameData.allowSmartgun = messagePtr->allowSmartgun; |
| | 1101 | netGameData.allowFlamer = messagePtr->allowFlamer; |
| | 1102 | netGameData.allowSadar = messagePtr->allowSadar; |
| | 1103 | netGameData.allowGrenadeLauncher = messagePtr->allowGrenadeLauncher; |
| | 1104 | netGameData.allowMinigun = messagePtr->allowMinigun; |
| | 1105 | netGameData.allowDisc = messagePtr->allowDisc; |
| | 1106 | netGameData.allowPistol = messagePtr->allowPistol; |
| | 1107 | netGameData.allowPlasmaCaster = messagePtr->allowPlasmaCaster; |
| | 1108 | netGameData.allowSpeargun = messagePtr->allowSpeargun; |
| | 1109 | netGameData.allowMedicomp = messagePtr->allowMedicomp; |
| | 1110 | netGameData.allowSmartDisc = messagePtr->allowSmartDisc; |
| | 1111 | netGameData.allowPistols = messagePtr->allowPistols; |
| | 1112 | netGameData.maxPredator = messagePtr->maxPredator; |
| | 1113 | netGameData.maxAlien = messagePtr->maxAlien; |
| | 1114 | netGameData.maxMarine = messagePtr->maxMarine; |
| | 1115 | netGameData.maxMarineGeneral = messagePtr->maxMarineGeneral; |
| | 1116 | netGameData.maxMarinePulseRifle = messagePtr->maxMarinePulseRifle; |
| | 1117 | netGameData.maxMarineSmartgun = messagePtr->maxMarineSmartgun; |
| | 1118 | netGameData.maxMarineFlamer = messagePtr->maxMarineFlamer; |
| | 1119 | netGameData.maxMarineSadar = messagePtr->maxMarineSadar; |
| | 1120 | netGameData.maxMarineGrenade = messagePtr->maxMarineGrenade; |
| | 1121 | netGameData.maxMarineMinigun = messagePtr->maxMarineMinigun; |
| | 1122 | netGameData.maxMarineSmartDisc = messagePtr->maxMarineSmartDisc; |
| | 1123 | netGameData.maxMarinePistols = messagePtr->maxMarinePistols; |
| | 1124 | netGameData.useSharedLives = messagePtr->useSharedLives; |
| | 1125 | netGameData.maxLives = messagePtr->maxLives; |
| | 1126 | netGameData.numDeaths[0] = messagePtr->numDeaths[0]; |
| | 1127 | netGameData.numDeaths[1] = messagePtr->numDeaths[1]; |
| | 1128 | netGameData.numDeaths[2] = messagePtr->numDeaths[2]; |
| | 1129 | netGameData.timeForRespawn = messagePtr->timeForRespawn; |
| | 1130 | netGameData.pointsForRespawn = messagePtr->pointsForRespawn; |
| | 1131 | |
| | 1132 | { |
| | 1133 | //check to if the host's elapsed time is |
| | 1134 | //significantly different from our elapsed time value |
| | 1135 | int receivedTime = messagePtr->GameTimeElapsed; |
| | 1136 | int diff = netGameData.GameTimeElapsed-receivedTime; |
| | 1137 | receivedTime <<= 16; |
| | 1138 | |
| | 1139 | if(diff < -ONE_FIXED || diff>ONE_FIXED || netGameData.myGameState == NGS_EndGameScreen) |
| | 1140 | { |
| | 1141 | //best take the host's value |
| | 1142 | netGameData.GameTimeElapsed = receivedTime; |
| | 1143 | } |
| | 1144 | } |
| | 1145 | } |
| | 1146 | |
| | 1147 | if(messagePtr->endGame) |
| | 1148 | { |
| | 1149 | if(netGameData.myGameState == NGS_Playing) |
| | 1150 | { |
| | 1151 | //we must have missed the end game message |
| | 1152 | netGameData.myGameState = NGS_EndGameScreen; |
| | 1153 | } |
| | 1154 | } |
| | 1155 | else |
| | 1156 | { |
| | 1157 | if(netGameData.myGameState == NGS_EndGameScreen) |
| | 1158 | { |
| | 1159 | //must have missed message to restart game |
| | 1160 | //therefore probably better restart now |
| | 1161 | RestartNetworkGame(0); |
| | 1162 | } |
| | 1163 | } |
| | 1164 | } |
| | 1165 | |
| | 1166 | static void ProcessNetMsg_PlayerDescription(NETMESSAGE_PLAYERDESCRIPTION *messagePtr, int senderId) |
| | 1167 | { |
| | 1168 | /* only act on this if we're the host and in start-up */ |
| | 1169 | if(NetworkHost != AvP.PlayMode) |
| | 1170 | return; |
| | 1171 | |
| | 1172 | /* find the player and fill out their details from the message */ |
| | 1173 | { |
| | 1174 | int id = PlayerIdInPlayerList(senderId); |
| | 1175 | |
| | 1176 | if(id == NET_IDNOTINPLAYERLIST) |
| | 1177 | { |
| | 1178 | /* player does not seem to be in the player list, so ignore it */ |
| | 1179 | return; |
| | 1180 | } |
| | 1181 | |
| | 1182 | netGameData.playerData[id].characterType = (NETGAME_CHARACTERTYPE)messagePtr->characterType; |
| | 1183 | netGameData.playerData[id].characterSubType = (NETGAME_SPECIALISTCHARACTERTYPE)messagePtr->characterSubType; |
| | 1184 | |
| | 1185 | if (netGameData.myGameState == NGS_Playing) |
| | 1186 | { |
| | 1187 | if(messagePtr->startFlag && (netGameData.playerData[id].startFlag != messagePtr->startFlag) ) |
| | 1188 | Inform_PlayerHasJoined(netGameData.playerData[id].playerId); |
| | 1189 | } |
| | 1190 | |
| | 1191 | netGameData.playerData[id].startFlag = messagePtr->startFlag; |
| | 1192 | } |
| | 1193 | } |
| | 1194 | |
| | 1195 | static void ProcessNetMsg_PlayerState(NETMESSAGE_PLAYERSTATE *messagePtr, int senderId) |
| | 1196 | { |
| | 1197 | VECTORCH position; |
| | 1198 | |
| | 1199 | position.vx = messagePtr->xPos; |
| | 1200 | position.vy = messagePtr->yPos; |
| | 1201 | position.vz = messagePtr->zPos; |
| | 1202 | { |
| | 1203 | //recored the players position , even if we aren't currntly playing |
| | 1204 | int playerIndex = PlayerIdInPlayerList(senderId); |
| | 1205 | |
| | 1206 | if(playerIndex != NET_IDNOTINPLAYERLIST) |
| | 1207 | netGameData.playerData[playerIndex].lastKnownPosition = position; |
| | 1208 | } |
| | 1209 | |
| | 1210 | /* if we're not playing, ignore it */ |
| | 1211 | if(netGameData.myGameState != NGS_Playing) |
| | 1212 | return; |
| | 1213 | |
| | 1214 | int playerIndex = PlayerIdInPlayerList(senderId); |
| | 1215 | |
| | 1216 | /* KJL 14:47:22 06/04/98 - we don't seem to know about this person yet... ignore them */ |
| | 1217 | if (playerIndex == NET_IDNOTINPLAYERLIST) |
| | 1218 | return; |
| | 1219 | |
| | 1220 | STRATEGYBLOCK *sbPtr = FindGhost(senderId, GHOST_PLAYEROBJECTID); |
| | 1221 | |
| | 1222 | //record whether the player is in the land of the living |
| | 1223 | netGameData.playerData[playerIndex].playerAlive = messagePtr->IAmAlive; |
| | 1224 | netGameData.playerData[playerIndex].playerHasLives = messagePtr->IHaveLifeLeft; |
| | 1225 | |
| | 1226 | //check the player type |
| | 1227 | //the value in the netgamedata should be set to next character type |
| | 1228 | netGameData.playerData[playerIndex].characterType = messagePtr->nextCharacterType; |
| | 1229 | netGameData.playerData[playerIndex].characterSubType = messagePtr->characterSubType; |
| | 1230 | |
| | 1231 | if(sbPtr) |
| | 1232 | { |
| | 1233 | NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->dataptr; |
| | 1234 | assert(ghostData); |
| | 1235 | |
| | 1236 | //here we need to use the current character type |
| | 1237 | switch(messagePtr->characterType) |
| | 1238 | { |
| | 1239 | case NGCT_Marine : |
| | 1240 | if(ghostData->type != I_BehaviourMarinePlayer) |
| | 1241 | { |
| | 1242 | sbPtr->please_destroy_me = 1; |
| | 1243 | return; |
| | 1244 | } |
| | 1245 | break; |
| | 1246 | case NGCT_Predator : |
| | 1247 | if(ghostData->type != I_BehaviourPredatorPlayer) |
| | 1248 | { |
| | 1249 | sbPtr->please_destroy_me = 1; |
| | 1250 | return; |
| | 1251 | } |
| | 1252 | break; |
| | 1253 | case NGCT_Alien : |
| | 1254 | if(ghostData->type != I_BehaviourAlienPlayer) |
| | 1255 | { |
| | 1256 | sbPtr->please_destroy_me = 1; |
| | 1257 | return; |
| | 1258 | } |
| | 1259 | } |
| | 1260 | } |
| | 1261 | |
| | 1262 | if(!MultiplayerObservedPlayer) |
| | 1263 | { |
| | 1264 | if(sbPtr && sbPtr->DisplayBlock) |
| | 1265 | { |
| | 1266 | //make sure the model is visivle |
| | 1267 | sbPtr->DisplayBlock->ObFlags&=~ObFlag_NotVis; |
| | 1268 | } |
| | 1269 | } |
| | 1270 | |
| | 1271 | { |
| | 1272 | EULER orientation; |
| | 1273 | |
| | 1274 | orientation.EulerX = (messagePtr->xOrient<<NET_EULERSCALESHIFT); |
| | 1275 | orientation.EulerY = (messagePtr->yOrient<<NET_EULERSCALESHIFT); |
| | 1276 | orientation.EulerZ = (messagePtr->zOrient<<NET_EULERSCALESHIFT); |
| | 1277 | int sequence = (int)messagePtr->sequence; |
| | 1278 | int weapon = (int)messagePtr->currentWeapon; |
| | 1279 | int firingPrimary = (int)messagePtr->IAmFiringPrimary; |
| | 1280 | int firingSecondary = (int)messagePtr->IAmFiringSecondary; |
| | 1281 | |
| | 1282 | if(!sbPtr) |
| | 1283 | { |
| | 1284 | /* If we are not a dead alien then we should have a ghost */ |
| | 1285 | // if(!(!messagePtr->IAmAlive && (netGameData.playerData[playerIndex].characterType == NGCT_Alien))) |
| | 1286 | if (messagePtr->IAmAlive) |
| | 1287 | { |
| | 1288 | AVP_BEHAVIOUR_TYPE type; |
| | 1289 | |
| | 1290 | if(messagePtr->characterType == NGCT_Marine) |
| | 1291 | type = I_BehaviourMarinePlayer; |
| | 1292 | else if(messagePtr->characterType == NGCT_Alien) |
| | 1293 | type = I_BehaviourAlienPlayer; |
| | 1294 | else |
| | 1295 | type = I_BehaviourPredatorPlayer; |
| | 1296 | |
| | 1297 | sbPtr = CreateNetGhost(senderId,GHOST_PLAYEROBJECTID,&position,&orientation,type,IOT_Non,0); |
| | 1298 | |
| | 1299 | if(sbPtr) |
| | 1300 | { |
| | 1301 | HandleWeaponElevation(sbPtr,(int)messagePtr->Elevation,weapon); |
| | 1302 | //don't draw muzzle flash if observing from this player |
| | 1303 | |
| | 1304 | if(MultiplayerObservedPlayer != senderId) |
| | 1305 | HandleGhostGunFlashEffect(sbPtr, messagePtr->IHaveAMuzzleFlash); |
| | 1306 | else |
| | 1307 | HandleGhostGunFlashEffect(sbPtr, 0); |
| | 1308 | |
| | 1309 | HandlePlayerGhostWeaponSound(sbPtr,weapon,firingPrimary,firingSecondary); |
| | 1310 | MaintainGhostCloakingStatus(sbPtr,(int)messagePtr->CloakingEffectiveness); |
| | 1311 | MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire); |
| | 1312 | } |
| | 1313 | } |
| | 1314 | } |
| | 1315 | else |
| | 1316 | { |
| | 1317 | if(! (!messagePtr->IAmAlive && (netGameData.playerData[playerIndex].characterType == NGCT_Alien))) |
| | 1318 | { |
| | 1319 | /* We are not a dead alien */ |
| | 1320 | HandleWeaponElevation(sbPtr,(int)messagePtr->Elevation,weapon); |
| | 1321 | UpdateGhost(sbPtr,&position,&orientation,sequence,messagePtr->Special); |
| | 1322 | //don't draw muzzle flash if observing from this player |
| | 1323 | |
| | 1324 | if(MultiplayerObservedPlayer != senderId) |
| | 1325 | HandleGhostGunFlashEffect(sbPtr, messagePtr->IHaveAMuzzleFlash); |
| | 1326 | else |
| | 1327 | HandleGhostGunFlashEffect(sbPtr, 0); |
| | 1328 | |
| | 1329 | HandlePlayerGhostWeaponSound(sbPtr,weapon,firingPrimary,firingSecondary); |
| | 1330 | MaintainGhostCloakingStatus(sbPtr,(int)messagePtr->CloakingEffectiveness); |
| | 1331 | MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire); |
| | 1332 | /* Now, more disc. */ |
| | 1333 | |
| | 1334 | if (messagePtr->IHaveADisk) |
| | 1335 | { |
| | 1336 | /* Find the thrower's ghost, and add his disc... */ |
| | 1337 | |
| | 1338 | NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->dataptr; |
| | 1339 | assert(ghostData); |
| | 1340 | assert(ghostData->type==I_BehaviourPredatorPlayer); |
| | 1341 | SECTION_DATA *disc = GetThisSectionData(ghostData->HModelController.section_data,"disk"); |
| | 1342 | |
| | 1343 | if (disc) |
| | 1344 | disc->flags &= ~section_data_notreal; |
| | 1345 | } |
| | 1346 | } |
| | 1347 | else |
| | 1348 | { |
| | 1349 | /* We are a dead alien with a ghost */ |
| | 1350 | RemoveGhost(sbPtr); |
| | 1351 | return; |
| | 1352 | } |
| | 1353 | } |
| | 1354 | |
| | 1355 | if(sbPtr && messagePtr->IAmAlive) |
| | 1356 | { |
| | 1357 | NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->dataptr; |
| | 1358 | |
| | 1359 | ghostData->invulnerable = messagePtr->IAmInvulnerable; |
| | 1360 | |
| | 1361 | #if EXTRAPOLATION_TEST |
| | 1362 | { |
| | 1363 | VECTORCH velocity,diff; |
| | 1364 | int playerTimer = netGameData.playerData[playerIndex].timer; |
| | 1365 | |
| | 1366 | velocity.vx = messagePtr->velocity_x*100; |
| | 1367 | velocity.vy = messagePtr->velocity_y*100; |
| | 1368 | velocity.vz = messagePtr->velocity_z*100; |
| | 1369 | |
| | 1370 | diff.vx = ghostData->velocity.vx - velocity.vx; |
| | 1371 | diff.vy = ghostData->velocity.vy - velocity.vy; |
| | 1372 | diff.vz = ghostData->velocity.vz - velocity.vz; |
| | 1373 | |
| | 1374 | if(Approximate3dMagnitude(&diff) > 1000) |
| | 1375 | { |
| | 1376 | //change in velocity , so reset extrapolation timer |
| | 1377 | ghostData->extrapTimer = -ONE_FIXED; |
| | 1378 | } |
| | 1379 | |
| | 1380 | ghostData->velocity = velocity; |
| | 1381 | ghostData->extrapTimerLast = 0; |
| | 1382 | |
| | 1383 | if(playerTimer >= ghostData->lastTimeRead) |
| | 1384 | ghostData->extrapTimer -= (playerTimer-ghostData->lastTimeRead); |
| | 1385 | else |
| | 1386 | ghostData->extrapTimer = -ONE_FIXED; |
| | 1387 | |
| | 1388 | ghostData->lastTimeRead = playerTimer; |
| | 1389 | } |
| | 1390 | |
| | 1391 | if(ghostData->type == I_BehaviourAlienPlayer) |
| | 1392 | { |
| | 1393 | sbPtr->DynPtr->UseStandardGravity = messagePtr->standard_gravity; |
| | 1394 | |
| | 1395 | if(!sbPtr->DynPtr->UseStandardGravity) |
| | 1396 | { |
| | 1397 | if(sbPtr->DynPtr->GravityDirection.vy == ONE_FIXED) |
| | 1398 | { |
| | 1399 | MATRIXCH mat; |
| | 1400 | //alien is crawling , so we need to get an appropriate gravity direction |
| | 1401 | CreateEulerMatrix(&orientation,&mat); |
| | 1402 | sbPtr->DynPtr->GravityDirection.vx = mat.mat12; |
| | 1403 | sbPtr->DynPtr->GravityDirection.vy = mat.mat22; |
| | 1404 | sbPtr->DynPtr->GravityDirection.vz = mat.mat32; |
| | 1405 | } |
| | 1406 | |
| | 1407 | sbPtr->DynPtr->LinImpulse.vx = 0; |
| | 1408 | sbPtr->DynPtr->LinImpulse.vy = 0; |
| | 1409 | sbPtr->DynPtr->LinImpulse.vz = 0; |
| | 1410 | sbPtr->DynPtr->ToppleForce = TOPPLE_FORCE_ALIEN; |
| | 1411 | } |
| | 1412 | } |
| | 1413 | #endif |
| | 1414 | |
| | 1415 | if(messagePtr->scream != 31) |
| | 1416 | { |
| | 1417 | //this character is screaming |
| | 1418 | switch(messagePtr->characterType) |
| | 1419 | { |
| | 1420 | case NGCT_Marine : |
| | 1421 | PlayMarineScream(0, (MARINE_SOUND_CATERGORY)messagePtr->scream,0,&ghostData->SoundHandle2,&position); |
| | 1422 | break; |
| | 1423 | case NGCT_Alien : |
| | 1424 | PlayAlienSound(0, (ALIEN_SOUND_CATEGORY)messagePtr->scream,0,&ghostData->SoundHandle2,&position); |
| | 1425 | break; |
| | 1426 | case NGCT_Predator : |
| | 1427 | if ((PREDATOR_SOUND_CATEGORY)messagePtr->scream == PSC_Medicomp_Special) |
| | 1428 | Sound_Play(SID_PRED_ROAR, "de", &position, &ghostData->SoundHandle2); |
| | 1429 | else |
| | 1430 | PlayPredatorSound(0, (PREDATOR_SOUND_CATEGORY)messagePtr->scream,0,&ghostData->SoundHandle2,&position); |
| | 1431 | } |
| | 1432 | } |
| | 1433 | |
| | 1434 | /* Landing noise. */ |
| | 1435 | if (messagePtr->landingNoise) |
| | 1436 | { |
| | 1437 | switch(messagePtr->characterType) |
| | 1438 | { |
| | 1439 | case NGCT_Marine : |
| | 1440 | Sound_Play(SID_MARINE_SMALLLANDING,"d",&position); |
| | 1441 | break; |
| | 1442 | case NGCT_Alien : |
| | 1443 | /* No sound for aliens. */ |
| | 1444 | break; |
| | 1445 | case NGCT_Predator : |
| | 1446 | Sound_Play(SID_PRED_SMALLLANDING,"d",&position); |
| | 1447 | } |
| | 1448 | } |
| | 1449 | |
| | 1450 | //are we currently following this player's movements |
| | 1451 | if(MultiplayerObservedPlayer) |
| | 1452 | { |
| | 1453 | if(MultiplayerObservedPlayer == senderId) |
| | 1454 | { |
| | 1455 | PlayerStatus.ViewPanX = messagePtr->Elevation; |
| | 1456 | PlayerStatus.sbptr->DynPtr->Position = position; |
| | 1457 | PlayerStatus.sbptr->DynPtr->PrevPosition = position; |
| | 1458 | PlayerStatus.sbptr->DynPtr->OrientEuler = orientation; |
| | 1459 | CreateEulerMatrix(&PlayerStatus.sbptr->DynPtr->OrientEuler, &PlayerStatus.sbptr->DynPtr->OrientMat); |
| | 1460 | TransposeMatrixCH(&PlayerStatus.sbptr->DynPtr->OrientMat); |
| | 1461 | |
| | 1462 | if(messagePtr->IAmCrouched) |
| | 1463 | PlayerStatus.Crouching = 1; |
| | 1464 | |
| | 1465 | //don't draw the player we're observing |
| | 1466 | if(sbPtr && sbPtr->DisplayBlock) |
| | 1467 | sbPtr->DisplayBlock->ObFlags |= ObFlag_NotVis; |
| | 1468 | } |
| | 1469 | } |
| | 1470 | } |
| | 1471 | } |
| | 1472 | } |
| | 1473 | |
| | 1474 | static void ProcessNetMsg_PlayerState_Minimal(NETMESSAGE_PLAYERSTATE_MINIMAL *messagePtr, int senderId,int orientation) |
| | 1475 | { |
| | 1476 | /* if we're not playing, ignore it */ |
| | 1477 | if(netGameData.myGameState != NGS_Playing) |
| | 1478 | return; |
| | 1479 | |
| | 1480 | int playerIndex = PlayerIdInPlayerList(senderId); |
| | 1481 | |
| | 1482 | /* KJL 14:47:22 06/04/98 - we don't seem to know about this person yet... ignore them */ |
| | 1483 | if (playerIndex == NET_IDNOTINPLAYERLIST) |
| | 1484 | return; |
| | 1485 | |
| | 1486 | STRATEGYBLOCK *sbPtr = FindGhost(senderId, GHOST_PLAYEROBJECTID); |
| | 1487 | |
| | 1488 | //record whether the player is in the land of the living |
| | 1489 | netGameData.playerData[playerIndex].playerAlive=messagePtr->IAmAlive; |
| | 1490 | netGameData.playerData[playerIndex].playerHasLives=messagePtr->IHaveLifeLeft; |
| | 1491 | |
| | 1492 | if(!sbPtr) |
| | 1493 | { |
| | 1494 | //if we don't have a ghost for this player , wait for a full player state message |
| | 1495 | return; |
| | 1496 | } |
| | 1497 | |
| | 1498 | if(!MultiplayerObservedPlayer) |
| | 1499 | { |
| | 1500 | if(sbPtr && sbPtr->DisplayBlock) |
| | 1501 | { |
| | 1502 | //make sure the model is visivle |
| | 1503 | sbPtr->DisplayBlock->ObFlags&=~ObFlag_NotVis; |
| | 1504 | } |
| | 1505 | } |
| | 1506 | |
| | 1507 | { |
| | 1508 | //int firingPrimary = (int)messagePtr->IAmFiringPrimary; |
| | 1509 | //int firingSecondary = (int)messagePtr->IAmFiringSecondary; |
| | 1510 | |
| | 1511 | if(!(!messagePtr->IAmAlive && (netGameData.playerData[playerIndex].characterType == NGCT_Alien))) |
| | 1512 | { |
| | 1513 | NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->dataptr; |
| | 1514 | assert(ghostData); |
| | 1515 | |
| | 1516 | if(orientation) |
| | 1517 | { |
| | 1518 | NETMESSAGE_PLAYERSTATE_MEDIUM* mediumMessage=(NETMESSAGE_PLAYERSTATE_MEDIUM*) messagePtr; |
| | 1519 | EULER orientation; |
| | 1520 | orientation.EulerX = (mediumMessage->xOrient<<NET_EULERSCALESHIFT); |
| | 1521 | orientation.EulerY = (mediumMessage->yOrient<<NET_EULERSCALESHIFT); |
| | 1522 | orientation.EulerZ = (mediumMessage->zOrient<<NET_EULERSCALESHIFT); |
| | 1523 | |
| | 1524 | UpdateGhost(sbPtr,&sbPtr->DynPtr->Position,&orientation,-1,messagePtr->Special); |
| | 1525 | } |
| | 1526 | |
| | 1527 | /* We are not a dead alien */ |
| | 1528 | HandleWeaponElevation(sbPtr,(int)messagePtr->Elevation,ghostData->CurrentWeapon); |
| | 1529 | //don't draw muzzle flash if observing from this player |
| | 1530 | |
| | 1531 | if(MultiplayerObservedPlayer != senderId) |
| | 1532 | HandleGhostGunFlashEffect(sbPtr, messagePtr->IHaveAMuzzleFlash); |
| | 1533 | else |
| | 1534 | HandleGhostGunFlashEffect(sbPtr, 0); |
| | 1535 | |
| | 1536 | MaintainGhostCloakingStatus(sbPtr,(int)messagePtr->CloakingEffectiveness<<8); |
| | 1537 | MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire); |
| | 1538 | /* Now, more disc. */ |
| | 1539 | |
| | 1540 | if (messagePtr->IHaveADisk) |
| | 1541 | { |
| | 1542 | /* Find the thrower's ghost, and add his disc... */ |
| | 1543 | |
| | 1544 | assert(ghostData->type == I_BehaviourPredatorPlayer); |
| | 1545 | |
| | 1546 | SECTION_DATA *disc = GetThisSectionData(ghostData->HModelController.section_data,"disk"); |
| | 1547 | |
| | 1548 | if (disc) |
| | 1549 | disc->flags &= ~section_data_notreal; |
| | 1550 | } |
| | 1551 | } |
| | 1552 | else |
| | 1553 | { |
| | 1554 | /* We are a dead alien with a ghost */ |
| | 1555 | RemoveGhost(sbPtr); |
| | 1556 | return; |
| | 1557 | } |
| | 1558 | |
| | 1559 | if(sbPtr && messagePtr->IAmAlive) |
| | 1560 | { |
| | 1561 | //are we currently following this player's movements |
| | 1562 | if(MultiplayerObservedPlayer) |
| | 1563 | { |
| | 1564 | if(MultiplayerObservedPlayer == senderId) |
| | 1565 | { |
| | 1566 | PlayerStatus.ViewPanX = messagePtr->Elevation; |
| | 1567 | |
| | 1568 | //don't draw the player we're observing |
| | 1569 | if(sbPtr && sbPtr->DisplayBlock) |
| | 1570 | sbPtr->DisplayBlock->ObFlags |= ObFlag_NotVis; |
| | 1571 | } |
| | 1572 | } |
| | 1573 | } |
| | 1574 | } |
| | 1575 | } |
| | 1576 | |
| | 1577 | static void ProcessNetMsg_FrameTimer(uint16_t frame_time,int senderId) |
| | 1578 | { |
| | 1579 | int senderPlayerIndex; |
| | 1580 | /* if we're not playing, ignore it */ |
| | 1581 | if(netGameData.myGameState != NGS_Playing) |
| | 1582 | return; |
| | 1583 | |
| | 1584 | senderPlayerIndex = PlayerIdInPlayerList(senderId); |
| | 1585 | |
| | 1586 | if(senderPlayerIndex == NET_IDNOTINPLAYERLIST) |
| | 1587 | return; |
| | 1588 | |
| | 1589 | netGameData.playerData[senderPlayerIndex].timer += frame_time; |
| | 1590 | } |
| | 1591 | |
| | 1592 | static void NetworkGameConsoleMessageWithWeaponIcon(const char * mesg, const char* name1, const char* name2, const char* weaponSymbol) |
| | 1593 | { |
| | 1594 | const char* string = mesg; |
| | 1595 | char* messageptr = &OnScreenMessageBuffer[0]; |
| | 1596 | |
| | 1597 | if(!string) |
| | 1598 | return; |
| | 1599 | |
| | 1600 | while(*string) |
| | 1601 | { |
| | 1602 | if(string[0] == '%') |
| | 1603 | { |
| | 1604 | if(string[1] >= '1' && string[1] <= '9') |
| | 1605 | { |
| | 1606 | if(string[1] == '1' && name1) |
| | 1607 | { |
| | 1608 | strcpy(messageptr,name1); |
| | 1609 | messageptr += strlen(name1); |
| | 1610 | } |
| | 1611 | if(string[1] == '2' && name2) |
| | 1612 | { |
| | 1613 | strcpy(messageptr,name2); |
| | 1614 | messageptr += strlen(name2); |
| | 1615 | } |
| | 1616 | |
| | 1617 | string += 2; |
| | 1618 | continue; |
| | 1619 | } |
| | 1620 | } |
| | 1621 | *messageptr++ = *string++; |
| | 1622 | } |
| | 1623 | *messageptr = 0; |
| | 1624 | |
| | 1625 | if(weaponSymbol) |
| | 1626 | strcat(OnScreenMessageBuffer, weaponSymbol); |
| | 1627 | |
| | 1628 | mission_messages = OnScreenMessageBuffer; |
| | 1629 | mission_messages_timer = timeGetTime() + strlen(mission_messages) * 80; |
| | 1630 | } |
| | 1631 | |
| | 1632 | static void Inform_PlayerHasDied(int killer, int victim, NETGAME_CHARACTERTYPE killerType, char weaponIcon) |
| | 1633 | { |
| | 1634 | int victimIndex = PlayerIdInPlayerList(victim); |
| | 1635 | |
| | 1636 | /* KJL 15:35:38 09/04/98 - not knowing who the victim is what make things a bit awkward... */ |
| | 1637 | if(victimIndex == NET_IDNOTINPLAYERLIST) |
| | 1638 | return; |
| | 1639 | |
| | 1640 | switch(killerType) |
| | 1641 | { |
| | 1642 | case NGCT_AI_Alien : |
| | 1643 | NetworkGameConsoleMessage("%1 has been killed by an Alien", netGameData.playerData[victimIndex].name, 0); |
| | 1644 | break; |
| | 1645 | case NGCT_AI_Predalien : |
| | 1646 | NetworkGameConsoleMessage("%1 has been killed by a Predalien", netGameData.playerData[victimIndex].name, 0); |
| | 1647 | break; |
| | 1648 | case NGCT_AI_Praetorian : |
| | 1649 | NetworkGameConsoleMessage("%1 has been killed by a Praetorian", netGameData.playerData[victimIndex].name, 0); |
| | 1650 | break; |
| | 1651 | default : |
| | 1652 | { |
| | 1653 | /* KJL 15:36:03 09/04/98 - killer should be set to null if it's a suicide */ |
| | 1654 | /*killer==vitim means suicide now ,as well*/ |
| | 1655 | if (killer && killer != victim) |
| | 1656 | { |
| | 1657 | int killerIndex = PlayerIdInPlayerList(killer); |
| | 1658 | |
| | 1659 | if(killerIndex != NET_IDNOTINPLAYERLIST) |
| | 1660 | { |
| | 1661 | char weaponSymbol[5] = ""; |
| | 1662 | |
| | 1663 | if(weaponIcon) |
| | 1664 | sprintf(weaponSymbol," %c",weaponIcon); |
| | 1665 | |
| | 1666 | NetworkGameConsoleMessageWithWeaponIcon("%1 has been killed by %2", netGameData.playerData[victimIndex].name,
netGameData.playerData[killerIndex].name, weaponSymbol); |
| | 1667 | } |
| | 1668 | } |
| | 1669 | else |
| | 1670 | { |
| | 1671 | NetworkGameConsoleMessage("%1 has commited suicide", netGameData.playerData[victimIndex].name, 0); |
| | 1672 | } |
| | 1673 | break; |
| | 1674 | } |
| | 1675 | } |
| | 1676 | } |
| | 1677 | |
| | 1678 | static void Handle_SpeciesTag_NewPersonIt(int predatorID) |
| | 1679 | { |
| | 1680 | /* if we're not playing, ignore it */ |
| | 1681 | if(netGameData.myGameState != NGS_Playing) |
| | 1682 | return; |
| | 1683 | |
| | 1684 | if(AVPDPNetID == predatorID) |
| | 1685 | { |
| | 1686 | //become aa predator or alien |
| | 1687 | if(netGameData.gameType == NGT_PredatorTag) |
| | 1688 | { |
| | 1689 | ChangeToPredator(); |
| | 1690 | } |
| | 1691 | else if(netGameData.gameType == NGT_AlienTag) |
| | 1692 | { |
| | 1693 | ChangeToAlien(); |
| | 1694 | } |
| | 1695 | } |
| | 1696 | |
| | 1697 | netGameData.stateCheckTimeDelay = 5*ONE_FIXED; |
| | 1698 | } |
| | 1699 | |
| | 1700 | //for messages that just require a player id |
| | 1701 | void AddNetMsg_PlayerID(int playerID, uint8_t message) |
| | 1702 | { |
| | 1703 | int headerSize = sizeof(NETMESSAGEHEADER); |
| | 1704 | int messageSize = sizeof(NETMESSAGE_PLAYERID); |
| | 1705 | |
| | 1706 | /* check there's enough room in the send buffer */ |
| | 1707 | { |
| | 1708 | int numBytesReqd = headerSize + messageSize; |
| | 1709 | int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); |
| | 1710 | |
| | 1711 | if(numBytesReqd > numBytesLeft) |
| | 1712 | { |
| | 1713 | assert(1==0); |
| | 1714 | /* don't add it */ |
| | 1715 | return; |
| | 1716 | } |
| | 1717 | } |
| | 1718 | |
| | 1719 | /* set up pointers to header and message structures */ |
| | 1720 | NETMESSAGEHEADER *headerPtr = (NETMESSAGEHEADER *)endSendBuffer; |
| | 1721 | endSendBuffer += headerSize; |
| | 1722 | NETMESSAGE_PLAYERID *messagePtr = (NETMESSAGE_PLAYERID *)endSendBuffer; |
| | 1723 | endSendBuffer += messageSize; |
| | 1724 | |
| | 1725 | /* fill out the header */ |
| | 1726 | headerPtr->type = message; |
| | 1727 | |
| | 1728 | /* Fill in message. */ |
| | 1729 | messagePtr->playerID = playerID; |
| | 1730 | } |
| | 1731 | |
| | 1732 | static int CountPlayersOfType(NETGAME_CHARACTERTYPE species) |
| | 1733 | { |
| | 1734 | int i=0; |
| | 1735 | int numPredators = 0; |
| | 1736 | |
| | 1737 | for(;i < NET_MAXPLAYERS; i++) |
| | 1738 | { |
| | 1739 | if(netGameData.playerData[i].playerId) |
| | 1740 | { |
| | 1741 | if(netGameData.playerData[i].characterType == species) |
| | 1742 | numPredators++; |
| | 1743 | } |
| | 1744 | } |
| | 1745 | |
| | 1746 | return numPredators; |
| | 1747 | } |
| | 1748 | |
| | 1749 | void AddNetMsg_SpeciesScores() |
| | 1750 | { |
| | 1751 | int headerSize = sizeof(NETMESSAGEHEADER); |
| | 1752 | int messageSize = sizeof(NETMESSAGE_SPECIESSCORES); |
| | 1753 | int i = 0; |
| | 1754 | |
| | 1755 | /* check there's enough room in the send buffer */ |
| | 1756 | { |
| | 1757 | int numBytesReqd = headerSize + messageSize; |
| | 1758 | int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); |
| | 1759 | |
| | 1760 | if(numBytesReqd > numBytesLeft) |
| | 1761 | { |
| | 1762 | assert(1==0); |
| | 1763 | /* don't add it */ |
| | 1764 | return; |
| | 1765 | } |
| | 1766 | } |
| | 1767 | |
| | 1768 | /* set up pointers to header and message structures */ |
| | 1769 | NETMESSAGEHEADER *headerPtr = (NETMESSAGEHEADER *)endSendBuffer; |
| | 1770 | endSendBuffer += headerSize; |
| | 1771 | NETMESSAGE_SPECIESSCORES *messagePtr = (NETMESSAGE_SPECIESSCORES *)endSendBuffer; |
| | 1772 | endSendBuffer += messageSize; |
| | 1773 | |
| | 1774 | /* fill out the header */ |
| | 1775 | headerPtr->type = (uint8_t)NetMT_SpeciesScores; |
| | 1776 | |
| | 1777 | /* Fill in message. */ |
| | 1778 | for(; i < 3; i++) |
| | 1779 | messagePtr->teamScores[i] = netGameData.teamScores[i]; |
| | 1780 | } |
| | 1781 | |
| | 1782 | void AddNetMsg_ScoreChange(int killerIndex,int victimIndex) |
| | 1783 | { |
| | 1784 | int headerSize = sizeof(NETMESSAGEHEADER); |
| | 1785 | int messageSize = sizeof(NETMESSAGE_SCORECHANGE); |
| | 1786 | |
| | 1787 | /* check there's enough room in the send buffer */ |
| | 1788 | { |
| | 1789 | int numBytesReqd = headerSize + messageSize; |
| | 1790 | int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); |
| | 1791 | |
| | 1792 | if(numBytesReqd > numBytesLeft) |
| | 1793 | { |
| | 1794 | assert(1==0); |
| | 1795 | /* don't add it */ |
| | 1796 | return; |
| | 1797 | } |
| | 1798 | } |
| | 1799 | |
| | 1800 | /* set up pointers to header and message structures */ |
| | 1801 | NETMESSAGEHEADER *headerPtr = (NETMESSAGEHEADER *)endSendBuffer; |
| | 1802 | endSendBuffer += headerSize; |
| | 1803 | NETMESSAGE_SCORECHANGE *messagePtr = (NETMESSAGE_SCORECHANGE *)endSendBuffer; |
| | 1804 | endSendBuffer += messageSize; |
| | 1805 | |
| | 1806 | /* fill out the header */ |
| | 1807 | headerPtr->type = (uint8_t)NetMT_ScoreChange; |
| | 1808 | |
| | 1809 | /* Fill in message. */ |
| | 1810 | messagePtr->killerIndex = (uint8_t) killerIndex; |
| | 1811 | messagePtr->victimIndex = (uint8_t) victimIndex; |
| | 1812 | |
| | 1813 | if(killerIndex == NET_MAXPLAYERS) |
| | 1814 | { |
| | 1815 | //killed by ai |
| | 1816 | messagePtr->fragCount = netGameData.playerData[victimIndex].deathsFromAI; |
| | 1817 | } |
| | 1818 | else |
| | 1819 | { |
| | 1820 | //killed by a player |
| | 1821 | messagePtr->fragCount = netGameData.playerData[killerIndex].playerFrags[victimIndex]; |
| | 1822 | messagePtr->killerScoreFor = netGameData.playerData[killerIndex].playerScore; |
| | 1823 | } |
| | 1824 | |
| | 1825 | messagePtr->victimScoreAgainst = netGameData.playerData[victimIndex].playerScoreAgainst; |
| | 1826 | } |
| | 1827 | |
| | 1828 | static int GetDynamicScoreMultiplier(int playerKilledIndex,int killerIndex) |
| | 1829 | { |
| | 1830 | int mult; |
| | 1831 | int playerCount=0; |
| | 1832 | int i = 0; |
| | 1833 | |
| | 1834 | assert(playerKilledIndex!=killerIndex); |
| | 1835 | |
| | 1836 | int scoreFor = netGameData.playerData[playerKilledIndex].playerScore; |
| | 1837 | int scoreAgainst = netGameData.playerData[playerKilledIndex].playerScoreAgainst; |
| | 1838 | |
| | 1839 | scoreFor = max(500, scoreFor+500); |
| | 1840 | scoreAgainst = max(500, scoreAgainst+500); |
| | 1841 | |
| | 1842 | //count players |
| | 1843 | for(; i < NET_MAXPLAYERS; i++) |
| | 1844 | { |
| | 1845 | if(netGameData.playerData[i].playerId == 0) |
| | 1846 | continue; |
| | 1847 | |
| | 1848 | playerCount++; |
| | 1849 | } |
| | 1850 | |
| | 1851 | //only bother if there are at least 3 players |
| | 1852 | if(playerCount < 3) |
| | 1853 | return ONE_FIXED; |
| | 1854 | |
| | 1855 | //value of player depends on comparing player's score with the number of points scored against that player |
| | 1856 | if(scoreFor > scoreAgainst) |
| | 1857 | { |
| | 1858 | int ratio = DIV_FIXED(scoreFor,scoreAgainst); |
| | 1859 | mult = DIV_FIXED(10*ratio,9*ONE_FIXED+ratio); |
| | 1860 | |
| | 1861 | if(mult < ONE_FIXED) |
| | 1862 | mult = ONE_FIXED; |
| | 1863 | } |
| | 1864 | else |
| | 1865 | { |
| | 1866 | int ratio = DIV_FIXED(scoreAgainst,scoreFor); |
| | 1867 | mult = DIV_FIXED(9*ONE_FIXED+ratio,10*ratio); |
| | 1868 | |
| | 1869 | if(mult > ONE_FIXED) |
| | 1870 | mult = ONE_FIXED; |
| | 1871 | } |
| | 1872 | |
| | 1873 | return mult; |
| | 1874 | } |
| | 1875 | |
| | 1876 | int GetNetScoreForKill(int playerKilledIndex,int killerIndex) |
| | 1877 | { |
| | 1878 | NETGAME_CHARACTERTYPE killerType = netGameData.playerData[killerIndex].characterType; |
| | 1879 | NETGAME_CHARACTERTYPE playerKilledType = netGameData.playerData[playerKilledIndex].characterType; |
| | 1880 | |
| | 1881 | int score = netGameData.baseKillValue; |
| | 1882 | |
| | 1883 | if(playerKilledIndex == killerIndex) |
| | 1884 | { |
| | 1885 | //suicide |
| | 1886 | return -netGameData.baseKillValue; |
| | 1887 | } |
| | 1888 | |
| | 1889 | switch(netGameData.gameType) |
| | 1890 | { |
| | 1891 | case NGT_PredatorTag: |
| | 1892 | { |
| | 1893 | //only the predator can score |
| | 1894 | if(killerType != NGCT_Predator) |
| | 1895 | return 0; |
| | 1896 | } |
| | 1897 | break; |
| | 1898 | case NGT_AlienTag: |
| | 1899 | { |
| | 1900 | //only the alien can score |
| | 1901 | if(killerType != NGCT_Alien) |
| | 1902 | return 0; |
| | 1903 | } |
| | 1904 | break; |
| | 1905 | case NGT_CoopDeathmatch: |
| | 1906 | { |
| | 1907 | //have we killed someone on the same team |
| | 1908 | if(killerType == playerKilledType) |
| | 1909 | return -netGameData.baseKillValue; |
| | 1910 | } |
| | 1911 | default: |
| | 1912 | break; |
| | 1913 | } |
| | 1914 | |
| | 1915 | if(netGameData.useCharacterKillValues) |
| | 1916 | score = netGameData.characterKillValues[playerKilledType]; |
| | 1917 | |
| | 1918 | if(netGameData.useDynamicScoring && score > 0) |
| | 1919 | { |
| | 1920 | int dynamicScoreMult = GetDynamicScoreMultiplier(playerKilledIndex,killerIndex); |
| | 1921 | score = MUL_FIXED(score, dynamicScoreMult); |
| | 1922 | //make sure player gets at least one point |
| | 1923 | if(score < 1) |
| | 1924 | score=1; |
| | 1925 | } |
| | 1926 | |
| | 1927 | return score; |
| | 1928 | } |
| | 1929 | |
| | 1930 | static void Handle_LastManStanding_LastMan(int marineID) |
| | 1931 | { |
| | 1932 | int i=0; |
| | 1933 | /* if we're not playing, ignore it */ |
| | 1934 | if(netGameData.myGameState != NGS_Playing) |
| | 1935 | return; |
| | 1936 | |
| | 1937 | //find the marine's name |
| | 1938 | for(; i < NET_MAXPLAYERS; i++) |
| | 1939 | { |
| | 1940 | if(netGameData.playerData[i].playerId == marineID) |
| | 1941 | NetworkGameConsoleMessage("%1 is the last man standing.", netGameData.playerData[i].name, 0); |
| | 1942 | } |
| | 1943 | } |
| | 1944 | |
| | 1945 | /* called by host only: updates the scores for a described kill, and sends a game score update message */ |
| | 1946 | static void UpdateNetworkGameScores(int playerKilledId, int killerId,NETGAME_CHARACTERTYPE playerKilledType,NETGAME_CHARACTERTYPE killerType) |
| | 1947 | { |
| | 1948 | int killerIndex; |
| | 1949 | int scoreForKill; |
| | 1950 | int i; |
| | 1951 | |
| | 1952 | if(netGameData.myGameState != NGS_Playing) |
| | 1953 | return; |
| | 1954 | |
| | 1955 | /* get the index of the player who has been killed. If they're not in |
| | 1956 | the player list, can't have been killed ! */ |
| | 1957 | int playerKilledIndex = PlayerIdInPlayerList(playerKilledId); |
| | 1958 | |
| | 1959 | if(playerKilledIndex == NET_IDNOTINPLAYERLIST) |
| | 1960 | return; |
| | 1961 | |
| | 1962 | if(killerId == 0 || killerId == playerKilledId || killerType >= NGCT_AI_Alien) |
| | 1963 | { |
| | 1964 | //suicide |
| | 1965 | killerIndex = playerKilledIndex; |
| | 1966 | } |
| | 1967 | else |
| | 1968 | { |
| | 1969 | killerIndex = PlayerIdInPlayerList(killerId); |
| | 1970 | |
| | 1971 | if(killerIndex == NET_IDNOTINPLAYERLIST) |
| | 1972 | return; |
| | 1973 | } |
| | 1974 | |
| | 1975 | if(killerType >= NGCT_AI_Alien) |
| | 1976 | { |
| | 1977 | //update deaths from AI; |
| | 1978 | netGameData.playerData[playerKilledIndex].deathsFromAI++; |
| | 1979 | } |
| | 1980 | else |
| | 1981 | { |
| | 1982 | //update frag count; |
| | 1983 | netGameData.playerData[killerIndex].playerFrags[playerKilledIndex]++; |
| | 1984 | } |
| | 1985 | |
| | 1986 | //update overall number of kills |
| | 1987 | netGameData.numDeaths[playerKilledType]++; |
| | 1988 | |
| | 1989 | if(netGameData.gameType == NGT_LastManStanding) |
| | 1990 | { |
| | 1991 | if(killerType == NGCT_Alien || killerIndex == playerKilledIndex) |
| | 1992 | { |
| | 1993 | if(playerKilledType != NGCT_Alien) |
| | 1994 | { |
| | 1995 | int marineCount = 0; |
| | 1996 | int marineIndex; |
| | 1997 | |
| | 1998 | //give a point to the alien for killing a marine |
| | 1999 | if(killerType == NGCT_Alien) |
| | 2000 | netGameData.playerData[killerIndex].playerScore += 1; |
| | 2001 | |
| | 2002 | //also give a point to every surviving marine |
| | 2003 | for(i=0; i < NET_MAXPLAYERS; i++) |
| | 2004 | { |
| | 2005 | if(i == playerKilledIndex) |
| | 2006 | continue; |
| | 2007 | |
| | 2008 | if(netGameData.playerData[i].playerId) |
| | 2009 | { |
| | 2010 | if(netGameData.playerData[i].characterType!=NGCT_Alien) |
| | 2011 | { |
| | 2012 | marineCount++; |
| | 2013 | marineIndex = i; |
| | 2014 | |
| | 2015 | netGameData.playerData[i].playerScore += 1; |
| | 2016 | AddNetMsg_ScoreChange(i, i); |
| | 2017 | } |
| | 2018 | } |
| | 2019 | } |
| | 2020 | |
| | 2021 | if(marineCount == 1) |
| | 2022 | { |
| | 2023 | //only one marine left , tell everyone |
| | 2024 | AddNetMsg_PlayerID(netGameData.playerData[marineIndex].playerId,NetMT_LastManStanding_LastMan); |
| | 2025 | Handle_LastManStanding_LastMan(netGameData.playerData[marineIndex].playerId); |
| | 2026 | } |
| | 2027 | } |
| | 2028 | } |
| | 2029 | else |
| | 2030 | { |
| | 2031 | if(playerKilledType != NGCT_Alien) |
| | 2032 | { |
| | 2033 | //lose a point for killing a marine |
| | 2034 | netGameData.playerData[killerIndex].playerScore-=1; |
| | 2035 | } |
| | 2036 | else |
| | 2037 | { |
| | 2038 | //if we're the last marine gain a point for killing an alien |
| | 2039 | for(i=0; i < NET_MAXPLAYERS; i++) |
| | 2040 | { |
| | 2041 | if(i == killerIndex) |
| | 2042 | continue; |
| | 2043 | |
| | 2044 | if(netGameData.playerData[i].playerId) |
| | 2045 | { |
| | 2046 | if(netGameData.playerData[i].characterType != NGCT_Alien) |
| | 2047 | break; |
| | 2048 | } |
| | 2049 | } |
| | 2050 | |
| | 2051 | if(i == NET_MAXPLAYERS) |
| | 2052 | netGameData.playerData[killerIndex].playerScore += 1; |
| | 2053 | } |
| | 2054 | } |
| | 2055 | } |
| | 2056 | else if(netGameData.gameType == NGT_Coop) |
| | 2057 | { |
| | 2058 | //do nothing |
| | 2059 | } |
| | 2060 | else |
| | 2061 | { |
| | 2062 | NETGAME_CHARACTERTYPE playerKilledCopy = netGameData.playerData[playerKilledIndex].characterType; |
| | 2063 | NETGAME_CHARACTERTYPE killerCopy = netGameData.playerData[killerIndex].characterType; |
| | 2064 | |
| | 2065 | //temporarily set the character types to what they were at the time of death |
| | 2066 | netGameData.playerData[playerKilledIndex].characterType = playerKilledType; |
| | 2067 | netGameData.playerData[killerIndex].characterType = killerType; |
| | 2068 | |
| | 2069 | //get score for this kill |
| | 2070 | scoreForKill = GetNetScoreForKill(playerKilledIndex,killerIndex); |
| | 2071 | |
| | 2072 | //restore character types |
| | 2073 | netGameData.playerData[playerKilledIndex].characterType = playerKilledCopy; |
| | 2074 | netGameData.playerData[killerIndex].characterType = killerCopy; |
| | 2075 | |
| | 2076 | //update score |
| | 2077 | netGameData.playerData[killerIndex].playerScore += scoreForKill; |
| | 2078 | |
| | 2079 | if(scoreForKill > 0) |
| | 2080 | { |
| | 2081 | //note score against person being killed |
| | 2082 | netGameData.playerData[playerKilledIndex].playerScoreAgainst += scoreForKill; |
| | 2083 | } |
| | 2084 | else |
| | 2085 | { |
| | 2086 | netGameData.playerData[killerIndex].playerScoreAgainst += scoreForKill; |
| | 2087 | } |
| | 2088 | |
| | 2089 | if(netGameData.gameType == NGT_CoopDeathmatch) |
| | 2090 | { |
| | 2091 | //need to adjust the species scores as well |
| | 2092 | netGameData.teamScores[killerType] += scoreForKill; |
| | 2093 | AddNetMsg_SpeciesScores(); |
| | 2094 | } |
| | 2095 | } |
| | 2096 | |
| | 2097 | if(killerType >= NGCT_AI_Alien) |
| | 2098 | { |
| | 2099 | //killed by alien ai |
| | 2100 | AddNetMsg_ScoreChange(NET_MAXPLAYERS,playerKilledIndex); |
| | 2101 | } |
| | 2102 | else |
| | 2103 | { |
| | 2104 | AddNetMsg_ScoreChange(killerIndex,playerKilledIndex); |
| | 2105 | } |
| | 2106 | |
| | 2107 | //AddNetMsg_PlayerScores(killerIndex); |
| | 2108 | |
| | 2109 | if(netGameData.gameType == NGT_PredatorTag || netGameData.gameType == NGT_AlienTag) |
| | 2110 | { |
| | 2111 | NETGAME_CHARACTERTYPE tagSpecies = NGCT_Predator; |
| | 2112 | |
| | 2113 | if(netGameData.gameType == NGT_AlienTag) |
| | 2114 | tagSpecies = NGCT_Alien; |
| | 2115 | |
| | 2116 | //was the predator killed? |
| | 2117 | if(playerKilledType == tagSpecies) |
| | 2118 | { |
| | 2119 | if(CountPlayersOfType(tagSpecies) == 1) |
| | 2120 | { |
| | 2121 | //select new predator |
| | 2122 | //if it wasn't suicide , choose killer |
| | 2123 | if(playerKilledIndex != killerIndex) |
| | 2124 | { |
| | 2125 | AddNetMsg_PlayerID(killerId,NetMT_PredatorTag_NewPredator); |
| | 2126 | Handle_SpeciesTag_NewPersonIt(killerId); |
| | 2127 | } |
| | 2128 | else |
| | 2129 | { |
| | 2130 | //choose next player |
| | 2131 | for(i = playerKilledIndex+1; ;i++) |
| | 2132 | { |
| | 2133 | i = i%NET_MAXPLAYERS; |
| | 2134 | |
| | 2135 | if(netGameData.playerData[i].playerId) |
| | 2136 | { |
| | 2137 | /* |
| | 2138 | don't choose player if he was the previous predator |
| | 2139 | (In fact this should only happen if someone is silly enough to player single player |
| | 2140 | predator tag). |
| | 2141 | */ |
| | 2142 | if(i != playerKilledIndex) |
| | 2143 | { |
| | 2144 | AddNetMsg_PlayerID(netGameData.playerData[i].playerId,NetMT_PredatorTag_NewPredator); |
| | 2145 | Handle_SpeciesTag_NewPersonIt(netGameData.playerData[i].playerId); |
| | 2146 | } |
| | 2147 | break; |
| | 2148 | } |
| | 2149 | } |
| | 2150 | } |
| | 2151 | } |
| | 2152 | } |
| | 2153 | } |
| | 2154 | } |
| | 2155 | |
| | 2156 | static void ProcessNetMsg_PlayerKilled(NETMESSAGE_PLAYERKILLED *messagePtr, int senderId) |
| | 2157 | { |
| | 2158 | /* if we're not playing, ignore it */ |
| | 2159 | if(netGameData.myGameState != NGS_Playing) |
| | 2160 | return; |
| | 2161 | |
| | 2162 | /* if this player is not in the play list, messages are probably out of order, |
| | 2163 | so just ignore it... */ |
| | 2164 | int senderPlayerIndex = PlayerIdInPlayerList(senderId); |
| | 2165 | |
| | 2166 | if(senderPlayerIndex == NET_IDNOTINPLAYERLIST) |
| | 2167 | return; |
| | 2168 | |
| | 2169 | /* find the ghost for this player */ |
| | 2170 | STRATEGYBLOCK *sbPtr = FindGhost(senderId, GHOST_PLAYEROBJECTID); |
| | 2171 | |
| | 2172 | if(!sbPtr) |
| | 2173 | { |
| | 2174 | /* we don't have a ghost for this player, which is odd, and implies that messages |
| | 2175 | have got dis-ordered... best just ignore it then */ |
| | 2176 | return; |
| | 2177 | } |
| | 2178 | |
| | 2179 | /* we have a ghost for this player: remove it if it's an alien */ |
| | 2180 | // if(netGameData.playerData[senderPlayerIndex].characterType==NGCT_Alien) |
| | 2181 | |
| | 2182 | //RemoveGhost(sbPtr); |
| | 2183 | KillGhost(sbPtr,messagePtr->objectId); |
| | 2184 | |
| | 2185 | Inform_PlayerHasDied(messagePtr->killerId, senderId,messagePtr->killerType,messagePtr->weaponIcon); |
| | 2186 | |
| | 2187 | /* now attempt to update the scores */ |
| | 2188 | if(NetworkHost == AvP.PlayMode) |
| | 2189 | UpdateNetworkGameScores(senderId, messagePtr->killerId,messagePtr->myType,messagePtr->killerType); |
| | 2190 | |
| | 2191 | /* do some sound... */ |
| | 2192 | assert(sbPtr->DynPtr); |
| | 2193 | |
| | 2194 | switch(netGameData.playerData[senderPlayerIndex].characterType) |
| | 2195 | { |
| | 2196 | case NGCT_Alien: |
| | 2197 | PlayAlienSound(0, ASC_Scream_Dying, 0, NULL, &sbPtr->DynPtr->Position); |
| | 2198 | break; |
| | 2199 | case NGCT_Marine: |
| | 2200 | PlayMarineScream(0, MSC_Death, 0, NULL, &sbPtr->DynPtr->Position); |
| | 2201 | break; |
| | 2202 | case NGCT_Predator: |
| | 2203 | PlayPredatorSound(0, PSC_Scream_Dying, 0, NULL, &sbPtr->DynPtr->Position); |
| | 2204 | break; |
| | 2205 | default: |
| | 2206 | { |
| | 2207 | assert(1==0); |
| | 2208 | break; |
| | 2209 | } |
| | 2210 | } |
| | 2211 | } |
| | 2212 | |
| | 2213 | /* Finds the local strategy block who's network object id is that passed */ |
| | 2214 | static STRATEGYBLOCK *FindObjectFromNetIndex(int obIndex) |
| | 2215 | { |
| | 2216 | int sbIndex = 0; |
| | 2217 | /* first of all, check for index "GHOST_PLAYEROBJECTID": that's the player */ |
| | 2218 | |
| | 2219 | if(obIndex == GHOST_PLAYEROBJECTID) |
| | 2220 | return PlayerStatus.sbptr; |
| | 2221 | |
| | 2222 | while(sbIndex < NumActiveStBlocks) |
| | 2223 | { |
| | 2224 | STRATEGYBLOCK *sbPtr = ActiveStBlockList[sbIndex++]; |
| | 2225 | /* need to be careful here: netIndexes maybe the same as pre-assigned names |
| | 2226 | for global objects, therefore we must check the type of the object */ |
| | 2227 | |
| | 2228 | switch(sbPtr->type) |
| | 2229 | { |
| | 2230 | case I_BehaviourRocket: |
| | 2231 | case I_BehaviourGrenade: |
| | 2232 | case I_BehaviourPulseGrenade: |
| | 2233 | case I_BehaviourFragmentationGrenade: |
| | 2234 | case I_BehaviourFlare: |
| | 2235 | case I_BehaviourPredatorEnergyBolt: |
| | 2236 | case I_BehaviourFrisbeeEnergyBolt: |
| | 2237 | case I_BehaviourPPPlasmaBolt: |
| | 2238 | case I_BehaviourSpeargunBolt: |
| | 2239 | case I_BehaviourPredatorDisc_SeekTrack: |
| | 2240 | case I_BehaviourAutoGun: |
| | 2241 | case I_BehaviourAlien: |
| | 2242 | case I_BehaviourCorpse: |
| | 2243 | case I_BehaviourInanimateObject: |
| | 2244 | case I_BehaviourProximityGrenade: |
| | 2245 | { |
| | 2246 | int *sbIdPtr = (int *)(&(sbPtr->SBname[4])); |
| | 2247 | |
| | 2248 | if(*sbIdPtr == obIndex) |
| | 2249 | return sbPtr; |
| | 2250 | } |
| | 2251 | default: |
| | 2252 | break; |
| | 2253 | } |
| | 2254 | } |
| | 2255 | |
| | 2256 | return NULL; |
| | 2257 | } |
| | 2258 | |
| | 2259 | static void ProcessNetMsg_LocalObjectDamaged(char *messagePtr, int senderId) |
| | 2260 | { |
| | 2261 | NETMESSAGE_LOBDAMAGED_HEADER *messageHeader=0; |
| | 2262 | NETMESSAGE_DAMAGE_PROFILE *messageProfile=0; |
| | 2263 | NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0; |
| | 2264 | NETMESSAGE_DAMAGE_SECTION *messageSection=0; |
| | 2265 | NETMESSAGE_DAMAGE_DELTA *messageDelta=0; |
| | 2266 | NETMESSAGE_DAMAGE_DIRECTION *messageDirection=0; |
| | 2267 | |
| | 2268 | if(netGameData.myGameState != NGS_Playing) |
| | 2269 | return; |
| | 2270 | |
| | 2271 | messageHeader = (NETMESSAGE_LOBDAMAGED_HEADER*) messagePtr; |
| | 2272 | messagePtr += sizeof(NETMESSAGE_LOBDAMAGED_HEADER); |
| | 2273 | |
| | 2274 | //find out which elements of the damage message have been sent |
| | 2275 | if(messageHeader->damageProfile) |
| | 2276 | { |
| | 2277 | messageProfile = (NETMESSAGE_DAMAGE_PROFILE*) messagePtr; |
| | 2278 | messagePtr += sizeof(NETMESSAGE_DAMAGE_PROFILE); |
| | 2279 | } |
| | 2280 | |
| | 2281 | if(messageHeader->multiple) |
| | 2282 | { |
| | 2283 | messageMultiple = (NETMESSAGE_DAMAGE_MULTIPLE*) messagePtr; |
| | 2284 | messagePtr += sizeof(NETMESSAGE_DAMAGE_MULTIPLE); |
| | 2285 | } |
| | 2286 | |
| | 2287 | if(messageHeader->sectionID) |
| | 2288 | { |
| | 2289 | messageSection = (NETMESSAGE_DAMAGE_SECTION*) messagePtr; |
| | 2290 | messagePtr += sizeof(NETMESSAGE_DAMAGE_SECTION); |
| | 2291 | } |
| | 2292 | |
| | 2293 | if(messageHeader->delta_seq) |
| | 2294 | { |
| | 2295 | messageDelta = (NETMESSAGE_DAMAGE_DELTA*) messagePtr; |
| | 2296 | messagePtr += sizeof(NETMESSAGE_DAMAGE_DELTA); |
| | 2297 | } |
| | 2298 | |
| | 2299 | if(messageHeader->direction) |
| | 2300 | { |
| | 2301 | messageDirection = (NETMESSAGE_DAMAGE_DIRECTION*) messagePtr; |
| | 2302 | messagePtr += sizeof(NETMESSAGE_DAMAGE_DIRECTION); |
| | 2303 | } |
| | 2304 | |
| | 2305 | /* This message is for the player who owns the object, so first check |
| | 2306 | if the message is meant for us */ |
| | 2307 | if(messageHeader->playerId != AVPDPNetID) |
| | 2308 | { |
| | 2309 | //however we may need to play a delta sequence on the ghost |
| | 2310 | if(messageDelta) |
| | 2311 | { |
| | 2312 | if(messageDelta->Delta_Sequence > 0 && messageDelta->Delta_Sub_Sequence > 0) |
| | 2313 | { |
| | 2314 | STRATEGYBLOCK *sbPtr = FindGhost(messageHeader->playerId,(int)messageHeader->objectId); |
| | 2315 | |
| | 2316 | if(sbPtr) |
| | 2317 | PlayHitDeltaOnGhost(sbPtr,messageDelta->Delta_Sequence,messageDelta->Delta_Sub_Sequence); |
| | 2318 | } |
| | 2319 | } |
| | 2320 | return; |
| | 2321 | } |
| | 2322 | |
| | 2323 | /* next we have to find this object in our strategyblock list */ |
| | 2324 | { |
| | 2325 | int multiple = ONE_FIXED; |
| | 2326 | |
| | 2327 | int objectId = (int)messageHeader->objectId; |
| | 2328 | STRATEGYBLOCK *sbPtr = FindObjectFromNetIndex(objectId); |
| | 2329 | |
| | 2330 | /* we set this global to remember the id of the player who sent this damage message, |
| | 2331 | so that if the player is killed, we know the id of the killer. this is a bit of |
| | 2332 | a nasty hack, but means that we don't have to make any changes to the core damage functions */ |
| | 2333 | assert(myNetworkKillerId == NULL || myNetworkKillerId == AVPDPNetID); |
| | 2334 | /* |
| | 2335 | Don't bother setting the killer id for molotov damage. This is because the only source of this damage |
| | 2336 | is explosions from flamethrowers. This damage will always come from the net host , and we don't want to credit the |
| | 2337 | host for all kills caused by this damage. |
| | 2338 | |
| | 2339 | Similarly all things that cause falling damage should count as suicide (in particular platform lifts) |
| | 2340 | */ |
| | 2341 | //if(messageHeader->ammo_id != AMMO_MOLOTOV && messageHeader->ammo_id != AMMO_FALLINGDAMAGE) myNetworkKillerId = senderId; |
| | 2342 | |
| | 2343 | /* check if we have found an sb: if not the object has probably been |
| | 2344 | destroyed already, so just ignore it */ |
| | 2345 | |
| | 2346 | if(sbPtr) |
| | 2347 | { |
| | 2348 | DAMAGE_PROFILE damage; |
| | 2349 | //fill out damage profile |
| | 2350 | damage.Id = messageHeader->ammo_id; |
| | 2351 | if(messageProfile) |
| | 2352 | { |
| | 2353 | damage.Impact = messageProfile->Impact; |
| | 2354 | damage.Cutting = messageProfile->Cutting; |
| | 2355 | damage.Penetrative = messageProfile->Penetrative; |
| | 2356 | damage.Fire = messageProfile->Fire; |
| | 2357 | damage.Electrical = messageProfile->Electrical; |
| | 2358 | damage.Acid = messageProfile->Acid; |
| | 2359 | |
| | 2360 | damage.ExplosivePower = messageProfile->ExplosivePower; |
| | 2361 | damage.Slicing = messageProfile->Slicing; |
| | 2362 | damage.ForceBoom = messageProfile->ForceBoom; |
| | 2363 | |
| | 2364 | damage.BlowUpSections = messageProfile->BlowUpSections; |
| | 2365 | damage.MakeExitWounds = messageProfile->MakeExitWounds; |
| | 2366 | } |
| | 2367 | else |
| | 2368 | { |
| | 2369 | if(damage.Id == AMMO_FLECHETTE) |
| | 2370 | { |
| | 2371 | damage = damage_profiles[FLECHETTEDAMAGE]; |
| | 2372 | } |
| | 2373 | else |
| | 2374 | { |
| | 2375 | assert(damage.Id > AMMO_NONE && damage.Id < MAX_NO_OF_AMMO_TEMPLATES); |
| | 2376 | damage = TemplateAmmo[damage.Id].MaxDamage; |
| | 2377 | } |
| | 2378 | } |
| | 2379 | |
| | 2380 | if(messageMultiple) |
| | 2381 | multiple = messageMultiple->multiple; |
| | 2382 | |
| | 2383 | SECTION_DATA *section_data = NULL; |
| | 2384 | HMODELCONTROLLER *controller = NULL; |
| | 2385 | VECTORCH direction; |
| | 2386 | VECTORCH incoming; |
| | 2387 | VECTORCH* incoming_ptr = 0; |
| | 2388 | |
| | 2389 | //get the direction vector if there is one |
| | 2390 | if(sbPtr->DynPtr && messageDirection) |
| | 2391 | { |
| | 2392 | if(messageDirection->direction_x || messageDirection->direction_y || messageDirection->direction_z) |
| | 2393 | { |
| | 2394 | MATRIXCH mat = sbPtr->DynPtr->OrientMat; |
| | 2395 | TransposeMatrixCH(&mat); |
| | 2396 | |
| | 2397 | //extract the direction vector |
| | 2398 | incoming.vx = messageDirection->direction_x; |
| | 2399 | incoming.vy = messageDirection->direction_y; |
| | 2400 | incoming.vz = messageDirection->direction_z; |
| | 2401 | //normalise it |
| | 2402 | Normalise(&incoming); |
| | 2403 | direction = incoming; |
| | 2404 | |
| | 2405 | //and rotate it from world space to the object's local space |
| | 2406 | RotateVector(&incoming,&mat); |
| | 2407 | |
| | 2408 | //set the incoming pointer |
| | 2409 | incoming_ptr = &incoming; |
| | 2410 | } |
| | 2411 | } |
| | 2412 | /*Record the id of the hit body part in a global variable. |
| | 2413 | This way , if this blow kill the player , we know which body part has been hit*/ |
| | 2414 | |
| | 2415 | if(messageSection) |
| | 2416 | MyHitBodyPartId = messageSection->SectionID; |
| | 2417 | else |
| | 2418 | MyHitBodyPartId = -1; |
| | 2419 | |
| | 2420 | if (messageSection && messageSection->SectionID != -1) |
| | 2421 | { |
| | 2422 | /* Hmm. */ |
| | 2423 | if (sbPtr->type == I_BehaviourAlien) |
| | 2424 | { |
| | 2425 | /* Only allowed for aliens, right now. */ |
| | 2426 | ALIEN_STATUS_BLOCK *alienStatusPtr = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2427 | |
| | 2428 | assert(alienStatusPtr); |
| | 2429 | |
| | 2430 | controller = &alienStatusPtr->HModelController; |
| | 2431 | section_data = GetThisSectionData_FromID(alienStatusPtr->HModelController.section_data, (int)messageSection->SectionID); |
| | 2432 | } |
| | 2433 | else if (sbPtr->type == I_BehaviourCorpse) |
| | 2434 | { |
| | 2435 | CORPSEDATABLOCK *corpseData = (CORPSEDATABLOCK *)sbPtr->dataptr; |
| | 2436 | |
| | 2437 | assert(corpseData); |
| | 2438 | |
| | 2439 | controller = &corpseData->HModelController; |
| | 2440 | section_data = GetThisSectionData_FromID(corpseData->HModelController.section_data, (int)messageSection->SectionID); |
| | 2441 | } |
| | 2442 | } |
| | 2443 | |
| | 2444 | if (section_data) |
| | 2445 | { |
| | 2446 | DISPLAYBLOCK *fragged_section = CauseDamageToHModel(controller,sbPtr,(&damage), multiple,section_data,incoming_ptr,NULL,0); |
| | 2447 | |
| | 2448 | if(fragged_section && damage.Id == AMMO_PRED_RIFLE && incoming_ptr) |
| | 2449 | { |
| | 2450 | //a speargun has fragged off a body part , so we need to create a spear |
| | 2451 | CreateSpearPossiblyWithFragment(fragged_section, &fragged_section->ObWorld,&direction); |
| | 2452 | } |
| | 2453 | } |
| | 2454 | else |
| | 2455 | { |
| | 2456 | CauseDamageToObject(sbPtr, (&damage), multiple,incoming_ptr); |
| | 2457 | } |
| | 2458 | } |
| | 2459 | myNetworkKillerId = AVPDPNetID; |
| | 2460 | MyHitBodyPartId = -1; |
| | 2461 | } |
| | 2462 | } |
| | 2463 | |
| | 2464 | static int GetSizeOfLocalObjectDamagedMessage(char *messagePtr) |
| | 2465 | { |
| | 2466 | int size = sizeof(NETMESSAGE_LOBDAMAGED_HEADER); |
| | 2467 | |
| | 2468 | NETMESSAGE_LOBDAMAGED_HEADER *messageHeader = (NETMESSAGE_LOBDAMAGED_HEADER*) messagePtr; |
| | 2469 | |
| | 2470 | if(messageHeader->damageProfile) |
| | 2471 | size += sizeof(NETMESSAGE_DAMAGE_PROFILE); |
| | 2472 | |
| | 2473 | if(messageHeader->multiple) |
| | 2474 | size += sizeof(NETMESSAGE_DAMAGE_MULTIPLE); |
| | 2475 | |
| | 2476 | if(messageHeader->sectionID) |
| | 2477 | size += sizeof(NETMESSAGE_DAMAGE_SECTION); |
| | 2478 | |
| | 2479 | if(messageHeader->delta_seq) |
| | 2480 | size += sizeof(NETMESSAGE_DAMAGE_DELTA); |
| | 2481 | |
| | 2482 | if(messageHeader->direction) |
| | 2483 | size += sizeof(NETMESSAGE_DAMAGE_DIRECTION); |
| | 2484 | |
| | 2485 | return size; |
| | 2486 | } |
| | 2487 | |
| | 2488 | static void ProcessNetMsg_LocalObjectDestroyed(NETMESSAGE_LOBDESTROYED *messagePtr, int senderId) |
| | 2489 | { |
| | 2490 | /* only do this if we're playing */ |
| | 2491 | if(netGameData.myGameState != NGS_Playing) |
| | 2492 | return; |
| | 2493 | |
| | 2494 | /* this message is a cue to destroy a ghost... except for the player which has |
| | 2495 | a seperate 'playerkilled' message... */ |
| | 2496 | |
| | 2497 | /* start by finding the ghost for this object */ |
| | 2498 | int objectId = (int)messagePtr->objectId; |
| | 2499 | STRATEGYBLOCK *sbPtr = FindGhost(senderId, objectId); |
| | 2500 | |
| | 2501 | if(!sbPtr) |
| | 2502 | { |
| | 2503 | /* if we haven't got a ghost for this object things have gone wrong: eg, we haven't |
| | 2504 | yet received the object creation message. Just ignore it then... */ |
| | 2505 | return; |
| | 2506 | } |
| | 2507 | |
| | 2508 | RemoveGhost(sbPtr); |
| | 2509 | } |
| | 2510 | |
| | 2511 | static void ProcessNetMsg_LocalObjectDestroyed_Request(NETMESSAGE_LOBDESTROYED_REQUEST *messagePtr, int senderId) |
| | 2512 | { |
| | 2513 | /* only do this if we're playing */ |
| | 2514 | if(netGameData.myGameState != NGS_Playing) |
| | 2515 | return; |
| | 2516 | |
| | 2517 | /* This message is for the player who owns the object, so first check |
| | 2518 | if the message is meant for us */ |
| | 2519 | |
| | 2520 | if(messagePtr->playerId == AVPDPNetID) |
| | 2521 | { |
| | 2522 | /* next we have to find this object in our strategyblock list */ |
| | 2523 | int objectId = (int)messagePtr->objectId; |
| | 2524 | STRATEGYBLOCK *sbPtr = FindObjectFromNetIndex(objectId); |
| | 2525 | |
| | 2526 | /* check if we have found an sb: if not the object has probably been |
| | 2527 | destroyed already, so just ignore it */ |
| | 2528 | |
| | 2529 | if(sbPtr) |
| | 2530 | { |
| | 2531 | /* Er... deal with it, okay? */ |
| | 2532 | if (sbPtr->type == I_BehaviourInanimateObject) |
| | 2533 | RemovePickedUpObject(sbPtr); |
| | 2534 | #if DEBUG |
| | 2535 | else |
| | 2536 | { |
| | 2537 | assert(0); |
| | 2538 | } |
| | 2539 | #endif |
| | 2540 | } |
| | 2541 | } |
| | 2542 | } |
| | 2543 | |
| | 2544 | static void ProcessNetMsg_ScoreChange(NETMESSAGE_SCORECHANGE *messagePtr) |
| | 2545 | { |
| | 2546 | /* should only get this if we're not the host */ |
| | 2547 | if(NetworkPeer != AvP.PlayMode) |
| | 2548 | { |
| | 2549 | //Vaguely possible that a host could receive a message that is only intended for peers |
| | 2550 | //if this computer has only just become the host. |
| | 2551 | assert(NetworkHost == AvP.PlayMode); |
| | 2552 | return; |
| | 2553 | } |
| | 2554 | |
| | 2555 | /* only do this if we're playing */ |
| | 2556 | if(netGameData.myGameState != NGS_Playing) |
| | 2557 | return; |
| | 2558 | |
| | 2559 | if(messagePtr->killerIndex == NET_MAXPLAYERS) |
| | 2560 | { |
| | 2561 | //killed by ai |
| | 2562 | netGameData.playerData[messagePtr->victimIndex].deathsFromAI=messagePtr->fragCount; |
| | 2563 | } |
| | 2564 | else |
| | 2565 | { |
| | 2566 | netGameData.playerData[messagePtr->killerIndex].playerFrags[messagePtr->victimIndex]=messagePtr->fragCount; |
| | 2567 | netGameData.playerData[messagePtr->killerIndex].playerScore=messagePtr->killerScoreFor; |
| | 2568 | } |
| | 2569 | |
| | 2570 | netGameData.playerData[messagePtr->victimIndex].playerScoreAgainst=messagePtr->victimScoreAgainst; |
| | 2571 | } |
| | 2572 | |
| | 2573 | STRATEGYBLOCK* CreateMultiplayerWeaponPickup(VECTORCH* location, int type, char* name) |
| | 2574 | { |
| | 2575 | TOOLS_DATA_INANIMATEOBJECT toolsdata; |
| | 2576 | |
| | 2577 | //fill out a tools template , and use the normal inanimate object creation function |
| | 2578 | toolsdata.position = *location; |
| | 2579 | toolsdata.orientation.EulerX = toolsdata.orientation.EulerY = toolsdata.orientation.EulerZ = 0; |
| | 2580 | |
| | 2581 | toolsdata.typeId = IOT_Weapon; |
| | 2582 | toolsdata.subType = type; |
| | 2583 | toolsdata.mass = 5; |
| | 2584 | toolsdata.integrity = 2; |
| | 2585 | toolsdata.triggering_event = 0; |
| | 2586 | toolsdata.explosionType = 0; |
| | 2587 | int shapeIndex; |
| | 2588 | |
| | 2589 | switch(type) |
| | 2590 | { |
| | 2591 | case WEAPON_PULSERIFLE: |
| | 2592 | shapeIndex = GetLoadedShapeMSL("pulse"); |
| | 2593 | break; |
| | 2594 | case WEAPON_SMARTGUN: |
| | 2595 | shapeIndex = GetLoadedShapeMSL("smart"); |
| | 2596 | break; |
| | 2597 | case WEAPON_FLAMETHROWER: |
| | 2598 | shapeIndex = GetLoadedShapeMSL("flame"); |
| | 2599 | break; |
| | 2600 | case WEAPON_FRISBEE_LAUNCHER: |
| | 2601 | shapeIndex = GetLoadedShapeMSL("Skeeter"); |
| | 2602 | toolsdata.orientation.EulerZ = 1024; |
| | 2603 | break; |
| | 2604 | case WEAPON_SADAR: |
| | 2605 | shapeIndex = GetLoadedShapeMSL("sadar"); |
| | 2606 | break; |
| | 2607 | case WEAPON_GRENADELAUNCHER: |
| | 2608 | shapeIndex = GetLoadedShapeMSL("grenade"); |
| | 2609 | break; |
| | 2610 | case WEAPON_MINIGUN: |
| | 2611 | shapeIndex = GetLoadedShapeMSL("minigun"); |
| | 2612 | break; |
| | 2613 | case WEAPON_MARINE_PISTOL: |
| | 2614 | shapeIndex = GetLoadedShapeMSL("Pistol"); |
| | 2615 | default: |
| | 2616 | return NULL; |
| | 2617 | } |
| | 2618 | |
| | 2619 | //adjust the weapon , so it isn't stuck through the floor |
| | 2620 | toolsdata.position.vy -= mainshapelist[shapeIndex]->shapemaxy; |
| | 2621 | |
| | 2622 | STRATEGYBLOCK * sbPtr = CreateActiveStrategyBlock(I_BehaviourInanimateObject); |
| | 2623 | |
| | 2624 | if(!sbPtr) |
| | 2625 | return NULL; |
| | 2626 | |
| | 2627 | sbPtr->shapeIndex = shapeIndex; |
| | 2628 | |
| | 2629 | EnableBehaviourType(sbPtr, &toolsdata); |
| | 2630 | |
| | 2631 | if(!sbPtr->dataptr) |
| | 2632 | return NULL; |
| | 2633 | |
| | 2634 | if(!name) |
| | 2635 | { |
| | 2636 | AssignNewSBName(sbPtr); |
| | 2637 | AddNetMsg_CreateWeapon(&sbPtr->SBname[0], type, location); |
| | 2638 | } |
| | 2639 | else |
| | 2640 | { |
| | 2641 | COPY_NAME(sbPtr->SBname, name); |
| | 2642 | } |
| | 2643 | |
| | 2644 | INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = (INANIMATEOBJECT_STATUSBLOCK*)sbPtr->dataptr; |
| | 2645 | objectstatusptr->lifespanTimer = 30 * ONE_FIXED; |
| | 2646 | |
| | 2647 | sbPtr->DynPtr->GravityOn = 1; |
| | 2648 | |
| | 2649 | return sbPtr; |
| | 2650 | } |
| | 2651 | |
| | 2652 | static void ProcessNetMsg_CreateWeapon(NETMESSAGE_CREATEWEAPON * messagePtr) |
| | 2653 | { |
| | 2654 | /* if we're not playing, ignore it */ |
| | 2655 | if(netGameData.myGameState != NGS_Playing) |
| | 2656 | return; |
| | 2657 | |
| | 2658 | //create the weapon |
| | 2659 | CreateMultiplayerWeaponPickup(&messagePtr->location, messagePtr->type, &messagePtr->name[0]); |
| | 2660 | } |
| | 2661 | |
| | 2662 | static void ProcessNetMsg_Gibbing(NETMESSAGE_GIBBING *messagePtr,int senderId) |
| | 2663 | { |
| | 2664 | /* only do this if we're playing */ |
| | 2665 | if(netGameData.myGameState != NGS_Playing) |
| | 2666 | return; |
| | 2667 | |
| | 2668 | /* get the object id from the message */ |
| | 2669 | int objectId = (int)messagePtr->Guid; |
| | 2670 | STRATEGYBLOCK *sbPtr = FindGhost(senderId, objectId); |
| | 2671 | |
| | 2672 | if(sbPtr) |
| | 2673 | { |
| | 2674 | NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->dataptr; |
| | 2675 | |
| | 2676 | //only interested in gibbing corpses |
| | 2677 | if(ghostData->type != I_BehaviourCorpse) |
| | 2678 | return; |
| | 2679 | |
| | 2680 | //use the random number seed |
| | 2681 | SetSeededFastRandom(messagePtr->seed); |
| | 2682 | //now do the gibbing |
| | 2683 | |
| | 2684 | //if (messagePtr->gibbFactor > 0) Extreme_Gibbing(sbPtr,ghostData->HModelController.section_data,messagePtr->gibbFactor); // jadda |
| | 2685 | } |
| | 2686 | } |
| | 2687 | |
| | 2688 | static void ProcessNetMsg_PlayerDeathAnim(NETMESSAGE_CORPSEDEATHANIM *messagePtr,int senderId) |
| | 2689 | { |
| | 2690 | /* if we're not playing, ignore it */ |
| | 2691 | if(netGameData.myGameState != NGS_Playing) |
| | 2692 | return; |
| | 2693 | |
| | 2694 | /* find the ghost for this player */ |
| | 2695 | STRATEGYBLOCK *sbPtr = FindGhost(senderId, messagePtr->objectId); |
| | 2696 | |
| | 2697 | if(!sbPtr) |
| | 2698 | { |
| | 2699 | /* we don't have a ghost for this player, which is odd, and implies that messages |
| | 2700 | have got dis-ordered... best just ignore it then */ |
| | 2701 | return; |
| | 2702 | } |
| | 2703 | |
| | 2704 | //set the death animation for this player |
| | 2705 | ApplyGhostCorpseDeathAnim(sbPtr,messagePtr->deathId); |
| | 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 | PlayAlienSound((int)messagePtr->alienType,(int)messagePtr->soundCategory,messagePtr->pitch,NULL,&position); |
| | 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 | } |