QUEUE.CPP (178697B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /* $Header: F:\projects\c&c0\vcs\code\queue.cpv 2.24 11 Oct 1995 13:47:40 JOE_BOSTIC $ */ 17 /*************************************************************************** 18 * * 19 * Project Name : Command & Conquer * 20 * * 21 * File Name : QUEUE.CPP * 22 * * 23 * Programmer : Bill R. Randolph * 24 * * 25 * Start Date : 11/28/95 * 26 * * 27 * Last Update : November 28, 1995 [BRR] * 28 * * 29 *-------------------------------------------------------------------------* 30 * Functions for Queueing Events: * 31 * Queue_Mission -- Queue a mega mission event. * 32 * Queue_Options -- Queue the options event. * 33 * Queue_Exit -- Add the exit game event to the queue. * 34 * * 35 * Functions for processing Queued Events: * 36 * Queue_AI -- Process all queued events. * 37 * Queue_AI_Normal -- Process all queued events. * 38 * Queue_AI_Multiplayer -- Process all queued events. * 39 * * 40 * Main Multiplayer Queue Logic: * 41 * Wait_For_Players -- Waits for other systems to come on-line * 42 * Generate_Timing_Event -- computes & queues a RESPONSE_TIME event * 43 * Process_Send_Period -- timing for sending packets every 'n' frames * 44 * Send_Packets -- sends out events from the OutList * 45 * Send_FrameSync -- Sends a FRAMESYNC packet * 46 * Process_Receive_Packet -- processes an incoming packet * 47 * Process_Serial_Packet -- Handles an incoming serial packet * 48 * Can_Advance -- determines if it's OK to advance to the next frame * 49 * Process_Reconnect_Dialog -- processes the reconnection dialog * 50 * Handle_Timeout -- attempts to reconnect; if fails, bails. * 51 * Stop_Game -- stops the game * 52 * * 53 * Packet Compression / Decompression: * 54 * Build_Send_Packet -- Builds a big packet from a bunch of little ones. * 55 * Add_Uncompressed_Events -- adds uncompressed events to a packet * 56 * Add_Compressed_Events -- adds compressed events to a packet * 57 * Breakup_Receive_Packet -- Splits a big packet into little ones. * 58 * Extract_Uncompressed_Events -- extracts events from a packet * 59 * Extract_Compressed_Events -- extracts events from a packet * 60 * * 61 * DoList Management: * 62 * Execute_DoList -- Executes commands from the DoList * 63 * Clean_DoList -- Cleans out old events from the DoList * 64 * Queue_Record -- Records the DoList to disk * 65 * Queue_Playback -- plays back queue entries from a record file * 66 * * 67 * Debugging: * 68 * Compute_Game_CRC -- Computes a CRC value of the entire game. * 69 * Add_CRC -- Adds a value to a CRC * 70 * Print_CRCs -- Prints a data file for finding Sync Bugs * 71 * Init_Queue_Mono -- inits mono display * 72 * Update_Queue_Mono -- updates mono display * 73 * Print_Framesync_Values -- displays frame-sync variables * 74 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 75 #include "function.h" 76 #include "tcpip.h" 77 78 /********************************** Defines *********************************/ 79 #define SHOW_MONO 1 80 81 int tmp_flag = 0; 82 83 /********************************** Globals *********************************/ 84 //--------------------------------------------------------------------------- 85 // GameCRC is the current computed CRC value for this frame. 86 // CRC[] is a record of our last 32 game CRC's. 87 // ColorNames is for debug output in Print_CRCs 88 //--------------------------------------------------------------------------- 89 #ifndef DEMO 90 static unsigned long GameCRC; 91 static unsigned long CRC[32] = 92 {0,0,0,0,0,0,0,0,0,0, 93 0,0,0,0,0,0,0,0,0,0, 94 0,0,0,0,0,0,0,0,0,0, 95 0,0}; 96 97 static char *ColorNames[6] = { 98 "Yellow", 99 "Red", 100 "BlueGreen", 101 "Orange", 102 "Green", 103 "Blue", 104 }; 105 #endif //DEMO 106 107 //........................................................................... 108 // Mono debugging variables: 109 // NetMonoMode: 0 = show connection output, 1 = flowcount output 110 // NewMonoMode: set by anything that toggles NetMonoMode; re-inits screen 111 // IsMono: used for taking control of Mono screen away from the engine 112 //........................................................................... 113 #ifndef DEMO 114 int NetMonoMode = 1; 115 int NewMonoMode = 1; 116 static int IsMono = 0; 117 #endif //DEMO 118 119 //--------------------------------------------------------------------------- 120 // Several routines return various codes; here's an enum for all of them. 121 //--------------------------------------------------------------------------- 122 typedef enum RetcodeEnum { 123 RC_NORMAL, // no news is good news 124 RC_PLAYER_READY, // a new player has been heard from 125 RC_SCENARIO_MISMATCH, // scenario mismatch 126 RC_DOLIST_FULL, // DoList is full 127 RC_SERIAL_PROCESSED, // modem: SERIAL packet was processed 128 RC_PLAYER_LEFT, // modem: other player left the game 129 RC_HUNG_UP, // modem has hung up 130 RC_NOT_RESPONDING, // other player not responding (timeout/hung up) 131 RC_CANCEL, // user cancelled 132 } RetcodeType; 133 134 135 /********************************* Prototypes *******************************/ 136 //........................................................................... 137 // Main multiplayer queue logic 138 //........................................................................... 139 static void Queue_AI_Normal(void); 140 #ifndef DEMO 141 static void Queue_AI_Multiplayer(void); 142 static RetcodeType Wait_For_Players(int first_time, ConnManClass *net, 143 int resend_delta, int dialog_time, int timeout, char *multi_packet_buf, 144 int my_sent, long *their_frame, unsigned short *their_sent, 145 unsigned short *their_recv); 146 static void Generate_Timing_Event(ConnManClass *net, int my_sent); 147 static void Generate_Real_Timing_Event(ConnManClass *net, int my_sent); 148 static void Generate_Process_Time_Event(ConnManClass *net); 149 static int Process_Send_Period(ConnManClass *net); 150 static int Send_Packets(ConnManClass *net, char *multi_packet_buf, 151 int multi_packet_max, int max_ahead, int my_sent); 152 static void Send_FrameSync(ConnManClass *net, int cmd_count); 153 static RetcodeType Process_Receive_Packet(ConnManClass *net, 154 char *multi_packet_buf, int id, int packetlen, long *their_frame, 155 unsigned short *their_sent, unsigned short *their_recv); 156 static RetcodeType Process_Serial_Packet(char *multi_packet_buf, 157 int first_time); 158 static int Can_Advance(ConnManClass *net, int max_ahead, long *their_frame, 159 unsigned short *their_sent, unsigned short *their_recv); 160 static int Process_Reconnect_Dialog(CountDownTimerClass *timeout_timer, 161 long *their_frame, int num_conn, int reconn, int fresh); 162 static int Handle_Timeout(ConnManClass *net, long *their_frame, 163 unsigned short *their_sent, unsigned short *their_recv); 164 static void Stop_Game(void); 165 #endif //DEMO 166 167 //........................................................................... 168 // Packet compression/decompression: 169 //........................................................................... 170 #ifndef DEMO 171 static int Build_Send_Packet(void *buf, int bufsize, int frame_delay, 172 int num_cmds, int cap); 173 static int Breakup_Receive_Packet(void *buf, int bufsize ); 174 #endif //DEMO 175 int Add_Uncompressed_Events(void *buf, int bufsize, int frame_delay, int size, 176 int cap); 177 int Add_Compressed_Events(void *buf, int bufsize, int frame_delay, int size, 178 int cap); 179 int Extract_Uncompressed_Events(void *buf, int bufsize); 180 int Extract_Compressed_Events(void *buf, int bufsize); 181 182 //........................................................................... 183 // DoList management: 184 //........................................................................... 185 static int Execute_DoList(int max_houses, HousesType base_house, 186 ConnManClass *net, TCountDownTimerClass *skip_crc, 187 long *their_frame, unsigned short *their_sent, unsigned short *their_recv); 188 static void Clean_DoList(ConnManClass *net); 189 #ifndef DEMO 190 static void Queue_Record(void); 191 static void Queue_Playback(void); 192 #endif //DEMO 193 194 //........................................................................... 195 // Debugging: 196 //........................................................................... 197 #ifndef DEMO 198 static void Compute_Game_CRC(void); 199 static void Init_Queue_Mono(ConnManClass *net); 200 static void Update_Queue_Mono(ConnManClass *net, int flow_index); 201 static void Print_Framesync_Values(long curframe, unsigned long max_ahead, 202 int num_connections, unsigned short *their_recv, 203 unsigned short *their_sent, unsigned short my_sent); 204 #endif //DEMO 205 void Add_CRC(unsigned long *crc, unsigned long val); 206 void Print_CRCs(EventClass *); 207 208 extern void Keyboard_Process(KeyNumType &input); 209 void Dump_Packet_Too_Late_Stuff(EventClass *event); 210 211 extern void Register_Game_End_Time(void); 212 extern void Send_Statistics_Packet(void); 213 214 /*************************************************************************** 215 * Queue_Mission -- Queue a mega mission event. * 216 * * 217 * This routine is called when the player causes a change to a game unit. * 218 * The event that initiates the change is queued to as a result of a call * 219 * to this routine. * 220 * * 221 * INPUT: * 222 * whom Whom this mission request applies to (a friendly unit). * 223 * mission The mission to assign to this object. * 224 * target The target of this mission (if any). * 225 * dest The movement destination for this mission (if any). * 226 * * 227 * OUTPUT: * 228 * Was the mission request queued successfully? * 229 * * 230 * WARNINGS: * 231 * none. * 232 * * 233 * HISTORY: * 234 * 09/21/1995 JLB : Created. * 235 *=========================================================================*/ 236 bool Queue_Mission(TARGET whom, MissionType mission, TARGET target, 237 TARGET destination) 238 { 239 if (! OutList.Add(EventClass(whom, mission, target, destination))) { 240 return(false); 241 } 242 else { 243 return(true); 244 } 245 246 } /* end of Queue_Mission */ 247 248 249 /*************************************************************************** 250 * Queue_Options -- Queue the options event. * 251 * * 252 * INPUT: * 253 * none. * 254 * * 255 * OUTPUT: * 256 * Was the options screen event queued successfully? * 257 * * 258 * WARNINGS: * 259 * none. * 260 * * 261 * HISTORY: * 262 * 09/21/1995 JLB : Created. * 263 *=========================================================================*/ 264 bool Queue_Options(void) 265 { 266 if (! OutList.Add(EventClass(EventClass::OPTIONS))) { 267 return(false); 268 } 269 else { 270 return(true); 271 } 272 273 } /* end of Queue_Options */ 274 275 276 /*************************************************************************** 277 * Queue_Exit -- Add the exit game event to the queue. * 278 * * 279 * INPUT: * 280 * none. * 281 * * 282 * OUTPUT: * 283 * Was the exit event queued successfully? * 284 * * 285 * WARNINGS: * 286 * none. * 287 * * 288 * HISTORY: * 289 * 09/21/1995 JLB : Created. * 290 *=========================================================================*/ 291 bool Queue_Exit(void) 292 { 293 if (! OutList.Add(EventClass(EventClass::EXIT))) { 294 return(false); 295 } 296 else { 297 return(true); 298 } 299 300 } /* end of Queue_Exit */ 301 302 303 /*************************************************************************** 304 * Queue_AI -- Process all queued events. * 305 * * 306 * INPUT: * 307 * none. * 308 * * 309 * OUTPUT: * 310 * none. * 311 * * 312 * WARNINGS: * 313 * none. * 314 * * 315 * HISTORY: * 316 * 09/21/1995 JLB : Created. * 317 *=========================================================================*/ 318 void Queue_AI(void) 319 { 320 #ifdef DEMO 321 Queue_AI_Normal(); 322 #else //DEMO 323 324 if (PlaybackGame) { 325 Queue_Playback(); 326 } 327 328 else { 329 330 switch (GameToPlay) { 331 332 case GAME_NORMAL: 333 Queue_AI_Normal(); 334 break; 335 336 case GAME_MODEM: 337 case GAME_NULL_MODEM: 338 case GAME_IPX: 339 case GAME_INTERNET: 340 Queue_AI_Multiplayer(); 341 break; 342 } 343 } 344 #endif //DEMO 345 346 } /* end of Queue_AI */ 347 348 349 /*************************************************************************** 350 * Queue_AI_Normal -- Process all queued events. * 351 * * 352 * This is the "normal" version of the queue management routine. It does * 353 * the following: * 354 * - Transfers items in the OutList to the DoList * 355 * - Executes any commands in the DoList that are supposed to be done on * 356 * this frame # * 357 * - Cleans out the DoList * 358 * * 359 * INPUT: * 360 * none. * 361 * * 362 * OUTPUT: * 363 * none. * 364 * * 365 * WARNINGS: * 366 * none. * 367 * * 368 * HISTORY: * 369 * 09/21/1995 JLB : Created. * 370 *=========================================================================*/ 371 static void Queue_AI_Normal(void) 372 { 373 //------------------------------------------------------------------------ 374 // Move events from the OutList (events generated by this player) into the 375 // DoList (the list of events to execute). 376 //------------------------------------------------------------------------ 377 while (OutList.Count) { 378 OutList.First().IsExecuted = false; 379 if (!DoList.Add(OutList.First())) { 380 ; 381 } 382 OutList.Next(); 383 } 384 385 //------------------------------------------------------------------------ 386 // Save the DoList to disk, if we're in "Record" mode 387 //------------------------------------------------------------------------ 388 #ifndef DEMO 389 if (RecordGame) { 390 Queue_Record(); 391 } 392 #endif //DEMO 393 394 //------------------------------------------------------------------------ 395 // Execute the DoList 396 //------------------------------------------------------------------------ 397 if (!Execute_DoList(1,PlayerPtr->Class->House, NULL, NULL, NULL, 398 NULL, NULL)) { 399 GameActive = 0; 400 return; 401 } 402 //------------------------------------------------------------------------ 403 // Clean out the DoList 404 //------------------------------------------------------------------------ 405 Clean_DoList(NULL); 406 407 } /* end of Queue_AI_Normal */ 408 409 #ifndef DEMO 410 411 /*************************************************************************** 412 * Queue_AI_Multiplayer -- Process all queued events. * 413 * * 414 * This is the network version of the queue management routine. It does * 415 * the following: * 416 * - If this is the 1st frame, waits for other systems to signal ready * 417 * - Generates a timing event, to allow the connection time to be dynamic * 418 * - Handles timing related to sending packets every 'n' frames * 419 * - Sends outgoing events * 420 * - Frame-syncs to the other systems (see below) * 421 * - Executes & cleans out the DoList * 422 * * 423 * The Frame-Sync'ing logic is the heart & soul of network play. It works * 424 * by ensuring that any system won't out-run the other system by more than * 425 * 'MaxAhead' frames; this in turn ensures that a packet's * 426 * execution frame # won't have been passed by the time that packet is * 427 * received by all systems. * 428 * * 429 * To achieve this, the system must keep track of all other system's * 430 * current frame #'s; these are stored in an array called 'their_frame[]'. * 431 * However, because current frame #'s are sent in FRAMEINFO packets, which * 432 * don't require an ACK, and command packets are sent in packets requiring * 433 * an ACK, it's possible for a command packet to get lost, and the next * 434 * frame's FRAMEINFO packet to not get lost; the other system may then * 435 * advance past the frame # the command is to execute on! So, to prevent * 436 * this, all FRAMEINFO packets include a CommandCount field. This value * 437 * tells the other system how many events it should have received by this * 438 * time. This system can therefore keep track of how many commands it's * 439 * actually received, and compare it to the CommandCount field, to see if * 440 * it's missed an event packet. The # of events we've received from each * 441 * system is stored in 'their_recv[]', and the # events they say they've * 442 * sent is stored in 'their_sent[]'. * 443 * * 444 * Thus, two conditions must be met in order to advance to the next frame: * 445 * - Our current frame # must be <= their_frame + MaxAhead * 446 * - their_recv[i] must be >= their_sent[i] * 447 * * 448 * 'their_frame[] is updated by Process_Receive_Packet() * 449 * 'their_recv[] is updated by Process_Receive_Packet() * 450 * 'their_sent[] is updated by Process_Receive_Packet() * 451 * 'my_sent' is updated by this routine. * 452 * * 453 * The only routines allowed to pop up dialogs are: * 454 * Wait_For_Players() (only pops up the reconnect dialog) * 455 * Execute_DoList() (tells if out of sync, or packet recv'd too late) * 456 * * 457 * Sign-off's are detected by: * 458 * - Timing out while waiting for a packet * 459 * - Detecting that the other player is now at the score screen or * 460 * connection dialog (serial) * 461 * - If we see an EventClass::EXIT event on the private channel * 462 * * 463 * The current communications protocol, COMM_PROTOCOL_MULTI_E_COMP, has * 464 * the following properites: * 465 * - It compresses packets, so that the minimum number of bytes are * 466 * transmitted. Packets are compressed by extracting all info common to * 467 * the events into the packet header, and then sending only the bytes * 468 * relevant to each type of event. For instance, if 100 infantry guys * 469 * are told to move to the same location, the command itself & the * 470 * location will be included in the 1st movement command only; after * 471 * that, there will be a rep count then 99 infantry TARGET numbers, * 472 * identifying all the infantry told to move. * 473 * - The protocol also only sends packets out every 'n' frames. This cuts * 474 * the data rate dramatically. It means that 'MaxAhead' must be * 475 * divisible by 'n'; also, the minimum value for 'MaxAhead' is * 476 * 'n * 2', to give both sides some "breathing" room in case a FRAMEINFO * 477 * packet gets missed. * 478 * * 479 * Note: For synchronization-waiting loops (like waiting to hear from all * 480 * other players, waiting to advance to the next frame, etc), use * 481 * Net.Num_Connections() rather than NumPlayers; this reflects the * 482 * actual # of connections, and can be "faked" into playing even when * 483 * there aren't any other players actually there. A typical example of * 484 * this is playing back a recorded game. For command-execution loops, use * 485 * NumPlayers. This ensures all commands get executed, even if * 486 * there isn't a human generating those commands. * 487 * * 488 * The modem works a little differently from the network in this respect: * 489 * - The connection has to stay "alive" even if the other player exits to * 490 * the join dialog. This prevents each system from timing out & hanging * 491 * the modem up. Thus, packets are sent back & forth & just thrown away,* 492 * but each system knows the other is still there. Messages may be sent * 493 * between systems, though. * 494 * - Destroy_Null_Connection doesn't hang up the modem, so * 495 * Num_Connections() still reports a value of 1 even though the other * 496 * player has left. * 497 * - Any waits on Num_Connections() must also check for * 498 * NumPlayers > 1, to keep from waiting forever if the other * 499 * guy has left * 500 * - Packets sent to a player who's left require no ACK * 501 * * 502 * INPUT: * 503 * none. * 504 * * 505 * OUTPUT: * 506 * none. * 507 * * 508 * WARNINGS: * 509 * none. * 510 * * 511 * HISTORY: * 512 * 11/21/1995 BRR : Created. * 513 *=========================================================================*/ 514 static void Queue_AI_Multiplayer(void) 515 { 516 //........................................................................ 517 // Enums: 518 //........................................................................ 519 enum { 520 MIXFILE_RESEND_DELTA = 120, // ticks b/w resends 521 MIXFILE_TIMEOUT = 3600, // timeout waiting for mixfiles 522 FRAMESYNC_DLG_TIME = (3*60), // time until displaying reconnect dialog 523 FRAMESYNC_TIMEOUT = (25*60), // timeout waiting for frame sync packet 524 }; 525 526 int timeout_factor = (GameToPlay == GAME_INTERNET) ? 6 : 1; 527 528 //........................................................................ 529 // Variables for sending, receiving & parsing packets: 530 //........................................................................ 531 ConnManClass *net; // ptr to access all multiplayer functions 532 EventClass packet; // for sending single frame-sync's 533 char *multi_packet_buf; // buffer for sending/receiving 534 int multi_packet_max; // max length of multi_packet_buf 535 536 //........................................................................ 537 // Frame-sync'ing variables. Values in these arrays are stored in the 538 // order in which the connections are created. 539 // (ie net->Connection_Index(id)) 540 //........................................................................ 541 static long 542 their_frame[MAX_PLAYERS - 1]; // other players' frame #'s 543 static unsigned short 544 their_sent[MAX_PLAYERS - 1]; // # cmds other player claims to have sent 545 static unsigned short 546 their_recv[MAX_PLAYERS - 1]; // # cmds actually received from others 547 static unsigned short 548 my_sent; // # cmds I've sent out 549 550 //........................................................................ 551 // Other misc variables 552 //........................................................................ 553 int i; 554 RetcodeType rc; 555 int reconnect_dlg = 0; // 1 = the reconnect dialog is displayed 556 557 //------------------------------------------------------------------------ 558 // Initialize the packet buffer pointer & its max size 559 //------------------------------------------------------------------------ 560 if (GameToPlay == GAME_MODEM 561 || GameToPlay == GAME_NULL_MODEM){ 562 //PG_TO_FIX 563 #if (0) 564 multi_packet_buf = NullModem.BuildBuf; 565 multi_packet_max = NullModem.MaxLen - sizeof (CommHeaderType); 566 net = &NullModem; 567 #endif 568 } 569 else if (GameToPlay == GAME_IPX || GameToPlay == GAME_INTERNET) { 570 multi_packet_buf = MetaPacket; 571 multi_packet_max = MetaSize; 572 net = &Ipx; 573 } 574 575 //------------------------------------------------------------------------ 576 // Debug stuff 577 //------------------------------------------------------------------------ 578 Init_Queue_Mono(net); 579 Update_Queue_Mono (net, 0); 580 581 //------------------------------------------------------------------------ 582 // If we've just started a game, or loaded a multiplayer game, we must 583 // wait for all other systems to signal ready. 584 //------------------------------------------------------------------------ 585 if (Frame==0) { 586 //..................................................................... 587 // Initialize static locals 588 //..................................................................... 589 for (i = 0; i < MAX_PLAYERS - 1; i++) { 590 their_frame[i] = -1; 591 their_sent[i] = 0; 592 their_recv[i] = 0; 593 TheirProcessTime[i] = -1; 594 } 595 my_sent = 0; 596 for (i = 0; i < 32; i++) { 597 CRC[i] = 0; 598 } 599 600 //..................................................................... 601 // Send our initial FRAMESYNC packet 602 //..................................................................... 603 Send_FrameSync(net, my_sent); 604 605 //..................................................................... 606 // Wait for the other guys 607 //..................................................................... 608 rc = Wait_For_Players (1, net, MIXFILE_RESEND_DELTA, FRAMESYNC_DLG_TIME*timeout_factor, 609 MIXFILE_TIMEOUT, multi_packet_buf, my_sent, their_frame, 610 their_sent, their_recv); 611 612 if (rc != RC_NORMAL) { 613 if (rc == RC_NOT_RESPONDING) { 614 CCMessageBox().Process (TXT_SYSTEM_NOT_RESPONDING); 615 } 616 else if (rc == RC_SCENARIO_MISMATCH) { 617 CCMessageBox().Process (TXT_SCENARIOS_DO_NOT_MATCH); 618 } 619 else if (rc == RC_DOLIST_FULL) { 620 CCMessageBox().Process(TXT_QUEUE_FULL); 621 } 622 Stop_Game(); 623 return; 624 } 625 626 //..................................................................... 627 // Re-initialize frame numbers (in case somebody signed off while I was 628 // waiting for MIX files to load; we would have fallen through, but 629 // their frame # would still be -1). 630 //..................................................................... 631 for (i = 0; i < MAX_PLAYERS - 1; i++) 632 their_frame[i] = 0; 633 634 //..................................................................... 635 // Reset the network response time computation, now that we're both 636 // sending data again (loading MIX files will have introduced 637 // deceptively large values). 638 //..................................................................... 639 net->Reset_Response_Time(); 640 641 //..................................................................... 642 // Initialize the frame timers 643 //..................................................................... 644 if (CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) { 645 Process_Send_Period(net); 646 } 647 648 } // end of Frame 0 wait 649 650 //------------------------------------------------------------------------ 651 // Adjust connection timing parameters every 128 frames. 652 //------------------------------------------------------------------------ 653 else if ( (Frame & 0x007f) == 0) { 654 // 655 // If we're using the new spiffy protocol, do proper timing handling. 656 // If we're the net "master", compute our desired frame rate & new 657 // 'MaxAhead' value. 658 // 659 if (CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) { 660 661 // 662 // All systems will transmit their required process time. 663 // 664 Generate_Process_Time_Event(net); 665 666 // 667 // The game "host" will transmit timing adjustment events. 668 // 669 if (MPlayerLocalID == MPlayerID[0]) { 670 Generate_Real_Timing_Event(net, my_sent); 671 } 672 } else { 673 // 674 // For the older protocols, do the old broken timing handling. 675 // 676 Generate_Timing_Event(net, my_sent); 677 } 678 } 679 680 //------------------------------------------------------------------------ 681 // Compute the Game's CRC 682 //------------------------------------------------------------------------ 683 Compute_Game_CRC(); 684 CRC[Frame & 0x001f] = GameCRC; 685 //unsigned long save_crc = GameCRC; 686 //Print_CRCs((EventClass *)NULL); 687 //GameCRC = save_crc; 688 689 //------------------------------------------------------------------------ 690 // Only process every 'FrameSendRate' frames 691 //------------------------------------------------------------------------ 692 if (CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) { 693 if (!Process_Send_Period(net)) { 694 if (IsMono) { 695 MonoClass::Disable(); 696 } 697 return; 698 } 699 } 700 701 //------------------------------------------------------------------------ 702 // Send our data packet(s); update my command-sent counter 703 //------------------------------------------------------------------------ 704 my_sent += Send_Packets(net, multi_packet_buf, multi_packet_max, 705 MPlayerMaxAhead, my_sent); 706 707 //------------------------------------------------------------------------ 708 // If this is our first time through, we're done. 709 //------------------------------------------------------------------------ 710 if (Frame==0) { 711 if (IsMono) { 712 MonoClass::Disable(); 713 } 714 return; 715 } 716 717 //------------------------------------------------------------------------ 718 // Frame-sync'ing: wait until it's OK to advance to the next frame. 719 //------------------------------------------------------------------------ 720 rc = Wait_For_Players (0, net, 721 (MPlayerMaxAhead << 3), 722 MAX ( net->Response_Time() * 3, (unsigned long)FRAMESYNC_DLG_TIME*timeout_factor ), 723 FRAMESYNC_TIMEOUT * (timeout_factor*2), 724 multi_packet_buf, my_sent, their_frame, 725 their_sent, their_recv); 726 727 if (rc != RC_NORMAL) { 728 if (rc == RC_NOT_RESPONDING) { 729 CCMessageBox().Process (TXT_SYSTEM_NOT_RESPONDING); 730 } 731 else if (rc == RC_SCENARIO_MISMATCH) { 732 CCMessageBox().Process (TXT_SCENARIOS_DO_NOT_MATCH); 733 } 734 else if (rc == RC_DOLIST_FULL) { 735 CCMessageBox().Process(TXT_QUEUE_FULL); 736 } 737 Stop_Game(); 738 return; 739 } 740 741 //------------------------------------------------------------------------ 742 // Save the DoList to disk, if we're in "Record" mode 743 //------------------------------------------------------------------------ 744 if (RecordGame) { 745 Queue_Record(); 746 } 747 748 //------------------------------------------------------------------------ 749 // Execute the DoList; if an error occurs, bail out. 750 //------------------------------------------------------------------------ 751 if (!Execute_DoList(MPlayerMax, HOUSE_MULTI1, net, NULL, 752 their_frame, their_sent, their_recv)) { 753 Stop_Game(); 754 return; 755 } 756 757 //------------------------------------------------------------------------ 758 // Clean out the DoList 759 //------------------------------------------------------------------------ 760 Clean_DoList(net); 761 762 if (IsMono) { 763 MonoClass::Disable(); 764 } 765 766 } // end of Queue_AI_Multiplayer 767 768 769 /*************************************************************************** 770 * Wait_For_Players -- Waits for other systems to come on-line * 771 * * 772 * This routine performs the most critical logic in multiplayer; that of * 773 * synchronizing my frame number with those of the other systems. * 774 * * 775 * INPUT: * 776 * first_time 1 = 1st time this routine is called * 777 * net ptr to connection manager * 778 * resend_delta time (ticks) between FRAMESYNC resends * 779 * dialog_time time (ticks) until pop up a reconnect dialog * 780 * timeout time (ticks) until we give up the ghost * 781 * multi_packet_buf buffer to store packets in * 782 * my_sent # commands I've sent so far * 783 * their_frame array of their frame #'s * 784 * their_sent array of their CommandCount values * 785 * their_recv array of # cmds I've received from them * 786 * * 787 * OUTPUT: * 788 * RC_NORMAL OK to advance to the next frame * 789 * RC_CANCEL user hit 'Cancel' at the timeout countdown dlg * 790 * RC_NOT_RESPONDING other player(s) not responding * 791 * RC_SCENARIO_MISMATCH scenario's don't match (first_time only) * 792 * RC_DOLIST_FULL DoList was full * 793 * * 794 * WARNINGS: * 795 * none. * 796 * * 797 * HISTORY: * 798 * 11/21/1995 BRR : Created. * 799 *=========================================================================*/ 800 static RetcodeType Wait_For_Players(int first_time, ConnManClass *net, 801 int resend_delta, int dialog_time, int timeout, char *multi_packet_buf, 802 int my_sent, long *their_frame, unsigned short *their_sent, 803 unsigned short *their_recv) 804 { 805 //........................................................................ 806 // Variables for sending, receiving & parsing packets: 807 //........................................................................ 808 EventClass *event; // event ptr for parsing incoming packets 809 int packetlen; // size of meta-packet sent, & received 810 int id; // id of other player 811 int messages_this_loop; // to limit # messages processed each loop 812 813 //........................................................................ 814 // Variables used only if 'first_time': 815 //........................................................................ 816 int num_ready; // # players signalling ready 817 818 //........................................................................ 819 // Timing variables 820 //........................................................................ 821 CountDownTimerClass retry_timer; // time between FRAMESYNC packet resends 822 CountDownTimerClass dialog_timer; // time to pop up a dialog 823 CountDownTimerClass timeout_timer; // general-purpose timeout 824 825 //........................................................................ 826 // Dialog variables 827 //........................................................................ 828 int reconnect_dlg = 0; // 1 = the reconnect dialog is displayed 829 830 //........................................................................ 831 // Other misc variables 832 //........................................................................ 833 KeyNumType input; // for user input 834 int x,y; // for map input 835 RetcodeType rc; 836 837 //------------------------------------------------------------------------ 838 // Wait to hear from all other players 839 //------------------------------------------------------------------------ 840 num_ready = 0; 841 retry_timer.Set (resend_delta, true); // time to retry 842 dialog_timer.Set (dialog_time, true); // time to show dlg 843 timeout_timer.Set (timeout, true); // time to bail out 844 845 while (1) { 846 847 Update_Queue_Mono (net, 2); 848 849 //--------------------------------------------------------------------- 850 // Resend a frame-sync packet if longer than one propogation delay goes 851 // by; this prevents a "deadlock". If he's waiting for me to advance, 852 // but has missed my last few FRAMEINFO packets, I may be waiting for 853 // him to advance. Resending a FRAMESYNC ensures he knows what frame 854 // number I'm on. 855 //--------------------------------------------------------------------- 856 if (!retry_timer.Time()) { 857 retry_timer.Set (resend_delta, true); // time to retry 858 Update_Queue_Mono (net, 3); 859 Send_FrameSync(net, my_sent); 860 } 861 862 //--------------------------------------------------------------------- 863 // Service the connections 864 //--------------------------------------------------------------------- 865 net->Service(); 866 867 //--------------------------------------------------------------------- 868 // Pop up a reconnect dialog if enough time goes by 869 //--------------------------------------------------------------------- 870 if (!dialog_timer.Time() && SpecialDialog==SDLG_NONE) { 871 if (Process_Reconnect_Dialog(&timeout_timer, their_frame, 872 net->Num_Connections(), (first_time==0), (reconnect_dlg==0))) { 873 return (RC_CANCEL); 874 } 875 reconnect_dlg = 1; 876 } 877 878 //--------------------------------------------------------------------- 879 // Exit if too much time goes by (the other system has crashed or 880 // bailed) 881 //--------------------------------------------------------------------- 882 if (!timeout_timer.Time()) { 883 //.................................................................. 884 // For the first-time run, just give up; something's wrong. 885 //.................................................................. 886 if (first_time) { 887 return (RC_NOT_RESPONDING); 888 } 889 //.................................................................. 890 // Otherwise, we're in the middle of a game; so, the modem & 891 // network must deal with a timeout differently. 892 //.................................................................. 893 else { 894 Update_Queue_Mono (net, 4); 895 896 if (Handle_Timeout(net, their_frame, their_sent, their_recv)) { 897 Map.Flag_To_Redraw(true); // erase modem reconnect dialog 898 Map.Render(); 899 retry_timer.Set (resend_delta, true); 900 dialog_timer.Set (dialog_time, true); 901 timeout_timer.Set (timeout, true); 902 } 903 else { 904 return (RC_NOT_RESPONDING); 905 } 906 } 907 } 908 909 //--------------------------------------------------------------------- 910 // Check for an incoming message. We must still process commands 911 // even if 'first_time' is set, in case the other system got my 1st 912 // FRAMESYNC, but I didn't get his; he'll be at the next frame, and 913 // may be sending commands. 914 // We have to limit the number of incoming messages we handle; it's 915 // possible to go into an infinite loop processing modem messages. 916 //--------------------------------------------------------------------- 917 messages_this_loop = 0; 918 while ( (messages_this_loop++ < 5) && 919 net->Get_Private_Message (multi_packet_buf, &packetlen, &id) ) { 920 Update_Queue_Mono (net, 5); 921 922 /*.................................................................. 923 Get an event ptr to the incoming message 924 ..................................................................*/ 925 event = (EventClass *)multi_packet_buf; 926 927 //------------------------------------------------------------------ 928 // Special processing for a modem game: process SERIAL packets 929 //------------------------------------------------------------------ 930 if (GameToPlay == GAME_MODEM 931 || GameToPlay == GAME_NULL_MODEM){ 932 //|| GameToPlay == GAME_INTERNET) { 933 rc = Process_Serial_Packet(multi_packet_buf, first_time); 934 //............................................................... 935 // SERIAL packet received & processed 936 //............................................................... 937 if (rc == RC_SERIAL_PROCESSED) { 938 net->Service(); 939 retry_timer.Set (resend_delta, true); 940 dialog_timer.Set (dialog_time, true); 941 timeout_timer.Set (timeout, true); 942 continue; 943 } 944 //............................................................... 945 // other player has left the game 946 //............................................................... 947 else if (rc == RC_PLAYER_LEFT) { 948 if (first_time) { 949 num_ready++; 950 } 951 break; 952 } 953 //............................................................... 954 // Connection was lost 955 //............................................................... 956 else if (rc == RC_HUNG_UP) { 957 return (RC_NOT_RESPONDING); 958 } 959 //............................................................... 960 // If it was any other type of serial packet, break 961 //............................................................... 962 else if (rc != RC_NORMAL) { 963 break; 964 } 965 } 966 967 //------------------------------------------------------------------ 968 // Process the incoming packet 969 //------------------------------------------------------------------ 970 rc = Process_Receive_Packet(net, multi_packet_buf, id, packetlen, 971 their_frame, their_sent, their_recv); 972 //.................................................................. 973 // New player heard from 974 //.................................................................. 975 if (rc == RC_PLAYER_READY) { 976 num_ready++; 977 } 978 //.................................................................. 979 // Scenario's don't match 980 //.................................................................. 981 else if (rc == RC_SCENARIO_MISMATCH) { 982 return (RC_SCENARIO_MISMATCH); 983 } 984 //.................................................................. 985 // DoList was full 986 //.................................................................. 987 else if (rc == RC_DOLIST_FULL) { 988 return (RC_DOLIST_FULL); 989 } 990 991 //.................................................................. 992 // Service the connection, to clean out the receive queues 993 //.................................................................. 994 net->Service(); 995 } 996 997 //--------------------------------------------------------------------- 998 // Debug output 999 //--------------------------------------------------------------------- 1000 Print_Framesync_Values(Frame, MPlayerMaxAhead, net->Num_Connections(), 1001 their_recv, their_sent, my_sent); 1002 1003 //--------------------------------------------------------------------- 1004 // Attempt to advance to the next frame. 1005 //--------------------------------------------------------------------- 1006 //..................................................................... 1007 // For the first-time run, just check to see if we've heard from 1008 // everyone. 1009 //..................................................................... 1010 if (first_time) { 1011 if (num_ready >= net->Num_Connections()) break; 1012 } 1013 //..................................................................... 1014 // For in-game processing, we have to check their_sent, their_recv, 1015 // their_frame, etc. 1016 //..................................................................... 1017 else { 1018 if (Can_Advance(net, MPlayerMaxAhead, their_frame, their_sent, 1019 their_recv)) { 1020 break; 1021 } 1022 } 1023 1024 //--------------------------------------------------------------------- 1025 // Service game stuff. Servicing the map's input, and rendering the 1026 // map, allows the map to scroll even though we're hung up waiting for 1027 // packets. Don't do this if 'first_time' is set, since users could be 1028 // waiting a very long time for all systems to load the scenario, and 1029 // it gets frustrating being able to scroll around without doing 1030 // anything. 1031 //--------------------------------------------------------------------- 1032 Call_Back(); 1033 if (!first_time && SpecialDialog == SDLG_NONE && reconnect_dlg==0) { 1034 WWMouse->Erase_Mouse(&HidPage, TRUE); 1035 Map.Input(input, x, y); 1036 if (input) 1037 Keyboard_Process(input); 1038 Map.Render(); 1039 } 1040 1041 } /* end of while */ 1042 1043 //------------------------------------------------------------------------ 1044 // If the reconnect dialog was shown, force the map to redraw. 1045 //------------------------------------------------------------------------ 1046 if (reconnect_dlg) { 1047 Map.Flag_To_Redraw(true); 1048 Map.Render(); 1049 } 1050 1051 return (RC_NORMAL); 1052 1053 } // end of Wait_For_Players 1054 1055 1056 /*************************************************************************** 1057 * Generate_Timing_Event -- computes & queues a RESPONSE_TIME event * 1058 * * 1059 * This routine adjusts the connection timing on the local system; it also * 1060 * optionally generates a RESPONSE_TIME event, to tell all systems to * 1061 * dynamically adjust the current MaxAhead value. This allows both the * 1062 * MaxAhead & the connection retry logic to have dynamic timing, to adjust * 1063 * to varying line conditions. * 1064 * * 1065 * INPUT: * 1066 * net ptr to connection manager * 1067 * my_sent # commands I've sent out so far * 1068 * * 1069 * OUTPUT: * 1070 * none. * 1071 * * 1072 * WARNINGS: * 1073 * none. * 1074 * * 1075 * HISTORY: * 1076 * 11/21/1995 BRR : Created. * 1077 *=========================================================================*/ 1078 static void Generate_Timing_Event(ConnManClass *net, int my_sent) 1079 { 1080 unsigned long resp_time; // connection response time, in ticks 1081 EventClass ev; 1082 1083 //------------------------------------------------------------------------ 1084 // Measure the current connection response time. This time will be in 1085 // 60ths of a second, and represents full round-trip time of a packet. 1086 // To convert to one-way packet time, divide by 2; to convert to game 1087 // frames, divide again by 4, assuming a game rate of 15 fps. 1088 //------------------------------------------------------------------------ 1089 resp_time = net->Response_Time(); 1090 1091 //------------------------------------------------------------------------ 1092 // Adjust my connection retry timing; only do this if I've sent out more 1093 // than 5 commands, so I know I have a measure of the response time. 1094 //------------------------------------------------------------------------ 1095 if (my_sent > 5) { 1096 1097 net->Set_Timing (resp_time + 10, -1, (resp_time * 4)+15); 1098 1099 //..................................................................... 1100 // If I'm the network "master", I'm also responsible for updating the 1101 // MaxAhead value on all systems, so do that here too. 1102 //..................................................................... 1103 if (MPlayerLocalID == MPlayerID[0]) { 1104 ev.Type = EventClass::RESPONSE_TIME; 1105 //.................................................................. 1106 // For multi-frame compressed events, the MaxAhead must be an even 1107 // multiple of the FrameSendRate. 1108 //.................................................................. 1109 if (CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) { 1110 ev.Data.FrameInfo.Delay = MAX( ((((resp_time / 8) + 1111 (FrameSendRate - 1)) / FrameSendRate) * 1112 FrameSendRate), (FrameSendRate * 2) ); 1113 char flip[128]; 1114 sprintf (flip, "C&C95 - Generating timing packet - MaxAhead = %d frames\n", ev.Data.FrameInfo.Delay); 1115 CCDebugString (flip); 1116 1117 } 1118 //.................................................................. 1119 // For sending packets every frame, just use the 1-way connection 1120 // response time. 1121 //.................................................................. 1122 else { 1123 if (GameToPlay == GAME_MODEM 1124 || GameToPlay == GAME_NULL_MODEM){ 1125 //|| GameToPlay == GAME_INTERNET) { 1126 ev.Data.FrameInfo.Delay = MAX( (resp_time / 8), 1127 (unsigned long)MODEM_MIN_MAX_AHEAD ); 1128 } 1129 else if (GameToPlay == GAME_IPX || GameToPlay == GAME_INTERNET) { 1130 ev.Data.FrameInfo.Delay = MAX( (resp_time / 8), 1131 (unsigned long)NETWORK_MIN_MAX_AHEAD ); 1132 } 1133 } 1134 OutList.Add(ev); 1135 } 1136 } 1137 1138 } // end of Generate_Timing_Event 1139 1140 1141 /*************************************************************************** 1142 * Generate_Real_Timing_Event -- Generates a TIMING event * 1143 * * 1144 * INPUT: * 1145 * net ptr to connection manager * 1146 * my_sent # commands I've sent out so far * 1147 * * 1148 * OUTPUT: * 1149 * none. * 1150 * * 1151 * WARNINGS: * 1152 * none. * 1153 * * 1154 * HISTORY: * 1155 * 07/02/1996 BRR : Created. * 1156 *=========================================================================*/ 1157 static void Generate_Real_Timing_Event(ConnManClass *net, int my_sent) 1158 { 1159 unsigned long resp_time; // connection response time, in ticks 1160 EventClass ev; 1161 int highest_ticks; 1162 int i; 1163 int specified_frame_rate; 1164 int maxahead; 1165 1166 // 1167 // If we haven't sent out at least 5 guaranteed-delivery packets, don't 1168 // bother trying to measure our connection response time; just return. 1169 // 1170 if (my_sent < 5) { 1171 return; 1172 } 1173 1174 // 1175 // Find the highest processing time we have stored 1176 // 1177 highest_ticks = 0; 1178 for (i = 0; i < MPlayerCount; i++) { 1179 // 1180 // If we haven't heard from all systems yet, bail out. 1181 // 1182 if (TheirProcessTime[i] == -1) { 1183 return; 1184 } 1185 if (TheirProcessTime[i] > highest_ticks) { 1186 highest_ticks = TheirProcessTime[i]; 1187 } 1188 } 1189 1190 // 1191 // Compute our "desired" frame rate as the lower of: 1192 // - What the user has dialed into the options screen 1193 // - What we're really able to run at 1194 // 1195 if (highest_ticks == 0) { 1196 DesiredFrameRate = 60; 1197 } else { 1198 DesiredFrameRate = 60 / highest_ticks; 1199 } 1200 1201 if (Options.GameSpeed == 0) { 1202 specified_frame_rate = 60; 1203 } else { 1204 specified_frame_rate = 60 / Options.GameSpeed; 1205 } 1206 1207 DesiredFrameRate = MIN (DesiredFrameRate, specified_frame_rate); 1208 1209 // 1210 // Measure the current connection response time. This time will be in 1211 // 60ths of a second, and represents full round-trip time of a packet. 1212 // To convert to one-way packet time, divide by 2; to convert to game 1213 // frames, ....uh.... 1214 // 1215 resp_time = net->Response_Time(); 1216 1217 // 1218 // Compute our new 'MaxAhead' value, based upon the response time of our 1219 // connection and our desired frame rate. 1220 // 'MaxAhead' in frames is: 1221 // 1222 // (resp_time / 2 ticks) * (1 sec/60 ticks) * (n Frames / sec) 1223 // 1224 // resp_time is divided by 2 because, as reported, it represents a round- 1225 // trip, and we only want to use a one-way trip. 1226 // 1227 maxahead = (resp_time * DesiredFrameRate) / (2 * 60); 1228 1229 // 1230 // Now, we have to round 'maxahead' so it's an even multiple of our 1231 // send rate. It also must be at least thrice the FrameSendRate. 1232 // (Isn't "thrice" a cool word?) 1233 // 1234 maxahead = ((maxahead + FrameSendRate - 1) / FrameSendRate) * FrameSendRate; 1235 maxahead = MAX (maxahead, (int)FrameSendRate * 3); 1236 1237 ev.Type = EventClass::TIMING; 1238 ev.Data.Timing.DesiredFrameRate = DesiredFrameRate; 1239 ev.Data.Timing.MaxAhead = maxahead; 1240 1241 OutList.Add(ev); 1242 1243 // 1244 // Adjust my connection retry timing. These values set the retry timeout 1245 // to just over one round-trip time, the 'maxretries' to -1, and the 1246 // connection timeout to allow for about 4 retries. 1247 // 1248 net->Set_Timing (resp_time + 10, -1, (resp_time * 4)+15); 1249 1250 } 1251 1252 1253 /*************************************************************************** 1254 * Generate_Process_Time_Event -- Generates a PROCESS_TIME event * 1255 * * 1256 * INPUT: * 1257 * net ptr to connection manager * 1258 * * 1259 * OUTPUT: * 1260 * none. * 1261 * * 1262 * WARNINGS: * 1263 * none. * 1264 * * 1265 * HISTORY: * 1266 * 07/02/1996 BRR : Created. * 1267 *=========================================================================*/ 1268 static void Generate_Process_Time_Event(ConnManClass *net) 1269 { 1270 EventClass ev; 1271 int avgticks; 1272 unsigned long resp_time; // connection response time, in ticks 1273 1274 // 1275 // Measure the current connection response time. This time will be in 1276 // 60ths of a second, and represents full round-trip time of a packet. 1277 // To convert to one-way packet time, divide by 2; to convert to game 1278 // frames, ....uh.... 1279 // 1280 resp_time = net->Response_Time(); 1281 1282 // 1283 // Adjust my connection retry timing. These values set the retry timeout 1284 // to just over one round-trip time, the 'maxretries' to -1, and the 1285 // connection timeout to allow for about 4 retries. 1286 // 1287 net->Set_Timing (resp_time + 10, -1, (resp_time * 4)+15); 1288 1289 if (IsMono) { 1290 MonoClass::Enable(); 1291 Mono_Set_Cursor(0,23); 1292 Mono_Printf("Processing Ticks:%03d Frames:%03d\n", ProcessTicks,ProcessFrames); 1293 MonoClass::Disable(); 1294 } 1295 1296 avgticks = ProcessTicks / ProcessFrames; 1297 1298 ev.Type = EventClass::PROCESS_TIME; 1299 ev.Data.ProcessTime.AverageTicks = avgticks; 1300 char flip[128]; 1301 sprintf (flip, "C&C95 - Sending PROCESS_TIME packet of %04x ticks\n", ev.Data.ProcessTime.AverageTicks); 1302 CCDebugString (flip); 1303 1304 OutList.Add(ev); 1305 1306 ProcessTicks = 0; 1307 ProcessFrames = 0; 1308 } 1309 1310 1311 /*************************************************************************** 1312 * Process_Send_Period -- timing for sending packets every 'n' frames * 1313 * * 1314 * This function is for a CommProtocol of COMM_PROTOCOL_MULTI_E_COMP only. * 1315 * It determines if it's time to send a packet or not. * 1316 * * 1317 * INPUT: * 1318 * net ptr to connection manager * 1319 * * 1320 * OUTPUT: * 1321 * 1 = it's time to send a packet; 0 = don't send a packet this frame. * 1322 * * 1323 * WARNINGS: * 1324 * * 1325 * HISTORY: * 1326 * 11/21/1995 BRR : Created. * 1327 *=========================================================================*/ 1328 static int Process_Send_Period(ConnManClass *net) 1329 { 1330 //------------------------------------------------------------------------ 1331 // If the current frame # is not an even multiple of 'FrameSendRate', then 1332 // it's not time to send a packet; just return. 1333 //------------------------------------------------------------------------ 1334 if (Frame != (((Frame + (FrameSendRate - 1)) / 1335 FrameSendRate) * FrameSendRate) ) { 1336 1337 net->Service(); 1338 1339 if (IsMono) { 1340 MonoClass::Disable(); 1341 } 1342 1343 return (0); 1344 } 1345 1346 return (1); 1347 1348 } // end of Process_Send_Period 1349 1350 1351 /*************************************************************************** 1352 * Send_Packets -- sends out events from the OutList * 1353 * * 1354 * This routine computes how many events can be sent this frame, and then * 1355 * builds the "meta-packet" & sends it. * 1356 * * 1357 * The 'cap' value is the max # of events we can send. Ideally, it should * 1358 * be based upon the bandwidth of our connection. Currently, it's just * 1359 * hardcoded to prevent the modem from having to resend "too much" data, * 1360 * which is about 200 bytes per frame. * 1361 * * 1362 * INPUT: * 1363 * net ptr to connection manager * 1364 * multi_packet_buf buffer to store packets in * 1365 * multi_packet_max max size of multi_packet_buf * 1366 * max_ahead current game MaxAhead value * 1367 * my_sent # commands I've sent this game * 1368 * * 1369 * OUTPUT: * 1370 * # events sent, NOT including the FRAMEINFO event * 1371 * * 1372 * WARNINGS: * 1373 * * 1374 * HISTORY: * 1375 * 11/21/1995 BRR : Created. * 1376 *=========================================================================*/ 1377 static int Send_Packets(ConnManClass *net, char *multi_packet_buf, 1378 int multi_packet_max, int max_ahead, int my_sent) 1379 { 1380 int cap; // max # events to send, NOT including FRAMEINFO event 1381 int do_once; // true: only go through packet loop once 1382 int ack_req; // 0 = no ack required on outgoing packet 1383 int packetlen; // size of meta-packet sent 1384 1385 //------------------------------------------------------------------------ 1386 // Determine how many events it's OK to send this frame. 1387 //------------------------------------------------------------------------ 1388 //........................................................................ 1389 // If we have 4 or more packets queue'd for sending, don't add any more 1390 // this frame. 1391 //........................................................................ 1392 if (net->Private_Num_Send() >= 4) { 1393 cap = 0; 1394 do_once = 1; 1395 } 1396 //........................................................................ 1397 // If there are 2 or more packets queued, the entire packet we send must 1398 // fit within a single ComQueue buffer, so limit # events to 5. 1399 // (The Modem connection manager has a max buffer size of 200 bytes, which 1400 // is large enough for 6 uncompressed events, which leaves room for 5 1401 // events plus a FRAMEINFO.) 1402 //........................................................................ 1403 else if (net->Private_Num_Send() >= 2) { 1404 cap = 5; 1405 do_once = 1; 1406 1407 } 1408 //........................................................................ 1409 // Otherwise, just send all events in the OutList 1410 //........................................................................ 1411 else { 1412 cap = OutList.Count; 1413 do_once = 0; 1414 } 1415 //........................................................................ 1416 // Make sure we aren't sending more events than are in the OutList 1417 //........................................................................ 1418 if (cap > OutList.Count) { 1419 cap = OutList.Count; 1420 } 1421 1422 //........................................................................ 1423 // Make sure we don't send so many events that our DoList fills up 1424 //........................................................................ 1425 if (cap > (MAX_EVENTS * 8) - DoList.Count) { 1426 cap = (MAX_EVENTS * 8) - DoList.Count; 1427 } 1428 1429 /* 1430 ** No cap for internet game 1431 ** 1432 ** Or for serial games for that matter ST - 5/31/96 4:00PM 1433 */ 1434 if (GameToPlay == GAME_INTERNET || GameToPlay == GAME_MODEM || GameToPlay == GAME_NULL_MODEM){ 1435 cap = OutList.Count; 1436 do_once = 0; 1437 } 1438 1439 //------------------------------------------------------------------------ 1440 // Build our meta-packet & transmit it. 1441 //------------------------------------------------------------------------ 1442 while (1) { 1443 1444 Update_Queue_Mono (net, 1); 1445 1446 //..................................................................... 1447 // If there are no commands this frame, we'll just be sending a FRAMEINFO 1448 // packet; no ack is required. For the modem's sake, check 1449 // MPlayerCount; no ACK is needed if we're just sending to someone 1450 // who's left the game. 1451 //..................................................................... 1452 if (cap == 0 || OutList.Count == 0 || MPlayerCount == 1) { 1453 ack_req = 0; 1454 } 1455 else { 1456 ack_req = 1; 1457 } 1458 1459 //..................................................................... 1460 // Build & send out our message 1461 //..................................................................... 1462 packetlen = Build_Send_Packet (multi_packet_buf, multi_packet_max, 1463 max_ahead, my_sent, cap); 1464 net->Send_Private_Message (multi_packet_buf, packetlen, ack_req); 1465 1466 //..................................................................... 1467 // Call Service() to actually send the packet 1468 //..................................................................... 1469 net->Service(); 1470 1471 //..................................................................... 1472 // Stop if there's no more data to send, or if our send queue is 1473 // filling up. 1474 //..................................................................... 1475 if (OutList.Count == 0 || do_once) { 1476 break; 1477 } 1478 } 1479 1480 return (cap); 1481 1482 } // end of Send_Packets 1483 1484 1485 /*************************************************************************** 1486 * Send_FrameSync -- Sends a FRAMESYNC packet * 1487 * * 1488 * This routine is used to periodically remind the other systems that * 1489 * we're still here, and to tell them what frame # we're on, in case * 1490 * they've missed my FRAMEINFO packets. * 1491 * * 1492 * INPUT: * 1493 * net ptr to connection manager * 1494 * cmd_count # commands I've sent so far * 1495 * * 1496 * OUTPUT: * 1497 * none. * 1498 * * 1499 * WARNINGS: * 1500 * none. * 1501 * * 1502 * HISTORY: * 1503 * 11/21/1995 BRR : Created. * 1504 *=========================================================================*/ 1505 static void Send_FrameSync(ConnManClass *net, int cmd_count) 1506 { 1507 EventClass packet; 1508 1509 //------------------------------------------------------------------------ 1510 // Build a frame-sync event to send. FRAMESYNC packets contain a 1511 // scenario-based CRC rather than a game-state-based CRC, to let the 1512 // games compare scenario CRC's on startup. 1513 //------------------------------------------------------------------------ 1514 memset (&packet, 0, sizeof(EventClass)); 1515 packet.Type = EventClass::FRAMESYNC; 1516 if (CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) { 1517 packet.Frame = ((Frame + MPlayerMaxAhead + (FrameSendRate - 1)) / 1518 FrameSendRate) * FrameSendRate; 1519 } 1520 else { 1521 packet.Frame = Frame + MPlayerMaxAhead; 1522 } 1523 packet.ID = Houses.ID(PlayerPtr); 1524 packet.MPlayerID = MPlayerLocalID; 1525 packet.Data.FrameInfo.CRC = ScenarioCRC; 1526 packet.Data.FrameInfo.CommandCount = cmd_count; 1527 packet.Data.FrameInfo.Delay = MPlayerMaxAhead; 1528 1529 //------------------------------------------------------------------------ 1530 // Send the event. For modem, this just sends to the other player; 1531 // for network, it sends to everyone we're connected to. 1532 //------------------------------------------------------------------------ 1533 net->Send_Private_Message (&packet, (offsetof(EventClass, Data) + 1534 size_of(EventClass, Data.FrameInfo)), 0 ); 1535 1536 return; 1537 1538 } // end of Send_FrameSync 1539 1540 1541 /*************************************************************************** 1542 * Process_Receive_Packet -- processes an incoming packet * 1543 * * 1544 * This routine receives a packet from another system, adds it to our * 1545 * execution queue (the DoList), and updates my arrays of their frame #, * 1546 * their commands-sent, and their commands-received. * 1547 * * 1548 * INPUT: * 1549 * net ptr to connection manager * 1550 * multi_packet_buf buffer containing packet(s) to parse * 1551 * id id of sender * 1552 * their_frame array containing frame #'s of other players * 1553 * their_sent array containing command count of other players * 1554 * their_recv array containing # recv'd cmds from other players * 1555 * * 1556 * OUTPUT: * 1557 * RC_NORMAL: nothing unusual happened, although * 1558 * their_sent or their_recv may have been * 1559 * altered * 1560 * RC_PLAYER_READY: player has been heard from for the 1st time; * 1561 * this presumes that his original * 1562 * 'their_frame[]' value was -1 when this * 1563 * routine was called * 1564 * RC_SCENARIO_MISMATCH: FRAMEINFO scenario CRC doesn't match; * 1565 * normally only applies after loading a new * 1566 * scenario or save-game * 1567 * RC_DOLIST_FULL: fatal error; unable to add events to DoList * 1568 * * 1569 * WARNINGS: * 1570 * none. * 1571 * * 1572 * HISTORY: * 1573 * 11/21/1995 BRR : Created. * 1574 *=========================================================================*/ 1575 static RetcodeType Process_Receive_Packet(ConnManClass *net, 1576 char *multi_packet_buf, int id, int packetlen, long *their_frame, 1577 unsigned short *their_sent, unsigned short *their_recv) 1578 { 1579 EventClass *event; 1580 int index; 1581 RetcodeType retcode = RC_NORMAL; 1582 int i; 1583 1584 //------------------------------------------------------------------------ 1585 // Get an event ptr to the incoming message 1586 //------------------------------------------------------------------------ 1587 event = (EventClass *)multi_packet_buf; 1588 1589 //------------------------------------------------------------------------ 1590 // Get the index of the sender 1591 //------------------------------------------------------------------------ 1592 index = net->Connection_Index(id); 1593 1594 //------------------------------------------------------------------------ 1595 // Compute the other player's frame # (at the time this packet was sent) 1596 //------------------------------------------------------------------------ 1597 if (their_frame[index] < 1598 (int)(event->Frame - event->Data.FrameInfo.Delay)) { 1599 1600 //..................................................................... 1601 // If the original frame # for this player is -1, it means we've heard 1602 // from this player for the 1st time; return the appropriate value. 1603 //..................................................................... 1604 if (their_frame[index]==-1) { 1605 retcode = RC_PLAYER_READY; 1606 } 1607 1608 their_frame[index] = event->Frame - event->Data.FrameInfo.Delay; 1609 } 1610 1611 //------------------------------------------------------------------------ 1612 // Extract the other player's CommandCount. This count will include 1613 // the commands in this packet, if there are any. 1614 //------------------------------------------------------------------------ 1615 if (event->Data.FrameInfo.CommandCount > their_sent[index]) { 1616 their_sent[index] = event->Data.FrameInfo.CommandCount; 1617 } 1618 1619 //------------------------------------------------------------------------ 1620 // If this packet was not a FRAMESYNC packet: 1621 // - Add the events in it to our DoList 1622 // - Increment our commands-received counter by the number of non- 1623 // FRAMEINFO packets received 1624 //------------------------------------------------------------------------ 1625 if (event->Type != EventClass::FRAMESYNC) { 1626 //..................................................................... 1627 // Break up the packet into its component events. A returned packet 1628 // count of -1 indicates a fatal queue-full error. 1629 //..................................................................... 1630 i = Breakup_Receive_Packet( multi_packet_buf, packetlen); 1631 if (i==-1) { 1632 return (RC_DOLIST_FULL); 1633 } 1634 //..................................................................... 1635 // Compute the actual # commands in the packet by subtracting off the 1636 // FRAMEINFO event 1637 //..................................................................... 1638 if ( (event->Type==EventClass::FRAMEINFO) && (i > 0)) { 1639 i--; 1640 } 1641 1642 their_recv[index] += i; 1643 } 1644 1645 //------------------------------------------------------------------------ 1646 // If the event was a FRAMESYNC packet, there will be no commands to add, 1647 // but we must check the ScenarioCRC value. 1648 //------------------------------------------------------------------------ 1649 else if (event->Data.FrameInfo.CRC != ScenarioCRC) { 1650 return (RC_SCENARIO_MISMATCH); 1651 } 1652 1653 return (retcode); 1654 1655 } // end of Process_Receive_Packet 1656 1657 1658 /*************************************************************************** 1659 * Process_Serial_Packet -- Handles an incoming serial packet * 1660 * * 1661 * This routine is needed because the modem classes don't support a * 1662 * "global channel" like the network classes do, but that functionality is * 1663 * still needed for modem communications. Specifically, the modem dialogs * 1664 * transmit their own special packets back & forth, and messages are sent * 1665 * using a special packet type. Thus, we have to call this routine when * 1666 * we receive a modem packet, to allow it to process messages & dialog * 1667 * packets. * 1668 * * 1669 * INPUT: * 1670 * multi_packet_buf packet buffer to process * 1671 * first_time 1 = this is the 1st game frame * 1672 * * 1673 * OUTPUT: * 1674 * RC_NORMAL: this wasn't a SERIAL-type packet * 1675 * RC_SERIAL_PROCESSED: this was a SERIAL-type packet, and was * 1676 * processed; the other player is still connected, * 1677 * even if he's not in the game. * 1678 * RC_PLAYER_LEFT: other player has left the game * 1679 * RC_HUNG_UP: we're getting our own packets back; thus, the * 1680 * modem is mirroring our packets, which means the * 1681 * modem hung up! * 1682 * * 1683 * WARNINGS: * 1684 * none. * 1685 * * 1686 * HISTORY: * 1687 * 11/21/1995 BRR : Created. * 1688 *=========================================================================*/ 1689 static RetcodeType Process_Serial_Packet(char *multi_packet_buf, 1690 int first_time) 1691 { 1692 multi_packet_buf; 1693 first_time; 1694 return (RC_NORMAL); 1695 #if (0) // ST - 1/2/2019 5:28PM 1696 SerialPacketType *serial_packet; // for parsing serial packets 1697 int player_gone; 1698 EventClass *event; 1699 char txt[MAX_MESSAGE_LENGTH+80]; 1700 unsigned short magic_number; 1701 unsigned short crc; 1702 1703 //------------------------------------------------------------------------ 1704 // Determine if this packet means that the other player has left the game 1705 //------------------------------------------------------------------------ 1706 serial_packet = (SerialPacketType *)multi_packet_buf; 1707 player_gone = 0; 1708 //........................................................................ 1709 // On Frame 0, only a SIGN_OFF means the other player left; the other 1710 // packet types may be left over from a previous session. 1711 //........................................................................ 1712 if (first_time) { 1713 if (serial_packet->Command == SERIAL_SIGN_OFF) { 1714 player_gone = 1; 1715 } 1716 } 1717 //........................................................................ 1718 // On subsequent frames, any of SIGN_OFF, TIMING, or SCORE_SCREEN means 1719 // the other player is gone. 1720 //........................................................................ 1721 else { 1722 if (serial_packet->Command == SERIAL_SIGN_OFF || 1723 serial_packet->Command == SERIAL_TIMING || 1724 serial_packet->Command == SERIAL_SCORE_SCREEN ) { 1725 player_gone = 1; 1726 } 1727 } 1728 if (player_gone) { 1729 Destroy_Null_Connection(serial_packet->Color, 0); 1730 return (RC_PLAYER_LEFT); 1731 } 1732 1733 //------------------------------------------------------------------------ 1734 // Process an incoming message 1735 //------------------------------------------------------------------------ 1736 if (serial_packet->Command == SERIAL_MESSAGE) { 1737 sprintf(txt, Text_String(TXT_FROM), serial_packet->Name, 1738 serial_packet->Message); 1739 1740 magic_number = *((unsigned short*)(serial_packet->Message + COMPAT_MESSAGE_LENGTH-4)); 1741 crc = *((unsigned short*)(serial_packet->Message + COMPAT_MESSAGE_LENGTH-2)); 1742 1743 Messages.Add_Message (txt, 1744 MPlayerTColors[MPlayerID_To_ColorIndex(serial_packet->ID)], 1745 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 600, magic_number, crc); 1746 1747 //..................................................................... 1748 // Save this message in our last-message buffer 1749 //..................................................................... 1750 if (strlen (serial_packet->Message)) { 1751 strcpy (LastMessage, serial_packet->Message); 1752 } 1753 1754 //..................................................................... 1755 // Tell the map to do a partial update (just to force the 1756 // messages to redraw). 1757 //..................................................................... 1758 Map.Flag_To_Redraw(false); 1759 return (RC_SERIAL_PROCESSED); 1760 } 1761 1762 //------------------------------------------------------------------------ 1763 // Any other SERIAL-type packet means the other player is still there; 1764 // throw them away, but let the caller know the connection is OK. 1765 //------------------------------------------------------------------------ 1766 if ( (serial_packet->Command >= SERIAL_CONNECT && 1767 serial_packet->Command < SERIAL_LAST_COMMAND) || 1768 MPlayerCount == 1) { 1769 return (RC_SERIAL_PROCESSED); 1770 } 1771 1772 //........................................................................ 1773 // are we getting our own packets back?? 1774 //........................................................................ 1775 event = (EventClass *)multi_packet_buf; 1776 if (event->ID == Houses.ID(PlayerPtr)) { 1777 return (RC_HUNG_UP); 1778 } 1779 1780 return (RC_NORMAL); 1781 #endif 1782 } // end of Process_Serial_Packet 1783 1784 1785 /*************************************************************************** 1786 * Can_Advance -- determines if it's OK to advance to the next frame * 1787 * * 1788 * This routine uses the current values stored in their_frame[], * 1789 * their_send[], and their_recv[] to see if it's OK to advance to the next * 1790 * game frame. We must not advance if: * 1791 * - If our frame # would be too far ahead of the slowest player (the * 1792 * lowest their_frame[] value). "Too far" means * 1793 * (Frame > their_frame + MaxAhead). * 1794 * - our current command count doesn't match the sent command count of one * 1795 * other player (meaning that we've missed a command packet from that * 1796 * player, and thus the frame # we're receiving from him may be due to a * 1797 * FRAMEINFO packet sent later than the command, so we shouldn't use * 1798 * this frame # to see if we should advance; we should wait until we * 1799 * have all the commands before we advance. * 1800 * * 1801 * Of course, this routine assumes the values in their_frame[] etc are * 1802 * kept current by the caller. * 1803 * * 1804 * INPUT: * 1805 * net ptr to connection manager * 1806 * max_ahead max frames ahead * 1807 * their_frame array of their frame #'s * 1808 * their_sent array of their sent command count * 1809 * their_recv array of their # received commands * 1810 * * 1811 * OUTPUT: * 1812 * 1 = OK to advance; 0 = not OK * 1813 * * 1814 * WARNINGS: * 1815 * none. * 1816 * * 1817 * HISTORY: * 1818 * 11/21/1995 BRR : Created. * 1819 *=========================================================================*/ 1820 static int Can_Advance(ConnManClass *net, int max_ahead, long *their_frame, 1821 unsigned short *their_sent, unsigned short *their_recv) 1822 { 1823 long their_oldest_frame; // other players' oldest frame # 1824 int count_ok; // true = my cmd count matches theirs 1825 int i; 1826 1827 //------------------------------------------------------------------------ 1828 // Special case for modem: if the other player has left, go ahead and 1829 // advance to the next frame; don't wait on him. 1830 //------------------------------------------------------------------------ 1831 if (MPlayerCount == 1) { 1832 return (1); 1833 } 1834 //------------------------------------------------------------------------ 1835 // Find the oldest frame # in 'their_frame' 1836 //------------------------------------------------------------------------ 1837 their_oldest_frame = Frame + 1000; 1838 for (i = 0; i < net->Num_Connections(); i++) { 1839 if (their_frame[i] < their_oldest_frame) 1840 their_oldest_frame = their_frame[i]; 1841 } 1842 1843 //------------------------------------------------------------------------ 1844 // I can advance to the next frame IF: 1845 // 1) I'm less than a one-way propogation delay ahead of the other 1846 // players' frame numbers, AND 1847 // 2) their_recv[i] >= their_sent[i] (ie I've received all the commands 1848 // the other players have sent so far). 1849 //------------------------------------------------------------------------ 1850 count_ok = 1; 1851 for (i = 0; i < net->Num_Connections(); i++) { 1852 if (their_recv[i] < their_sent[i]) { 1853 count_ok = 0; 1854 break; 1855 } 1856 } 1857 if (count_ok && (Frame < (their_oldest_frame + max_ahead))) { 1858 return (1); 1859 } 1860 1861 return (0); 1862 1863 } // end of Can_Advance 1864 1865 1866 /*************************************************************************** 1867 * Process_Reconnect_Dialog -- processes the reconnection dialog * 1868 * * 1869 * This routine [re]draws the reconnection dialog; if 'reconn' is set, * 1870 * it tells the user who we're trying to reconnect to; otherwise, is just * 1871 * says something generic like "Waiting for connections". * 1872 * * 1873 * INPUT: * 1874 * timeout_timer ptr to count down timer, showing time remaining * 1875 * their_frame array of other players' frame #'s * 1876 * num_conn # connections in 'their_frame' * 1877 * reconn 1 = reconnect, 0 = waiting for first-time connection * 1878 * fresh 1 = draw from scratch, 0 = only update time counter * 1879 * * 1880 * OUTPUT: * 1881 * 1 = user wants to cancel, 0 = not * 1882 * * 1883 * WARNINGS: * 1884 * * 1885 * HISTORY: * 1886 * 11/21/1995 BRR : Created. * 1887 *=========================================================================*/ 1888 static int Process_Reconnect_Dialog(CountDownTimerClass *timeout_timer, 1889 long *their_frame, int num_conn, int reconn, int fresh) 1890 { 1891 static int displayed_time = 0; // time value currently displayed 1892 int new_time; 1893 int oldest_index; // index of person requiring a reconnect 1894 int i,j; 1895 1896 //------------------------------------------------------------------------ 1897 // Convert the timer to seconds 1898 //------------------------------------------------------------------------ 1899 new_time = timeout_timer->Time() / 60; 1900 1901 //-------------------------------------------------------------------------------- 1902 // If we have just received input focus again after running in the background then 1903 // we need to redraw the whole dialog. 1904 //-------------------------------------------------------------------------------- 1905 if (AllSurfaces.SurfacesRestored){ 1906 AllSurfaces.SurfacesRestored=FALSE; 1907 fresh = true; 1908 } 1909 1910 //------------------------------------------------------------------------ 1911 // If the timer has changed, or 'fresh' is set, redraw the dialog 1912 //------------------------------------------------------------------------ 1913 if (fresh || (new_time != displayed_time)) { 1914 //..................................................................... 1915 // Find the index of the person we're trying to reconnect to 1916 //..................................................................... 1917 if (reconn) { 1918 j = 0x7fffffff; 1919 oldest_index = 0; 1920 for (i = 0; i < num_conn; i++) { 1921 if (their_frame[i] < j) { 1922 j = their_frame[i]; 1923 oldest_index = i; 1924 } 1925 } 1926 } 1927 Net_Reconnect_Dialog(reconn, fresh, oldest_index, new_time); 1928 } 1929 displayed_time = new_time; 1930 1931 //........................................................................ 1932 // If user hits ESC, bail out 1933 //........................................................................ 1934 if (Check_Key()) { 1935 if (Get_Key_Num()==KN_ESC) { 1936 return (1); 1937 } 1938 } 1939 1940 return (0); 1941 1942 } // end of Process_Reconnect_Dialog 1943 1944 1945 /*************************************************************************** 1946 * Handle_Timeout -- handles a timeout in the wait-for-players loop * 1947 * * 1948 * This routine "gracefully" handles a timeout in the frame-sync loop. * 1949 * The timeout must be handled differently by a modem game or network * 1950 * game. * 1951 * * 1952 * The modem game must detect if the other player is still connected * 1953 * physically, even if he's not playing the game any more; if so, this * 1954 * routine returns an OK status. If the other player isn't even * 1955 * physically connected, an error is returned. * 1956 * * 1957 * The network game must find the connection that's causing the timeout, * 1958 * and destroy it. The game continues, even if there are no more human * 1959 * players left. * 1960 * * 1961 * INPUT: * 1962 * net ptr to connection manager * 1963 * their_frame array containing frame #'s of other players * 1964 * their_sent array containing command count of other players * 1965 * their_recv array containing # recv'd cmds from other players * 1966 * * 1967 * OUTPUT: * 1968 * 1 = it's OK; reset timeout timers & keep processing * 1969 * 0 = game over, man * 1970 * * 1971 * WARNINGS: * 1972 * * 1973 * HISTORY: * 1974 * 11/21/1995 BRR : Created. * 1975 *=========================================================================*/ 1976 static int Handle_Timeout(ConnManClass *net, long *their_frame, 1977 unsigned short *their_sent, unsigned short *their_recv) 1978 { 1979 int oldest_index; // index of person requiring a reconnect 1980 int i,j; 1981 int id; 1982 1983 //------------------------------------------------------------------------ 1984 // For modem, attempt to reconnect; if that fails, save the game & bail. 1985 //------------------------------------------------------------------------ 1986 if (GameToPlay == GAME_MODEM || GameToPlay == GAME_NULL_MODEM) { 1987 #if (0) //ST - 1/2/2019 5:28PM 1988 if ( net->Num_Connections() ) { 1989 if (!Reconnect_Modem()) { 1990 return (0); 1991 } 1992 else { 1993 return (1); 1994 } 1995 } 1996 #endif 1997 } 1998 1999 //------------------------------------------------------------------------ 2000 // For network, destroy the oldest connection 2001 //------------------------------------------------------------------------ 2002 else if (GameToPlay == GAME_IPX || GameToPlay == GAME_INTERNET) { 2003 j = 0x7fffffff; 2004 oldest_index = 0; 2005 for (i = 0; i < net->Num_Connections(); i++) { 2006 if (their_frame[i] < j) { 2007 j = their_frame[i]; 2008 oldest_index = i; 2009 } 2010 } 2011 2012 id = net->Connection_ID(oldest_index); 2013 2014 /* 2015 ** Send the game statistics packet now if the game is effectivly over 2016 */ 2017 if (MPlayerCount == 2 && 2018 GameToPlay == GAME_INTERNET && 2019 !GameStatisticsPacketSent){ 2020 Register_Game_End_Time(); 2021 ConnectionLost = true; 2022 Send_Statistics_Packet(); 2023 } 2024 2025 if (id != ConnManClass::CONNECTION_NONE) { 2026 for (i = oldest_index; i < net->Num_Connections() - 1; i++) { 2027 their_frame[i] = their_frame[i+1]; 2028 their_sent[i] = their_sent[i+1]; 2029 their_recv[i] = their_recv[i+1]; 2030 } 2031 CCDebugString ("C&C95 = Destroying connection due to time out\n"); 2032 Destroy_Connection(id,1); 2033 } 2034 } 2035 2036 return (1); 2037 2038 } // end of Handle_Timeout 2039 2040 2041 /*************************************************************************** 2042 * Stop_Game -- stops the game * 2043 * * 2044 * This routine clears any global flags that need it, in preparation for * 2045 * halting the game prematurely. * 2046 * * 2047 * INPUT: * 2048 * none. * 2049 * * 2050 * OUTPUT: * 2051 * none. * 2052 * * 2053 * WARNINGS: * 2054 * none. * 2055 * * 2056 * HISTORY: * 2057 * 11/22/1995 BRR : Created. * 2058 *=========================================================================*/ 2059 static void Stop_Game(void) 2060 { 2061 CCDebugString ("C&C95 - In Stop_Game.\n"); 2062 GameActive = 0; 2063 if (IsMono) { 2064 MonoClass::Disable(); 2065 } 2066 2067 if (GameToPlay == GAME_INTERNET){ 2068 ConnectionLost = true; 2069 CCDebugString ("C&C95 - About to send statistics packet.\n"); 2070 Register_Game_End_Time(); 2071 Send_Statistics_Packet(); 2072 CCDebugString ("C&C95 - Returned from sending stats packet.\n"); 2073 } 2074 2075 return; 2076 2077 } // end of Stop_Game 2078 2079 2080 /*************************************************************************** 2081 * Build_Send_Packet -- Builds a big packet from a bunch of little ones. * 2082 * * 2083 * This routine takes events from the OutList, and puts them into a * 2084 * "meta-packet", which is transmitted to all systems we're connected to. * 2085 * Also, these events are added to our own DoList. * 2086 * * 2087 * Every Meta-Packet we send uses a FRAMEINFO packet as a header; this * 2088 * tells the other systems what frame we're on, as well as serving as a * 2089 * standard packet header. * 2090 * * 2091 * INPUT: * 2092 * buf buffer to store packet in * 2093 * bufsize max size of buffer * 2094 * frame_delay desired frame delay to attach to all outgoing packets * 2095 * num_cmds value to use for the CommandCount field * 2096 * cap max # events to send * 2097 * * 2098 * OUTPUT: * 2099 * new size of packet * 2100 * * 2101 * WARNINGS: * 2102 * 'num_cmds' should be the total of of commands, including all those sent * 2103 * this frame! * 2104 * * 2105 * HISTORY: * 2106 * 11/21/1995 BRR : Created. * 2107 *=========================================================================*/ 2108 static int Build_Send_Packet(void *buf, int bufsize, int frame_delay, 2109 int num_cmds, int cap) 2110 { 2111 int size = 0; 2112 EventClass *finfo; 2113 2114 //------------------------------------------------------------------------ 2115 // All events start with a FRAMEINFO event; fill this part in. 2116 //------------------------------------------------------------------------ 2117 //........................................................................ 2118 // Set the event type 2119 //........................................................................ 2120 finfo = (EventClass *)buf; 2121 finfo->Type = EventClass::FRAMEINFO; 2122 //........................................................................ 2123 // Set the frame to execute this event on; this is protocol-specific 2124 //........................................................................ 2125 if (CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) { 2126 finfo->Frame = ((Frame + frame_delay + (FrameSendRate - 1)) / 2127 FrameSendRate) * FrameSendRate; 2128 } 2129 else { 2130 finfo->Frame = Frame + frame_delay; 2131 } 2132 //........................................................................ 2133 // Fill in the rest of the event 2134 //........................................................................ 2135 finfo->ID = Houses.ID(PlayerPtr); 2136 finfo->MPlayerID = MPlayerLocalID; 2137 finfo->Data.FrameInfo.CRC = GameCRC; 2138 finfo->Data.FrameInfo.CommandCount = num_cmds; 2139 finfo->Data.FrameInfo.Delay = frame_delay; 2140 2141 //------------------------------------------------------------------------ 2142 // Initialize the # of bytes processed; this is protocol-specific 2143 //------------------------------------------------------------------------ 2144 if (CommProtocol==COMM_PROTOCOL_SINGLE_NO_COMP) { 2145 size += sizeof(EventClass); 2146 } 2147 else { 2148 size += (offsetof(EventClass, Data) + 2149 size_of(EventClass, Data.FrameInfo)); 2150 } 2151 2152 //------------------------------------------------------------------------ 2153 // Transfer all events from the OutList into the DoList, building our 2154 // packet while we go. 2155 //------------------------------------------------------------------------ 2156 switch (CommProtocol) { 2157 //..................................................................... 2158 // COMM_PROTOCOL_SINGLE_NO_COMP: 2159 // We'll send at least a FRAMEINFO every single frame, no compression 2160 //..................................................................... 2161 case (COMM_PROTOCOL_SINGLE_NO_COMP): 2162 size = Add_Uncompressed_Events(buf, bufsize, frame_delay, size, cap); 2163 break; 2164 2165 //..................................................................... 2166 // COMM_PROTOCOL_SINGLE_E_COMP: 2167 // Compress a group of packets into our send buffer; send out 2168 // compressed packets every frame. 2169 // COMM_PROTOCOL_MULTI_E_COMP: 2170 // Compress a group of packets into our send buffer; send out 2171 // compressed packets every 'n' frames. 2172 //..................................................................... 2173 case (COMM_PROTOCOL_SINGLE_E_COMP): 2174 case (COMM_PROTOCOL_MULTI_E_COMP): 2175 size = Add_Compressed_Events(buf, bufsize, frame_delay, size, cap); 2176 break; 2177 2178 //..................................................................... 2179 // Default: We have no idea what to do, so do nothing. 2180 //..................................................................... 2181 default: 2182 size = 0; 2183 break; 2184 } 2185 2186 return( size ); 2187 2188 } /* end of Build_Send_Packet */ 2189 2190 2191 /*************************************************************************** 2192 * Add_Uncompressed_Events -- adds uncompressed events to a packet * 2193 * * 2194 * INPUT: * 2195 * buf buffer to store packet in * 2196 * bufsize max size of buffer * 2197 * frame_delay desired frame delay to attach to all outgoing packets * 2198 * size current packet size * 2199 * cap max # events to process * 2200 * * 2201 * OUTPUT: * 2202 * new size value * 2203 * * 2204 * WARNINGS: * 2205 * This routine MUST check to be sure it doesn't overflow the buffer. * 2206 * * 2207 * HISTORY: * 2208 * 11/21/1995 DRD : Created. * 2209 *=========================================================================*/ 2210 static int Add_Uncompressed_Events(void *buf, int bufsize, int frame_delay, 2211 int size, int cap) 2212 { 2213 int num = 0; // # of events processed 2214 int ev_size; // size of event we're adding 2215 2216 //------------------------------------------------------------------------ 2217 // Loop until there are no more events, or we've processed our max # of 2218 // events, or the buffer is full. 2219 //------------------------------------------------------------------------ 2220 while (OutList.Count && (num < cap)) { 2221 ev_size = sizeof(EventClass); 2222 //..................................................................... 2223 // Will the next event exceed the size of the buffer? If so, break. 2224 //..................................................................... 2225 if ( (size + ev_size) > bufsize ) { 2226 return (size); 2227 } 2228 2229 //..................................................................... 2230 // Set the event's frame delay 2231 //..................................................................... 2232 OutList.First().Frame = Frame + frame_delay; 2233 2234 //..................................................................... 2235 // Set the event's ID 2236 //..................................................................... 2237 OutList.First().ID = Houses.ID(PlayerPtr); 2238 OutList.First().MPlayerID = MPlayerLocalID; 2239 2240 //..................................................................... 2241 // Transfer the event in OutList to DoList, un-queue the OutList 2242 // event. If the DoList is full, stop transferring immediately. 2243 //..................................................................... 2244 OutList.First().IsExecuted = 0; 2245 if (!DoList.Add(OutList.First())) { 2246 return (size); 2247 } 2248 2249 //..................................................................... 2250 // Add event to the send packet 2251 //..................................................................... 2252 memcpy ( ((char *)buf) + size, &OutList.First(), sizeof(EventClass) ); 2253 size += sizeof(EventClass); 2254 2255 //..................................................................... 2256 // Increment our event counter; delete the last event from the queue 2257 //..................................................................... 2258 num++; 2259 OutList.Next(); 2260 } 2261 2262 return (size); 2263 2264 } // end of Add_Uncompressed_Events 2265 2266 2267 /*************************************************************************** 2268 * Add_Compressed_Events -- adds an compressed events to a packet * 2269 * * 2270 * INPUT: * 2271 * buf buffer to store packet in * 2272 * bufsize max size of buffer * 2273 * frame_delay desired frame delay to attach to all outgoing packets * 2274 * size reference to current packet size * 2275 * cap max # events to process * 2276 * * 2277 * OUTPUT: * 2278 * new size value * 2279 * * 2280 * WARNINGS: * 2281 * This routine MUST check to be sure it doesn't overflow the buffer. * 2282 * * 2283 * HISTORY: * 2284 * 11/21/1995 DRD : Created. * 2285 *=========================================================================*/ 2286 static int Add_Compressed_Events(void *buf, int bufsize, int frame_delay, 2287 int size, int cap) 2288 { 2289 int num = 0; // # of events processed 2290 EventClass::EventType eventtype; // type of event being compressed 2291 EventClass prevevent; // last event processed 2292 int datasize; // size of element plucked from event union 2293 int storedsize; // actual # bytes stored from event 2294 unsigned char *unitsptr = NULL; // ptr to buffer pos to store mega. rep count 2295 unsigned char numunits = 0; // megamission rep count value 2296 bool missiondup = false; // flag: is this event a megamission repeat? 2297 2298 //------------------------------------------------------------------------ 2299 // clear previous event 2300 //------------------------------------------------------------------------ 2301 memset (&prevevent, 0, sizeof(EventClass)); 2302 2303 //------------------------------------------------------------------------ 2304 // Loop until there are no more events, we've processed our max # of 2305 // events, or the buffer is full. 2306 //------------------------------------------------------------------------ 2307 while (OutList.Count && (num < cap)) { 2308 eventtype = OutList.First().Type; 2309 datasize = EventClass::EventLength[ eventtype ]; 2310 //..................................................................... 2311 // For a variable-sized event, pull the size from the event; otherwise, 2312 // the size will be the data element size plus the event type value. 2313 //..................................................................... 2314 storedsize = datasize + sizeof (EventClass::EventType); 2315 2316 //..................................................................... 2317 // MegaMission compression: MegaMissions are stored as: 2318 // EventType 2319 // Rep Count 2320 // MegaMission structure (event # 1 only) 2321 // Whom #2 2322 // Whom #3 2323 // Whom #4 2324 // ... 2325 // Whom #n 2326 //..................................................................... 2327 if (prevevent.Type == EventClass::MEGAMISSION) { 2328 //.................................................................. 2329 // If previous & current events are both MegaMissions: 2330 //.................................................................. 2331 if (eventtype == EventClass::MEGAMISSION) { 2332 //............................................................... 2333 // If the Mission, Target, & Destination are the same, compress 2334 // the events into one: 2335 // - Change datasize to the size of the 'Whom' field only 2336 // - set total # bytes to store to the size of the 'Whom' only 2337 // - increment the MegaMission rep count 2338 // - set the MegaMission rep flag 2339 //............................................................... 2340 if (OutList.First().Data.MegaMission.Mission == 2341 prevevent.Data.MegaMission.Mission && 2342 OutList.First().Data.MegaMission.Target == 2343 prevevent.Data.MegaMission.Target && 2344 OutList.First().Data.MegaMission.Destination == 2345 prevevent.Data.MegaMission.Destination) { 2346 2347 datasize = sizeof(prevevent.Data.MegaMission.Whom); 2348 storedsize = datasize; 2349 numunits++; 2350 missiondup = true; 2351 } 2352 //............................................................... 2353 // Data doesn't match; start a new run of MegaMissions: 2354 // - Store previous MegaMission rep count 2355 // - Init 'unitsptr' to buffer pos after next EventType 2356 // - set total # bytes to store to 'datasize' + sizeof(EventType) + 2357 // sizeof (numunits) 2358 // - init the MegaMission rep count to 1 2359 // - clear the MegaMission rep flag 2360 //............................................................... 2361 else { 2362 *unitsptr = numunits; 2363 unitsptr = ((unsigned char *)buf) + size + 2364 sizeof(EventClass::EventType); 2365 storedsize += sizeof(numunits); 2366 numunits = 1; 2367 missiondup = false; 2368 } 2369 } 2370 //.................................................................. 2371 // Previous event was a MegaMission, but this one isn't: end the 2372 // run of MegaMissions: 2373 // - Store previous MegaMission rep count 2374 // - Clear variables 2375 //.................................................................. 2376 else { 2377 *unitsptr = numunits; // save # events in our run 2378 unitsptr = NULL; // init other values 2379 numunits = 0; 2380 missiondup = false; 2381 } 2382 } 2383 2384 //..................................................................... 2385 // The previous event is not a MEGAMISSION but the current event is: 2386 // Set up a new run of MegaMissions: 2387 // - Init 'unitsptr' to buffer pos after next EventType 2388 // - set total # bytes to store to 'datasize' + sizeof(EventType) + 2389 // sizeof (numunits) 2390 // - init the MegaMission rep count to 1 2391 // - clear the MegaMission rep flag 2392 //..................................................................... 2393 else if (eventtype == EventClass::MEGAMISSION) { 2394 unitsptr = ((unsigned char *)buf) + size + 2395 sizeof(EventClass::EventType); 2396 storedsize += sizeof(numunits); 2397 numunits = 1; 2398 missiondup = false; 2399 } 2400 2401 //..................................................................... 2402 // Will the next event exceed the size of the buffer? If so, 2403 // stop compressing. 2404 //..................................................................... 2405 if ( (size + storedsize) > bufsize ) 2406 break; 2407 2408 //..................................................................... 2409 // Set the event's frame delay (this is protocol-dependent) 2410 //..................................................................... 2411 if (CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) { 2412 OutList.First().Frame = ((Frame + frame_delay + 2413 (FrameSendRate - 1)) / FrameSendRate) * 2414 FrameSendRate; 2415 } 2416 else { 2417 OutList.First().Frame = Frame + frame_delay; 2418 } 2419 2420 //..................................................................... 2421 // Set the event's ID 2422 //..................................................................... 2423 OutList.First().ID = Houses.ID(PlayerPtr); 2424 OutList.First().MPlayerID = MPlayerLocalID; 2425 2426 //..................................................................... 2427 // Transfer the event in OutList to DoList, un-queue the OutList event. 2428 // If the DoList is full, stop transferring immediately. 2429 //..................................................................... 2430 OutList.First().IsExecuted = 0; 2431 if ( !DoList.Add( OutList.First() ) ) { 2432 break; 2433 } 2434 2435 //--------------------------------------------------------------------- 2436 // Compress the event into the send packet buffer 2437 //--------------------------------------------------------------------- 2438 switch ( eventtype ) { 2439 //.................................................................. 2440 // RESPONSE_TIME: just use the Delay field of the FrameInfo union 2441 //.................................................................. 2442 case (EventClass::RESPONSE_TIME): 2443 2444 *(EventClass::EventType *)( ((char *)buf) + size) = eventtype; 2445 2446 memcpy ( ((char *)buf) + size + sizeof(EventClass::EventType), 2447 &OutList.First().Data.FrameInfo.Delay, datasize ); 2448 2449 size += (datasize + sizeof(EventClass::EventType)); 2450 break; 2451 2452 //.................................................................. 2453 // MEGAMISSION: 2454 //.................................................................. 2455 case (EventClass::MEGAMISSION): 2456 //............................................................... 2457 // Repeated mission in a run: 2458 // - Update the rep count (in case we break out) 2459 // - Copy the Whom field only 2460 //............................................................... 2461 if (missiondup) { 2462 *unitsptr = numunits; 2463 2464 memcpy ( ((char *)buf) + size, 2465 &OutList.First().Data.MegaMission.Whom, datasize ); 2466 2467 size += datasize; 2468 } 2469 //............................................................... 2470 // 1st mission in a run: 2471 // - Init the rep count (in case we break out) 2472 // - Set the EventType 2473 // - Copy the MegaMission structure, leaving room for 'numunits' 2474 //............................................................... 2475 else { 2476 *unitsptr = numunits; 2477 2478 *(EventClass::EventType *)( ((char *)buf) + size) = eventtype; 2479 2480 memcpy ( ((char *)buf) + size + 2481 sizeof(EventClass::EventType) + sizeof(numunits), 2482 &OutList.First().Data.MegaMission, datasize ); 2483 2484 size += (datasize + sizeof(EventClass::EventType) + sizeof(numunits)); 2485 } 2486 break; 2487 2488 //.................................................................. 2489 // Default case: Just copy over the data field from the union 2490 //.................................................................. 2491 default: 2492 *(EventClass::EventType *)( ((char *)buf) + size) = eventtype; 2493 2494 memcpy ( ((char *)buf) + size + sizeof(EventClass::EventType), 2495 &OutList.First().Data, datasize ); 2496 2497 size += (datasize + sizeof(EventClass::EventType)); 2498 2499 break; 2500 } 2501 2502 //--------------------------------------------------------------------- 2503 // update # events processed 2504 //--------------------------------------------------------------------- 2505 num++; 2506 2507 //--------------------------------------------------------------------- 2508 // Update 'prevevent' 2509 //--------------------------------------------------------------------- 2510 memcpy ( &prevevent, &OutList.First(), sizeof(EventClass) ); 2511 2512 //--------------------------------------------------------------------- 2513 // Go to the next event to process 2514 //--------------------------------------------------------------------- 2515 OutList.Next(); 2516 } 2517 2518 return (size); 2519 2520 } // end of Add_Compressed_Events 2521 2522 2523 /*************************************************************************** 2524 * Breakup_Receive_Packet -- Splits a big packet into little ones. * 2525 * * 2526 * INPUT: * 2527 * buf buffer to break up * 2528 * bufsize length of buffer * 2529 * * 2530 * OUTPUT: * 2531 * # events added to queue, -1 if fatal error (queue is full) * 2532 * (return value includes any FRAMEINFO packets encountered; * 2533 * FRAMESYNC's are ignored) * 2534 * * 2535 * WARNINGS: * 2536 * none. * 2537 * * 2538 * HISTORY: * 2539 * 11/21/1995 BRR : Created. * 2540 *=========================================================================*/ 2541 static int Breakup_Receive_Packet(void *buf, int bufsize ) 2542 { 2543 int count = 0; 2544 2545 /* 2546 ** is there enough leftover for another record 2547 */ 2548 switch (CommProtocol) { 2549 case (COMM_PROTOCOL_SINGLE_NO_COMP): 2550 count = Extract_Uncompressed_Events(buf, bufsize); 2551 break; 2552 2553 default: 2554 count = Extract_Compressed_Events(buf, bufsize); 2555 break; 2556 } 2557 2558 return (count); 2559 2560 } /* end of Breakup_Receive_Packet */ 2561 2562 2563 /*************************************************************************** 2564 * Extract_Uncompressed_Events -- extracts events from a packet * 2565 * * 2566 * INPUT: * 2567 * buf buffer containing events to extract * 2568 * bufsize length of 'buf' * 2569 * * 2570 * OUTPUT: * 2571 * # events extracted * 2572 * * 2573 * WARNINGS: * 2574 * none. * 2575 * * 2576 * HISTORY: * 2577 * 11/21/1995 DRD : Created. * 2578 *=========================================================================*/ 2579 static int Extract_Uncompressed_Events(void *buf, int bufsize) 2580 { 2581 int count = 0; 2582 int pos = 0; 2583 int leftover = bufsize; 2584 EventClass *event; 2585 2586 //------------------------------------------------------------------------ 2587 // Loop until there are no more events in the packet 2588 //------------------------------------------------------------------------ 2589 while (leftover >= sizeof(EventClass) ) { 2590 event = (EventClass *)(((char *)buf) + pos); 2591 2592 //..................................................................... 2593 // add event to the DoList, only if it's not a FRAMESYNC 2594 // (but FRAMEINFO's do get added.) 2595 //..................................................................... 2596 if (event->Type != EventClass::FRAMESYNC) { 2597 event->IsExecuted = 0; 2598 2599 if (!DoList.Add( *event )) { 2600 return (-1); 2601 } 2602 2603 //.................................................................. 2604 // Keep count of how many events we add to the queue 2605 //.................................................................. 2606 count++; 2607 } 2608 2609 //..................................................................... 2610 // Point to the next position in the buffer; decrement our 'leftover' 2611 //..................................................................... 2612 pos += sizeof(EventClass); 2613 leftover -= sizeof(EventClass); 2614 } 2615 2616 return (count); 2617 2618 } // end of Extract_Uncompressed_Events 2619 2620 2621 /*************************************************************************** 2622 * Extract_Compressed_Events -- extracts events from a packet * 2623 * * 2624 * INPUT: * 2625 * buf buffer containing events to extract * 2626 * bufsize length of 'buf' * 2627 * * 2628 * OUTPUT: * 2629 * # events extracted * 2630 * * 2631 * WARNINGS: * 2632 * none. * 2633 * * 2634 * HISTORY: * 2635 * 11/21/1995 DRD : Created. * 2636 *=========================================================================*/ 2637 static int Extract_Compressed_Events(void *buf, int bufsize) 2638 { 2639 int pos = 0; // current buffer parsing position 2640 int leftover = bufsize; // # bytes left to process 2641 EventClass *event; // event ptr for parsing buffer 2642 int count = 0; // # events processed 2643 int datasize = 0; // size of data to copy 2644 EventClass eventdata; // stores Frame, ID, etc 2645 unsigned char numunits = 0; // # units stored in compressed MegaMissions 2646 //int lasteventtype=0; 2647 //------------------------------------------------------------------------ 2648 // Clear work event structure 2649 //------------------------------------------------------------------------ 2650 memset (&eventdata, 0, sizeof(EventClass)); 2651 2652 //------------------------------------------------------------------------ 2653 // Assume the first event is a FRAMEINFO event 2654 // Init 'datasize' to the amount of data to copy, minus the EventType value 2655 // For the 1st packet only, this will include all info before the Data 2656 // union, plus the size of the FrameInfo structure, minus the EventType size. 2657 //------------------------------------------------------------------------ 2658 datasize = (offsetof(EventClass, Data) + 2659 size_of(EventClass, Data.FrameInfo)) - sizeof(EventClass::EventType); 2660 event = (EventClass *)(((char *)buf) + pos); 2661 2662 while ((unsigned)leftover >= (datasize + sizeof(EventClass::EventType)) ) { 2663 //..................................................................... 2664 // add event to the DoList, only if it's not a FRAMESYNC 2665 // (but FRAMEINFO's do get added.) 2666 //..................................................................... 2667 if (event->Type != EventClass::FRAMESYNC) { 2668 //.................................................................. 2669 // initialize the common data from the FRAMEINFO event 2670 // keeping IsExecuted 0 2671 //.................................................................. 2672 if (event->Type == EventClass::FRAMEINFO) { 2673 eventdata.Frame = event->Frame; 2674 eventdata.ID = event->ID; 2675 eventdata.MPlayerID = event->MPlayerID; 2676 2677 //............................................................... 2678 // Adjust position past the common data 2679 //............................................................... 2680 pos += (offsetof(EventClass, Data) - 2681 sizeof(EventClass::EventType)); 2682 leftover -= (offsetof(EventClass, Data) - 2683 sizeof(EventClass::EventType)); 2684 } 2685 //.................................................................. 2686 // if MEGAMISSION event get the number of units (events to generate) 2687 //.................................................................. 2688 else if (event->Type == EventClass::MEGAMISSION) { 2689 numunits = *(((unsigned char *)buf) + pos + sizeof(eventdata.Type)); 2690 pos += sizeof(numunits); 2691 leftover -= sizeof(numunits); 2692 } 2693 2694 //.................................................................. 2695 // clear the union data portion of the event 2696 //.................................................................. 2697 memset (&eventdata.Data, 0, sizeof(eventdata.Data)); 2698 eventdata.Type = event->Type; 2699 datasize = EventClass::EventLength[ eventdata.Type ]; 2700 2701 switch (eventdata.Type) { 2702 case (EventClass::RESPONSE_TIME): 2703 memcpy ( &eventdata.Data.FrameInfo.Delay, 2704 ((char *)buf) + pos + sizeof(EventClass::EventType), 2705 datasize ); 2706 break; 2707 2708 case (EventClass::MEGAMISSION): 2709 memcpy ( &eventdata.Data.MegaMission, 2710 ((char *)buf) + pos + sizeof(EventClass::EventType), 2711 datasize ); 2712 2713 if (numunits > 1) { 2714 pos += (datasize + sizeof(EventClass::EventType)); 2715 leftover -= (datasize + sizeof(EventClass::EventType)); 2716 datasize = sizeof(eventdata.Data.MegaMission.Whom); 2717 2718 while (numunits) { 2719 if ( !DoList.Add( eventdata ) ) { 2720 return (-1); 2721 } 2722 2723 //...................................................... 2724 // Keep count of how many events we add to the queue 2725 //...................................................... 2726 count++; 2727 numunits--; 2728 memcpy ( &eventdata.Data.MegaMission.Whom, 2729 ((char *)buf) + pos, datasize ); 2730 2731 //...................................................... 2732 // if one unit left fall thru to normal code 2733 //...................................................... 2734 if (numunits == 1) { 2735 datasize -= sizeof(EventClass::EventType); 2736 break; 2737 } 2738 else { 2739 pos += datasize; 2740 leftover -= datasize; 2741 } 2742 } 2743 } 2744 break; 2745 2746 default: 2747 memcpy ( &eventdata.Data, 2748 ((char *)buf) + pos + sizeof(EventClass::EventType), 2749 datasize ); 2750 break; 2751 } 2752 2753 char flip[128]; 2754 sprintf (flip, "C&C95 - Adding event type %d to queue\n", eventdata.Type); 2755 CCDebugString (flip); 2756 2757 //if (lasteventtype == 11){ 2758 // break; 2759 //} 2760 2761 //lasteventtype = (int) eventdata.Type; 2762 2763 2764 if ( !DoList.Add( eventdata ) ) { 2765 return (-1); 2766 } 2767 2768 //.................................................................. 2769 // Keep count of how many events we add to the queue 2770 //.................................................................. 2771 count++; 2772 2773 pos += (datasize + sizeof(EventClass::EventType)); 2774 leftover -= (datasize + sizeof(EventClass::EventType)); 2775 2776 if (leftover) { 2777 event = (EventClass *)(((char *)buf) + pos); 2778 datasize = EventClass::EventLength[ event->Type ]; 2779 if (event->Type == EventClass::MEGAMISSION) { 2780 datasize += sizeof(numunits); 2781 } 2782 } 2783 } 2784 //..................................................................... 2785 // FRAMESYNC event: This >should< be the only event in the buffer, 2786 // and it will be uncompressed. 2787 //..................................................................... 2788 else { 2789 pos += (datasize + sizeof(EventClass::EventType)); 2790 leftover -= (datasize + sizeof(EventClass::EventType)); 2791 event = (EventClass *)(((char *)buf) + pos); 2792 2793 //.................................................................. 2794 // size of FRAMESYNC event - EventType size 2795 //.................................................................. 2796 datasize = (offsetof(EventClass, Data) + 2797 size_of(EventClass, Data.FrameInfo)) - 2798 sizeof(EventClass::EventType); 2799 } 2800 } 2801 2802 return (count); 2803 2804 } // end of Extract_Compressed_Events 2805 2806 #endif //DEMO 2807 2808 /*************************************************************************** 2809 * Execute_DoList -- Executes commands from the DoList * 2810 * * 2811 * This routine executes any events in the DoList that need to be executed * 2812 * on the current game frame. The events must be executed in a special * 2813 * order, so that all systems execute all events in exactly the same * 2814 * order. * 2815 * * 2816 * This routine also handles checking the Game CRC sent by other systems * 2817 * against my own, to be sure we're still in sync. * 2818 * * 2819 * INPUT: * 2820 * max_houses # houses to execute commands for * 2821 * base_house HousesType to start with * 2822 * net ptr to connection manager; NULL if none * 2823 * skip_crc a frame-based countdown timer; if it's non-zero, the * 2824 * CRC check will be skipped. Ignored if NULL. * 2825 * their_frame array of their frame #'s * 2826 * their_sent array of # commands they've sent * 2827 * their_recv array of # commands I've received from them * 2828 * * 2829 * (their_xxx are ignored if 'net' is NULL.) * 2830 * * 2831 * OUTPUT: * 2832 * 1 = OK, 0 = some error occurred (CRC error, packet rcv'd too late.) * 2833 * * 2834 * WARNINGS: * 2835 * * 2836 * HISTORY: * 2837 * 11/21/1995 BRR : Created. * 2838 *=========================================================================*/ 2839 static int Execute_DoList(int , HousesType , 2840 ConnManClass *net, TCountDownTimerClass *, 2841 long *their_frame, unsigned short *their_sent, unsigned short *their_recv) 2842 { 2843 int i,j,k,wibble; 2844 int index; 2845 2846 //------------------------------------------------------------------------ 2847 // For a single-player game, just execute all events in the queue. 2848 //------------------------------------------------------------------------ 2849 if (GameToPlay == GAME_NORMAL) { 2850 for (i = 0; i < DoList.Count; i++) { 2851 if ((unsigned)Frame >= DoList[i].Frame && !DoList[i].IsExecuted) { 2852 DoList[i].Execute(); // execute it 2853 DoList[i].IsExecuted = true; // mark as having been executed 2854 } 2855 } 2856 return (1); 2857 } 2858 2859 //#if(TIMING_FIX) 2860 // 2861 // If MPlayerMaxAhead is recomputed such that it increases, the systems 2862 // may try to free-run to the new MaxAhead value. If so, they may miss 2863 // an event that was generated after the TIMING event was created, but 2864 // before it executed; this event will be scheduled with the older, 2865 // shorter MaxAhead value. If a system doesn't receive this event, it 2866 // may execute past the frame it's scheduled to execute on, creating 2867 // a Packet-Recieved-Too-Late error. To prevent this, find any events 2868 // that are scheduled to execute during this "period of vulnerability", 2869 // and re-schedule for the end of that period. 2870 // 2871 if (CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) { 2872 for (j = 0; j < DoList.Count; j++) { 2873 if (DoList[j].Type != EventClass::FRAMEINFO && 2874 DoList[j].Frame > (unsigned)NewMaxAheadFrame1 && 2875 DoList[j].Frame < (unsigned)NewMaxAheadFrame2) { 2876 DoList[j].Frame = (unsigned)NewMaxAheadFrame2; 2877 } 2878 } 2879 } 2880 //#endif 2881 2882 //------------------------------------------------------------------------ 2883 // Execute the DoList. Events must be executed in the same order on all 2884 // systems; so, execute them in the order of the MPlayerID array. This 2885 // array is stored in the same order on all systems. 2886 //------------------------------------------------------------------------ 2887 for (i = 0; i < MPlayerCount; i++) { 2888 2889 HousesType house; 2890 HouseClass *housep; 2891 2892 house = MPlayerHouses [i]; 2893 housep= HouseClass::As_Pointer (house); 2894 2895 //..................................................................... 2896 // If for some reason this house doesn't exist, skip it. 2897 // Also, if this house has exited the game, skip it. (The user can 2898 // generate events after he exits, because the exit event is scheduled 2899 // at least FrameSendRate*3 frames ahead. If one system gets these 2900 // packets & another system doesn't, they'll go out of sync because 2901 // they aren't checking the CommandCount for that house, since that 2902 // house isn't connected any more.) 2903 //..................................................................... 2904 if (!housep){ 2905 continue; 2906 } 2907 2908 if (!housep->IsHuman){ 2909 continue; 2910 } 2911 2912 //..................................................................... 2913 // Loop through all events 2914 //..................................................................... 2915 for (j = 0; j < DoList.Count; j++) { 2916 2917 #ifndef DEMO 2918 if (net) 2919 Update_Queue_Mono (net, 6); 2920 #endif //DEMO 2921 2922 //.................................................................. 2923 // If this event was from the currently-executing player ID, and it's 2924 // time to execute it, execute it. 2925 //.................................................................. 2926 if (DoList[j].MPlayerID == MPlayerID[i] && (unsigned)Frame >= DoList[j].Frame && 2927 !DoList[j].IsExecuted) { 2928 2929 //............................................................... 2930 // Error if it's too late to execute this packet! 2931 //............................................................... 2932 if ((unsigned)Frame > DoList[j].Frame && DoList[j].Type != 2933 EventClass::FRAMEINFO) { 2934 #ifndef DEMO 2935 Dump_Packet_Too_Late_Stuff(&DoList[j]); 2936 #endif //DEMO 2937 CCMessageBox().Process (TXT_PACKET_TOO_LATE); 2938 return (0); 2939 } 2940 2941 //............................................................... 2942 // Only execute EXIT & OPTIONS commands if they're from myself. 2943 //............................................................... 2944 if (DoList[j].Type==EventClass::EXIT || 2945 DoList[j].Type==EventClass::OPTIONS) { 2946 2947 2948 if (DoList[j].Type==EventClass::EXIT){ 2949 CCDebugString ("C&C95 - Received EXIT packet\n"); 2950 2951 /* 2952 ** Flag that this house lost because it quit. ST - 6/5/96 0:29AM 2953 */ 2954 for (wibble = 0; wibble < MPlayerCount; wibble++) { 2955 if (MPlayerID[wibble] == DoList[j].MPlayerID) { 2956 house = MPlayerHouses[wibble]; 2957 housep = HouseClass::As_Pointer (house); 2958 housep->IGaveUp = true; 2959 break; 2960 } 2961 } 2962 2963 /* 2964 ** Send the game statistics packet now since the game is effectivly over 2965 */ 2966 if (MPlayerCount == 2 && 2967 GameToPlay == GAME_INTERNET && 2968 !GameStatisticsPacketSent){ 2969 Register_Game_End_Time(); 2970 Send_Statistics_Packet(); 2971 } 2972 } 2973 2974 2975 2976 if (DoList[j].ID == Houses.ID(PlayerPtr)) { 2977 DoList[j].Execute(); 2978 } 2979 2980 //............................................................ 2981 // If this EXIT event isn't from myself, destroy the connection 2982 // for that player. The HousesType for this event is the 2983 // connection ID. 2984 //............................................................ 2985 else if (DoList[j].Type==EventClass::EXIT) { 2986 if (GameToPlay == GAME_MODEM 2987 || GameToPlay == GAME_NULL_MODEM){ 2988 //|| GameToPlay == GAME_INTERNET) { 2989 2990 //ST - 1/2/2019 5:29PM 2991 //Destroy_Null_Connection( DoList[j].MPlayerID, 0 ); 2992 } 2993 2994 else if ((GameToPlay == GAME_IPX || GameToPlay == GAME_INTERNET) && net) { 2995 index = net->Connection_Index (DoList[j].MPlayerID); 2996 if (index != -1) { 2997 for (k = index; k < net->Num_Connections() - 1; k++) { 2998 their_frame[k] = their_frame[k+1]; 2999 their_sent[k] = their_sent[k+1]; 3000 their_recv[k] = their_recv[k+1]; 3001 } 3002 CCDebugString ("C&C95 = Destroying connection due to exit event\n"); 3003 #ifndef DEMO 3004 Destroy_Connection(DoList[j].MPlayerID,0); 3005 #endif //DEMO 3006 } 3007 } 3008 } 3009 } 3010 3011 //............................................................... 3012 // For a FRAMEINFO event, check the CRC value. 3013 // This could be an old FRAMEINFO packet that was floating around 3014 // for awhile and just arrived; if so, its Frame value will be 3015 // old. Ignore these packets. (This created bogus sync bugs on 3016 // the Internet, when packets that were 35 frames old arrived.) 3017 //............................................................... 3018 #ifndef DEMO 3019 else if (DoList[j].Type == EventClass::FRAMEINFO) { 3020 if (DoList[j].Frame == Frame && 3021 DoList[j].Data.FrameInfo.Delay < 32) { 3022 index = ((DoList[j].Frame - DoList[j].Data.FrameInfo.Delay) & 3023 0x001f); 3024 if (CRC[index] != DoList[j].Data.FrameInfo.CRC) { 3025 Print_CRCs(&DoList[j]); 3026 if (CCMessageBox().Process (TXT_OUT_OF_SYNC, 3027 TXT_CONTINUE, TXT_STOP) == 0) { 3028 if (GameToPlay == GAME_MODEM || 3029 GameToPlay == GAME_NULL_MODEM){ 3030 #if (0)//ST - 1/2/2019 5:29PM 3031 Destroy_Null_Connection( DoList[j].MPlayerID, -1 ); 3032 Shutdown_Modem(); 3033 #endif 3034 GameToPlay = GAME_NORMAL; 3035 } 3036 else if ((GameToPlay == GAME_IPX || GameToPlay == GAME_INTERNET) && net) { 3037 CCDebugString ("C&C95 = Destroying connections due to bad frame info packet\n"); 3038 while (net->Num_Connections()) { 3039 Destroy_Connection (net->Connection_ID(0), -1); 3040 } 3041 } 3042 Map.Flag_To_Redraw(true); 3043 } 3044 else { 3045 return (0); 3046 } 3047 return (1); 3048 } 3049 } 3050 } 3051 #endif //DEMO 3052 //............................................................... 3053 // Execute other commands 3054 //............................................................... 3055 else { 3056 DoList[j].Execute(); 3057 } 3058 3059 //............................................................... 3060 // Mark this event as executed. 3061 //............................................................... 3062 DoList[j].IsExecuted = 1; 3063 } 3064 } 3065 } 3066 3067 return (1); 3068 3069 } // end of Execute_DoList 3070 3071 3072 /*************************************************************************** 3073 * Clean_DoList -- Cleans out old events from the DoList * 3074 * * 3075 * Currently, an event can only be removed from the DoList if it's at the * 3076 * head of the list; and event can't be removed from the middle. So, * 3077 * this routine loops as long as the next event in the DoList has been * 3078 * executed, it's removed. * 3079 * * 3080 * INPUT: * 3081 * net ptr to connection manager; ignored if NULL * 3082 * * 3083 * OUTPUT: * 3084 * none. * 3085 * * 3086 * WARNINGS: * 3087 * none. * 3088 * * 3089 * HISTORY: * 3090 * 11/21/1995 BRR : Created. * 3091 *=========================================================================*/ 3092 static void Clean_DoList(ConnManClass *net) 3093 { 3094 while (DoList.Count) { 3095 3096 #ifndef DEMO 3097 if (net) 3098 Update_Queue_Mono (net, 7); 3099 #else 3100 net = net; 3101 #endif //DEMO 3102 3103 //..................................................................... 3104 // Discard events that have been executed, OR it's too late to execute. 3105 // (This happens if another player exits the game; he'll leave FRAMEINFO 3106 // events lying around in my queue. They won't have been "executed", 3107 // because his IPX connection was destroyed.) 3108 //..................................................................... 3109 if ( (DoList.First().IsExecuted) || ((unsigned)Frame > DoList.First().Frame) ) { 3110 DoList.Next(); 3111 } 3112 else { 3113 break; 3114 } 3115 } 3116 3117 } // end of Clean_DoList 3118 3119 #ifndef DEMO 3120 3121 /*************************************************************************** 3122 * Queue_Record -- Records the DoList to disk * 3123 * * 3124 * This routine just saves any events in the DoList to disk; we can later * 3125 * "play back" the recording just be pulling events from disk rather than * 3126 * from the network! * 3127 * * 3128 * INPUT: * 3129 * none. * 3130 * * 3131 * OUTPUT: * 3132 * none. * 3133 * * 3134 * WARNINGS: * 3135 * none. * 3136 * * 3137 * HISTORY: * 3138 * 08/14/1995 BRR : Created. * 3139 *=========================================================================*/ 3140 static void Queue_Record(void) 3141 { 3142 int i,j; 3143 3144 //------------------------------------------------------------------------ 3145 // Compute # of events to save this frame 3146 //------------------------------------------------------------------------ 3147 j = 0; 3148 for (i = 0; i < DoList.Count; i++) { 3149 if (Frame == DoList[i].Frame && !DoList[i].IsExecuted) { 3150 j++; 3151 } 3152 } 3153 3154 //------------------------------------------------------------------------ 3155 // Save the # of events, then all events. 3156 //------------------------------------------------------------------------ 3157 RecordFile.Write (&j,sizeof(j)); 3158 for (i = 0; i < DoList.Count; i++) { 3159 if (Frame == DoList[i].Frame && !DoList[i].IsExecuted) { 3160 RecordFile.Write (&DoList[i],sizeof (EventClass)); 3161 j--; 3162 } 3163 } 3164 3165 } /* end of Queue_Record */ 3166 3167 3168 /*************************************************************************** 3169 * Queue_Playback -- plays back queue entries from a record file * 3170 * * 3171 * This routine reads events from disk, putting them into the DoList; * 3172 * it then executes the DoList just like the network version does. The * 3173 * result is that the game "plays back" like a recording. * 3174 * * 3175 * This routine detects mouse motion and stops playback, so it can work * 3176 * like an "attract" mode, showing a demo of the game itself. * 3177 * * 3178 * INPUT: * 3179 * none. * 3180 * * 3181 * OUTPUT: * 3182 * none. * 3183 * * 3184 * WARNINGS: * 3185 * none. * 3186 * * 3187 * HISTORY: * 3188 * 05/15/1995 BRR : Created. * 3189 *=========================================================================*/ 3190 static void Queue_Playback(void) 3191 { 3192 int numevents; 3193 EventClass event; 3194 int i; 3195 int ok; 3196 static int mx,my; 3197 int max_houses; 3198 HousesType base_house; 3199 int key; 3200 int testframe; 3201 3202 //------------------------------------------------------------------------ 3203 // If the user hits ESC, stop the playback 3204 //------------------------------------------------------------------------ 3205 if (Check_Key_Num()) { 3206 key = Get_Key(); 3207 // 3208 // If the user hit ESC, end the recording. If this is an Attract-mode 3209 // recording, end it no matter what the user does (any key or mouse). 3210 // 3211 if (key == KA_ESC || AllowAttract) { 3212 GameActive = 0; 3213 return; 3214 } 3215 } 3216 3217 //------------------------------------------------------------------------ 3218 // If we're in "Attact" mode, and the user moves the mouse, stop the 3219 // playback. 3220 //------------------------------------------------------------------------ 3221 if (AllowAttract && Frame > 0 && 3222 (mx != Get_Mouse_X() || my != Get_Mouse_Y())) { 3223 GameActive = 0; 3224 return; 3225 } 3226 mx = Get_Mouse_X(); 3227 my = Get_Mouse_Y(); 3228 3229 //------------------------------------------------------------------------ 3230 // Compute the Game's CRC 3231 //------------------------------------------------------------------------ 3232 Compute_Game_CRC(); 3233 CRC[Frame & 0x001f] = GameCRC; 3234 3235 //------------------------------------------------------------------------ 3236 // Don't read anything the first time through (since the Queue_AI_Network 3237 // routine didn't write anything the first time through); do this after the 3238 // CRC is computed, since we'll still need a CRC for Frame 0. 3239 //------------------------------------------------------------------------ 3240 if (Frame==0 && GameToPlay!=GAME_NORMAL) { 3241 return; 3242 } 3243 3244 //------------------------------------------------------------------------ 3245 // Only process every 'FrameSendRate' frames 3246 //------------------------------------------------------------------------ 3247 testframe = ((Frame + (FrameSendRate - 1)) / FrameSendRate) * FrameSendRate; 3248 3249 if (GameToPlay != GAME_NORMAL && 3250 CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) { 3251 if (Frame != testframe) { 3252 return; 3253 } 3254 } 3255 3256 //------------------------------------------------------------------------ 3257 // Read the DoList from disk 3258 //------------------------------------------------------------------------ 3259 ok = 1; 3260 if (RecordFile.Read (&numevents, sizeof(numevents)) == 3261 sizeof(numevents)) { 3262 for (i = 0; i < numevents; i++) { 3263 if (RecordFile.Read (&event, sizeof(EventClass)) == 3264 sizeof(EventClass)) { 3265 event.IsExecuted = 0; 3266 DoList.Add (event); 3267 } 3268 else { 3269 ok = 0; 3270 break; 3271 } 3272 } 3273 } 3274 else { 3275 ok = 0; 3276 } 3277 3278 if (!ok) { 3279 GameActive = 0; 3280 return; 3281 } 3282 3283 3284 //------------------------------------------------------------------------ 3285 // Execute the DoList; if an error occurs, bail out. 3286 //------------------------------------------------------------------------ 3287 if (GameToPlay == GAME_NORMAL) { 3288 max_houses = 1; 3289 base_house = PlayerPtr->Class->House; 3290 } 3291 else { 3292 max_houses = MPlayerMax; 3293 base_house = HOUSE_MULTI1; 3294 } 3295 if (!Execute_DoList(max_houses, base_house, NULL, NULL, NULL, NULL, NULL)) { 3296 GameActive = 0; 3297 return; 3298 } 3299 3300 //------------------------------------------------------------------------ 3301 // Clean out the DoList 3302 //------------------------------------------------------------------------ 3303 Clean_DoList(NULL); 3304 3305 } /* end of Queue_Playback */ 3306 3307 3308 /*************************************************************************** 3309 * Compute_Game_CRC -- Computes a CRC value of the entire game. * 3310 * * 3311 * INPUT: * 3312 * none. * 3313 * * 3314 * OUTPUT: * 3315 * none. * 3316 * * 3317 * WARNINGS: * 3318 * none. * 3319 * * 3320 * HISTORY: * 3321 * 05/09/1995 BRR : Created. * 3322 *=========================================================================*/ 3323 static void Compute_Game_CRC(void) 3324 { 3325 int i; 3326 InfantryClass *infp; 3327 UnitClass *unitp; 3328 BuildingClass *bldgp; 3329 //ObjectClass *objp; 3330 3331 GameCRC = 0; 3332 3333 //------------------------------------------------------------------------ 3334 // Infantry 3335 //------------------------------------------------------------------------ 3336 for (i = 0; i < Infantry.Count(); i++) { 3337 infp = (InfantryClass *)Infantry.Active_Ptr(i); 3338 Add_CRC (&GameCRC, (int)infp->Coord + (int)infp->PrimaryFacing); 3339 } 3340 3341 //------------------------------------------------------------------------ 3342 // Units 3343 //------------------------------------------------------------------------ 3344 for (i = 0; i < Units.Count(); i++) { 3345 unitp = (UnitClass *)Units.Active_Ptr(i); 3346 Add_CRC (&GameCRC, (int)unitp->Coord + (int)unitp->PrimaryFacing + 3347 (int)unitp->SecondaryFacing); 3348 } 3349 3350 //------------------------------------------------------------------------ 3351 // Buildings 3352 //------------------------------------------------------------------------ 3353 for (i = 0; i < Buildings.Count(); i++) { 3354 bldgp = (BuildingClass *)Buildings.Active_Ptr(i); 3355 Add_CRC (&GameCRC, (int)bldgp->Coord + (int)bldgp->PrimaryFacing); 3356 } 3357 3358 #if(0) 3359 //------------------------------------------------------------------------ 3360 // Map Layers 3361 //------------------------------------------------------------------------ 3362 for (i = 0; i < LAYER_COUNT; i++) { 3363 for (j = 0; j < Map.Layer[i].Count(); j++) { 3364 objp = Map.Layer[i][j]; 3365 Add_CRC (&GameCRC, (int)objp->Coord + (int)objp->What_Am_I()); 3366 } 3367 } 3368 3369 //------------------------------------------------------------------------ 3370 // Logic Layers 3371 //------------------------------------------------------------------------ 3372 for (i = 0; i < Logic.Count(); i++) { 3373 objp = Logic[i]; 3374 Add_CRC (&GameCRC, (int)objp->Coord + (int)objp->What_Am_I()); 3375 } 3376 #endif 3377 3378 //------------------------------------------------------------------------ 3379 // A random # 3380 //------------------------------------------------------------------------ 3381 Add_CRC(&GameCRC, rand()); 3382 3383 } /* end of Compute_Game_CRC */ 3384 3385 3386 /*************************************************************************** 3387 * Add_CRC -- Adds a value to a CRC * 3388 * * 3389 * INPUT: * 3390 * crc ptr to crc * 3391 * val value to add * 3392 * * 3393 * OUTPUT: * 3394 * none * 3395 * * 3396 * WARNINGS: * 3397 * none * 3398 * * 3399 * HISTORY: * 3400 * 05/09/1995 BRR : Created. * 3401 *=========================================================================*/ 3402 void Add_CRC(unsigned long *crc, unsigned long val) 3403 { 3404 int hibit; 3405 3406 if ( (*crc) & 0x80000000) { 3407 hibit = 1; 3408 } 3409 else { 3410 hibit = 0; 3411 } 3412 3413 (*crc) <<= 1; 3414 (*crc) += val; 3415 (*crc) += hibit; 3416 3417 } /* end of Add_CRC */ 3418 3419 3420 /*************************************************************************** 3421 * Print_CRCs -- Prints a data file for finding Sync Bugs * 3422 * * 3423 * INPUT: * 3424 * none. * 3425 * * 3426 * OUTPUT: * 3427 * none * 3428 * * 3429 * WARNINGS: * 3430 * none * 3431 * * 3432 * HISTORY: * 3433 * 05/09/1995 BRR : Created. * 3434 *=========================================================================*/ 3435 void Print_CRCs(EventClass *ev) 3436 { 3437 ev=ev; 3438 3439 int i; //,j; 3440 InfantryClass *infp; 3441 UnitClass *unitp; 3442 BuildingClass *bldgp; 3443 //ObjectClass *objp; 3444 FILE *fp; 3445 int rnd; 3446 HouseClass *housep; 3447 //HousesType house; 3448 int color; 3449 3450 Mono_Clear_Screen(); 3451 Mono_Set_Cursor (0,0); 3452 3453 char filename[80]; 3454 sprintf (filename, "CRC%02d.TXT", Frame & 0x1f); 3455 3456 fp = fopen(filename, "wt"); //"OUT.TXT","wt"); 3457 if (fp==NULL) { 3458 return; 3459 } 3460 3461 for (i = 0; i < 32; i++) { 3462 fprintf(fp,"CRC[%d]=%x\n",i,CRC[i]); 3463 } 3464 3465 3466 housep = HouseClass::As_Pointer (HOUSE_MULTI1); 3467 if (housep) { 3468 color = housep->RemapColor; 3469 fprintf(fp,"Multi1: IsHuman:%d Color:%s\n",housep->IsHuman, 3470 ColorNames[color]); 3471 } 3472 3473 housep = HouseClass::As_Pointer (HOUSE_MULTI2); 3474 if (housep) { 3475 color = housep->RemapColor; 3476 fprintf(fp,"Multi2: IsHuman:%d Color:%s\n",housep->IsHuman, 3477 ColorNames[color]); 3478 } 3479 3480 housep = HouseClass::As_Pointer (HOUSE_MULTI3); 3481 if (housep) { 3482 color = housep->RemapColor; 3483 fprintf(fp,"Multi3: IsHuman:%d Color:%s\n",housep->IsHuman, 3484 ColorNames[color]); 3485 } 3486 3487 housep = HouseClass::As_Pointer (HOUSE_MULTI4); 3488 if (housep) { 3489 color = housep->RemapColor; 3490 fprintf(fp,"Multi4: IsHuman:%d Color:%s\n",housep->IsHuman, 3491 ColorNames[color]); 3492 } 3493 3494 housep = HouseClass::As_Pointer (HOUSE_MULTI5); 3495 if (housep) { 3496 color = housep->RemapColor; 3497 fprintf(fp,"Multi5: IsHuman:%d Color:%s\n",housep->IsHuman, 3498 ColorNames[color]); 3499 } 3500 3501 housep = HouseClass::As_Pointer (HOUSE_MULTI6); 3502 if (housep) { 3503 color = housep->RemapColor; 3504 fprintf(fp,"Multi6: IsHuman:%d Color:%s\n",housep->IsHuman, 3505 ColorNames[color]); 3506 } 3507 3508 3509 //------------------------------------------------------------------------ 3510 // Multi1 Infantry 3511 //------------------------------------------------------------------------ 3512 if (HouseClass::As_Pointer(HOUSE_MULTI1)) { 3513 GameCRC = 0; 3514 fprintf(fp,"-------------------- MULTI1 INFANTRY -------------------\n"); 3515 for (i = 0; i < Infantry.Count(); i++) { 3516 infp = (InfantryClass *)Infantry.Active_Ptr(i); 3517 if (infp->Owner()==HOUSE_MULTI1) { 3518 Add_CRC (&GameCRC, (int)infp->Coord + (int)infp->PrimaryFacing); 3519 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3520 infp->Coord,(int)infp->PrimaryFacing,infp->Get_Mission(), 3521 infp->Class->Type); 3522 } 3523 } 3524 Mono_Printf("Multi1 Infantry:%d\n",GameCRC); 3525 } 3526 3527 //------------------------------------------------------------------------ 3528 // Multi2 Infantry 3529 //------------------------------------------------------------------------ 3530 if (HouseClass::As_Pointer(HOUSE_MULTI2)) { 3531 GameCRC = 0; 3532 fprintf(fp,"-------------------- MULTI2 INFANTRY -------------------\n"); 3533 for (i = 0; i < Infantry.Count(); i++) { 3534 infp = (InfantryClass *)Infantry.Active_Ptr(i); 3535 if (infp->Owner()==HOUSE_MULTI2) { 3536 Add_CRC (&GameCRC, (int)infp->Coord + (int)infp->PrimaryFacing); 3537 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3538 infp->Coord,(int)infp->PrimaryFacing,infp->Get_Mission(), 3539 infp->Class->Type); 3540 } 3541 } 3542 Mono_Printf("Multi2 Infantry:%d\n",GameCRC); 3543 } 3544 3545 //------------------------------------------------------------------------ 3546 // Multi3 Infantry 3547 //------------------------------------------------------------------------ 3548 if (HouseClass::As_Pointer(HOUSE_MULTI3)) { 3549 GameCRC = 0; 3550 fprintf(fp,"-------------------- MULTI3 INFANTRY -------------------\n"); 3551 for (i = 0; i < Infantry.Count(); i++) { 3552 infp = (InfantryClass *)Infantry.Active_Ptr(i); 3553 if (infp->Owner()==HOUSE_MULTI3) { 3554 Add_CRC (&GameCRC, (int)infp->Coord + (int)infp->PrimaryFacing); 3555 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3556 infp->Coord,(int)infp->PrimaryFacing,infp->Get_Mission(), 3557 infp->Class->Type); 3558 } 3559 } 3560 Mono_Printf("Multi3 Infantry:%d\n",GameCRC); 3561 } 3562 3563 //------------------------------------------------------------------------ 3564 // Multi4 Infantry 3565 //------------------------------------------------------------------------ 3566 if (HouseClass::As_Pointer(HOUSE_MULTI4)) { 3567 GameCRC = 0; 3568 fprintf(fp,"-------------------- MULTI4 INFANTRY -------------------\n"); 3569 for (i = 0; i < Infantry.Count(); i++) { 3570 infp = (InfantryClass *)Infantry.Active_Ptr(i); 3571 if (infp->Owner()==HOUSE_MULTI4) { 3572 Add_CRC (&GameCRC, (int)infp->Coord + (int)infp->PrimaryFacing); 3573 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3574 infp->Coord,(int)infp->PrimaryFacing,infp->Get_Mission(), 3575 infp->Class->Type); 3576 } 3577 } 3578 Mono_Printf("Multi4 Infantry:%d\n",GameCRC); 3579 } 3580 3581 //------------------------------------------------------------------------ 3582 // Multi5 Infantry 3583 //------------------------------------------------------------------------ 3584 if (HouseClass::As_Pointer(HOUSE_MULTI5)) { 3585 GameCRC = 0; 3586 fprintf(fp,"-------------------- MULTI5 INFANTRY -------------------\n"); 3587 for (i = 0; i < Infantry.Count(); i++) { 3588 infp = (InfantryClass *)Infantry.Active_Ptr(i); 3589 if (infp->Owner()==HOUSE_MULTI5) { 3590 Add_CRC (&GameCRC, (int)infp->Coord + (int)infp->PrimaryFacing); 3591 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3592 infp->Coord,(int)infp->PrimaryFacing,infp->Get_Mission(), 3593 infp->Class->Type); 3594 } 3595 } 3596 Mono_Printf("Multi5 Infantry:%d\n",GameCRC); 3597 } 3598 3599 //------------------------------------------------------------------------ 3600 // Multi6 Infantry 3601 //------------------------------------------------------------------------ 3602 if (HouseClass::As_Pointer(HOUSE_MULTI6)) { 3603 GameCRC = 0; 3604 fprintf(fp,"-------------------- MULTI6 INFANTRY -------------------\n"); 3605 for (i = 0; i < Infantry.Count(); i++) { 3606 infp = (InfantryClass *)Infantry.Active_Ptr(i); 3607 if (infp->Owner()==HOUSE_MULTI6) { 3608 Add_CRC (&GameCRC, (int)infp->Coord + (int)infp->PrimaryFacing); 3609 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3610 infp->Coord,(int)infp->PrimaryFacing,infp->Get_Mission(), 3611 infp->Class->Type); 3612 } 3613 } 3614 Mono_Printf("Multi6 Infantry:%d\n",GameCRC); 3615 } 3616 3617 //------------------------------------------------------------------------ 3618 // Multi1 Units 3619 //------------------------------------------------------------------------ 3620 if (HouseClass::As_Pointer(HOUSE_MULTI1)) { 3621 GameCRC = 0; 3622 fprintf(fp,"-------------------- MULTI1 UNITS -------------------\n"); 3623 for (i = 0; i < Units.Count(); i++) { 3624 unitp = (UnitClass *)Units.Active_Ptr(i); 3625 if (unitp->Owner()==HOUSE_MULTI1) { 3626 Add_CRC (&GameCRC, (int)unitp->Coord + (int)unitp->PrimaryFacing); 3627 fprintf(fp, 3628 "COORD:%x Facing:%d Facing2:%d Mission:%d Type:%d\n", 3629 unitp->Coord,(int)unitp->PrimaryFacing, 3630 (int)unitp->SecondaryFacing,unitp->Get_Mission(), 3631 unitp->Class->Type); 3632 } 3633 } 3634 Mono_Printf("Multi1 Units:%d\n",GameCRC); 3635 } 3636 3637 //------------------------------------------------------------------------ 3638 // Multi2 Units 3639 //------------------------------------------------------------------------ 3640 if (HouseClass::As_Pointer(HOUSE_MULTI2)) { 3641 GameCRC = 0; 3642 fprintf(fp,"-------------------- MULTI2 UNITS -------------------\n"); 3643 for (i = 0; i < Units.Count(); i++) { 3644 unitp = (UnitClass *)Units.Active_Ptr(i); 3645 if (unitp->Owner()==HOUSE_MULTI2) { 3646 Add_CRC (&GameCRC, (int)unitp->Coord + (int)unitp->PrimaryFacing); 3647 fprintf(fp, 3648 "COORD:%x Facing:%d Facing2:%d Mission:%d Type:%d\n", 3649 unitp->Coord,(int)unitp->PrimaryFacing, 3650 (int)unitp->SecondaryFacing,unitp->Get_Mission(), 3651 unitp->Class->Type); 3652 } 3653 } 3654 Mono_Printf("Multi2 Units:%d\n",GameCRC); 3655 } 3656 3657 //------------------------------------------------------------------------ 3658 // Multi3 Units 3659 //------------------------------------------------------------------------ 3660 if (HouseClass::As_Pointer(HOUSE_MULTI3)) { 3661 GameCRC = 0; 3662 fprintf(fp,"-------------------- MULTI3 UNITS -------------------\n"); 3663 for (i = 0; i < Units.Count(); i++) { 3664 unitp = (UnitClass *)Units.Active_Ptr(i); 3665 if (unitp->Owner()==HOUSE_MULTI3) { 3666 Add_CRC (&GameCRC, (int)unitp->Coord + (int)unitp->PrimaryFacing); 3667 fprintf(fp, 3668 "COORD:%x Facing:%d Facing2:%d Mission:%d Type:%d\n", 3669 unitp->Coord,(int)unitp->PrimaryFacing, 3670 (int)unitp->SecondaryFacing,unitp->Get_Mission(), 3671 unitp->Class->Type); 3672 } 3673 } 3674 Mono_Printf("Multi3 Units:%d\n",GameCRC); 3675 } 3676 3677 //------------------------------------------------------------------------ 3678 // Multi4 Units 3679 //------------------------------------------------------------------------ 3680 if (HouseClass::As_Pointer(HOUSE_MULTI4)) { 3681 GameCRC = 0; 3682 fprintf(fp,"-------------------- MULTI4 UNITS -------------------\n"); 3683 for (i = 0; i < Units.Count(); i++) { 3684 unitp = (UnitClass *)Units.Active_Ptr(i); 3685 if (unitp->Owner()==HOUSE_MULTI4) { 3686 Add_CRC (&GameCRC, (int)unitp->Coord + (int)unitp->PrimaryFacing); 3687 fprintf(fp, 3688 "COORD:%x Facing:%d Facing2:%d Mission:%d Type:%d\n", 3689 unitp->Coord,(int)unitp->PrimaryFacing, 3690 (int)unitp->SecondaryFacing,unitp->Get_Mission(), 3691 unitp->Class->Type); 3692 } 3693 } 3694 Mono_Printf("Multi4 Units:%d\n",GameCRC); 3695 } 3696 3697 //------------------------------------------------------------------------ 3698 // Multi5 Units 3699 //------------------------------------------------------------------------ 3700 if (HouseClass::As_Pointer(HOUSE_MULTI5)) { 3701 GameCRC = 0; 3702 fprintf(fp,"-------------------- MULTI5 UNITS -------------------\n"); 3703 for (i = 0; i < Units.Count(); i++) { 3704 unitp = (UnitClass *)Units.Active_Ptr(i); 3705 if (unitp->Owner()==HOUSE_MULTI5) { 3706 Add_CRC (&GameCRC, (int)unitp->Coord + (int)unitp->PrimaryFacing); 3707 fprintf(fp, 3708 "COORD:%x Facing:%d Facing2:%d Mission:%d Type:%d\n", 3709 unitp->Coord,(int)unitp->PrimaryFacing, 3710 (int)unitp->SecondaryFacing,unitp->Get_Mission(), 3711 unitp->Class->Type); 3712 } 3713 } 3714 Mono_Printf("Multi5 Units:%d\n",GameCRC); 3715 } 3716 3717 //------------------------------------------------------------------------ 3718 // Multi6 Units 3719 //------------------------------------------------------------------------ 3720 if (HouseClass::As_Pointer(HOUSE_MULTI6)) { 3721 GameCRC = 0; 3722 fprintf(fp,"-------------------- MULTI6 UNITS -------------------\n"); 3723 for (i = 0; i < Units.Count(); i++) { 3724 unitp = (UnitClass *)Units.Active_Ptr(i); 3725 if (unitp->Owner()==HOUSE_MULTI6) { 3726 Add_CRC (&GameCRC, (int)unitp->Coord + (int)unitp->PrimaryFacing); 3727 fprintf(fp, 3728 "COORD:%x Facing:%d Facing2:%d Mission:%d Type:%d\n", 3729 unitp->Coord,(int)unitp->PrimaryFacing, 3730 (int)unitp->SecondaryFacing,unitp->Get_Mission(), 3731 unitp->Class->Type); 3732 } 3733 } 3734 Mono_Printf("Multi6 Units:%d\n",GameCRC); 3735 } 3736 3737 //------------------------------------------------------------------------ 3738 // Multi1 Buildings 3739 //------------------------------------------------------------------------ 3740 if (HouseClass::As_Pointer(HOUSE_MULTI1)) { 3741 GameCRC = 0; 3742 fprintf(fp,"-------------------- MULTI1 BUILDINGS -------------------\n"); 3743 for (i = 0; i < Buildings.Count(); i++) { 3744 bldgp = (BuildingClass *)Buildings.Active_Ptr(i); 3745 if (bldgp->Owner()==HOUSE_MULTI1) { 3746 Add_CRC (&GameCRC, (int)bldgp->Coord + (int)bldgp->PrimaryFacing); 3747 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3748 bldgp->Coord,(int)bldgp->PrimaryFacing,bldgp->Get_Mission(), 3749 bldgp->Class->Type); 3750 } 3751 } 3752 Mono_Printf("Multi1 Buildings:%d\n",GameCRC); 3753 } 3754 3755 //------------------------------------------------------------------------ 3756 // Multi2 Buildings 3757 //------------------------------------------------------------------------ 3758 if (HouseClass::As_Pointer(HOUSE_MULTI2)) { 3759 GameCRC = 0; 3760 fprintf(fp,"-------------------- MULTI2 BUILDINGS -------------------\n"); 3761 for (i = 0; i < Buildings.Count(); i++) { 3762 bldgp = (BuildingClass *)Buildings.Active_Ptr(i); 3763 if (bldgp->Owner()==HOUSE_MULTI2) { 3764 Add_CRC (&GameCRC, (int)bldgp->Coord + (int)bldgp->PrimaryFacing); 3765 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3766 bldgp->Coord,(int)bldgp->PrimaryFacing,bldgp->Get_Mission(), 3767 bldgp->Class->Type); 3768 } 3769 } 3770 Mono_Printf("Multi2 Buildings:%d\n",GameCRC); 3771 } 3772 3773 //------------------------------------------------------------------------ 3774 // Multi3 Buildings 3775 //------------------------------------------------------------------------ 3776 if (HouseClass::As_Pointer(HOUSE_MULTI3)) { 3777 GameCRC = 0; 3778 fprintf(fp,"-------------------- MULTI3 BUILDINGS -------------------\n"); 3779 for (i = 0; i < Buildings.Count(); i++) { 3780 bldgp = (BuildingClass *)Buildings.Active_Ptr(i); 3781 if (bldgp->Owner()==HOUSE_MULTI3) { 3782 Add_CRC (&GameCRC, (int)bldgp->Coord + (int)bldgp->PrimaryFacing); 3783 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3784 bldgp->Coord,(int)bldgp->PrimaryFacing,bldgp->Get_Mission(), 3785 bldgp->Class->Type); 3786 } 3787 } 3788 Mono_Printf("Multi3 Buildings:%d\n",GameCRC); 3789 } 3790 3791 //------------------------------------------------------------------------ 3792 // Multi4 Buildings 3793 //------------------------------------------------------------------------ 3794 if (HouseClass::As_Pointer(HOUSE_MULTI4)) { 3795 GameCRC = 0; 3796 fprintf(fp,"-------------------- MULTI4 BUILDINGS -------------------\n"); 3797 for (i = 0; i < Buildings.Count(); i++) { 3798 bldgp = (BuildingClass *)Buildings.Active_Ptr(i); 3799 if (bldgp->Owner()==HOUSE_MULTI4) { 3800 Add_CRC (&GameCRC, (int)bldgp->Coord + (int)bldgp->PrimaryFacing); 3801 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3802 bldgp->Coord,(int)bldgp->PrimaryFacing,bldgp->Get_Mission(), 3803 bldgp->Class->Type); 3804 } 3805 } 3806 Mono_Printf("Multi4 Buildings:%d\n",GameCRC); 3807 } 3808 3809 //------------------------------------------------------------------------ 3810 // Multi5 Buildings 3811 //------------------------------------------------------------------------ 3812 if (HouseClass::As_Pointer(HOUSE_MULTI5)) { 3813 GameCRC = 0; 3814 fprintf(fp,"-------------------- MULTI5 BUILDINGS -------------------\n"); 3815 for (i = 0; i < Buildings.Count(); i++) { 3816 bldgp = (BuildingClass *)Buildings.Active_Ptr(i); 3817 if (bldgp->Owner()==HOUSE_MULTI5) { 3818 Add_CRC (&GameCRC, (int)bldgp->Coord + (int)bldgp->PrimaryFacing); 3819 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3820 bldgp->Coord,(int)bldgp->PrimaryFacing,bldgp->Get_Mission(), 3821 bldgp->Class->Type); 3822 } 3823 } 3824 Mono_Printf("Multi5 Buildings:%d\n",GameCRC); 3825 } 3826 3827 //------------------------------------------------------------------------ 3828 // Multi6 Buildings 3829 //------------------------------------------------------------------------ 3830 if (HouseClass::As_Pointer(HOUSE_MULTI6)) { 3831 GameCRC = 0; 3832 fprintf(fp,"-------------------- MULTI6 BUILDINGS -------------------\n"); 3833 for (i = 0; i < Buildings.Count(); i++) { 3834 bldgp = (BuildingClass *)Buildings.Active_Ptr(i); 3835 if (bldgp->Owner()==HOUSE_MULTI6) { 3836 Add_CRC (&GameCRC, (int)bldgp->Coord + (int)bldgp->PrimaryFacing); 3837 fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d\n", 3838 bldgp->Coord,(int)bldgp->PrimaryFacing,bldgp->Get_Mission(), 3839 bldgp->Class->Type); 3840 } 3841 } 3842 Mono_Printf("Multi6 Buildings:%d\n",GameCRC); 3843 } 3844 #if (0) 3845 //------------------------------------------------------------------------ 3846 // Map Layers 3847 //------------------------------------------------------------------------ 3848 GameCRC = 0; 3849 for (i = 0; i < LAYER_COUNT; i++) { 3850 fprintf(fp,">>>> MAP LAYER %d <<<<\n",i); 3851 for (j = 0; j < Map.Layer[i].Count(); j++) { 3852 objp = Map.Layer[i][j]; 3853 Add_CRC (&GameCRC, (int)objp->Coord + (int)objp->What_Am_I()); 3854 fprintf(fp,"Object %d: %x ",j,objp->Coord); 3855 3856 if (objp->What_Am_I() == RTTI_AIRCRAFT) 3857 fprintf(fp,"Aircraft (Type:%d) ", 3858 (AircraftType)(*((AircraftClass *)objp))); 3859 else if (objp->What_Am_I() == RTTI_ANIM) 3860 fprintf(fp,"Anim (Type:%d) ", 3861 (AnimType)(*((AnimClass *)objp))); 3862 else if (objp->What_Am_I() == RTTI_BUILDING) 3863 fprintf(fp,"Building (Type:%d) ", 3864 (StructType)(*((BuildingClass *)objp))); 3865 else if (objp->What_Am_I() == RTTI_BULLET) 3866 fprintf(fp,"Bullet (Type:%d) ", 3867 (BulletType)(*((BulletClass *)objp))); 3868 else if (objp->What_Am_I() == RTTI_INFANTRY) 3869 fprintf(fp,"Infantry (Type:%d) ", 3870 (InfantryType)(*((InfantryClass *)objp))); 3871 else if (objp->What_Am_I() == RTTI_OVERLAY) 3872 fprintf(fp,"Overlay (Type:%d) ", 3873 (OverlayType)(*((OverlayClass *)objp))); 3874 else if (objp->What_Am_I() == RTTI_SMUDGE) 3875 fprintf(fp,"Smudge (Type:%d) ", 3876 (SmudgeType)(*((SmudgeClass *)objp))); 3877 else if (objp->What_Am_I() == RTTI_TEMPLATE) 3878 fprintf(fp,"Template (Type:%d) ", 3879 (TemplateType)(*((TemplateClass *)objp))); 3880 else if (objp->What_Am_I() == RTTI_TERRAIN) 3881 fprintf(fp,"Terrain (Type:%d) ", 3882 (TerrainType)(*((TerrainClass *)objp))); 3883 else if (objp->What_Am_I() == RTTI_UNIT) 3884 fprintf(fp,"Unit (Type:%d) ", 3885 (UnitType)(*((UnitClass *)objp))); 3886 3887 house = objp->Owner(); 3888 if (house!=HOUSE_NONE) { 3889 housep = HouseClass::As_Pointer (house); 3890 fprintf(fp,"Owner: %s\n",housep->Class->IniName); 3891 } 3892 else { 3893 fprintf(fp,"Owner: NONE\n"); 3894 } 3895 } 3896 } 3897 Mono_Printf("Map Layers:%d\n",GameCRC); 3898 3899 //------------------------------------------------------------------------ 3900 // Logic Layers 3901 //------------------------------------------------------------------------ 3902 GameCRC = 0; 3903 fprintf(fp,">>>> LOGIC LAYER <<<<\n"); 3904 for (i = 0; i < Logic.Count(); i++) { 3905 objp = Logic[i]; 3906 Add_CRC (&GameCRC, (int)objp->Coord + (int)objp->What_Am_I()); 3907 fprintf(fp,"Object %d: %x ",i,objp->Coord); 3908 3909 if (objp->What_Am_I() == RTTI_AIRCRAFT) 3910 fprintf(fp,"Aircraft (Type:%d) ", 3911 (AircraftType)(*((AircraftClass *)objp))); 3912 else if (objp->What_Am_I() == RTTI_ANIM) 3913 fprintf(fp,"Anim (Type:%d) ", 3914 (AnimType)(*((AnimClass *)objp))); 3915 else if (objp->What_Am_I() == RTTI_BUILDING) 3916 fprintf(fp,"Building (Type:%d) ", 3917 (StructType)(*((BuildingClass *)objp))); 3918 else if (objp->What_Am_I() == RTTI_BULLET) 3919 fprintf(fp,"Bullet (Type:%d) ", 3920 (BulletType)(*((BulletClass *)objp))); 3921 else if (objp->What_Am_I() == RTTI_INFANTRY) 3922 fprintf(fp,"Infantry (Type:%d) ", 3923 (InfantryType)(*((InfantryClass *)objp))); 3924 else if (objp->What_Am_I() == RTTI_OVERLAY) 3925 fprintf(fp,"Overlay (Type:%d) ", 3926 (OverlayType)(*((OverlayClass *)objp))); 3927 else if (objp->What_Am_I() == RTTI_SMUDGE) 3928 fprintf(fp,"Smudge (Type:%d) ", 3929 (SmudgeType)(*((SmudgeClass *)objp))); 3930 else if (objp->What_Am_I() == RTTI_TEMPLATE) 3931 fprintf(fp,"Template (Type:%d) ", 3932 (TemplateType)(*((TemplateClass *)objp))); 3933 else if (objp->What_Am_I() == RTTI_TERRAIN) 3934 fprintf(fp,"Terrain (Type:%d) ", 3935 (TerrainType)(*((TerrainClass *)objp))); 3936 else if (objp->What_Am_I() == RTTI_UNIT) 3937 fprintf(fp,"Unit (Type:%d) ", 3938 (UnitType)(*((UnitClass *)objp))); 3939 3940 house = objp->Owner(); 3941 if (house!=HOUSE_NONE) { 3942 housep = HouseClass::As_Pointer (house); 3943 fprintf(fp,"Owner: %s\n",housep->Class->IniName); 3944 } 3945 else { 3946 fprintf(fp,"Owner: NONE\n"); 3947 } 3948 } 3949 Mono_Printf("Logic:%d\n",GameCRC); 3950 #endif 3951 3952 //------------------------------------------------------------------------ 3953 // Random # generator, frame # 3954 //------------------------------------------------------------------------ 3955 rnd = rand(); 3956 3957 Mono_Printf("Random Number:%d\n",rnd); 3958 fprintf(fp,"\nRandom Number:%d\n",rnd); 3959 3960 Mono_Printf("My Frame:%d\n",Frame); 3961 fprintf(fp,"My Frame:%d\n",Frame); 3962 #if (0) 3963 fprintf(fp,"-------------- Offending event: ----------------\n"); 3964 fprintf(fp,"Type: %d\n",ev->Type); 3965 fprintf(fp,"Frame: %d\n",ev->Frame); 3966 fprintf(fp,"MPlayerID: %04x\n",ev->MPlayerID); 3967 if (ev->Type == EventClass::FRAMEINFO) { 3968 fprintf(fp,"CRC: %x\n",ev->Data.FrameInfo.CRC); 3969 fprintf(fp,"CommandCount: %x\n",ev->Data.FrameInfo.CommandCount); 3970 fprintf(fp,"Delay: %x\n",ev->Data.FrameInfo.Delay); 3971 } 3972 #endif 3973 fclose(fp); 3974 3975 } /* end of Print_CRCs */ 3976 3977 3978 /*************************************************************************** 3979 * Init_Queue_Mono -- inits mono display * 3980 * * 3981 * This routine steals control of the mono screen away from the rest of * 3982 * the engine, by setting the global IsMono; if IsMono is set, the other * 3983 * routines in this module turn off the Mono display when they're done * 3984 * with it, so the rest of the engine won't over-write what we're writing. * 3985 * * 3986 * INPUT: * 3987 * net ptr to connection manager * 3988 * * 3989 * OUTPUT: * 3990 * none. * 3991 * * 3992 * WARNINGS: * 3993 * none. * 3994 * * 3995 * HISTORY: * 3996 * 11/21/1995 BRR : Created. * 3997 *=========================================================================*/ 3998 static void Init_Queue_Mono(ConnManClass *net) 3999 { 4000 #if(SHOW_MONO) 4001 //------------------------------------------------------------------------ 4002 // Set 'IsMono' so we can steal the mono screen from the engine 4003 //------------------------------------------------------------------------ 4004 if (Frame==0 && MonoClass::Is_Enabled()) { 4005 IsMono = true; 4006 } 4007 4008 //------------------------------------------------------------------------ 4009 // Enable mono output for our stuff; we must Disable it before we return 4010 // control to the engine. 4011 //------------------------------------------------------------------------ 4012 if (IsMono) 4013 MonoClass::Enable(); 4014 4015 if (net->Num_Connections() > 0) { 4016 //..................................................................... 4017 // Network mono debugging screen 4018 //..................................................................... 4019 if (NetMonoMode==0) { 4020 if (Frame==0 || NewMonoMode) { 4021 net->Configure_Debug (0, sizeof (CommHeaderType), 4022 sizeof(EventClass::EventType), EventClass::EventNames, 0); 4023 net->Mono_Debug_Print (0,1); 4024 NewMonoMode = 0; 4025 } 4026 else { 4027 net->Mono_Debug_Print (0,0); 4028 } 4029 } 4030 //..................................................................... 4031 // Flow control debugging output 4032 //..................................................................... 4033 else { 4034 if (NewMonoMode) { 4035 Mono_Clear_Screen(); 4036 Mono_Printf(" Queue AI:\n"); // flowcount[0] 4037 Mono_Printf(" Build Packet Loop:\n"); // flowcount[1] 4038 Mono_Printf(" Frame Sync:\n"); // flowcount[2] 4039 Mono_Printf(" Frame Sync Resend:\n"); // flowcount[3] 4040 Mono_Printf(" Frame Sync Timeout:\n"); // flowcount[4] 4041 Mono_Printf(" Frame Sync New Message:\n"); // flowcount[5] 4042 Mono_Printf(" DoList Execution:\n"); // flowcount[6] 4043 Mono_Printf(" DoList Cleaning:\n"); // flowcount[7] 4044 Mono_Printf("\n"); 4045 Mono_Printf(" Frame:\n"); 4046 Mono_Printf(" MPlayerMaxAhead:\n"); 4047 Mono_Printf(" their_recv:\n"); 4048 Mono_Printf(" their_sent:\n"); 4049 Mono_Printf(" my_sent:\n"); 4050 Mono_Printf(" DesiredFrameRate:\n"); 4051 NewMonoMode = 0; 4052 } 4053 } 4054 } 4055 #else 4056 net = net; 4057 #endif 4058 } // end of Init_Queue_Mono 4059 4060 4061 /*************************************************************************** 4062 * Update_Queue_Mono -- updates mono display * 4063 * * 4064 * INPUT: * 4065 * net ptr to connection manager * 4066 * flow_index index # for flow-count updates * 4067 * -1: display * 4068 * * 4069 * OUTPUT: * 4070 * none. * 4071 * * 4072 * WARNINGS: * 4073 * none. * 4074 * * 4075 * HISTORY: * 4076 * 11/21/1995 BRR : Created. * 4077 *=========================================================================*/ 4078 static void Update_Queue_Mono(ConnManClass *net, int flow_index) 4079 { 4080 #if(SHOW_MONO) 4081 static int flowcount[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 4082 4083 //------------------------------------------------------------------------ 4084 // If 'NetMonoMode' is 1, display flowcount info 4085 //------------------------------------------------------------------------ 4086 if (NetMonoMode==1) { 4087 if (flow_index >= 0 && flow_index < 20) { 4088 Mono_Set_Cursor(35,flow_index); 4089 flowcount[flow_index]++; 4090 Mono_Printf("%d",flowcount[flow_index]); 4091 } 4092 } 4093 //------------------------------------------------------------------------ 4094 // Otherwise, display the connection debug screen 4095 //------------------------------------------------------------------------ 4096 else { 4097 net->Mono_Debug_Print (0,0); 4098 } 4099 4100 #else 4101 flow_index = flow_index; 4102 net = net; 4103 #endif 4104 4105 } // end of Update_Queue_Mono 4106 4107 4108 /*************************************************************************** 4109 * Print_Framesync_Values -- displays frame-sync variables * 4110 * * 4111 * INPUT: * 4112 * curframe current game Frame # * 4113 * max_ahead max-ahead value * 4114 * num_connections # connections * 4115 * their_recv # commands I've received from my connections * 4116 * their_sent # commands each connection claims to have sent * 4117 * my_sent # commands I've sent * 4118 * * 4119 * OUTPUT: * 4120 * none. * 4121 * * 4122 * WARNINGS: * 4123 * none. * 4124 * * 4125 * HISTORY: * 4126 * 11/21/1995 BRR : Created. * 4127 *=========================================================================*/ 4128 static void Print_Framesync_Values(long curframe, unsigned long max_ahead, 4129 int num_connections, unsigned short *their_recv, 4130 unsigned short *their_sent, unsigned short my_sent) 4131 { 4132 #if(SHOW_MONO) 4133 int i; 4134 4135 if (NetMonoMode==1) { 4136 Mono_Set_Cursor(35,9); 4137 Mono_Printf("%d",curframe); 4138 4139 Mono_Set_Cursor(35,10); 4140 Mono_Printf("%d",max_ahead); 4141 4142 for (i = 0; i < num_connections; i++) { 4143 Mono_Set_Cursor(35 + i*5,11); 4144 Mono_Printf("%4d",(int)their_recv[i]); 4145 } 4146 4147 for (i = 0; i < num_connections; i++) { 4148 Mono_Set_Cursor(35 + i*5,12); 4149 Mono_Printf("%4d",(int)their_sent[i]); 4150 } 4151 4152 Mono_Set_Cursor(35,13); 4153 Mono_Printf("%4d",(int)my_sent); 4154 4155 Mono_Set_Cursor(35,14); 4156 Mono_Printf("%2d",(int)DesiredFrameRate); 4157 } 4158 #else 4159 curframe = curframe; 4160 max_ahead = max_ahead; 4161 num_connections = num_connections; 4162 their_recv = their_recv; 4163 their_sent = their_sent; 4164 my_sent = my_sent; 4165 #endif 4166 } // end of Print_Framesync_Values 4167 4168 4169 /*************************************************************************** 4170 * Dump_Packet_Too_Late_Stuff -- Dumps a debug file to disk * 4171 * * 4172 * INPUT: * 4173 * event ptr to event to print * 4174 * * 4175 * OUTPUT: * 4176 * none. * 4177 * * 4178 * WARNINGS: * 4179 * none. * 4180 * * 4181 * HISTORY: * 4182 * 06/28/1996 BRR : Created. * 4183 *=========================================================================*/ 4184 void Dump_Packet_Too_Late_Stuff(EventClass *event) 4185 { 4186 FILE *fp; 4187 int i; 4188 4189 fp = fopen("toolate.txt", "wt"); 4190 if (!fp) { 4191 return; 4192 } 4193 fprintf(fp,"--------- Event data: -------------------\n"); 4194 fprintf(fp,"Type: %s\n",EventClass::EventNames[event->Type]); 4195 fprintf(fp,"Frame: %d\n",event->Frame); 4196 fprintf(fp,"ID: %d\n",event->ID); 4197 fprintf(fp,"MPlayerID: %04x\n",event->MPlayerID); 4198 4199 for (i = 0; i < MPlayerCount; i++) { 4200 if (event->MPlayerID == MPlayerID[i]) { 4201 fprintf(fp,"Player's Name: %s",MPlayerNames[i]); 4202 } 4203 } 4204 4205 fprintf(fp,"----------- My data: ------------------\n"); 4206 fprintf(fp,"Frame:%d\n",Frame); 4207 fprintf(fp,"MaxAhead:%d\n",MPlayerMaxAhead); 4208 4209 fclose(fp); 4210 } 4211 4212 #endif //DEMO 4213 4214 /*************************** end of queue.cpp ******************************/