NETDLG.CPP (211680B)
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&c\vcs\code\netdlg.cpv 2.17 16 Oct 1995 16:52:26 JOE_BOSTIC $ */ 17 /*********************************************************************************************** 18 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** 19 *********************************************************************************************** 20 * * 21 * Project Name : Command & Conquer * 22 * * 23 * File Name : NETDLG.CPP * 24 * * 25 * Programmer : Bill Randolph * 26 * * 27 * Start Date : January 23, 1995 * 28 * * 29 * Last Update : July 8, 1995 [BRR] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * * 33 * These routines establish & maintain peer-to-peer connections between this system * 34 * and all others in the game. Each system finds out the IPX address of the others, * 35 * and forms a direct connection (IPXConnectionClass) to that system. Systems are * 36 * found out via broadcast queries. Every system broadcasts its queries, and every * 37 * system replies to queries it receives. At the point when the game owner signals * 38 * 'OK', every system must know about all the other systems in the game. * 39 * * 40 * How Bridges are handled: * 41 * Currently, bridges are handled by specifying the destination IPX address of the * 42 * "server" (game owner's system) on the command-line. This address is used to * 43 * derive a broadcast address to that destination network, and this system's queries * 44 * are broadcast over its network & the server's network; replies to the queries come * 45 * with each system's IPX address attached, so once we have the address, we can form * 46 * a connection with any system on the bridged net. * 47 * * 48 * The flaw in this plan is that we can only cross one bridge. If there are 3 nets * 49 * bridged (A, B, & C), and the server is on net B, and we're on net A, our broadcasts * 50 * will reach nets A & B, but not C. The way to circumvent this (if it becomes a problem) * 51 * would be to have the server tell us what other systems are in its game, not each * 52 * individual player's system. Thus, each system would find out about all the other systems * 53 * by interacting with the game's owner system (this would be more involved than what * 54 * I'm doing here). * 55 * * 56 * Here's a list of all the different packets sent over the Global Channel: * 57 * * 58 * NET_QUERY_GAME * 59 * (no other data) * 60 * NET_ANSWER_GAME * 61 * Name: game owner's name * 62 * GameInfo: game's version & open state * 63 * NET_QUERY_PLAYER * 64 * Name: name of game we want players to respond for * 65 * NET_ANSWER_PLAYER * 66 * Name: player's name * 67 * PlayerInfo: info about player * 68 * NET_QUERY_JOIN * 69 * Name: name of player wanting to join * 70 * PlayerInfo: player's requested house & color * 71 * NET_CONFIRM_JOIN * 72 * PlayerInfo: approves player's house & color * 73 * NET_REJECT_JOIN * 74 * (no other data) * 75 * NET_GAME_OPTIONS * 76 * ScenarioInfo: info about scenario * 77 * NET_SIGN_OFF * 78 * Name: name of player signing off * 79 * NET_PING * 80 * (no other data) * 81 * NET_GO * 82 * Delay: value of one-way response time, in frames * 83 * * 84 *---------------------------------------------------------------------------------------------* 85 * Functions: * 86 * Clear_Game_List -- Clears the game-name listbox & 'Games' Vector * 87 * Clear_Player_List -- Clears the player-name listbox & Vector * 88 * Destroy_Connection -- destroys the given connection * 89 * Get_Join_Responses -- sends queries for the Join Dialog * 90 * Get_NewGame_Responses -- processes packets for New Game dialog * 91 * Init_Network -- initializes network stuff * 92 * Net_Join_Dialog -- lets user join an existing game, or start a new one * 93 * Net_New_Dialog -- lets user start a new game * 94 * Process_Global_Packet -- responds to remote queries * 95 * Remote_Connect -- handles connecting this user to others * 96 * Request_To_Join -- Sends a JOIN request packet to game owner * 97 * Send_Join_Queries -- sends queries for the Join Dialog * 98 * Shutdown_Network -- shuts down network stuff * 99 * Compute_Name_CRC -- computes CRC from char string * 100 * Net_Reconnect_Dialog -- Draws/updates the network reconnect dialog * 101 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 102 103 #include "function.h" 104 #include <time.h> 105 #include "tcpip.h" 106 #include "ccdde.h" 107 #define SHOW_MONO 0 108 109 // ST = 12/17/2018 5:44PM 110 #ifndef TickCount 111 extern TimerClass TickCount; 112 #endif 113 114 #ifndef DEMO 115 116 /*--------------------------------------------------------------------------- 117 The possible states of the join-game dialog 118 ---------------------------------------------------------------------------*/ 119 typedef enum { 120 JOIN_REJECTED = -1, // we've been rejected 121 JOIN_NOTHING, // we're not trying to join a game 122 JOIN_WAIT_CONFIRM, // we're asking to join, & waiting for confirmation 123 JOIN_CONFIRMED, // we've been confirmed 124 JOIN_GAME_START, // the game we've joined is starting 125 } JoinStateType; 126 127 /*--------------------------------------------------------------------------- 128 The possible return codes from Get_Join_Responses() 129 ---------------------------------------------------------------------------*/ 130 typedef enum { 131 EV_NONE, // nothing happened 132 EV_STATE_CHANGE, // Join dialog is in a new state 133 EV_NEW_GAME, // a new game was detected 134 EV_NEW_PLAYER, // a new player was detected 135 EV_PLAYER_SIGNOFF, // a player has signed off 136 EV_GAME_SIGNOFF, // a gamed owner has signed off 137 EV_GAME_OPTIONS, // a game options packet was received 138 EV_MESSAGE, // a message was received 139 } JoinEventType; 140 141 142 /* 143 ******************************** Prototypes ********************************* 144 */ 145 static int Net_Join_Dialog(void); 146 static void Clear_Game_List (ListClass *gamelist); 147 static void Clear_Player_List (ListClass *playerlist); 148 static int Request_To_Join (char *playername, int join_index, ListClass *playerlist, 149 HousesType house, int color); 150 static void Send_Join_Queries(int curgame, int gamenow, int playernow); 151 static JoinEventType Get_Join_Responses(JoinStateType *joinstate, ListClass *gamelist, 152 ColorListClass *playerlist, int join_index); 153 static int Net_New_Dialog(void); 154 static JoinEventType Get_NewGame_Responses(ColorListClass *playerlist); 155 static int Net_Fake_New_Dialog(void); 156 static int Net_Fake_Join_Dialog(void); 157 158 159 /*********************************************************************************************** 160 * Init_Network -- initializes network stuff * 161 * * 162 * INPUT: * 163 * none. * 164 * * 165 * OUTPUT: * 166 * true = Initialization OK, false = error * 167 * * 168 * WARNINGS: * 169 * none. * 170 * * 171 * HISTORY: * 172 * 02/14/1995 BR : Created. * 173 *=============================================================================================*/ 174 bool Init_Network (void) 175 { 176 NetNumType net; 177 NetNodeType node; 178 179 /*------------------------------------------------------------------------ 180 This call allocates all necessary queue buffers, allocates Real-mode 181 memory, and commands IPX to start listening on the Global Channel. 182 ------------------------------------------------------------------------*/ 183 if (!Ipx.Init()) 184 return(false); 185 186 /*------------------------------------------------------------------------ 187 Allocate our "meta-packet" buffer 188 ------------------------------------------------------------------------*/ 189 if (!MetaPacket) { 190 MetaPacket = new char [sizeof (EventClass) * MAX_EVENTS]; 191 } 192 193 /*------------------------------------------------------------------------ 194 Set up the IPX manager to cross a bridge 195 ------------------------------------------------------------------------*/ 196 if (!(GameToPlay == GAME_INTERNET)){ 197 if (IsBridge) { 198 BridgeNet.Get_Address(net,node); 199 Ipx.Set_Bridge(net); 200 } 201 } 202 203 return(true); 204 205 } /* end of Init_Network */ 206 207 208 /*********************************************************************************************** 209 * Shutdown_Network -- shuts down network stuff * 210 * * 211 * INPUT: * 212 * none. * 213 * * 214 * OUTPUT: * 215 * none. * 216 * * 217 * WARNINGS: * 218 * none. * 219 * * 220 * HISTORY: * 221 * 02/14/1995 BR : Created. * 222 *=============================================================================================*/ 223 void Shutdown_Network (void) 224 { 225 226 // 227 // Note: The thought behind this section of code was that if the program 228 // terminates early, without an EventClass::EXIT event, it still needs to 229 // tell the other systems that it's gone, so it would send a SIGN_OFF packet. 230 // BUT, this causes a sync bug if the systems are running slow and this system 231 // is running ahead of the others; it will send the NET_SIGN_OFF >>before<< 232 // the other system execute their EventClass::EXIT event, and the other systems 233 // will kill the connection at some random Frame # & turn my stuff over to 234 // the computer possibly at different times. 235 // BRR, 10/29/96 236 // 237 #if (0) 238 /*------------------------------------------------------------------------ 239 Broadcast a sign-off packet, by sending the packet over the Global Channel, 240 telling the IPX Manager that no ACK is required, and specifying a NULL 241 destination address. 242 ------------------------------------------------------------------------*/ 243 memset (&GPacket, 0, sizeof(GlobalPacketType)); 244 245 GPacket.Command = NET_SIGN_OFF; 246 strcpy (GPacket.Name, MPlayerName); 247 248 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 0, NULL); 249 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 0, NULL); 250 251 if (IsBridge && !Winsock.Get_Connected()) { 252 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, &BridgeNet); 253 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, &BridgeNet); 254 } 255 256 /*------------------------------------------------------------------------ 257 Wait for the packets to finish going out (or the Global Channel times out) 258 ------------------------------------------------------------------------*/ 259 for (;;) { 260 if (Ipx.Global_Num_Send()==0) { 261 break; 262 } 263 Ipx.Service(); 264 } 265 266 #endif //(0) 267 268 /*------------------------------------------------------------------------ 269 Delete our "meta-packet" 270 ------------------------------------------------------------------------*/ 271 delete [] MetaPacket; 272 MetaPacket = 0; 273 274 /*------------------------------------------------------------------------ 275 If I was in a game, I'm not now, so clear the game name 276 ------------------------------------------------------------------------*/ 277 MPlayerGameName[0] = 0; 278 } 279 280 281 /*********************************************************************************************** 282 * Process_Global_Packet -- responds to remote queries * 283 * * 284 * The only commands from other systems this routine responds to are NET_QUERY_GAME * 285 * and NET_QUERY_PLAYER. The other commands are too context-specific to be able * 286 * to handle here, such as joining the game or signing off; but this routine handles * 287 * the majority of the program's needs. * 288 * * 289 * INPUT: * 290 * packet ptr to packet to process * 291 * address source address of sender * 292 * * 293 * OUTPUT: * 294 * true = packet was processed, false = wasn't * 295 * * 296 * WARNINGS: * 297 * MPlayerName & MPlayerGameName must have been filled in before this function * 298 * can be called. * 299 * * 300 * HISTORY: * 301 * 02/15/1995 BR : Created. * 302 *=============================================================================================*/ 303 bool Process_Global_Packet(GlobalPacketType *packet, IPXAddressClass *address) 304 { 305 GlobalPacketType mypacket; 306 307 /* 308 ---------------- Another system asking what game this is ----------------- 309 */ 310 if (packet->Command==NET_QUERY_GAME && NetStealth==0) { 311 /*..................................................................... 312 If the game is closed, let every player respond, and let the sender of 313 the query sort it all out. This way, if the game's host exits the game, 314 the game still shows up on other players' dialogs. 315 If the game is open, only the game owner may respond. 316 .....................................................................*/ 317 if (strlen(MPlayerName) > 0 && strlen(MPlayerGameName) > 0 && 318 ((!NetOpen) || (NetOpen && !strcmp(MPlayerName,MPlayerGameName)))) { 319 memset (packet, 0, sizeof(GlobalPacketType)); 320 321 mypacket.Command = NET_ANSWER_GAME; 322 strcpy(mypacket.Name, MPlayerGameName); 323 #ifdef PATCH 324 if (IsV107) { 325 mypacket.GameInfo.Version = 1; 326 } else { 327 mypacket.GameInfo.Version = 2; 328 } 329 #else 330 mypacket.GameInfo.Version = Version_Number(); 331 #endif 332 mypacket.GameInfo.IsOpen = NetOpen; 333 334 Ipx.Send_Global_Message (&mypacket, sizeof(GlobalPacketType), 1, 335 address); 336 } 337 return(true); 338 } else { 339 340 /* 341 ----------------- Another system asking what player I am ----------------- 342 */ 343 if (packet->Command==NET_QUERY_PLAYER && 344 !strcmp (packet->Name, MPlayerGameName) && 345 (strlen(MPlayerGameName) > 0) && NetStealth==0) { 346 memset (packet, 0, sizeof(GlobalPacketType)); 347 348 mypacket.Command = NET_ANSWER_PLAYER; 349 strcpy(mypacket.Name, MPlayerName); 350 mypacket.PlayerInfo.House = MPlayerHouse; 351 mypacket.PlayerInfo.Color = MPlayerColorIdx; 352 mypacket.PlayerInfo.NameCRC = Compute_Name_CRC(MPlayerGameName); 353 354 Ipx.Send_Global_Message (&mypacket, sizeof(GlobalPacketType), 1, address); 355 return(true); 356 } 357 } 358 return(false); 359 } 360 361 362 /*********************************************************************************************** 363 * Destroy_Connection -- destroys the given connection * 364 * * 365 * Call this routine when a connection goes bad, or another player signs off. * 366 * * 367 * INPUT: * 368 * id connection ID to destroy * 369 * error 0 = user signed off; 1 = connection error; otherwise, no error is shown. * 370 * * 371 * OUTPUT: * 372 * none. * 373 * * 374 * WARNINGS: * 375 * none. * 376 * * 377 * HISTORY: * 378 * 04/22/1995 BR : Created. * 379 *=============================================================================================*/ 380 void Destroy_Connection(int id, int error) 381 { 382 int i,j; 383 HousesType house; 384 HouseClass *housep; 385 char txt[80]; 386 387 /*------------------------------------------------------------------------ 388 Create a message to display to the user 389 ------------------------------------------------------------------------*/ 390 txt[0] = '\0'; 391 if (error==1) { 392 sprintf(txt,Text_String(TXT_CONNECTION_LOST),Ipx.Connection_Name(id)); 393 } else if (error==0) { 394 sprintf(txt,Text_String(TXT_LEFT_GAME),Ipx.Connection_Name(id)); 395 } 396 397 if (strlen(txt)) { 398 Messages.Add_Message (txt, 399 MPlayerTColors[MPlayerID_To_ColorIndex((unsigned char)id)], 400 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 600, 0, 0); 401 Map.Flag_To_Redraw(false); 402 } 403 404 /*------------------------------------------------------------------------ 405 Delete the IPX connection, shift the MPlayerID's & MPlayerHouses' back one. 406 ------------------------------------------------------------------------*/ 407 Ipx.Delete_Connection(id); 408 409 for (i = 0; i < MPlayerCount; i++) { 410 if (MPlayerID[i] == (unsigned char)id) { 411 /*.................................................................. 412 Turn the player's house over to the computer's AI 413 ..................................................................*/ 414 house = MPlayerHouses[i]; 415 housep = HouseClass::As_Pointer (house); 416 housep->IsHuman = false; 417 housep->IsStarted = true; 418 419 /*.................................................................. 420 Move arrays back by one 421 ..................................................................*/ 422 for (j = i; j < MPlayerCount - 1; j++) { 423 MPlayerID[j] = MPlayerID[j + 1]; 424 MPlayerHouses[j] = MPlayerHouses[j + 1]; 425 strcpy (MPlayerNames[j], MPlayerNames[j+1]); 426 TheirProcessTime[j] = TheirProcessTime[j+1]; 427 } 428 } 429 } 430 431 MPlayerCount--; 432 433 /*------------------------------------------------------------------------ 434 If we're the last player left, tell the user. 435 ------------------------------------------------------------------------*/ 436 if (MPlayerCount == 1) { 437 sprintf(txt,"%s",Text_String(TXT_JUST_YOU_AND_ME)); 438 Messages.Add_Message (txt, 439 MPlayerTColors[MPlayerID_To_ColorIndex((unsigned char)id)], 440 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 600, 0, 0); 441 Map.Flag_To_Redraw(false); 442 } 443 444 } /* end of Destroy_Connection */ 445 446 447 /*********************************************************************************************** 448 * Remote_Connect -- handles connecting this user to others * 449 * * 450 * INPUT: * 451 * none. * 452 * * 453 * OUTPUT: * 454 * true = connections established; false = not * 455 * * 456 * WARNINGS: * 457 * none. * 458 * * 459 * HISTORY: * 460 * 02/14/1995 BR : Created. * 461 *=============================================================================================*/ 462 bool Remote_Connect(void) 463 { 464 int rc; 465 int stealth; // original state of NetStealth flag 466 467 /*------------------------------------------------------------------------ 468 Init network timing parameters; these values should work for both a "real" 469 network, and a simulated modem network (ie Kali) 470 ------------------------------------------------------------------------*/ 471 Ipx.Set_Timing ( 30, // retry 2 times per second 472 -1, // ignore max retries 473 600); // give up after 10 seconds 474 475 /*------------------------------------------------------------------------ 476 Save the original value of the NetStealth flag, so we can turn stealth 477 off for now (during this portion of the dialogs, we must show ourselves) 478 ------------------------------------------------------------------------*/ 479 stealth = NetStealth; 480 NetStealth = 0; 481 482 /*------------------------------------------------------------------------ 483 Init my game name to 0-length, since I haven't joined any game yet. 484 ------------------------------------------------------------------------*/ 485 MPlayerGameName[0] = 0; 486 487 /*------------------------------------------------------------------------ 488 The game is now "open" for joining. Close it as soon as we exit this 489 routine. 490 ------------------------------------------------------------------------*/ 491 NetOpen = 1; 492 493 /*------------------------------------------------------------------------ 494 Read the default values from the INI file 495 ------------------------------------------------------------------------*/ 496 Read_MultiPlayer_Settings (); 497 498 /*------------------------------------------------------------------------ 499 Keep looping until something useful happens. 500 ------------------------------------------------------------------------*/ 501 while (1) { 502 /*--------------------------------------------------------------------- 503 Pop up the network Join/New dialog 504 ---------------------------------------------------------------------*/ 505 rc = Net_Join_Dialog(); 506 507 /*--------------------------------------------------------------------- 508 -1 = user selected Cancel 509 ---------------------------------------------------------------------*/ 510 if (rc==-1) { 511 NetStealth = stealth; 512 NetOpen = 0; 513 return(false); 514 } else { 515 516 /*--------------------------------------------------------------------- 517 0 = user has joined an existing game; save values & return 518 ---------------------------------------------------------------------*/ 519 if (rc==0) { 520 Write_MultiPlayer_Settings (); 521 NetStealth = stealth; 522 NetOpen = 0; 523 524 return(true); 525 } else { 526 527 /*--------------------------------------------------------------------- 528 1 = user requests New Network Game 529 ---------------------------------------------------------------------*/ 530 if (rc==1) { 531 /*.................................................................. 532 Pop up the New Network Game dialog; if user selects OK, return 533 'true'; otherwise, return to the Join Dialog. 534 ..................................................................*/ 535 if (Net_New_Dialog()) { 536 Write_MultiPlayer_Settings (); 537 NetOpen = 0; 538 NetStealth = stealth; 539 NetOpen = 0; 540 541 return(true); 542 } else { 543 continue; 544 } 545 } 546 } 547 } 548 } 549 } 550 551 552 553 /*********************************************************************************************** 554 * Remote_Connect -- handles connecting this host to the server in an internet game * 555 * * 556 * INPUT: * 557 * none. * 558 * * 559 * OUTPUT: * 560 * true = connections established; false = not * 561 * * 562 * WARNINGS: * 563 * none. * 564 * * 565 * HISTORY: * 566 * 02/14/1995 BR : Created. * 567 *=============================================================================================*/ 568 bool Server_Remote_Connect(void) 569 { 570 int stealth; // original state of NetStealth flag 571 572 /*------------------------------------------------------------------------ 573 Init network timing parameters; these values should work for both a "real" 574 network, and a simulated modem network (ie Kali) 575 ------------------------------------------------------------------------*/ 576 Ipx.Set_Timing ( 30, // retry 2 times per second 577 -1, // ignore max retries 578 600); // give up after 10 seconds 579 580 /*------------------------------------------------------------------------ 581 Save the original value of the NetStealth flag, so we can turn stealth 582 off for now (during this portion of the dialogs, we must show ourselves) 583 ------------------------------------------------------------------------*/ 584 stealth = NetStealth; 585 NetStealth = 0; 586 587 /*------------------------------------------------------------------------ 588 The game is now "open" for joining. Close it as soon as we exit this 589 routine. 590 ------------------------------------------------------------------------*/ 591 NetOpen = 1; 592 593 /*------------------------------------------------------------------------ 594 Read the default values from the INI file 595 ------------------------------------------------------------------------*/ 596 Read_MultiPlayer_Settings (); 597 598 if (!Net_Fake_New_Dialog()){ 599 Write_MultiPlayer_Settings (); 600 return (false); 601 } 602 603 NetOpen = 0; 604 NetStealth = stealth; 605 Write_MultiPlayer_Settings (); 606 return (true); 607 } 608 609 610 /*********************************************************************************************** 611 * Client_Remote_Connect -- handles connecting this client to the server in an internet game * 612 * * 613 * INPUT: * 614 * none. * 615 * * 616 * OUTPUT: * 617 * true = connections established; false = not * 618 * * 619 * WARNINGS: * 620 * none. * 621 * * 622 * HISTORY: * 623 * 02/14/1995 ST : Created. * 624 *=============================================================================================*/ 625 bool Client_Remote_Connect(void) 626 { 627 int rc; 628 int stealth; // original state of NetStealth flag 629 630 /*------------------------------------------------------------------------ 631 Init network timing parameters; these values should work for both a "real" 632 network, and a simulated modem network (ie Kali) 633 ------------------------------------------------------------------------*/ 634 Ipx.Set_Timing ( 30, // retry 2 times per second 635 -1, // ignore max retries 636 600); // give up after 10 seconds 637 638 /*------------------------------------------------------------------------ 639 Save the original value of the NetStealth flag, so we can turn stealth 640 off for now (during this portion of the dialogs, we must show ourselves) 641 ------------------------------------------------------------------------*/ 642 stealth = NetStealth; 643 NetStealth = 0; 644 645 /*------------------------------------------------------------------------ 646 The game is now "open" for joining. Close it as soon as we exit this 647 routine. 648 ------------------------------------------------------------------------*/ 649 NetOpen = 1; 650 651 /*------------------------------------------------------------------------ 652 Read the default values from the INI file 653 ------------------------------------------------------------------------*/ 654 Read_MultiPlayer_Settings (); 655 656 /*--------------------------------------------------------------------- 657 Pop up the network Join/New dialog 658 ---------------------------------------------------------------------*/ 659 rc = Net_Fake_Join_Dialog(); 660 Write_MultiPlayer_Settings (); 661 662 NetStealth = stealth; 663 NetOpen = 0; 664 665 if (rc == -1) { 666 return(false); 667 } else { 668 return(true); 669 } 670 } 671 672 673 674 /*********************************************************************************************** 675 * Net_Join_Dialog -- lets user join an existing game or start a new one * 676 * * 677 * This dialog displays an edit field for the player's name, and a list of all non-stealth- * 678 * mode games. Clicking once on a game name displays a list of who's in that game. Clicking * 679 * "New" takes the user to the Net_New dialog, where he waits for other users to join his * 680 * game. All other input is done through this dialog. * 681 * * 682 * The dialog has several "states": * 683 * * 684 * 1) Initially, it waits for the user to fill in his/her name and then to select Join or New; * 685 * if New is selected, this dialog is exited. * 686 * * 687 * 2) If Join is selected, the Join & New buttons are removed, but the Cancel button remains. * 688 * The join request is transmitted to the game's owner, and the message "Waiting for * 689 * Confirmation" is displayed, until a confirmation or denial is received from the game's * 690 * owner. The user may click Cancel at this point to cancel the join request. * 691 * (Once Join is selected, the name editing field is disabled, and becomes a display-only * 692 * field. If cancel is selected, it reappears as an edit field.) The user can still click * 693 * around & see who's in which games. * 694 * * 695 * 3) If the join request is denied, the dialog re-initializes to its pre-join state; the * 696 * Join & New buttons reappear, & the Name field is available again. * 697 * * 698 * 4) If join confirmation is obtained, the message just changes to "Confirmed. Waiting for * 699 * Entry Signal." or some such nonsense. The user can still click around & see who's * 700 * in which games. * 701 * * 702 * Any game running in Stealth mode won't show up on this dialog. * 703 * * 704 * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ * 705 * ³ Network Games ³ * 706 * ³ ³ * 707 * ³ Your Name: ____________ ³ * 708 * ³ House: [GDI] [NOD] ³ * 709 * ³ Desired Color: [ ][ ][ ][ ] ³ * 710 * ³ ³ * 711 * ³ Games Players ³ * 712 * ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿ ³ * 713 * ³ ³(Bill's Game )³³ ³ Peter Parker GDI ³³ ³ * 714 * ³ ³ Peter Parker's Game ÃÄ´ ³ Mary Jane GDI ÃÄ´ ³ * 715 * ³ ³(Magnum PI's Game )³ ³ ³ JJ Jameson NOD ³ ³ ³ * 716 * ³ ³ ÃÄ´ ³ ÃÄ´ ³ * 717 * ³ ³ ³³ ³ ³³ ³ * 718 * ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ ³ * 719 * ³ Scenario: Big Long Description ³ * 720 * ³ Starting Credits: xxxx ³ * 721 * ³ Count: --- Level: --- ³ * 722 * ³ Bases: ON Crates: ON ³ * 723 * ³ Tiberium: ON AI Players: ON ³ * 724 * ³ ³ * 725 * ³ [Join] [Cancel] [New] ³ * 726 * ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ * 727 * ³ ³ ³ ³ * 728 * ³ ³ ³ ³ * 729 * ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ * 730 * ³ [Send Message] ³ * 731 * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ * 732 * * 733 * INPUT: * 734 * none. * 735 * * 736 * OUTPUT: * 737 * -1 = cancel, 0 = OK, 1 = New net game requested * 738 * * 739 * WARNINGS: * 740 * none. * 741 * * 742 * HISTORY: * 743 * 02/14/1995 BR : Created. * 744 *=============================================================================================*/ 745 static int Net_Join_Dialog(void) 746 { 747 int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2; 748 /*........................................................................ 749 Dialog & button dimensions 750 ........................................................................*/ 751 /* ###Change collision detected! C:\PROJECTS\CODE\NETDLG.CPP... */ 752 int d_dialog_w = 287 *factor; // dialog width 753 int d_dialog_h = 198*factor; // dialog height 754 int d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord 755 int d_dialog_y = ((200*factor - d_dialog_h) / 2); // centered y-coord 756 int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord 757 758 int d_txt6_h = 6*factor+1; // ht of 6-pt text 759 int d_margin1 = 5*factor; // large margin 760 int d_margin2 = 2*factor; // small margin 761 762 int d_name_w = 70*factor; 763 int d_name_h = 9*factor; 764 int d_name_x = d_dialog_cx - 10*factor; 765 int d_name_y = d_dialog_y + d_margin1 + d_txt6_h + d_txt6_h; 766 767 int d_gdi_w = 30*factor; 768 int d_gdi_h = 9*factor; 769 int d_gdi_x = d_dialog_cx - 10*factor; 770 int d_gdi_y = d_name_y + d_name_h + d_margin2; 771 772 int d_nod_w = 30*factor; 773 int d_nod_h = 9*factor; 774 int d_nod_x = d_gdi_x + d_gdi_w; 775 int d_nod_y = d_name_y + d_name_h + d_margin2; 776 777 int d_color_w = 10*factor; 778 int d_color_h = 9*factor; 779 int d_color_y = d_nod_y + d_nod_h + d_margin2; 780 781 int d_gamelist_w = 160*factor; 782 int d_gamelist_h = 27*factor; 783 int d_gamelist_x = d_dialog_x + d_margin1; 784 int d_gamelist_y = d_color_y + d_color_h + d_margin1 + d_txt6_h; 785 786 int d_playerlist_w = 106*factor; 787 int d_playerlist_h = 27*factor; 788 int d_playerlist_x = d_dialog_x + d_dialog_w - d_margin1 - d_playerlist_w; 789 int d_playerlist_y = d_color_y + d_color_h + d_margin1 + d_txt6_h; 790 791 int d_msg1_y = d_gamelist_y + d_gamelist_h + d_margin1; 792 int d_msg2_y = d_msg1_y + d_txt6_h; 793 int d_msg3_y = d_msg2_y + d_txt6_h; 794 int d_msg4_y = d_msg3_y + d_txt6_h; 795 int d_msg5_y = d_msg4_y + d_txt6_h; 796 797 int d_join_w = 40*factor; 798 int d_join_h = 9*factor; 799 int d_join_x = d_dialog_x + (d_dialog_w / 6) - (d_join_w / 2); 800 int d_join_y = d_msg5_y + d_txt6_h + d_margin1; 801 802 #if (GERMAN | FRENCH) 803 int d_cancel_w = 50*factor; 804 #else 805 int d_cancel_w = 40*factor; 806 #endif 807 int d_cancel_h = 9*factor; 808 int d_cancel_x = d_dialog_cx - d_cancel_w / 2; 809 int d_cancel_y = d_msg5_y + d_txt6_h + d_margin1; 810 811 int d_new_w = 40*factor; 812 int d_new_h = 9*factor; 813 int d_new_x = d_dialog_x + ((d_dialog_w * 5) / 6) - (d_new_w / 2); 814 int d_new_y = d_msg5_y + d_txt6_h + d_margin1; 815 816 int d_message_w = d_dialog_w - (d_margin1 * 2); 817 int d_message_h = 34*factor; 818 int d_message_x = d_dialog_x + d_margin1; 819 int d_message_y = d_cancel_y + d_cancel_h + d_margin1; 820 821 int d_send_w = 80*factor; 822 int d_send_h = 9*factor; 823 int d_send_x = d_dialog_cx - (d_send_w / 2); 824 int d_send_y = d_message_y + d_message_h + d_margin2; 825 826 /*........................................................................ 827 Button Enumerations 828 ........................................................................*/ 829 enum { 830 BUTTON_NAME = 100, 831 BUTTON_GDI, 832 BUTTON_NOD, 833 BUTTON_GAMELIST, 834 BUTTON_PLAYERLIST, 835 BUTTON_JOIN, 836 BUTTON_CANCEL, 837 BUTTON_NEW, 838 BUTTON_SEND, 839 }; 840 841 /*........................................................................ 842 Redraw values: in order from "top" to "bottom" layer of the dialog 843 ........................................................................*/ 844 typedef enum { 845 REDRAW_NONE = 0, 846 REDRAW_MESSAGE, 847 REDRAW_COLORS, 848 REDRAW_BUTTONS, 849 REDRAW_BACKGROUND, 850 REDRAW_ALL = REDRAW_BACKGROUND 851 } RedrawType; 852 853 /*........................................................................ 854 Dialog variables 855 ........................................................................*/ 856 RedrawType display = REDRAW_ALL; // redraw level 857 bool process = true; // process while true 858 KeyNumType input; 859 int cbox_x[] = { d_gdi_x, 860 d_gdi_x + d_color_w, 861 d_gdi_x + (d_color_w * 2), 862 d_gdi_x + (d_color_w * 3), 863 d_gdi_x + (d_color_w * 4), 864 d_gdi_x + (d_color_w * 5)}; 865 866 JoinStateType joinstate = JOIN_NOTHING; // current "state" of this dialog 867 char namebuf[MPLAYER_NAME_MAX] = {0}; // buffer for player's name 868 int tabs[] = {77*factor}; // tabs for player list box 869 int game_index = -1; // index of currently-selected game 870 int join_index = -1; // index of game we're joining 871 int rc = 0; // -1 = user cancelled, 1 = New 872 JoinEventType event; // event from incoming packet 873 int i,j; // loop counter 874 char txt[80]; 875 char const *p; 876 int parms_received; // 1 = game options received 877 int found; 878 879 unsigned char tmp_id[MAX_PLAYERS]; // temp storage for sorting player ID's 880 int min_index; // for sorting player ID's 881 unsigned char min_id; // for sorting player ID's 882 unsigned char id; // connection ID 883 char * item; 884 unsigned long starttime; 885 886 NodeNameType *who; 887 888 int message_length; 889 int sent_so_far; 890 unsigned short magic_number; 891 unsigned short crc; 892 893 void const *up_button; 894 void const *down_button; 895 896 if (InMainLoop){ 897 up_button = Hires_Retrieve("BTN-UP.SHP"); 898 down_button = Hires_Retrieve("BTN-DN.SHP"); 899 }else{ 900 up_button = Hires_Retrieve("BTN-UP2.SHP"); 901 down_button = Hires_Retrieve("BTN-DN2.SHP"); 902 } 903 904 905 /*........................................................................ 906 Buttons 907 ........................................................................*/ 908 GadgetClass *commands; // button list 909 910 EditClass name_edt (BUTTON_NAME, 911 namebuf, MPLAYER_NAME_MAX, TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 912 d_name_x, d_name_y, d_name_w, d_name_h, EditClass::ALPHANUMERIC); 913 914 TextButtonClass gdibtn(BUTTON_GDI, TXT_G_D_I, 915 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 916 d_gdi_x, d_gdi_y, d_gdi_w, d_gdi_h); 917 918 TextButtonClass nodbtn(BUTTON_NOD, TXT_N_O_D, 919 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 920 d_nod_x, d_nod_y, d_nod_w, d_nod_h); 921 922 ListClass gamelist(BUTTON_GAMELIST, 923 d_gamelist_x, d_gamelist_y, d_gamelist_w, d_gamelist_h, 924 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 925 up_button, 926 down_button); 927 928 ColorListClass playerlist(BUTTON_PLAYERLIST, 929 d_playerlist_x, d_playerlist_y, d_playerlist_w, d_playerlist_h, 930 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 931 up_button, 932 down_button); 933 934 TextButtonClass joinbtn(BUTTON_JOIN, TXT_JOIN, 935 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 936 #ifdef FRENCH 937 d_join_x, d_join_y); 938 #else 939 d_join_x, d_join_y, d_join_w, d_join_h); 940 #endif 941 942 TextButtonClass cancelbtn(BUTTON_CANCEL, TXT_CANCEL, 943 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 944 //#if (GERMAN | FRENCH) 945 // d_cancel_x, d_cancel_y); 946 //#else 947 d_cancel_x, d_cancel_y, d_cancel_w, d_cancel_h); 948 //#endif 949 950 TextButtonClass newbtn(BUTTON_NEW, TXT_NEW, 951 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 952 d_new_x, d_new_y, d_new_w, d_new_h); 953 954 TextButtonClass sendbtn(BUTTON_SEND, TXT_SEND_MESSAGE, 955 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 956 //#if (GERMAN | FRENCH) 957 // d_send_x, d_send_y); 958 //#else 959 d_send_x, d_send_y, d_send_w, d_send_h); 960 //#endif 961 962 playerlist.Set_Tabs(tabs); 963 964 /* 965 ----------------------------- Various Inits ------------------------------ 966 */ 967 MPlayerColorIdx = MPlayerPrefColor; // init my preferred color 968 strcpy (namebuf, MPlayerName); // set my name 969 name_edt.Set_Text(namebuf,MPLAYER_NAME_MAX); 970 name_edt.Set_Color (MPlayerTColors[MPlayerColorIdx]); 971 972 playerlist.Set_Selected_Style(ColorListClass::SELECT_NONE); 973 974 if (MPlayerHouse==HOUSE_GOOD) { 975 gdibtn.Turn_On(); 976 } else { 977 nodbtn.Turn_On(); 978 } 979 980 Fancy_Text_Print("", 0, 0, CC_GREEN, TBLACK, 981 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 982 983 Messages.Init (d_message_x + 2, d_message_y + 2, 4, 984 MAX_MESSAGE_LENGTH, d_txt6_h); 985 986 /* 987 --------------------------- Send network query --------------------------- 988 */ 989 Send_Join_Queries (game_index, 1, 0); 990 991 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 992 Blit_Hid_Page_To_Seen_Buff(); 993 Set_Palette(Palette); 994 995 /* 996 ---------------------------- Init Mono Output ---------------------------- 997 */ 998 #if(SHOW_MONO) 999 Ipx.Configure_Debug(-1, sizeof (GlobalHeaderType), 1000 sizeof(NetCommandType), GlobalPacketNames, 11); 1001 Ipx.Mono_Debug_Print(-1,1); 1002 #endif 1003 while (Get_Mouse_State() > 0) Show_Mouse(); 1004 1005 /* 1006 ---------------------------- Processing loop ----------------------------- 1007 */ 1008 while (process) { 1009 1010 /* 1011 ** If we have just received input focus again after running in the background then 1012 ** we need to redraw. 1013 */ 1014 if (AllSurfaces.SurfacesRestored){ 1015 AllSurfaces.SurfacesRestored=FALSE; 1016 display=REDRAW_ALL; 1017 } 1018 1019 #if(SHOW_MONO) 1020 Ipx.Mono_Debug_Print(-1,0); 1021 #endif 1022 /* 1023 ...................... Refresh display if needed ...................... 1024 */ 1025 if (display) { 1026 Hide_Mouse(); 1027 /* 1028 .................. Redraw backgound & dialog box ................... 1029 */ 1030 if (display >= REDRAW_BACKGROUND) { 1031 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 1032 Blit_Hid_Page_To_Seen_Buff(); 1033 Set_Palette(Palette); 1034 1035 Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h); 1036 1037 /*............................................................... 1038 Dialog & Field labels 1039 ...............................................................*/ 1040 Draw_Caption (TXT_JOIN_NETWORK_GAME, d_dialog_x, d_dialog_y, d_dialog_w); 1041 1042 Fancy_Text_Print(TXT_YOUR_NAME, 1043 d_name_x - 5, d_name_y + 1, CC_GREEN, TBLACK, 1044 TPF_RIGHT | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1045 1046 Fancy_Text_Print(TXT_SIDE_COLON, 1047 d_gdi_x - 5, d_gdi_y + 1, CC_GREEN, TBLACK, 1048 TPF_RIGHT | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1049 1050 Fancy_Text_Print(TXT_COLOR_COLON, 1051 cbox_x[0] - 5, d_color_y + 1, CC_GREEN, TBLACK, 1052 TPF_RIGHT | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1053 1054 Fancy_Text_Print(TXT_GAMES, 1055 d_gamelist_x + (d_gamelist_w / 2), d_gamelist_y - d_txt6_h, 1056 CC_GREEN, TBLACK, 1057 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1058 1059 Fancy_Text_Print(TXT_PLAYERS, 1060 d_playerlist_x + (d_playerlist_w / 2), d_playerlist_y - d_txt6_h, 1061 CC_GREEN, TBLACK, 1062 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1063 1064 /*............................................................... 1065 Join-state-specific labels: 1066 ...............................................................*/ 1067 if (joinstate > JOIN_NOTHING) { 1068 Fancy_Text_Print(namebuf, d_name_x, d_name_y + 1, CC_GREEN, 1069 TBLACK, TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1070 if (MPlayerHouse==HOUSE_GOOD) { 1071 Fancy_Text_Print(TXT_G_D_I, d_gdi_x, d_gdi_y + 1, CC_GREEN, 1072 TBLACK, TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1073 } else { 1074 Fancy_Text_Print(TXT_N_O_D, d_gdi_x, d_gdi_y + 1, CC_GREEN, 1075 TBLACK, TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1076 } 1077 } 1078 1079 /* 1080 .................... Rebuild the button list .................... 1081 */ 1082 cancelbtn.Zap(); 1083 gamelist.Zap(); 1084 playerlist.Zap(); 1085 gdibtn.Zap(); 1086 nodbtn.Zap(); 1087 name_edt.Zap(); 1088 joinbtn.Zap(); 1089 newbtn.Zap(); 1090 sendbtn.Zap(); 1091 1092 commands = &cancelbtn; 1093 gamelist.Add_Tail(*commands); 1094 playerlist.Add_Tail(*commands); 1095 /*............................................................... 1096 Only add the name edit field, the House, Join & New buttons if 1097 we're doing nothing, or we've just been rejected. 1098 ...............................................................*/ 1099 if (joinstate <= JOIN_NOTHING) { 1100 gdibtn.Add_Tail(*commands); 1101 nodbtn.Add_Tail(*commands); 1102 name_edt.Add_Tail(*commands); 1103 joinbtn.Add_Tail(*commands); 1104 newbtn.Add_Tail(*commands); 1105 } 1106 if (joinstate == JOIN_CONFIRMED) 1107 sendbtn.Add_Tail(*commands); 1108 } 1109 /* 1110 .......................... Redraw buttons .......................... 1111 */ 1112 if (display >= REDRAW_BUTTONS) { 1113 commands->Draw_All(); 1114 } 1115 1116 /*.................................................................. 1117 Draw the color boxes 1118 ..................................................................*/ 1119 if (display >= REDRAW_COLORS) { 1120 for (i = 0; i < MAX_MPLAYER_COLORS; i++) { 1121 LogicPage->Fill_Rect (cbox_x[i] + 1, d_color_y + 1, 1122 cbox_x[i] + 1 + d_color_w - 2, d_color_y + 1 + d_color_h - 2, 1123 MPlayerGColors[i]); 1124 1125 if (i == MPlayerColorIdx) { 1126 Draw_Box(cbox_x[i], d_color_y, d_color_w, d_color_h, 1127 BOXSTYLE_GREEN_DOWN, false); 1128 } else { 1129 Draw_Box(cbox_x[i], d_color_y, d_color_w, d_color_h, 1130 BOXSTYLE_GREEN_RAISED, false); 1131 } 1132 } 1133 } 1134 1135 /*.................................................................. 1136 Draw the message: 1137 - Erase an old message first 1138 - If we're in a game, print the game options (if they've been 1139 received) 1140 - If we've been rejected from a game, print that message 1141 ..................................................................*/ 1142 if (display >= REDRAW_MESSAGE) { 1143 Draw_Box(d_message_x, d_message_y, d_message_w, d_message_h, 1144 BOXSTYLE_GREEN_BORDER, true); 1145 Messages.Draw(); 1146 1147 LogicPage->Fill_Rect( d_dialog_x + 2, 1148 d_msg1_y, 1149 d_dialog_x + d_dialog_w - 4, 1150 d_msg5_y + d_txt6_h, 1151 BLACK); 1152 1153 if (joinstate==JOIN_CONFIRMED && parms_received) { 1154 /*............................................................ 1155 Scenario title 1156 ............................................................*/ 1157 p = Text_String(TXT_SCENARIO_COLON); 1158 if (ScenarioIdx != -1) { 1159 sprintf(txt,"%s %s",p, MPlayerScenarios[ScenarioIdx]); 1160 1161 Fancy_Text_Print (txt, d_dialog_cx, 1162 d_msg1_y, CC_GREEN, TBLACK, 1163 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW | TPF_CENTER); 1164 } else { 1165 sprintf(txt,"%s %s",p,Text_String(TXT_NOT_FOUND)); 1166 1167 Fancy_Text_Print (txt, d_dialog_cx, 1168 d_msg1_y, CC_NOD_COLOR, TBLACK, 1169 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW | TPF_CENTER); 1170 } 1171 1172 /*............................................................ 1173 # of credits 1174 ............................................................*/ 1175 p = Text_String(TXT_START_CREDITS_COLON); 1176 sprintf(txt, "%s %d", p, MPlayerCredits); 1177 Fancy_Text_Print (txt, d_dialog_cx, 1178 d_msg2_y, CC_GREEN, TBLACK, 1179 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW | TPF_CENTER); 1180 1181 /*............................................................ 1182 Count & Level values 1183 ............................................................*/ 1184 p = Text_String(TXT_COUNT); 1185 sprintf(txt,"%s %d",p,MPlayerUnitCount); 1186 Fancy_Text_Print (txt, 1187 d_dialog_x + (d_dialog_w / 4) - String_Pixel_Width(p), 1188 d_msg3_y, CC_GREEN, TBLACK, 1189 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1190 1191 p = Text_String(TXT_LEVEL); 1192 if (BuildLevel <= MPLAYER_BUILD_LEVEL_MAX) { 1193 sprintf(txt, "%s %d", p, BuildLevel); 1194 } else { 1195 sprintf(txt, "%s **", p); 1196 } 1197 Fancy_Text_Print (txt, 1198 d_dialog_x + d_dialog_w - (d_dialog_w / 4) - String_Pixel_Width(p), 1199 d_msg3_y, CC_GREEN, TBLACK, 1200 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1201 1202 /*............................................................ 1203 Bases 1204 ............................................................*/ 1205 p = Text_String(TXT_BASES_COLON); 1206 if (MPlayerBases) { 1207 sprintf(txt,"%s %s",p,Text_String(TXT_ON)); 1208 } else { 1209 sprintf(txt,"%s %s",p,Text_String(TXT_OFF)); 1210 } 1211 Fancy_Text_Print (txt, 1212 d_dialog_x + (d_dialog_w / 4) - String_Pixel_Width(p), 1213 d_msg4_y, CC_GREEN, TBLACK, 1214 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1215 1216 /*............................................................ 1217 Tiberium 1218 ............................................................*/ 1219 p = Text_String(TXT_TIBERIUM_COLON); 1220 if (MPlayerTiberium) { 1221 sprintf(txt,"%s %s",p,Text_String(TXT_ON)); 1222 } else { 1223 sprintf(txt,"%s %s",p,Text_String(TXT_OFF)); 1224 } 1225 1226 Fancy_Text_Print (txt, 1227 d_dialog_x + (d_dialog_w / 4) - String_Pixel_Width(p), 1228 d_msg5_y, CC_GREEN, TBLACK, 1229 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1230 1231 /*............................................................ 1232 Goody boxes 1233 ............................................................*/ 1234 p = Text_String(TXT_CRATES_COLON); 1235 if (MPlayerGoodies) { 1236 sprintf(txt,"%s %s",p,Text_String(TXT_ON)); 1237 } else { 1238 sprintf(txt,"%s %s",p,Text_String(TXT_OFF)); 1239 } 1240 1241 Fancy_Text_Print (txt, 1242 d_dialog_x + d_dialog_w - (d_dialog_w / 4) - String_Pixel_Width(p), 1243 d_msg4_y, CC_GREEN, TBLACK, 1244 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1245 1246 /*............................................................ 1247 Computer AI players 1248 ............................................................*/ 1249 if (Special.IsCaptureTheFlag) { 1250 p = Text_String(TXT_CAPTURE_THE_FLAG_COLON); 1251 sprintf(txt,"%s %s",p,Text_String(TXT_ON)); 1252 } else { 1253 p = Text_String(TXT_AI_PLAYERS_COLON); 1254 if (MPlayerGhosts) { 1255 sprintf(txt,"%s %s",p,Text_String(TXT_ON)); 1256 } else { 1257 sprintf(txt,"%s %s",p,Text_String(TXT_OFF)); 1258 } 1259 } 1260 Fancy_Text_Print (txt, 1261 d_dialog_x + d_dialog_w - (d_dialog_w / 4) - String_Pixel_Width(p), 1262 d_msg5_y, CC_GREEN, TBLACK, 1263 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1264 1265 } else { 1266 1267 /*............................................................... 1268 Rejection notice 1269 ...............................................................*/ 1270 if (joinstate==JOIN_REJECTED) { 1271 Fancy_Text_Print(TXT_REQUEST_DENIED, 1272 d_dialog_cx, d_msg3_y, CC_GREEN, TBLACK, 1273 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 1274 } 1275 } 1276 } 1277 1278 Show_Mouse(); 1279 display = REDRAW_NONE; 1280 } 1281 1282 /* 1283 ........................... Get user input ............................ 1284 */ 1285 input = commands->Input(); 1286 1287 /* 1288 ---------------------------- Process input ---------------------------- 1289 */ 1290 switch (input) { 1291 /*------------------------------------------------------------------ 1292 User clicks on a color button: 1293 - If we've joined a game, don't allow a new color selection 1294 - otherwise, select that color 1295 ------------------------------------------------------------------*/ 1296 case KN_LMOUSE: 1297 if (joinstate > JOIN_NOTHING) 1298 break; 1299 if (_Kbd->MouseQX > cbox_x[0] && 1300 _Kbd->MouseQX < (cbox_x[MAX_MPLAYER_COLORS - 1] + d_color_w) && 1301 _Kbd->MouseQY > d_color_y && 1302 _Kbd->MouseQY < (d_color_y + d_color_h)) { 1303 MPlayerPrefColor = (_Kbd->MouseQX - cbox_x[0]) / d_color_w; 1304 MPlayerColorIdx = MPlayerPrefColor; 1305 1306 name_edt.Set_Color (MPlayerTColors[MPlayerColorIdx]); 1307 name_edt.Flag_To_Redraw(); 1308 1309 display = REDRAW_COLORS; 1310 } 1311 break; 1312 1313 /*------------------------------------------------------------------ 1314 User clicks on the game list: 1315 - If we've joined a game, don't allow the selected item to change; 1316 otherwise: 1317 - Clear the player list 1318 - Send an immediate player query 1319 ------------------------------------------------------------------*/ 1320 case (BUTTON_GAMELIST | KN_BUTTON): 1321 if (joinstate==JOIN_CONFIRMED) { 1322 gamelist.Set_Selected_Index(game_index); 1323 } else { 1324 if (gamelist.Current_Index() != game_index) { 1325 Clear_Player_List (&playerlist); 1326 game_index = gamelist.Current_Index(); 1327 Send_Join_Queries (game_index, 0, 1); 1328 } 1329 } 1330 break; 1331 1332 /*------------------------------------------------------------------ 1333 House Buttons: set the player's desired House 1334 ------------------------------------------------------------------*/ 1335 case (BUTTON_GDI | KN_BUTTON): 1336 MPlayerHouse = HOUSE_GOOD; 1337 gdibtn.Turn_On(); 1338 nodbtn.Turn_Off(); 1339 break; 1340 1341 case (BUTTON_NOD | KN_BUTTON): 1342 MPlayerHouse = HOUSE_BAD; 1343 gdibtn.Turn_Off(); 1344 nodbtn.Turn_On(); 1345 break; 1346 1347 /*------------------------------------------------------------------ 1348 JOIN: send a join request packet & switch to waiting-for-confirmation 1349 mode. (Request_To_Join fills in MPlayerName with my namebuf.) 1350 ------------------------------------------------------------------*/ 1351 case (BUTTON_JOIN | KN_BUTTON): 1352 name_edt.Clear_Focus(); 1353 name_edt.Flag_To_Redraw(); 1354 1355 join_index = gamelist.Current_Index(); 1356 parms_received = 0; 1357 if (Request_To_Join (namebuf, join_index, &playerlist, MPlayerHouse, 1358 MPlayerColorIdx)) { 1359 joinstate = JOIN_WAIT_CONFIRM; 1360 } else { 1361 display = REDRAW_ALL; 1362 } 1363 break; 1364 1365 /*------------------------------------------------------------------ 1366 CANCEL: send a SIGN_OFF 1367 - If we're part of a game, stay in this dialog; otherwise, exit 1368 ------------------------------------------------------------------*/ 1369 case (KN_ESC): 1370 if (Messages.Get_Edit_Buf() != NULL) { 1371 Messages.Input(input); 1372 display = REDRAW_MESSAGE; 1373 break; 1374 } 1375 case (BUTTON_CANCEL | KN_BUTTON): 1376 memset (&GPacket, 0, sizeof(GlobalPacketType)); 1377 1378 GPacket.Command = NET_SIGN_OFF; 1379 strcpy(GPacket.Name,MPlayerName); 1380 1381 /*............................................................... 1382 If we're joined to a game, make extra sure the other players in 1383 that game know I'm exiting; send my SIGN_OFF as an ack-required 1384 packet. Do not send this packet to myself (index 0). 1385 ...............................................................*/ 1386 if (joinstate == JOIN_CONFIRMED) { 1387 // 1388 // Remove myself from the player list box 1389 // 1390 if (playerlist.Count()) { // added: BRR 6/14/96 1391 item = (char *)(playerlist.Get_Item(0)); 1392 playerlist.Remove_Item(item); 1393 delete [] item; 1394 playerlist.Flag_To_Redraw(); 1395 } 1396 1397 // 1398 // Remove myself from the Players list 1399 // 1400 if (Players.Count()) { // added: BRR 6/14/96 1401 who = Players[0]; 1402 Players.Delete(0); 1403 delete who; 1404 } 1405 1406 for (i = 0; i < Players.Count(); i++) { 1407 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1, 1408 &(Players[i]->Address)); 1409 Ipx.Service(); 1410 } 1411 } 1412 1413 /*............................................................... 1414 Now broadcast my SIGN_OFF so other players looking at this game 1415 know I'm leaving. 1416 ...............................................................*/ 1417 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 1418 0, NULL); 1419 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 1420 0, NULL); 1421 1422 if (IsBridge) { 1423 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 1424 &BridgeNet); 1425 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 1426 &BridgeNet); 1427 } 1428 1429 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 1430 1431 if (joinstate != JOIN_CONFIRMED) { 1432 process = false; 1433 rc = -1; 1434 } else { 1435 MPlayerGameName[0] = 0; 1436 joinstate = JOIN_NOTHING; 1437 display = REDRAW_ALL; 1438 } 1439 break; 1440 1441 /*------------------------------------------------------------------ 1442 NEW: bail out with return code 1 1443 ------------------------------------------------------------------*/ 1444 case (BUTTON_NEW | KN_BUTTON): 1445 /* 1446 .................. Force user to enter a name ................... 1447 */ 1448 if (strlen(namebuf)==0) { 1449 CCMessageBox().Process(TXT_NAME_ERROR); 1450 display = REDRAW_ALL; 1451 break; 1452 } 1453 /* 1454 ..................... Ensure name is unique ..................... 1455 */ 1456 found = 0; 1457 for (i = 0; i < Games.Count(); i++) { 1458 if (!stricmp(Games[i]->Name, namebuf)) { 1459 found = 1; 1460 CCMessageBox().Process (TXT_GAMENAME_MUSTBE_UNIQUE); 1461 display = REDRAW_ALL; 1462 break; 1463 } 1464 } 1465 if (found) 1466 break; 1467 /* 1468 .................... Save player & game name .................... 1469 */ 1470 strcpy(MPlayerName,namebuf); 1471 strcpy(MPlayerGameName,namebuf); 1472 1473 name_edt.Clear_Focus(); 1474 name_edt.Flag_To_Redraw(); 1475 1476 rc = 1; 1477 process = false; 1478 break; 1479 1480 /*------------------------------------------------------------------ 1481 Default: manage the inter-player messages 1482 ------------------------------------------------------------------*/ 1483 default: 1484 /*............................................................... 1485 F4/SEND/'M' = edit a message 1486 ...............................................................*/ 1487 if (Messages.Get_Edit_Buf()==NULL) { 1488 if ( (input == KN_M && joinstate==JOIN_CONFIRMED) || 1489 input==(BUTTON_SEND | KN_BUTTON) || input == KN_F4) { 1490 memset (txt, 0, 80); 1491 1492 strcpy(txt,Text_String(TXT_TO_ALL)); // "To All:" 1493 1494 Messages.Add_Edit (MPlayerTColors[MPlayerColorIdx], 1495 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, d_message_w-70*factor); 1496 1497 if (joinstate <= JOIN_NOTHING) { 1498 name_edt.Clear_Focus(); 1499 name_edt.Flag_To_Redraw(); 1500 } 1501 1502 display = REDRAW_MESSAGE; 1503 1504 break; 1505 } 1506 } else 1507 1508 /*............................................................... 1509 If we're already editing a message and the user clicks on 1510 'Send', translate our input to a Return so Messages.Input() will 1511 work properly. 1512 ...............................................................*/ 1513 if (input==(BUTTON_SEND | KN_BUTTON)) { 1514 input = KN_RETURN; 1515 } 1516 1517 /*............................................................... 1518 Manage the message system (get rid of old messages) 1519 ...............................................................*/ 1520 if (Messages.Manage()) { 1521 display = REDRAW_MESSAGE; 1522 } 1523 1524 /*............................................................... 1525 Service keyboard input for any message being edited. 1526 ...............................................................*/ 1527 i = Messages.Input(input); 1528 1529 /*............................................................... 1530 If 'Input' returned 1, it means refresh the message display. 1531 ...............................................................*/ 1532 if (i==1) { 1533 Messages.Draw(); 1534 } else { 1535 1536 /*............................................................... 1537 If 'Input' returned 2, it means redraw the message display. 1538 ...............................................................*/ 1539 if (i==2) { 1540 display = REDRAW_MESSAGE; 1541 } else { 1542 1543 /*............................................................... 1544 If 'input' returned 3, it means send the current message. 1545 ...............................................................*/ 1546 if (i==3) { 1547 long actual_message_size; 1548 char *the_string; 1549 1550 sent_so_far = 0; 1551 magic_number = MESSAGE_HEAD_MAGIC_NUMBER; 1552 message_length = strlen(Messages.Get_Edit_Buf()); 1553 crc = (unsigned short) 1554 (Calculate_CRC(Messages.Get_Edit_Buf(),message_length) &0xffff); 1555 1556 while ( sent_so_far < message_length ){ 1557 GPacket.Command = NET_MESSAGE; 1558 strcpy (GPacket.Name, namebuf); 1559 memcpy (GPacket.Message.Buf, Messages.Get_Edit_Buf()+sent_so_far, COMPAT_MESSAGE_LENGTH-5); 1560 1561 /* 1562 ** Steve I's stuff for splitting message on word boundries 1563 */ 1564 actual_message_size = COMPAT_MESSAGE_LENGTH - 5; 1565 1566 /* Start at the end of the message and find a space with 10 chars. */ 1567 the_string = GPacket.Message.Buf; 1568 while ( (COMPAT_MESSAGE_LENGTH -5) -actual_message_size < 10 && 1569 the_string[actual_message_size] != ' '){ 1570 --actual_message_size; 1571 } 1572 if ( the_string[actual_message_size] == ' ' ){ 1573 1574 /* Now delete the extra characters after the space (they musnt print) */ 1575 for ( int i=0 ; i< (COMPAT_MESSAGE_LENGTH-5) - actual_message_size; i++ ){ 1576 the_string[i + actual_message_size] = 0; //0xff; ST - 12/18/2018 11:36AM 1577 } 1578 }else{ 1579 actual_message_size = COMPAT_MESSAGE_LENGTH - 5; 1580 } 1581 1582 1583 *(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-5) = 0; 1584 *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-4)) = magic_number; 1585 *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-2)) = crc; 1586 GPacket.Message.ID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse); 1587 GPacket.Message.NameCRC = Compute_Name_CRC(MPlayerGameName); 1588 1589 /*.................................................................. 1590 Send the message to every player in our player list. The local 1591 system will also receive this message, since it's in the Player list. 1592 ..................................................................*/ 1593 if (joinstate == JOIN_CONFIRMED) { 1594 for (i = 1; i < Players.Count(); i++) { 1595 Ipx.Send_Global_Message (&GPacket, 1596 sizeof(GlobalPacketType), 1, &(Players[i]->Address)); 1597 Ipx.Service(); 1598 } 1599 1600 sprintf(txt,Text_String (TXT_FROM), MPlayerName, GPacket.Message.Buf); 1601 Messages.Add_Message (txt, 1602 MPlayerTColors[MPlayerColorIdx], 1603 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 600, magic_number, crc); 1604 } 1605 else { 1606 for (i = 0; i < Players.Count(); i++) { 1607 Ipx.Send_Global_Message (&GPacket, 1608 sizeof(GlobalPacketType), 1, &(Players[i]->Address)); 1609 Ipx.Service(); 1610 } 1611 } 1612 magic_number++; 1613 sent_so_far += actual_message_size; //COMPAT_MESSAGE_LENGTH-5; 1614 } 1615 } 1616 } 1617 } 1618 break; 1619 } 1620 1621 /*--------------------------------------------------------------------- 1622 Resend our query packets 1623 ---------------------------------------------------------------------*/ 1624 Send_Join_Queries(game_index, 0, 0); 1625 1626 /*--------------------------------------------------------------------- 1627 Process incoming packets 1628 ---------------------------------------------------------------------*/ 1629 event = Get_Join_Responses(&joinstate, &gamelist, &playerlist, 1630 join_index); 1631 /*..................................................................... 1632 If we've changed state, redraw everything; if we're starting the game, 1633 break out of the loop. If we've just joined, send out a player query 1634 so I'll get added to the list instantly. 1635 .....................................................................*/ 1636 if (event == EV_STATE_CHANGE) { 1637 display = REDRAW_ALL; 1638 if (joinstate==JOIN_GAME_START) { 1639 rc = 0; 1640 process = false; 1641 } else { 1642 1643 /*.................................................................. 1644 If we're newly-confirmed, immediately send out a player query 1645 ..................................................................*/ 1646 if (joinstate==JOIN_CONFIRMED) { 1647 1648 Clear_Player_List(&playerlist); 1649 1650 item = new char [MPLAYER_NAME_MAX + 4]; 1651 if (MPlayerHouse==HOUSE_GOOD) { 1652 sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_G_D_I)); 1653 } else { 1654 sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_N_O_D)); 1655 } 1656 playerlist.Add_Item (item, MPlayerTColors[MPlayerColorIdx]); 1657 1658 who = new NodeNameType; 1659 strcpy(who->Name, MPlayerName); 1660 who->Address = IPXAddressClass(); 1661 who->Player.House = MPlayerHouse; 1662 who->Player.Color = MPlayerColorIdx; 1663 Players.Add (who); 1664 1665 Send_Join_Queries (game_index, 0, 1); 1666 } else { 1667 1668 /*.................................................................. 1669 If we've been rejected, clear any messages we may have been typing. 1670 ..................................................................*/ 1671 if (joinstate==JOIN_REJECTED) { 1672 1673 // 1674 // Remove myself from the player list box 1675 // 1676 if (playerlist.Count()) { // added: BRR 6/14/96 1677 item = (char *)(playerlist.Get_Item(0)); 1678 if (item){ 1679 playerlist.Remove_Item(item); 1680 delete [] item; 1681 playerlist.Flag_To_Redraw(); 1682 } 1683 } 1684 1685 // 1686 // Remove myself from the Players list 1687 // 1688 if (Players.Count()){ 1689 who = Players[0]; 1690 Players.Delete(0); 1691 delete who; 1692 } 1693 1694 Messages.Init (d_message_x + 2, d_message_y + 2, 4, 1695 MAX_MESSAGE_LENGTH, d_txt6_h); 1696 } 1697 } 1698 } 1699 } else 1700 1701 /*..................................................................... 1702 If a new game is detected, and it's the first game on our list, 1703 automatically send out a player query for that game. 1704 .....................................................................*/ 1705 if (event == EV_NEW_GAME && gamelist.Count()==1) { 1706 gamelist.Set_Selected_Index(0); 1707 game_index = gamelist.Current_Index(); 1708 Send_Join_Queries (game_index, 0, 1); 1709 } else 1710 1711 /*..................................................................... 1712 If the game options have changed, print them. 1713 .....................................................................*/ 1714 if (event == EV_GAME_OPTIONS) { 1715 parms_received = 1; 1716 display = REDRAW_MESSAGE; 1717 } else 1718 1719 /*..................................................................... 1720 Draw an incoming message 1721 .....................................................................*/ 1722 if (event == EV_MESSAGE) { 1723 display = REDRAW_MESSAGE; 1724 } else 1725 1726 /*..................................................................... 1727 A game before the one I've selected is gone, so we have a new index now. 1728 'game_index' must be kept set to the currently-selected list item, so 1729 we send out queries for the currently-selected game. It's therefore 1730 imperative that we detect any changes to the game list. 1731 If we're joined in a game, we must decrement our game_index to keep 1732 it aligned with the game we're joined to. 1733 .....................................................................*/ 1734 if (event == EV_GAME_SIGNOFF) { 1735 if (joinstate==JOIN_CONFIRMED) { 1736 game_index--; 1737 join_index--; 1738 gamelist.Set_Selected_Index(join_index); 1739 } else { 1740 gamelist.Flag_To_Redraw(); 1741 Clear_Player_List(&playerlist); 1742 game_index = gamelist.Current_Index(); 1743 Send_Join_Queries (game_index, 0, 1); 1744 } 1745 } 1746 1747 /*--------------------------------------------------------------------- 1748 Service the Ipx connections 1749 ---------------------------------------------------------------------*/ 1750 Ipx.Service(); 1751 1752 /*--------------------------------------------------------------------- 1753 Clean out the Game List; if an old entry is found: 1754 - Remove it 1755 - Clear the player list 1756 - Send queries for the new selected game, if there is one 1757 ---------------------------------------------------------------------*/ 1758 for (i = 0; i < Games.Count(); i++) { 1759 if (TickCount.Time() - Games[i]->Game.LastTime > 400) { 1760 Games.Delete(Games[i]); 1761 item = (char *)(gamelist.Get_Item (i)); 1762 gamelist.Remove_Item (item); 1763 delete [] item; 1764 if (i <= game_index) { 1765 gamelist.Flag_To_Redraw(); 1766 Clear_Player_List(&playerlist); 1767 game_index = gamelist.Current_Index(); 1768 Send_Join_Queries (game_index, 0, 1); 1769 } 1770 } 1771 } 1772 1773 /*--------------------------------------------------------------------- 1774 Service the sounds & score; GameActive must be false at this point, 1775 so Call_Back() doesn't intercept global messages from me! 1776 ---------------------------------------------------------------------*/ 1777 Call_Back(); 1778 } 1779 1780 /*------------------------------------------------------------------------ 1781 Establish connections with all other players. 1782 ------------------------------------------------------------------------*/ 1783 if (rc == 0) { 1784 /*..................................................................... 1785 If the other guys are playing a scenario I don't have (sniff), I can't 1786 play. Try to bail gracefully. 1787 .....................................................................*/ 1788 if (ScenarioIdx==-1) { 1789 CCMessageBox().Process (TXT_UNABLE_PLAY_WAAUGH); 1790 1791 // 1792 // Remove myself from the player list box 1793 // 1794 if (playerlist.Count()) { // added: BRR 6/14/96 1795 item = (char *)(playerlist.Get_Item(0)); 1796 playerlist.Remove_Item(item); 1797 delete [] item; 1798 playerlist.Flag_To_Redraw(); 1799 } 1800 1801 // 1802 // Remove myself from the Players list 1803 // 1804 if (Players.Count()) { // added: BRR 6/14/96 1805 who = Players[0]; 1806 Players.Delete(0); 1807 delete who; 1808 } 1809 1810 memset (&GPacket, 0, sizeof(GlobalPacketType)); 1811 1812 GPacket.Command = NET_SIGN_OFF; 1813 strcpy (GPacket.Name, MPlayerName); 1814 1815 for (i = 0; i < Players.Count(); i++) { 1816 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1, 1817 &(Players[i]->Address)); 1818 Ipx.Service(); 1819 } 1820 1821 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 1822 0, NULL); 1823 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 1824 0, NULL); 1825 1826 if (IsBridge) { 1827 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 1828 &BridgeNet); 1829 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 1830 &BridgeNet); 1831 } 1832 1833 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 1834 1835 rc = -1; 1836 1837 } else { 1838 1839 /*.................................................................. 1840 Set the number of players in this game, and my ID 1841 ..................................................................*/ 1842 MPlayerCount = Players.Count(); 1843 MPlayerLocalID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse); 1844 1845 /*.................................................................. 1846 Get the scenario number 1847 ..................................................................*/ 1848 Scenario = MPlayerFilenum[ScenarioIdx]; 1849 1850 /*.................................................................. 1851 Form connections with all other players. Form the IPX Connection ID 1852 from the player's Color and House. This will let us extract any 1853 player's color & house at any time. Fill in 'tmp_id' while we're 1854 doing this. 1855 ..................................................................*/ 1856 for (i = 0; i < Players.Count(); i++) { 1857 1858 /*............................................................... 1859 Only create the connection if it's not myself! 1860 ...............................................................*/ 1861 if (strcmp (MPlayerName, Players[i]->Name)) { 1862 id = Build_MPlayerID(Players[i]->Player.Color, 1863 Players[i]->Player.House); 1864 1865 tmp_id[i] = id; 1866 1867 Ipx.Create_Connection((int)id, Players[i]->Name, &(Players[i]->Address) ); 1868 } else { 1869 tmp_id[i] = MPlayerLocalID; 1870 } 1871 } 1872 1873 /*.................................................................. 1874 Store every player's ID in the MPlayerID[] array. This array will 1875 determine the order of event execution, so the ID's must be stored 1876 in the same order on all systems. 1877 ..................................................................*/ 1878 for (i = 0; i < MPlayerCount; i++) { 1879 min_index = 0; 1880 min_id = 0xff; 1881 for (j = 0; j < MPlayerCount; j++) { 1882 if (tmp_id[j] < min_id) { 1883 min_id = tmp_id[j]; 1884 min_index = j; 1885 } 1886 } 1887 MPlayerID[i] = tmp_id[min_index]; 1888 tmp_id[min_index] = 0xff; 1889 } 1890 /*.................................................................. 1891 Fill in the array of player names, including my own. 1892 ..................................................................*/ 1893 for (i = 0; i < MPlayerCount; i++) { 1894 if (MPlayerID[i] == MPlayerLocalID) { 1895 strcpy (MPlayerNames[i], MPlayerName); 1896 } else { 1897 strcpy (MPlayerNames[i], Ipx.Connection_Name(MPlayerID[i])); 1898 } 1899 } 1900 } 1901 /*--------------------------------------------------------------------- 1902 Wait a while, polling the IPX service routines, to give our ACK 1903 a chance to get to the other system. If he doesn't get our ACK, he'll 1904 be waiting the whole time we load MIX files. 1905 ---------------------------------------------------------------------*/ 1906 i = MAX(Ipx.Global_Response_Time() * 2, (unsigned long)60); 1907 starttime = TickCount.Time(); 1908 while (TickCount.Time() - starttime < (unsigned)i) { 1909 Ipx.Service(); 1910 } 1911 } 1912 1913 /*------------------------------------------------------------------------ 1914 Init network timing values, using previous response times as a measure 1915 of what our retry delta & timeout should be. 1916 ------------------------------------------------------------------------*/ 1917 Ipx.Set_Timing (Ipx.Global_Response_Time() + 2, -1, 1918 Ipx.Global_Response_Time() * 4); 1919 1920 /*------------------------------------------------------------------------ 1921 Clear all lists 1922 ------------------------------------------------------------------------*/ 1923 Clear_Game_List(&gamelist); 1924 Clear_Player_List(&playerlist); 1925 1926 /*------------------------------------------------------------------------ 1927 Restore screen 1928 ------------------------------------------------------------------------*/ 1929 Hide_Mouse(); 1930 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 1931 Blit_Hid_Page_To_Seen_Buff(); 1932 Show_Mouse(); 1933 1934 return(rc); 1935 } 1936 1937 1938 /*************************************************************************** 1939 * Clear_Game_List -- Clears the game-name listbox & 'Games' Vector * 1940 * * 1941 * Assumes each entry in 'Games' & the list box have been allocated * 1942 * separately. * 1943 * * 1944 * INPUT: * 1945 * gamelist ptr to list box * 1946 * * 1947 * OUTPUT: * 1948 * none * 1949 * * 1950 * WARNINGS: * 1951 * none * 1952 * * 1953 * HISTORY: * 1954 *=========================================================================*/ 1955 static void Clear_Game_List (ListClass *gamelist) 1956 { 1957 char * item; 1958 int i; 1959 1960 /*------------------------------------------------------------------------ 1961 Clear the list box 1962 ------------------------------------------------------------------------*/ 1963 while (gamelist->Count()) { 1964 item = (char *)(gamelist->Get_Item (0)); 1965 gamelist->Remove_Item(item); 1966 delete [] item; 1967 } 1968 gamelist->Flag_To_Redraw(); 1969 1970 /*------------------------------------------------------------------------ 1971 Clear the 'Games' Vector 1972 ------------------------------------------------------------------------*/ 1973 for (i = 0; i < Games.Count(); i++) 1974 delete Games[i]; 1975 1976 Games.Clear(); 1977 1978 } /* end of Clear_Game_List */ 1979 1980 1981 /*************************************************************************** 1982 * Clear_Player_List -- Clears the player-name listbox & Vector * 1983 * * 1984 * Assumes each entry in 'Players' & the list box have been allocated * 1985 * separately. * 1986 * * 1987 * INPUT: * 1988 * playerlist ptr to list box * 1989 * * 1990 * OUTPUT: * 1991 * none * 1992 * * 1993 * WARNINGS: * 1994 * none * 1995 * * 1996 * HISTORY: * 1997 *=========================================================================*/ 1998 static void Clear_Player_List (ListClass *playerlist) 1999 { 2000 char * item; 2001 int i; 2002 2003 /*------------------------------------------------------------------------ 2004 Clear the list box 2005 ------------------------------------------------------------------------*/ 2006 while (playerlist->Count()) { 2007 item = (char *)(playerlist->Get_Item(0)); 2008 playerlist->Remove_Item(item); 2009 delete [] item; 2010 } 2011 playerlist->Flag_To_Redraw(); 2012 2013 /*------------------------------------------------------------------------ 2014 Clear the 'Players' Vector 2015 ------------------------------------------------------------------------*/ 2016 for (i = 0; i < Players.Count(); i++) 2017 delete Players[i]; 2018 2019 Players.Clear(); 2020 2021 } /* end of Clear_Player_List */ 2022 2023 2024 /*************************************************************************** 2025 * Request_To_Join -- Sends a JOIN request packet to game owner * 2026 * * 2027 * Regardless of the return code, the Join Dialog will need to be redrawn * 2028 * after calling this routine. * 2029 * * 2030 * INPUT: * 2031 * playername player's name * 2032 * join_index index of game we're joining * 2033 * playerlist listbox containing other players' names * 2034 * house requested house * 2035 * color requested color * 2036 * * 2037 * OUTPUT: * 2038 * 1 = Packet sent, 0 = wasn't * 2039 * * 2040 * WARNINGS: * 2041 * none. * 2042 * * 2043 * HISTORY: * 2044 *=========================================================================*/ 2045 static int Request_To_Join (char *playername, int join_index, ListClass *playerlist, 2046 HousesType house, int color) 2047 { 2048 int i; 2049 2050 playerlist = playerlist; // shaddup, Mr stupid compiler! 2051 2052 /* 2053 --------------------------- Validate join_index -------------------------- 2054 */ 2055 if ( (Games.Count()==0) || join_index > Games.Count() || join_index < 0) { 2056 CCMessageBox().Process (TXT_NOTHING_TO_JOIN); 2057 return(false); 2058 } 2059 2060 /* 2061 ----------------------- Force user to enter a name ----------------------- 2062 */ 2063 if (strlen(playername)==0) { 2064 CCMessageBox().Process (TXT_NAME_ERROR); 2065 return(false); 2066 } 2067 2068 /* 2069 ------------------------- The game must be open -------------------------- 2070 */ 2071 if (!Games[join_index]->Game.IsOpen) { 2072 CCMessageBox().Process(TXT_GAME_IS_CLOSED); 2073 return (false); 2074 } 2075 2076 /* 2077 ------------------------ Make sure name is unique ------------------------ 2078 */ 2079 for (i = 0; i < Players.Count(); i++) { 2080 if (!stricmp(playername, Players[i]->Name)) { 2081 CCMessageBox().Process (TXT_NAME_MUSTBE_UNIQUE); 2082 return(false); 2083 } 2084 } 2085 2086 /* 2087 ----------------------------- Check version #'s -------------------------- 2088 */ 2089 int v; 2090 #ifdef PATCH 2091 if (IsV107) { 2092 v = 1; 2093 } else { 2094 v = 2; 2095 } 2096 #else 2097 v = Version_Number(); 2098 #endif 2099 if (Games[join_index]->Game.Version > v) { 2100 CCMessageBox().Process (TXT_YOURGAME_OUTDATED); 2101 return(false); 2102 } else { 2103 if (Games[join_index]->Game.Version < v) { 2104 CCMessageBox().Process (TXT_DESTGAME_OUTDATED); 2105 return(false); 2106 } 2107 } 2108 2109 /* 2110 ----------------------------- Save game name ----------------------------- 2111 */ 2112 strcpy (MPlayerName,playername); 2113 2114 /* 2115 ----------------------- Send packet to game's owner ---------------------- 2116 */ 2117 memset (&GPacket, 0, sizeof(GlobalPacketType)); 2118 2119 GPacket.Command = NET_QUERY_JOIN; 2120 strcpy (GPacket.Name, MPlayerName); 2121 GPacket.PlayerInfo.House = house; 2122 GPacket.PlayerInfo.Color = color; 2123 2124 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1, 2125 &(Games[join_index]->Address)); 2126 2127 return(true); 2128 } 2129 2130 2131 /*********************************************************************************************** 2132 * Send_Join_Queries -- sends queries for the Join Dialog * 2133 * * 2134 * This routine [re]sends the queries related to the Join Dialog: * 2135 * - NET_QUERY_GAME * 2136 * - NET_QUERY_PLAYER for the game currently selected (if there is one) * 2137 * * 2138 * The queries are "staggered" in time so they aren't all sent at once; otherwise, we'd * 2139 * be inundated with reply packets & we'd miss some (even though the replies will require * 2140 * ACK's). * 2141 * * 2142 * INPUT: * 2143 * curgame index of currently-selected game; -1 = none * 2144 * gamenow if 1, will immediately send the game query * 2145 * playernow if 1, will immediately send the player query for currently-selected game * 2146 * * 2147 * OUTPUT: * 2148 * none. * 2149 * * 2150 * WARNINGS: * 2151 * none. * 2152 * * 2153 * HISTORY: * 2154 * 02/14/1995 BR : Created. * 2155 * 04/15/1995 BRR : Created. * 2156 *=============================================================================================*/ 2157 static void Send_Join_Queries(int curgame, int gamenow, int playernow) 2158 { 2159 static int lasttime1 = 0; // time since last Game query sent out 2160 static int lasttime2 = 0; // time since last Player query sent out 2161 2162 /*------------------------------------------------------------------------ 2163 Send the game-name query if the time has expired, or we're told to do 2164 it right now 2165 ------------------------------------------------------------------------*/ 2166 if ( (TickCount.Time() - lasttime1 > 120) || gamenow) { 2167 lasttime1 = TickCount.Time(); 2168 2169 memset (&GPacket, 0, sizeof(GlobalPacketType)); 2170 2171 GPacket.Command = NET_QUERY_GAME; 2172 2173 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, NULL); 2174 2175 /*..................................................................... 2176 If the user specified a remote server address, broadcast over that 2177 network, too. 2178 .....................................................................*/ 2179 if (IsBridge) 2180 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 2181 &BridgeNet); 2182 } 2183 2184 /*------------------------------------------------------------------------ 2185 Send the player query for the game currently clicked on, if the time has 2186 expired and there is a currently-selected game, or we're told to do it 2187 right now 2188 ------------------------------------------------------------------------*/ 2189 if ( (curgame != -1) && curgame < Games.Count() && 2190 ((TickCount.Time() - lasttime2 > 35) || playernow) ) { 2191 lasttime2 = TickCount.Time(); 2192 2193 memset (&GPacket, 0, sizeof(GlobalPacketType)); 2194 2195 GPacket.Command = NET_QUERY_PLAYER; 2196 strcpy (GPacket.Name, Games[curgame]->Name); 2197 2198 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, NULL); 2199 2200 /*..................................................................... 2201 If the user specified a remote server address, broadcast over that 2202 network, too. 2203 .....................................................................*/ 2204 if (IsBridge) 2205 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 2206 &BridgeNet); 2207 } 2208 2209 } /* end of Send_Join_Queries */ 2210 2211 2212 /*********************************************************************************************** 2213 * Get_Join_Responses -- sends queries for the Join Dialog * 2214 * * 2215 * This routine polls the Global Channel to see if there are any incoming packets; * 2216 * if so, it processes them. This routine can change the state of the Join Dialog, or * 2217 * the contents of the list boxes, based on what the packet is. * 2218 * * 2219 * The list boxes are passed in as pointers; they can't be made globals, because they * 2220 * can't be constructed, because they require shape pointers to the arrow buttons, and * 2221 * the mix files won't have been initialized when the global variables' constructors are * 2222 * called. * 2223 * * 2224 * This routine sets the globals * 2225 * MPlayerHouse (from NET_CONFIRM_JOIN) * 2226 * MPlayerColorIdx (from NET_CONFIRM_JOIN) * 2227 * MPlayerBases (from NET_GAME_OPTIONS) * 2228 * MPlayerTiberium (from NET_GAME_OPTIONS) * 2229 * MPlayerGoodies (from NET_GAME_OPTIONS) * 2230 * MPlayerGhosts (from NET_GAME_OPTIONS) * 2231 * ScenarioIdx (from NET_GAME_OPTIONS; -1 = scenario not found) * 2232 * * 2233 * INPUT: * 2234 * joinstate current state of Join Dialog * 2235 * gamelist list box containing game names * 2236 * playerlist list box containing player names for the currently-selected game * 2237 * join_index index of the game we've joined or are asking to join * 2238 * * 2239 * OUTPUT: * 2240 * Event that occurred * 2241 * * 2242 * WARNINGS: * 2243 * none. * 2244 * * 2245 * HISTORY: * 2246 * 02/14/1995 BR : Created. * 2247 * 04/15/1995 BRR : Created. * 2248 *=============================================================================================*/ 2249 static JoinEventType Get_Join_Responses(JoinStateType *joinstate, ListClass *gamelist, 2250 ColorListClass *playerlist, int join_index) 2251 { 2252 int rc; 2253 char * item; // general-purpose string 2254 NodeNameType *who; // node to add to Games or Players 2255 int i; 2256 int found; 2257 JoinEventType retcode = EV_NONE; 2258 char txt[80]; 2259 int color; 2260 unsigned short magic_number; 2261 unsigned short crc; 2262 2263 /*------------------------------------------------------------------------ 2264 If there is no incoming packet, just return 2265 ------------------------------------------------------------------------*/ 2266 rc = Ipx.Get_Global_Message (&GPacket, &GPacketlen, &GAddress, &GProductID); 2267 if (!rc || GProductID != IPXGlobalConnClass::COMMAND_AND_CONQUER) 2268 return(EV_NONE); 2269 2270 /*------------------------------------------------------------------------ 2271 If we're joined in a game, handle the packet in a standard way; otherwise, 2272 don't answer standard queries. 2273 ------------------------------------------------------------------------*/ 2274 if ( (*joinstate)==JOIN_CONFIRMED && 2275 Process_Global_Packet(&GPacket,&GAddress)!=0) 2276 return(EV_NONE); 2277 2278 /*------------------------------------------------------------------------ 2279 NET_ANSWER_GAME: Another system is answering our GAME query, so add that 2280 system to our list box if it's new. 2281 ------------------------------------------------------------------------*/ 2282 if (GPacket.Command==NET_ANSWER_GAME) { 2283 /*..................................................................... 2284 See if this name is unique 2285 .....................................................................*/ 2286 retcode = EV_NONE; 2287 found = 0; 2288 for (i = 0; i < Games.Count(); i++) { 2289 if (!strcmp(Games[i]->Name, GPacket.Name)) { 2290 found = 1; 2291 /*............................................................... 2292 If name was found, update the node's time stamp & IsOpen flag. 2293 ...............................................................*/ 2294 Games[i]->Game.LastTime = TickCount.Time(); 2295 if (Games[i]->Game.IsOpen != GPacket.GameInfo.IsOpen) { 2296 item = (char *)gamelist->Get_Item(i); 2297 if (GPacket.GameInfo.IsOpen) { 2298 sprintf(item,Text_String(TXT_THATGUYS_GAME),GPacket.Name); 2299 } else { 2300 sprintf(item,Text_String(TXT_THATGUYS_GAME_BRACKET),GPacket.Name); 2301 } 2302 Games[i]->Game.IsOpen = GPacket.GameInfo.IsOpen; 2303 gamelist->Flag_To_Redraw(); 2304 /*............................................................ 2305 If this game has gone from closed to open, copy the responder's 2306 address into our Game slot, since the guy responding to this 2307 must be game owner. 2308 ............................................................*/ 2309 if (Games[i]->Game.IsOpen) 2310 Games[i]->Address = GAddress; 2311 } 2312 break; 2313 } 2314 } 2315 /*..................................................................... 2316 name not found (or addresses are different); add it to 'Games' 2317 .....................................................................*/ 2318 if (found==0) { 2319 /*.................................................................. 2320 Create a new node structure, fill it in, add it to 'Games' 2321 ..................................................................*/ 2322 who = new NodeNameType; 2323 strcpy(who->Name, GPacket.Name); 2324 who->Address = GAddress; 2325 who->Game.Version = GPacket.GameInfo.Version; 2326 who->Game.IsOpen = GPacket.GameInfo.IsOpen; 2327 who->Game.LastTime = TickCount.Time(); 2328 Games.Add (who); 2329 2330 /*.................................................................. 2331 Create a string for "xxx's Game", leaving room for brackets around 2332 the string if it's a closed game 2333 ..................................................................*/ 2334 item = new char [MPLAYER_NAME_MAX + 9]; 2335 if (GPacket.GameInfo.IsOpen) { 2336 sprintf(item,Text_String(TXT_THATGUYS_GAME),GPacket.Name); 2337 } else { 2338 sprintf(item,Text_String(TXT_THATGUYS_GAME_BRACKET),GPacket.Name); 2339 } 2340 gamelist->Add_Item(item); 2341 2342 retcode = EV_NEW_GAME; 2343 } 2344 } 2345 2346 /*------------------------------------------------------------------------ 2347 NET_ANSWER_PLAYER: Another system is answering our PLAYER query, so add it 2348 to our player list box & the Player Vector if it's new 2349 ------------------------------------------------------------------------*/ 2350 else if (GPacket.Command==NET_ANSWER_PLAYER) { 2351 /*..................................................................... 2352 See if this name is unique 2353 .....................................................................*/ 2354 retcode = EV_NONE; 2355 found = 0; 2356 for (i = 0; i < Players.Count(); i++) { 2357 /*.................................................................. 2358 If the address is already present, re-copy their name, color & 2359 house into the existing entry, in case they've changed it without 2360 our knowledge; set the 'found' flag so we won't create a new entry. 2361 ..................................................................*/ 2362 if (Players[i]->Address==GAddress) { 2363 strcpy(Players[i]->Name, GPacket.Name); 2364 Players[i]->Player.House = GPacket.PlayerInfo.House; 2365 Players[i]->Player.Color = GPacket.PlayerInfo.Color; 2366 playerlist->Colors[i] = MPlayerTColors[GPacket.PlayerInfo.Color]; 2367 found = 1; 2368 break; 2369 } 2370 } 2371 /*..................................................................... 2372 Don't add this player if he's not part of the game that's selected. 2373 .....................................................................*/ 2374 i = gamelist->Current_Index(); 2375 if (Games.Count() && GPacket.PlayerInfo.NameCRC != Compute_Name_CRC(Games[i]->Name)) 2376 found = 1; 2377 2378 /* 2379 ** Dont add this player if its really me! (hack, hack) 2380 */ 2381 if (!strcmp(GPacket.Name, MPlayerName)){ 2382 found = 1; 2383 } 2384 2385 2386 /*..................................................................... 2387 name not found (or address didn't match); add to player list box & Vector 2388 .....................................................................*/ 2389 if (found==0) { 2390 /*.................................................................. 2391 Create & add a node to the Vector 2392 ..................................................................*/ 2393 who = new NodeNameType; 2394 strcpy(who->Name, GPacket.Name); 2395 who->Address = GAddress; 2396 who->Player.House = GPacket.PlayerInfo.House; 2397 who->Player.Color = GPacket.PlayerInfo.Color; 2398 Players.Add (who); 2399 2400 /*.................................................................. 2401 Create & add a string to the list box 2402 ..................................................................*/ 2403 item = new char [MPLAYER_NAME_MAX + 4]; 2404 if (GPacket.PlayerInfo.House==HOUSE_GOOD) { 2405 sprintf(item,"%s\t%s",GPacket.Name,Text_String(TXT_G_D_I)); 2406 } else { 2407 sprintf(item,"%s\t%s",GPacket.Name,Text_String(TXT_N_O_D)); 2408 } 2409 playerlist->Add_Item(item, MPlayerTColors[who->Player.Color]); 2410 2411 retcode = EV_NEW_PLAYER; 2412 } 2413 } 2414 2415 /*------------------------------------------------------------------------ 2416 NET_CONFIRM_JOIN: The game owner has confirmed our JOIN query; mark us as 2417 being confirmed, and start answering queries from other systems 2418 ------------------------------------------------------------------------*/ 2419 else if (GPacket.Command==NET_CONFIRM_JOIN) { 2420 if ( (*joinstate) != JOIN_CONFIRMED) { 2421 strcpy (MPlayerGameName, GPacket.Name); 2422 MPlayerHouse = GPacket.PlayerInfo.House; 2423 MPlayerColorIdx = GPacket.PlayerInfo.Color; 2424 2425 (*joinstate) = JOIN_CONFIRMED; 2426 retcode = EV_STATE_CHANGE; 2427 } 2428 } 2429 2430 /*------------------------------------------------------------------------ 2431 NET_REJECT_JOIN: The game owner has turned down our JOIN query; restore 2432 the dialog state to its first pop-up state. Broadcast a sign-off to 2433 tell all other systems that I'm no longer a part of any game; this way, 2434 I'll be properly removed from their dialogs. 2435 ------------------------------------------------------------------------*/ 2436 else if (GPacket.Command==NET_REJECT_JOIN) { 2437 if ( (*joinstate) != JOIN_REJECTED) { 2438 memset (&GPacket, 0, sizeof(GlobalPacketType)); 2439 2440 GPacket.Command = NET_SIGN_OFF; 2441 strcpy (GPacket.Name,MPlayerName); 2442 2443 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 0, NULL); 2444 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 0, NULL); 2445 2446 if (IsBridge) { 2447 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 2448 &BridgeNet); 2449 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 2450 &BridgeNet); 2451 } 2452 2453 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 2454 2455 MPlayerGameName[0] = 0; 2456 2457 (*joinstate) = JOIN_REJECTED; 2458 retcode = EV_STATE_CHANGE; 2459 } 2460 } 2461 2462 /*------------------------------------------------------------------------ 2463 NET_GAME_OPTIONS: The game owner has changed the game options & is sending 2464 us the new values. 2465 ------------------------------------------------------------------------*/ 2466 else if (GPacket.Command==NET_GAME_OPTIONS) { 2467 if ( (*joinstate)==JOIN_CONFIRMED) { 2468 MPlayerCredits = GPacket.ScenarioInfo.Credits; 2469 MPlayerBases = GPacket.ScenarioInfo.IsBases; 2470 MPlayerTiberium = GPacket.ScenarioInfo.IsTiberium; 2471 MPlayerGoodies = GPacket.ScenarioInfo.IsGoodies; 2472 MPlayerGhosts = GPacket.ScenarioInfo.IsGhosties; 2473 BuildLevel = GPacket.ScenarioInfo.BuildLevel; 2474 MPlayerUnitCount = GPacket.ScenarioInfo.UnitCount; 2475 Seed = GPacket.ScenarioInfo.Seed; 2476 Special = GPacket.ScenarioInfo.Special; 2477 Options.GameSpeed = GPacket.ScenarioInfo.GameSpeed; 2478 2479 if (MPlayerTiberium) { 2480 Special.IsTGrowth = 1; 2481 Special.IsTSpread = 1; 2482 } else { 2483 Special.IsTGrowth = 0; 2484 Special.IsTSpread = 0; 2485 } 2486 2487 if (Winsock.Get_Connected()){ 2488 ScenarioIdx = GPacket.ScenarioInfo.Scenario; 2489 }else{ 2490 2491 ScenarioIdx = -1; 2492 for (i = 0; i < MPlayerFilenum.Count(); i++) { 2493 if (GPacket.ScenarioInfo.Scenario == MPlayerFilenum[i]) 2494 ScenarioIdx = i; 2495 } 2496 } 2497 2498 retcode = EV_GAME_OPTIONS; 2499 } 2500 } 2501 2502 /*------------------------------------------------------------------------ 2503 NET_SIGN_OFF: Another system is signing off: search for that system in 2504 both the game list & player list, & remove it if found 2505 ------------------------------------------------------------------------*/ 2506 else if (GPacket.Command==NET_SIGN_OFF) { 2507 /*..................................................................... 2508 Remove this name from the list of games 2509 .....................................................................*/ 2510 for (i = 0; i < Games.Count(); i++) { 2511 if (!strcmp(Games[i]->Name, GPacket.Name) && 2512 Games[i]->Address==GAddress) { 2513 /*............................................................... 2514 If the system signing off is the currently-selected list 2515 item, clear the player list since that game is no longer 2516 forming. 2517 ...............................................................*/ 2518 if (i==gamelist->Current_Index()) { 2519 Clear_Player_List (playerlist); 2520 } 2521 2522 /*............................................................... 2523 If the system signing off was the owner of our game, mark 2524 ourselves as rejected 2525 ...............................................................*/ 2526 if ( (*joinstate) > JOIN_NOTHING && i==join_index) { 2527 (*joinstate) = JOIN_REJECTED; 2528 retcode = EV_STATE_CHANGE; 2529 } 2530 2531 /* 2532 ....................... Set my return code ...................... 2533 */ 2534 if (retcode == EV_NONE) { 2535 if (i <= gamelist->Current_Index()) { 2536 retcode = EV_GAME_SIGNOFF; 2537 } else { 2538 retcode = EV_PLAYER_SIGNOFF; 2539 } 2540 } 2541 2542 /* 2543 ................. Remove game name from game list ............... 2544 */ 2545 Games.Delete(Games[i]); 2546 item = (char *)(gamelist->Get_Item (i)); 2547 gamelist->Remove_Item (item); 2548 delete [] item; 2549 gamelist->Flag_To_Redraw(); 2550 2551 } 2552 } 2553 /*..................................................................... 2554 Remove this name from the list of players 2555 .....................................................................*/ 2556 for (i = 0; i < Players.Count(); i++) { 2557 /* 2558 ..................... Name found; remove it ..................... 2559 */ 2560 if (Players[i]->Address==GAddress) { 2561 item = (char *)(playerlist->Get_Item(i)); 2562 playerlist->Remove_Item(item); 2563 delete [] item; 2564 Players.Delete(Players[i]); 2565 playerlist->Flag_To_Redraw(); 2566 2567 if (retcode == EV_NONE) 2568 retcode = EV_PLAYER_SIGNOFF; 2569 } 2570 } 2571 } 2572 2573 /*------------------------------------------------------------------------ 2574 NET_GO: The game's owner is signalling us to start playing. 2575 ------------------------------------------------------------------------*/ 2576 else if (GPacket.Command==NET_GO) { 2577 if ( (*joinstate)==JOIN_CONFIRMED) { 2578 MPlayerMaxAhead = GPacket.ResponseTime.OneWay; 2579 (*joinstate) = JOIN_GAME_START; 2580 retcode = EV_STATE_CHANGE; 2581 CCDebugString ("C&C95 - Received the 'GO' packet\n"); 2582 } 2583 } 2584 2585 /*------------------------------------------------------------------------ 2586 NET_MESSAGE: Someone is sending us a message 2587 ------------------------------------------------------------------------*/ 2588 else if (GPacket.Command==NET_MESSAGE) { 2589 sprintf(txt,Text_String (TXT_FROM), GPacket.Name, GPacket.Message.Buf); 2590 magic_number = *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-4)); 2591 crc = *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-2)); 2592 color = MPlayerID_To_ColorIndex(GPacket.Message.ID); 2593 Messages.Add_Message (txt, MPlayerTColors[color], 2594 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 1200, magic_number, crc); 2595 retcode = EV_MESSAGE; 2596 } 2597 2598 /*------------------------------------------------------------------------ 2599 NET_PING: Someone is pinging me to get a response time measure (will only 2600 happen after I've joined a game). Do nothing; the IPX Manager will handle 2601 sending an ACK, and updating the response time measurements. 2602 ------------------------------------------------------------------------*/ 2603 else if (GPacket.Command==NET_PING) { 2604 retcode = EV_NONE; 2605 } 2606 2607 /*------------------------------------------------------------------------ 2608 Default case: nothing happened. (This case will be hit every time I 2609 receive my own NET_QUERY_GAME or NET_QUERY_PLAYER packets.) 2610 ------------------------------------------------------------------------*/ 2611 else { 2612 retcode = EV_NONE; 2613 } 2614 2615 return(retcode); 2616 } 2617 2618 2619 /*********************************************************************************************** 2620 * Net_New_Dialog -- lets user start a new game * 2621 * * 2622 * This dialog shows a list of who's requesting to join this game, and lets * 2623 * the game initiator selectively approve each user. * 2624 * * 2625 * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ * 2626 * ³ New Network Game ³ * 2627 * ³ ³ * 2628 * ³ Players Scenario ³ * 2629 * ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿ ³ * 2630 * ³ ³ Boffo ³³ ³ Hell's Kitchen ³³ ³ * 2631 * ³ ³ Bozo ÃÄ´ ³ Heaven's Gate ÃÄ´ ³ * 2632 * ³ ³ Bonzo ³ ³ ³ ... ³ ³ ³ * 2633 * ³ ³ ÃÄ´ ³ ÃÄ´ ³ * 2634 * ³ ³ ³³ ³ ³³ ³ * 2635 * ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ ³ * 2636 * ³ [Reject] Count:--- ## ³ * 2637 * ³ Level:--- ## ³ * 2638 * ³ ³ * 2639 * ³ Credits: _____ ³ * 2640 * ³ [ Bases ] [ Crates ] ³ * 2641 * ³ [ Tiberium ] [ AI Players ] ³ * 2642 * ³ ³ * 2643 * ³ [OK] [Cancel] ³ * 2644 * ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ * 2645 * ³ ³ ³ ³ * 2646 * ³ ³ ³ ³ * 2647 * ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ * 2648 * ³ [Send Message] ³ * 2649 * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ * 2650 * * 2651 * INPUT: * 2652 * none. * 2653 * * 2654 * OUTPUT: * 2655 * true = success, false = cancel * 2656 * * 2657 * WARNINGS: * 2658 * MPlayerName & MPlayerGameName must contain this player's name. * 2659 * * 2660 * HISTORY: * 2661 * 02/14/1995 BR : Created. * 2662 *=============================================================================================*/ 2663 static int Net_New_Dialog(void) 2664 { 2665 /* ###Change collision detected! C:\PROJECTS\CODE\NETDLG.CPP... */ 2666 int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2; 2667 /*........................................................................ 2668 Dialog & button dimensions 2669 ........................................................................*/ 2670 //D_DIALOG_W = 281; // dialog width 2671 int d_dialog_w = 287*factor; // dialog width 2672 int d_dialog_h = 177*factor; // dialog height 2673 int d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord 2674 int d_dialog_y = ((200*factor - d_dialog_h) / 2); // centered y-coord 2675 int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord 2676 2677 int d_txt6_h = 6*factor+1; // ht of 6-pt text 2678 int d_margin1 = 5*factor; // margin width/height 2679 int d_margin2 = 2*factor; // margin width/height 2680 2681 //d_playerlist_w = 100; 2682 int d_playerlist_w = 106*factor; 2683 int d_playerlist_h = 27*factor; 2684 int d_playerlist_x = d_dialog_x + d_margin1; 2685 int d_playerlist_y = d_dialog_y + d_margin1 + (d_txt6_h * 3); 2686 2687 int d_scenariolist_w = 162*factor; 2688 int d_scenariolist_h = 27*factor; 2689 int d_scenariolist_x = d_dialog_x + d_dialog_w - d_margin1 - d_scenariolist_w; 2690 int d_scenariolist_y = d_dialog_y + d_margin1 + (d_txt6_h * 3); 2691 2692 #if (GERMAN | FRENCH) 2693 int d_reject_w = 55*factor; 2694 #else 2695 int d_reject_w = 45*factor; 2696 #endif 2697 int d_reject_h = 9*factor; 2698 int d_reject_x = d_playerlist_x + (d_playerlist_w / 2) - (d_reject_w / 2); 2699 int d_reject_y = d_playerlist_y + d_playerlist_h + d_margin2; 2700 2701 int d_count_w = 25*factor; 2702 int d_count_h = d_txt6_h; 2703 int d_count_x = d_scenariolist_x + (d_scenariolist_w / 2); 2704 int d_count_y = d_scenariolist_y + d_scenariolist_h + d_margin2; 2705 2706 int d_level_w = 25*factor; 2707 int d_level_h = d_txt6_h; 2708 int d_level_x = d_scenariolist_x + (d_scenariolist_w / 2); 2709 int d_level_y = d_count_y + d_count_h; 2710 2711 int d_credits_w = ((CREDITSBUF_MAX - 1) * 7*factor) + 4*factor; 2712 //int d_credits_w = ((CREDITSBUF_MAX - 1) * 6*factor) + 3*factor; 2713 int d_credits_h = 9*factor; 2714 int d_credits_x = d_dialog_cx + 2*factor; 2715 int d_credits_y = d_level_y + d_level_h + d_margin1; 2716 2717 #if (GERMAN | FRENCH) 2718 int d_bases_w = 120*factor;//bga:100; 2719 #else 2720 int d_bases_w = 100*factor; 2721 #endif 2722 int d_bases_h = 9*factor; 2723 int d_bases_x = d_dialog_cx - d_bases_w - d_margin2; 2724 int d_bases_y = d_credits_y + d_credits_h + d_margin2; 2725 2726 #if (GERMAN | FRENCH) 2727 int d_tiberium_w = 120*factor; 2728 #else 2729 int d_tiberium_w = 100*factor; 2730 #endif 2731 int d_tiberium_h = 9*factor; 2732 int d_tiberium_x = d_dialog_cx - d_bases_w - d_margin2; 2733 int d_tiberium_y = d_bases_y + d_bases_h + d_margin2; 2734 2735 #if (GERMAN | FRENCH) 2736 int d_goodies_w = 120*factor; 2737 #else 2738 int d_goodies_w = 100*factor; 2739 #endif 2740 int d_goodies_h = 9*factor; 2741 int d_goodies_x = d_dialog_cx + d_margin2; 2742 int d_goodies_y = d_credits_y + d_credits_h + d_margin2; 2743 2744 #if (GERMAN | FRENCH) 2745 int d_ghosts_w = 120*factor; 2746 #else 2747 int d_ghosts_w = 100*factor; 2748 #endif 2749 int d_ghosts_h = 9*factor; 2750 int d_ghosts_x = d_dialog_cx + d_margin2; 2751 int d_ghosts_y = d_goodies_y + d_goodies_h + d_margin2; 2752 2753 int d_ok_w = 45*factor; 2754 int d_ok_h = 9*factor; 2755 int d_ok_x = d_dialog_cx - d_margin2 - (d_bases_w / 2) - (d_ok_w / 2); 2756 int d_ok_y = d_ghosts_y + d_ghosts_h + d_margin1; 2757 2758 #if (GERMAN | FRENCH) 2759 int d_cancel_w = 50*factor; 2760 #else 2761 int d_cancel_w = 45*factor; 2762 #endif 2763 int d_cancel_h = 9*factor; 2764 int d_cancel_x = d_dialog_cx + d_margin2 + (d_goodies_w / 2) - (d_cancel_w / 2); 2765 int d_cancel_y = d_ghosts_y + d_ghosts_h + d_margin1; 2766 2767 int d_message_w = d_dialog_w - (d_margin1 * 2); 2768 int d_message_h = 34*factor; 2769 int d_message_x = d_dialog_x + d_margin1; 2770 int d_message_y = d_cancel_y + d_cancel_h + d_margin1; 2771 2772 int d_send_w = 80*factor; 2773 int d_send_h = 9*factor; 2774 int d_send_x = d_dialog_cx - (d_send_w / 2); 2775 int d_send_y = d_message_y + d_message_h + d_margin2; 2776 2777 /*........................................................................ 2778 Button Enumerations 2779 ........................................................................*/ 2780 enum { 2781 BUTTON_PLAYERLIST = 100, 2782 BUTTON_SCENARIOLIST, 2783 BUTTON_REJECT, 2784 BUTTON_COUNT, 2785 BUTTON_LEVEL, 2786 BUTTON_CREDITS, 2787 BUTTON_BASES, 2788 BUTTON_TIBERIUM, 2789 BUTTON_GOODIES, 2790 BUTTON_GHOSTS, 2791 BUTTON_OK, 2792 BUTTON_CANCEL, 2793 BUTTON_SEND, 2794 }; 2795 2796 /*........................................................................ 2797 Redraw values: in order from "top" to "bottom" layer of the dialog 2798 ........................................................................*/ 2799 typedef enum { 2800 REDRAW_NONE = 0, 2801 REDRAW_UNIT_COUNT, 2802 REDRAW_MESSAGE, 2803 REDRAW_BUTTONS, 2804 REDRAW_BACKGROUND, 2805 REDRAW_ALL = REDRAW_BACKGROUND 2806 } RedrawType; 2807 2808 /*........................................................................ 2809 Dialog variables 2810 ........................................................................*/ 2811 RedrawType display = REDRAW_ALL; // redraw level 2812 bool process = true; // process while true 2813 KeyNumType input; 2814 2815 char credbuf[CREDITSBUF_MAX]; // for credit edit box 2816 int old_cred; // old value in credits buffer 2817 int transmit; // 1 = re-transmit new game options 2818 2819 long ok_timer = 0; // for timing OK button 2820 int index; // index for rejecting a player 2821 int rc; 2822 int i,j; 2823 char *item; 2824 int tabs[] = {77*factor}; // tabs for player list box 2825 2826 long ping_timer = 0; // for sending Ping packets 2827 2828 unsigned char tmp_id[MAX_PLAYERS]; // temp storage for sorting player ID's 2829 int min_index; // for sorting player ID's 2830 unsigned char min_id; // for sorting player ID's 2831 unsigned char id; // connection ID 2832 char txt[80]; 2833 JoinEventType whahoppa; // event generated by received packets 2834 static int first_time = 1; // 1 = 1st time this dialog is run 2835 2836 int message_length; 2837 int sent_so_far; 2838 unsigned short magic_number; 2839 unsigned short crc; 2840 2841 /*........................................................................ 2842 Buttons 2843 ........................................................................*/ 2844 GadgetClass *commands; // button list 2845 2846 void const *up_button; 2847 void const *down_button; 2848 2849 if (InMainLoop){ 2850 up_button = Hires_Retrieve("BTN-UP.SHP"); 2851 down_button = Hires_Retrieve("BTN-DN.SHP"); 2852 }else{ 2853 up_button = Hires_Retrieve("BTN-UP2.SHP"); 2854 down_button = Hires_Retrieve("BTN-DN2.SHP"); 2855 } 2856 2857 2858 ColorListClass playerlist(BUTTON_PLAYERLIST, 2859 d_playerlist_x, d_playerlist_y, d_playerlist_w, d_playerlist_h, 2860 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2861 up_button, 2862 down_button); 2863 2864 ListClass scenariolist(BUTTON_SCENARIOLIST, 2865 d_scenariolist_x, d_scenariolist_y, d_scenariolist_w, d_scenariolist_h, 2866 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2867 up_button, 2868 down_button); 2869 2870 EditClass credit_edt (BUTTON_CREDITS, 2871 credbuf, CREDITSBUF_MAX, 2872 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2873 d_credits_x, d_credits_y, d_credits_w, d_credits_h, EditClass::ALPHANUMERIC); 2874 2875 TextButtonClass rejectbtn(BUTTON_REJECT, TXT_REJECT, 2876 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2877 //#if (GERMAN | FRENCH) 2878 // d_reject_x, d_reject_y); 2879 //#else 2880 d_reject_x, d_reject_y, d_reject_w, d_reject_h); 2881 //#endif 2882 2883 GaugeClass countgauge (BUTTON_COUNT, 2884 d_count_x, d_count_y, d_count_w, d_count_h); 2885 2886 GaugeClass levelgauge (BUTTON_LEVEL, 2887 d_level_x, d_level_y, d_level_w, d_level_h); 2888 2889 TextButtonClass basesbtn(BUTTON_BASES, TXT_BASES_OFF, 2890 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2891 d_bases_x, d_bases_y, d_bases_w, d_bases_h); 2892 2893 TextButtonClass tiberiumbtn(BUTTON_TIBERIUM, TXT_TIBERIUM_OFF, 2894 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2895 d_tiberium_x, d_tiberium_y, d_tiberium_w, d_tiberium_h); 2896 2897 TextButtonClass goodiesbtn(BUTTON_GOODIES, TXT_CRATES_OFF, 2898 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2899 d_goodies_x, d_goodies_y, d_goodies_w, d_goodies_h); 2900 2901 TextButtonClass ghostsbtn(BUTTON_GHOSTS, TXT_AI_PLAYERS_OFF, 2902 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2903 d_ghosts_x, d_ghosts_y, d_ghosts_w, d_ghosts_h); 2904 2905 TextButtonClass okbtn(BUTTON_OK, TXT_OK, 2906 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2907 d_ok_x, d_ok_y, d_ok_w, d_ok_h); 2908 2909 TextButtonClass cancelbtn(BUTTON_CANCEL, TXT_CANCEL, 2910 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2911 //#if (GERMAN | FRENCH) 2912 // d_cancel_x, d_cancel_y); 2913 //#else 2914 d_cancel_x, d_cancel_y, d_cancel_w, d_cancel_h); 2915 //#endif 2916 2917 TextButtonClass sendbtn(BUTTON_SEND, TXT_SEND_MESSAGE, 2918 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 2919 //#if (GERMAN | FRENCH) 2920 // d_send_x, d_send_y); 2921 //#else 2922 d_send_x, d_send_y, d_send_w, d_send_h); 2923 //#endif 2924 2925 /* 2926 ------------------------- Build the button list -------------------------- 2927 */ 2928 commands = &playerlist; 2929 scenariolist.Add_Tail(*commands); 2930 credit_edt.Add_Tail(*commands); 2931 rejectbtn.Add_Tail(*commands); 2932 countgauge.Add_Tail(*commands); 2933 levelgauge.Add_Tail(*commands); 2934 basesbtn.Add_Tail(*commands); 2935 tiberiumbtn.Add_Tail(*commands); 2936 goodiesbtn.Add_Tail(*commands); 2937 ghostsbtn.Add_Tail(*commands); 2938 okbtn.Add_Tail(*commands); 2939 cancelbtn.Add_Tail(*commands); 2940 sendbtn.Add_Tail(*commands); 2941 2942 playerlist.Set_Tabs(tabs); 2943 2944 /* 2945 ----------------------------- Various Inits ------------------------------ 2946 */ 2947 /*........................................................................ 2948 Init dialog values, only the first time through 2949 ........................................................................*/ 2950 if (first_time) { 2951 MPlayerCredits = 3000; // init credits & credit buffer 2952 MPlayerBases = 1; // init scenario parameters 2953 MPlayerTiberium = 0; 2954 MPlayerGoodies = 0; 2955 MPlayerGhosts = 0; 2956 Special.IsCaptureTheFlag = 0; 2957 MPlayerUnitCount = (MPlayerCountMax[MPlayerBases] + MPlayerCountMin[MPlayerBases]) / 2; 2958 first_time = 0; 2959 } 2960 2961 /*........................................................................ 2962 Init button states 2963 ........................................................................*/ 2964 if (MPlayerBases) { 2965 basesbtn.Turn_On(); 2966 basesbtn.Set_Text(TXT_BASES_ON); 2967 } 2968 if (MPlayerTiberium) { 2969 tiberiumbtn.Turn_On(); 2970 tiberiumbtn.Set_Text(TXT_TIBERIUM_ON); 2971 } 2972 if (MPlayerGoodies) { 2973 goodiesbtn.Turn_On(); 2974 goodiesbtn.Set_Text(TXT_CRATES_ON); 2975 } 2976 if (MPlayerGhosts) { 2977 ghostsbtn.Turn_On(); 2978 ghostsbtn.Set_Text(TXT_AI_PLAYERS_ON); 2979 } 2980 if (Special.IsCaptureTheFlag) { 2981 MPlayerGhosts = 0; 2982 ghostsbtn.Turn_On(); 2983 ghostsbtn.Set_Text(TXT_CAPTURE_THE_FLAG); 2984 } 2985 2986 sprintf(credbuf, "%d", MPlayerCredits); 2987 credit_edt.Set_Text(credbuf, CREDITSBUF_MAX); 2988 old_cred = MPlayerCredits; 2989 2990 levelgauge.Set_Maximum(MPLAYER_BUILD_LEVEL_MAX - 1); 2991 levelgauge.Set_Value(BuildLevel - 1); 2992 2993 countgauge.Set_Maximum(MPlayerCountMax[MPlayerBases] - MPlayerCountMin[MPlayerBases]); 2994 countgauge.Set_Value(MPlayerUnitCount - MPlayerCountMin[MPlayerBases]); 2995 2996 /*........................................................................ 2997 Init other scenario parameters 2998 ........................................................................*/ 2999 Special.IsTGrowth = MPlayerTiberium; 3000 Special.IsTSpread = MPlayerTiberium; 3001 transmit = 0; 3002 3003 /*........................................................................ 3004 Init scenario description list box 3005 ........................................................................*/ 3006 for (i = 0; i < MPlayerScenarios.Count(); i++) { 3007 scenariolist.Add_Item (strupr(MPlayerScenarios[i])); 3008 } 3009 ScenarioIdx = 0; // 1st scenario is selected 3010 3011 /*........................................................................ 3012 Init player color-used flags 3013 ........................................................................*/ 3014 for (i = 0; i < MAX_MPLAYER_COLORS; i++) { 3015 ColorUsed[i] = 0; // init all colors to available 3016 } 3017 ColorUsed[MPlayerColorIdx] = 1; // set my color to used 3018 playerlist.Set_Selected_Style(ColorListClass::SELECT_BAR, CC_GREEN_SHADOW); 3019 3020 /*........................................................................ 3021 Init random-number generator, & create a seed to be used for all random 3022 numbers from here on out 3023 ........................................................................*/ 3024 //ST - 12/18/2018 11:37AM 3025 //randomize(); 3026 //Seed = rand(); 3027 3028 /*........................................................................ 3029 Init the message display system 3030 ........................................................................*/ 3031 Messages.Init (d_message_x + 2*factor, d_message_y + 2*factor, 4, MAX_MESSAGE_LENGTH, 3032 d_txt6_h); 3033 3034 /*------------------------------------------------------------------------ 3035 Add myself to the list. Note that since I'm not in the Players Vector, 3036 the Vector & listbox are now 1 out of sync. 3037 ------------------------------------------------------------------------*/ 3038 item = new char [MPLAYER_NAME_MAX + 4]; 3039 if (MPlayerHouse==HOUSE_GOOD) { 3040 sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_G_D_I)); 3041 } else { 3042 sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_N_O_D)); 3043 } 3044 playerlist.Add_Item(item, MPlayerTColors[MPlayerColorIdx]); 3045 3046 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 3047 Blit_Hid_Page_To_Seen_Buff(); 3048 Set_Palette(Palette); 3049 while (Get_Mouse_State() > 0) Show_Mouse(); 3050 3051 /* 3052 ---------------------------- Processing loop ----------------------------- 3053 */ 3054 while (process) { 3055 3056 /* 3057 ** If we have just received input focus again after running in the background then 3058 ** we need to redraw. 3059 */ 3060 if (AllSurfaces.SurfacesRestored){ 3061 AllSurfaces.SurfacesRestored=FALSE; 3062 display=REDRAW_ALL; 3063 } 3064 3065 #if(SHOW_MONO) 3066 Ipx.Mono_Debug_Print(-1,0); 3067 #endif 3068 /* 3069 ...................... Refresh display if needed ...................... 3070 */ 3071 if (display == REDRAW_UNIT_COUNT){ 3072 /* 3073 ** Wipe the background behind the unit count then reprint it 3074 */ 3075 LogicPage->Fill_Rect(d_count_x + d_count_w + 2*factor, 3076 d_count_y, 3077 d_count_x + d_count_w + 2*factor + 20, 3078 d_count_y + 12, 3079 0 ); 3080 sprintf(txt,"%d",MPlayerUnitCount); 3081 Fancy_Text_Print (txt, d_count_x + d_count_w + 2*factor, d_count_y, 3082 CC_GREEN, TBLACK, 3083 TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL); 3084 display = REDRAW_NONE; 3085 } 3086 3087 3088 if (display) { 3089 Hide_Mouse(); 3090 /* 3091 .................. Redraw backgound & dialog box ................... 3092 */ 3093 if (display >= REDRAW_BACKGROUND) { 3094 3095 /* 3096 ** Reload and draw the title page 3097 */ 3098 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 3099 Blit_Hid_Page_To_Seen_Buff(); 3100 Set_Palette(Palette); 3101 3102 Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h); 3103 3104 /*............................................................... 3105 Dialog & Field labels 3106 ...............................................................*/ 3107 Draw_Caption (TXT_NETGAME_SETUP, d_dialog_x, d_dialog_y, d_dialog_w); 3108 3109 Fancy_Text_Print(TXT_PLAYERS, 3110 d_playerlist_x + (d_playerlist_w / 2), d_playerlist_y - d_txt6_h, 3111 CC_GREEN, TBLACK, 3112 TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_CENTER); 3113 3114 Fancy_Text_Print(TXT_SCENARIOS, 3115 d_scenariolist_x + (d_scenariolist_w / 2), 3116 d_scenariolist_y - d_txt6_h, 3117 CC_GREEN, TBLACK, 3118 TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_CENTER); 3119 3120 Fancy_Text_Print (TXT_COUNT, d_count_x - 2*factor, d_count_y, 3121 CC_GREEN, TBLACK, 3122 TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_RIGHT); 3123 3124 sprintf(txt,"%d",MPlayerUnitCount); 3125 Fancy_Text_Print (txt, d_count_x + d_count_w + 2*factor, d_count_y, 3126 CC_GREEN, TBLACK, 3127 TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL); 3128 3129 Fancy_Text_Print (TXT_LEVEL, d_level_x - 2*factor, d_level_y, 3130 CC_GREEN, TBLACK, 3131 TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_RIGHT); 3132 3133 if (BuildLevel <= MPLAYER_BUILD_LEVEL_MAX) { 3134 sprintf(txt,"%d",BuildLevel); 3135 } else { 3136 sprintf(txt, "**"); 3137 } 3138 Fancy_Text_Print (txt, d_level_x + d_level_w + 2*factor, d_level_y, 3139 CC_GREEN, TBLACK, 3140 TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL); 3141 3142 Fancy_Text_Print (TXT_START_CREDITS_COLON, d_credits_x - 5*factor, 3143 d_credits_y + 1*factor, CC_GREEN, TBLACK, 3144 TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_RIGHT); 3145 3146 } 3147 3148 /* 3149 .......................... Redraw buttons .......................... 3150 */ 3151 if (display >= REDRAW_BUTTONS) { 3152 commands->Draw_All(); 3153 } 3154 3155 /*.................................................................. 3156 Draw the messages: 3157 - Erase an old message first 3158 - If we're in a game, print the game options (if they've been 3159 received) 3160 - If we've been rejected from a game, print that message 3161 ..................................................................*/ 3162 if (display >= REDRAW_MESSAGE) { 3163 Draw_Box(d_message_x, d_message_y, d_message_w, d_message_h, 3164 BOXSTYLE_GREEN_BORDER, true); 3165 Messages.Draw(); 3166 } 3167 3168 Show_Mouse(); 3169 display = REDRAW_NONE; 3170 } 3171 3172 /* 3173 ........................... Get user input ............................ 3174 */ 3175 input = commands->Input(); 3176 3177 /* 3178 ---------------------------- Process input ---------------------------- 3179 */ 3180 switch (input) { 3181 /*------------------------------------------------------------------ 3182 New Scenario selected. 3183 ------------------------------------------------------------------*/ 3184 case (BUTTON_SCENARIOLIST | KN_BUTTON): 3185 if (scenariolist.Current_Index() != ScenarioIdx) { 3186 ScenarioIdx = scenariolist.Current_Index(); 3187 MPlayerCredits = atoi(credbuf); 3188 transmit = 1; 3189 } 3190 break; 3191 3192 /*------------------------------------------------------------------ 3193 Reject the currently-selected player (don't allow rejecting myself, 3194 who will be the first entry in the list) 3195 ------------------------------------------------------------------*/ 3196 case (BUTTON_REJECT | KN_BUTTON): 3197 index = playerlist.Current_Index(); 3198 if (index == 0) { 3199 CCMessageBox().Process (TXT_CANT_REJECT_SELF, TXT_OOPS); 3200 display = REDRAW_ALL; 3201 break; 3202 } else { 3203 if (index < 0 || index >= playerlist.Count()) { 3204 CCMessageBox().Process (TXT_SELECT_PLAYER_REJECT,TXT_OOPS); 3205 display = REDRAW_ALL; 3206 break; 3207 } 3208 } 3209 memset (&GPacket, 0, sizeof(GlobalPacketType)); 3210 3211 GPacket.Command = NET_REJECT_JOIN; 3212 3213 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 1, 3214 &(Players[index - 1]->Address)); 3215 break; 3216 3217 /*------------------------------------------------------------------ 3218 User adjusts max # units 3219 ------------------------------------------------------------------*/ 3220 case (BUTTON_COUNT | KN_BUTTON): 3221 MPlayerUnitCount = countgauge.Get_Value() + MPlayerCountMin[MPlayerBases]; 3222 3223 Hide_Mouse(); 3224 LogicPage->Fill_Rect (d_count_x + d_count_w + 2*factor, d_count_y, 3225 d_count_x + d_count_w + 14*factor, d_count_y + 6*factor, BLACK); 3226 3227 sprintf(txt,"%d",MPlayerUnitCount); 3228 Fancy_Text_Print (txt, d_count_x + d_count_w + 2*factor, d_count_y, 3229 CC_GREEN, TBLACK, 3230 TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL); 3231 Show_Mouse(); 3232 3233 transmit = 1; 3234 break; 3235 3236 /*------------------------------------------------------------------ 3237 User adjusts build level 3238 ------------------------------------------------------------------*/ 3239 case (BUTTON_LEVEL | KN_BUTTON): 3240 BuildLevel = levelgauge.Get_Value() + 1; 3241 if (BuildLevel > MPLAYER_BUILD_LEVEL_MAX) // if it's pegged, max it out 3242 BuildLevel = MPLAYER_BUILD_LEVEL_MAX; 3243 3244 Hide_Mouse(); 3245 LogicPage->Fill_Rect (d_level_x + d_level_w + 2*factor, d_level_y, 3246 d_level_x + d_level_w + 14*factor, d_level_y + 6*factor, BLACK); 3247 3248 if (BuildLevel <= MPLAYER_BUILD_LEVEL_MAX) { 3249 sprintf(txt,"%d",BuildLevel); 3250 } else { 3251 sprintf(txt, "**"); 3252 } 3253 Fancy_Text_Print (txt, d_level_x + d_level_w + 2*factor, d_level_y, 3254 CC_GREEN, TBLACK, 3255 TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL); 3256 Show_Mouse(); 3257 3258 transmit = 1; 3259 break; 3260 3261 /*------------------------------------------------------------------ 3262 User edits the credits value; retransmit new game options 3263 ------------------------------------------------------------------*/ 3264 case (BUTTON_CREDITS | KN_BUTTON): 3265 MPlayerCredits = atoi(credbuf); 3266 transmit = 1; 3267 break; 3268 3269 /*------------------------------------------------------------------ 3270 Toggle bases: 3271 - Clear scenario list & rebuild it with new names 3272 - toggle bases button, change its text 3273 - adjust the MPlayerUnitCount to reflect the new allowed range, 3274 using the current gauge setting 3275 - Change the unit count gauge limit & value 3276 ------------------------------------------------------------------*/ 3277 case (BUTTON_BASES | KN_BUTTON): 3278 if (MPlayerBases) { 3279 MPlayerBases = 0; 3280 basesbtn.Turn_Off(); 3281 basesbtn.Set_Text(TXT_BASES_OFF); 3282 MPlayerUnitCount = Fixed_To_Cardinal (MPlayerCountMax[0]-MPlayerCountMin[0], 3283 Cardinal_To_Fixed(MPlayerCountMax[1]-MPlayerCountMin[1], 3284 MPlayerUnitCount-MPlayerCountMin[1])) + MPlayerCountMin[0]; 3285 } else { 3286 MPlayerBases = 1; 3287 basesbtn.Turn_On(); 3288 basesbtn.Set_Text(TXT_BASES_ON); 3289 MPlayerUnitCount = Fixed_To_Cardinal (MPlayerCountMax[1]-MPlayerCountMin[1], 3290 Cardinal_To_Fixed(MPlayerCountMax[0]-MPlayerCountMin[0], 3291 MPlayerUnitCount-MPlayerCountMin[0])) + MPlayerCountMin[1]; 3292 } 3293 MPlayerCredits = atoi(credbuf); 3294 countgauge.Set_Maximum(MPlayerCountMax[MPlayerBases] - MPlayerCountMin[MPlayerBases]); 3295 countgauge.Set_Value(MPlayerUnitCount - MPlayerCountMin[MPlayerBases]); 3296 transmit = 1; 3297 countgauge.Flag_To_Redraw(); 3298 display = REDRAW_UNIT_COUNT; 3299 break; 3300 3301 /*------------------------------------------------------------------ 3302 Toggle tiberium 3303 ------------------------------------------------------------------*/ 3304 case (BUTTON_TIBERIUM | KN_BUTTON): 3305 if (MPlayerTiberium) { 3306 MPlayerTiberium = 0; 3307 Special.IsTGrowth = 0; 3308 Special.IsTSpread = 0; 3309 tiberiumbtn.Turn_Off(); 3310 tiberiumbtn.Set_Text(TXT_TIBERIUM_OFF); 3311 } else { 3312 MPlayerTiberium = 1; 3313 Special.IsTGrowth = 1; 3314 Special.IsTSpread = 1; 3315 tiberiumbtn.Turn_On(); 3316 tiberiumbtn.Set_Text(TXT_TIBERIUM_ON); 3317 } 3318 MPlayerCredits = atoi(credbuf); 3319 transmit = 1; 3320 break; 3321 3322 /*------------------------------------------------------------------ 3323 Toggle goodies 3324 ------------------------------------------------------------------*/ 3325 case (BUTTON_GOODIES | KN_BUTTON): 3326 if (MPlayerGoodies) { 3327 MPlayerGoodies = 0; 3328 goodiesbtn.Turn_Off(); 3329 goodiesbtn.Set_Text(TXT_CRATES_OFF); 3330 } else { 3331 MPlayerGoodies = 1; 3332 goodiesbtn.Turn_On(); 3333 goodiesbtn.Set_Text(TXT_CRATES_ON); 3334 } 3335 MPlayerCredits = atoi(credbuf); 3336 transmit = 1; 3337 break; 3338 3339 /*------------------------------------------------------------------ 3340 Toggle ghosts/capture-the-flag 3341 ------------------------------------------------------------------*/ 3342 case (BUTTON_GHOSTS | KN_BUTTON): 3343 if (!MPlayerGhosts && !Special.IsCaptureTheFlag) { // ghosts OFF => ghosts ON 3344 MPlayerGhosts = 1; 3345 Special.IsCaptureTheFlag = 0; 3346 ghostsbtn.Turn_On(); 3347 ghostsbtn.Set_Text(TXT_AI_PLAYERS_ON); 3348 } else { 3349 if (MPlayerGhosts) { // ghosts ON => capture-flag 3350 MPlayerGhosts = 0; 3351 Special.IsCaptureTheFlag = 1; 3352 ghostsbtn.Turn_On(); 3353 ghostsbtn.Set_Text(TXT_CAPTURE_THE_FLAG); 3354 } else { 3355 if (Special.IsCaptureTheFlag) { // capture-flag => AI OFF 3356 MPlayerGhosts = 0; 3357 Special.IsCaptureTheFlag = 0; 3358 ghostsbtn.Turn_Off(); 3359 ghostsbtn.Set_Text(TXT_AI_PLAYERS_OFF); 3360 } 3361 } 3362 } 3363 3364 MPlayerCredits = atoi(credbuf); 3365 transmit = 1; 3366 break; 3367 3368 /*------------------------------------------------------------------ 3369 OK: exit loop with TRUE status 3370 ------------------------------------------------------------------*/ 3371 case (BUTTON_OK | KN_BUTTON): 3372 /*............................................................... 3373 If a new player has joined in the last second, don't allow 3374 an OK; force a wait longer than 1 second (to give all players 3375 a chance to know about this new guy) 3376 ...............................................................*/ 3377 i = MAX(Ipx.Global_Response_Time() * 2, (unsigned long)60); 3378 while (TickCount.Time() - ok_timer < i) 3379 Ipx.Service(); 3380 3381 /*............................................................... 3382 If there are at least 2 players, go ahead & play; error otherwise 3383 ...............................................................*/ 3384 if (MPlayerSolo || Players.Count() > 0) { 3385 rc = TRUE; 3386 process = FALSE; 3387 } else { 3388 CCMessageBox().Process (TXT_ONLY_ONE,TXT_OOPS,NULL); 3389 display = REDRAW_ALL; 3390 } 3391 break; 3392 3393 /*------------------------------------------------------------------ 3394 CANCEL: send a SIGN_OFF, bail out with error code 3395 ------------------------------------------------------------------*/ 3396 case (KN_ESC): 3397 if (Messages.Get_Edit_Buf() != NULL) { 3398 Messages.Input(input); 3399 if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE; 3400 break; 3401 } 3402 case (BUTTON_CANCEL | KN_BUTTON): 3403 memset (&GPacket, 0, sizeof(GlobalPacketType)); 3404 3405 GPacket.Command = NET_SIGN_OFF; 3406 strcpy (GPacket.Name, MPlayerName); 3407 3408 /*............................................................... 3409 Broadcast my sign-off over my network 3410 ...............................................................*/ 3411 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 3412 0, NULL); 3413 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 3414 0, NULL); 3415 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 3416 3417 /*............................................................... 3418 Broadcast my sign-off over a bridged network if there is one 3419 ...............................................................*/ 3420 if (IsBridge) { 3421 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 3422 &BridgeNet); 3423 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 3424 &BridgeNet); 3425 } 3426 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 3427 3428 /*............................................................... 3429 And now, just be absolutely sure, send my sign-off to each 3430 player in my game. (If there's a bridge between us, the other 3431 player will have specified my address, so he can cross the 3432 bridge; but I may not have specified a bridge address, so the 3433 only way I have of crossing the bridge is to send a packet 3434 directly to him.) 3435 ...............................................................*/ 3436 for (i = 0; i < Players.Count(); i++) { 3437 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1, 3438 &(Players[i]->Address)); 3439 Ipx.Service(); 3440 } 3441 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 3442 MPlayerGameName[0] = 0; 3443 process = false; 3444 rc = false; 3445 break; 3446 3447 /*------------------------------------------------------------------ 3448 Default: manage the inter-player messages 3449 ------------------------------------------------------------------*/ 3450 default: 3451 /*............................................................... 3452 F4/SEND/'M' = send a message 3453 ...............................................................*/ 3454 if (Messages.Get_Edit_Buf()==NULL) { 3455 if (input == KN_M || input==(BUTTON_SEND | KN_BUTTON) || 3456 input == KN_F4) { 3457 memset (txt, 0, 80); 3458 3459 strcpy(txt,Text_String(TXT_TO_ALL)); // "To All:" 3460 3461 Messages.Add_Edit (MPlayerTColors[MPlayerColorIdx], 3462 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, d_message_w-70*factor); 3463 3464 credit_edt.Clear_Focus(); 3465 credit_edt.Flag_To_Redraw(); 3466 if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE; 3467 3468 break; 3469 } 3470 } else { 3471 3472 /*............................................................... 3473 If we're already editing a message and the user clicks on 3474 'Send', translate our input to a Return so Messages.Input() will 3475 work properly. 3476 ...............................................................*/ 3477 if (input==(BUTTON_SEND | KN_BUTTON)) { 3478 input = KN_RETURN; 3479 } 3480 } 3481 3482 /*............................................................... 3483 Manage the message system (get rid of old messages) 3484 ...............................................................*/ 3485 if (Messages.Manage()) { 3486 if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE; 3487 } 3488 3489 /*............................................................... 3490 Re-draw the messages & service keyboard input for any message 3491 being edited. 3492 ...............................................................*/ 3493 i = Messages.Input(input); 3494 3495 /*............................................................... 3496 If 'Input' returned 1, it means refresh the message display. 3497 ...............................................................*/ 3498 if (i==1) { 3499 Messages.Draw(); 3500 } 3501 3502 /*............................................................... 3503 If 'Input' returned 2, it means redraw the message display. 3504 ...............................................................*/ 3505 else if (i==2) { 3506 if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE; 3507 } 3508 3509 /*............................................................... 3510 If 'input' returned 3, it means send the current message. 3511 ...............................................................*/ 3512 else if (i==3) { 3513 long actual_message_size; 3514 char *the_string; 3515 3516 sent_so_far = 0; 3517 magic_number = MESSAGE_HEAD_MAGIC_NUMBER; 3518 message_length = strlen(Messages.Get_Edit_Buf()); 3519 crc = (unsigned short) 3520 (Calculate_CRC(Messages.Get_Edit_Buf(), message_length) &0xffff); 3521 while ( sent_so_far < message_length ){ 3522 memset (&GPacket, 0, sizeof(GlobalPacketType)); 3523 GPacket.Command = NET_MESSAGE; 3524 strcpy (GPacket.Name, MPlayerName); 3525 memcpy (GPacket.Message.Buf, Messages.Get_Edit_Buf()+sent_so_far, COMPAT_MESSAGE_LENGTH-5); 3526 3527 /* 3528 ** Steve I's stuff for splitting message on word boundries 3529 */ 3530 actual_message_size = COMPAT_MESSAGE_LENGTH - 5; 3531 3532 /* Start at the end of the message and find a space with 10 chars. */ 3533 the_string = GPacket.Message.Buf; 3534 while ( (COMPAT_MESSAGE_LENGTH -5) -actual_message_size < 10 && 3535 the_string[actual_message_size] != ' '){ 3536 --actual_message_size; 3537 } 3538 if ( the_string[actual_message_size] == ' ' ){ 3539 3540 /* Now delete the extra characters after the space (they musnt print) */ 3541 for ( int i=0 ; i< (COMPAT_MESSAGE_LENGTH-5) - actual_message_size; i++ ){ 3542 the_string[i + actual_message_size] = 0; //0xff; ST - 12/18/2018 11:37AM 3543 } 3544 }else{ 3545 actual_message_size = COMPAT_MESSAGE_LENGTH - 5; 3546 } 3547 3548 *(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-5) = 0; 3549 *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-4)) = magic_number; 3550 *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-2)) = crc; 3551 GPacket.Message.ID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse); 3552 GPacket.Message.NameCRC = Compute_Name_CRC(MPlayerGameName); 3553 3554 /*.................................................................. 3555 Send the message to every player in our player list. 3556 ..................................................................*/ 3557 for (i = 0; i < Players.Count(); i++) { 3558 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1, 3559 &(Players[i]->Address)); 3560 Ipx.Service(); 3561 } 3562 /*.................................................................. 3563 Add the message to our own list, since we're not in the player list 3564 on this dialog. 3565 ..................................................................*/ 3566 sprintf(txt,Text_String (TXT_FROM), MPlayerName, GPacket.Message.Buf); 3567 Messages.Add_Message (txt, MPlayerTColors[MPlayerColorIdx], 3568 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 1200, magic_number, crc); 3569 3570 magic_number++; 3571 sent_so_far += actual_message_size; //COMPAT_MESSAGE_LENGTH-5; 3572 3573 } 3574 if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE; 3575 } 3576 } 3577 3578 /*--------------------------------------------------------------------- 3579 Detect editing of the credits buffer, transmit new values to players 3580 ---------------------------------------------------------------------*/ 3581 if (atoi(credbuf) != old_cred) { 3582 old_cred = Bound(atoi(credbuf), 0, 9999); 3583 MPlayerCredits = old_cred; 3584 transmit = 1; 3585 sprintf(credbuf, "%d", MPlayerCredits); 3586 credit_edt.Set_Text(credbuf, CREDITSBUF_MAX); 3587 } 3588 3589 /*--------------------------------------------------------------------- 3590 Process incoming packets 3591 ---------------------------------------------------------------------*/ 3592 whahoppa = Get_NewGame_Responses(&playerlist); 3593 if (whahoppa == EV_NEW_PLAYER) { 3594 ok_timer = TickCount.Time(); 3595 transmit = 1; 3596 } else { 3597 if (whahoppa == EV_MESSAGE) { 3598 if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE; 3599 } 3600 } 3601 3602 /*--------------------------------------------------------------------- 3603 If our Transmit flag is set, we need to send out a game option packet 3604 ---------------------------------------------------------------------*/ 3605 if (transmit) { 3606 for (i = 0; i < Players.Count(); i++) { 3607 memset (&GPacket, 0, sizeof(GlobalPacketType)); 3608 3609 GPacket.Command = NET_GAME_OPTIONS; 3610 GPacket.ScenarioInfo.Scenario = MPlayerFilenum[ScenarioIdx]; 3611 GPacket.ScenarioInfo.Credits = MPlayerCredits; 3612 GPacket.ScenarioInfo.IsBases = MPlayerBases; 3613 GPacket.ScenarioInfo.IsTiberium = MPlayerTiberium; 3614 GPacket.ScenarioInfo.IsGoodies = MPlayerGoodies; 3615 GPacket.ScenarioInfo.IsGhosties = MPlayerGhosts; 3616 GPacket.ScenarioInfo.BuildLevel = BuildLevel; 3617 GPacket.ScenarioInfo.UnitCount = MPlayerUnitCount; 3618 GPacket.ScenarioInfo.Seed = Seed; 3619 GPacket.ScenarioInfo.Special = Special; 3620 GPacket.ScenarioInfo.GameSpeed = Options.GameSpeed; 3621 3622 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 3623 1, &(Players[i]->Address) ); 3624 } 3625 transmit = 0; 3626 } 3627 3628 /*--------------------------------------------------------------------- 3629 Ping every player in my game, to force the Global Channel to measure 3630 the connection response time. 3631 ---------------------------------------------------------------------*/ 3632 if (TickCount.Time() - ping_timer > 15) { 3633 memset (&GPacket, 0, sizeof(GlobalPacketType)); 3634 GPacket.Command = NET_PING; 3635 for (i = 0; i < Players.Count(); i++) { 3636 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 3637 1, &(Players[i]->Address) ); 3638 } 3639 ping_timer = TickCount.Time(); 3640 } 3641 3642 /*--------------------------------------------------------------------- 3643 Service the Ipx connections 3644 ---------------------------------------------------------------------*/ 3645 Ipx.Service(); 3646 3647 /*--------------------------------------------------------------------- 3648 Service the sounds & score; GameActive must be false at this point, 3649 so Call_Back() doesn't intercept global messages from me! 3650 ---------------------------------------------------------------------*/ 3651 Call_Back(); 3652 3653 } /* end of while */ 3654 3655 /*------------------------------------------------------------------------ 3656 Establish connections with all other players. 3657 ------------------------------------------------------------------------*/ 3658 if (rc) { 3659 /*..................................................................... 3660 Set the number of players in this game, and my ID 3661 .....................................................................*/ 3662 MPlayerCount = Players.Count() + 1; 3663 MPlayerLocalID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse); 3664 3665 /*..................................................................... 3666 Get the scenario filename 3667 .....................................................................*/ 3668 Scenario = MPlayerFilenum[ScenarioIdx]; 3669 3670 /*..................................................................... 3671 Compute frame delay value for packet transmissions: 3672 - Divide global channel's response time by 8 (2 to convert to 1-way 3673 value, 4 more to convert from ticks to frames) 3674 .....................................................................*/ 3675 MPlayerMaxAhead = MAX( (Ipx.Global_Response_Time() / 8), (unsigned long)2); 3676 3677 /*..................................................................... 3678 Send all players the NET_GO packet. Wait until all ACK's have been 3679 received. 3680 .....................................................................*/ 3681 memset (&GPacket, 0, sizeof(GlobalPacketType)); 3682 GPacket.Command = NET_GO; 3683 GPacket.ResponseTime.OneWay = MPlayerMaxAhead; 3684 for (i = 0; i < Players.Count(); i++) { 3685 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 3686 1, &(Players[i]->Address) ); 3687 /*.................................................................. 3688 Wait for all the ACK's to come in. 3689 ..................................................................*/ 3690 while (Ipx.Global_Num_Send() > 0) 3691 Ipx.Service(); 3692 } 3693 3694 /*..................................................................... 3695 Form connections with all other players. Form the IPX Connection ID 3696 from the player's Color (high byte) and House (low byte). This 3697 will let us extract any player's color & house at any time. 3698 Fill in 'tmp_id' while we're doing this. 3699 .....................................................................*/ 3700 for (i = 0; i < Players.Count(); i++) { 3701 id = Build_MPlayerID (Players[i]->Player.Color, 3702 Players[i]->Player.House); 3703 3704 tmp_id[i] = id; 3705 3706 Ipx.Create_Connection(id, Players[i]->Name, &(Players[i]->Address) ); 3707 } 3708 tmp_id[i] = MPlayerLocalID; 3709 3710 /*..................................................................... 3711 Store every player's ID in the MPlayerID[] array. This array will 3712 determine the order of event execution, so the ID's must be stored 3713 in the same order on all systems. 3714 .....................................................................*/ 3715 for (i = 0; i < MPlayerCount; i++) { 3716 min_index = 0; 3717 min_id = 0xff; 3718 for (j = 0; j < MPlayerCount; j++) { 3719 if (tmp_id[j] < min_id) { 3720 min_id = tmp_id[j]; 3721 min_index = j; 3722 } 3723 } 3724 MPlayerID[i] = tmp_id[min_index]; 3725 tmp_id[min_index] = 0xff; 3726 } 3727 /*..................................................................... 3728 Fill in the array of player names, including my own. 3729 .....................................................................*/ 3730 for (i = 0; i < MPlayerCount; i++) { 3731 if (MPlayerID[i] == MPlayerLocalID) { 3732 strcpy (MPlayerNames[i], MPlayerName); 3733 } else { 3734 strcpy (MPlayerNames[i], Ipx.Connection_Name(MPlayerID[i])); 3735 } 3736 } 3737 } 3738 3739 /*------------------------------------------------------------------------ 3740 Init network timing values, using previous response times as a measure 3741 of what our retry delta & timeout should be. 3742 ------------------------------------------------------------------------*/ 3743 Ipx.Set_Timing (Ipx.Global_Response_Time() + 2, -1, 3744 Ipx.Global_Response_Time() * 4); 3745 3746 /*------------------------------------------------------------------------ 3747 Clear all lists 3748 ------------------------------------------------------------------------*/ 3749 while (scenariolist.Count()) { 3750 scenariolist.Remove_Item(scenariolist.Get_Item(0)); 3751 } 3752 Clear_Player_List(&playerlist); 3753 3754 /*------------------------------------------------------------------------ 3755 Restore screen 3756 ------------------------------------------------------------------------*/ 3757 Hide_Mouse(); 3758 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 3759 Blit_Hid_Page_To_Seen_Buff(); 3760 Show_Mouse(); 3761 3762 return(rc); 3763 } 3764 3765 3766 /*************************************************************************** 3767 * Get_NewGame_Responses -- processes packets for New Game dialog * 3768 * * 3769 * This routine can modify the contents of the given list box, as well * 3770 * as the contents of the Players Vector global. * 3771 * * 3772 * INPUT: * 3773 * playerlist list of players in this game * 3774 * * 3775 * OUTPUT: * 3776 * EV_NONE = nothing happened * 3777 * EV_NEW_PLAYER = a new player has joined; false otherwise * 3778 * EV_MESSAGE = a message was received * 3779 * * 3780 * WARNINGS: * 3781 * none. * 3782 * * 3783 * HISTORY: * 3784 * 04/18/1995 BRR : Created. * 3785 *=========================================================================*/ 3786 static JoinEventType Get_NewGame_Responses(ColorListClass *playerlist) 3787 { 3788 int rc; 3789 char * item; // general-purpose string 3790 NodeNameType *who; // node to add to Players Vector 3791 int i; 3792 int found; 3793 JoinEventType retval = EV_NONE; 3794 int resend; 3795 char txt[80]; 3796 int color; 3797 unsigned short magic_number; 3798 unsigned short crc; 3799 3800 /*------------------------------------------------------------------------ 3801 If there is no incoming packet, just return 3802 ------------------------------------------------------------------------*/ 3803 rc = Ipx.Get_Global_Message (&GPacket, &GPacketlen, &GAddress, &GProductID); 3804 if (!rc || GProductID != IPXGlobalConnClass::COMMAND_AND_CONQUER) { 3805 return(EV_NONE); 3806 } 3807 3808 /*------------------------------------------------------------------------ 3809 Try to handle the packet in a standard way 3810 ------------------------------------------------------------------------*/ 3811 if (Process_Global_Packet(&GPacket,&GAddress) != 0) { 3812 return(EV_NONE); 3813 } else 3814 3815 /*------------------------------------------------------------------------ 3816 NET_QUERY_JOIN: 3817 ------------------------------------------------------------------------*/ 3818 if (GPacket.Command==NET_QUERY_JOIN) { 3819 /*..................................................................... 3820 See if this name is unique: 3821 - If the name matches, but the address is different, reject this player 3822 - If the name & address match, this packet must be a re-send of a 3823 prevous request; in this case, do nothing. The other player must have 3824 received my CONFIRM_JOIN packet (since it was sent with an ACK 3825 required), so we can ignore this resend. 3826 .....................................................................*/ 3827 found = 0; 3828 resend = 0; 3829 for (i = 0; i < Players.Count(); i++) { 3830 if (!strcmp(Players[i]->Name,GPacket.Name)) { 3831 if (Players[i]->Address != GAddress) { 3832 found = 1; 3833 } 3834 else { 3835 resend = 1; 3836 } 3837 break; 3838 } 3839 } 3840 if (!strcmp (MPlayerName, GPacket.Name)) { 3841 found = 1; 3842 } 3843 3844 /*..................................................................... 3845 Reject if name is a duplicate, or if there are too many players: 3846 .....................................................................*/ 3847 if (found || (Players.Count() >= (MPlayerMax - 1) && !resend) ) { 3848 memset (&GPacket, 0, sizeof(GlobalPacketType)); 3849 3850 GPacket.Command = NET_REJECT_JOIN; 3851 3852 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 3853 1, &GAddress); 3854 } 3855 3856 /*..................................................................... 3857 If this packet is NOT a resend, accept the player. Grant him the 3858 requested color if possible. 3859 .....................................................................*/ 3860 else if (!resend) { 3861 /*.................................................................. 3862 Add node to the Vector list 3863 ..................................................................*/ 3864 who = new NodeNameType; 3865 strcpy(who->Name, GPacket.Name); 3866 who->Address = GAddress; 3867 who->Player.House = GPacket.PlayerInfo.House; 3868 Players.Add (who); 3869 3870 /*.................................................................. 3871 Set player's color; if requested color isn't used, give it to him; 3872 otherwise, give him the 1st available color. Mark the color we 3873 give him as used. 3874 ..................................................................*/ 3875 if (ColorUsed[GPacket.PlayerInfo.Color] == 0) { 3876 who->Player.Color = GPacket.PlayerInfo.Color; 3877 } else { 3878 for (i = 0; i < MAX_MPLAYER_COLORS; i++) { 3879 if (ColorUsed[i]==0) { 3880 who->Player.Color = i; 3881 break; 3882 } 3883 } 3884 } 3885 ColorUsed[who->Player.Color] = 1; 3886 3887 /*.................................................................. 3888 Add player name to the list box 3889 ..................................................................*/ 3890 item = new char [MPLAYER_NAME_MAX + 4]; 3891 if (GPacket.PlayerInfo.House==HOUSE_GOOD) { 3892 sprintf(item,"%s\t%s",GPacket.Name,Text_String(TXT_G_D_I)); 3893 } else { 3894 sprintf(item,"%s\t%s",GPacket.Name,Text_String(TXT_N_O_D)); 3895 } 3896 playerlist->Add_Item (item, MPlayerTColors[who->Player.Color]); 3897 3898 /*.................................................................. 3899 Send a confirmation packet 3900 ..................................................................*/ 3901 memset (&GPacket, 0, sizeof(GlobalPacketType)); 3902 3903 GPacket.Command = NET_CONFIRM_JOIN; 3904 strcpy(GPacket.Name,MPlayerName); 3905 GPacket.PlayerInfo.House = who->Player.House; 3906 GPacket.PlayerInfo.Color = who->Player.Color; 3907 3908 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 3909 1, &GAddress); 3910 3911 retval = EV_NEW_PLAYER; 3912 } 3913 } 3914 3915 /*------------------------------------------------------------------------ 3916 NET_SIGN_OFF: Another system is signing off: search for that system in 3917 the player list, & remove it if found 3918 ------------------------------------------------------------------------*/ 3919 else if (GPacket.Command==NET_SIGN_OFF) { 3920 for (i = 0; i < Players.Count(); i++) { 3921 /* 3922 ....................... Name found; remove it ...................... 3923 */ 3924 if (!strcmp (Players[i]->Name, GPacket.Name) && 3925 Players[i]->Address==GAddress) { 3926 /*............................................................... 3927 Remove from the list box 3928 ...............................................................*/ 3929 item = (char *)(playerlist->Get_Item(i + 1)); 3930 playerlist->Remove_Item(item); 3931 playerlist->Flag_To_Redraw(); 3932 delete [] item; 3933 /*............................................................... 3934 Mark his color as available 3935 ...............................................................*/ 3936 ColorUsed[Players[i]->Player.Color] = 0; 3937 /*............................................................... 3938 Delete from the Vector list 3939 ...............................................................*/ 3940 Players.Delete(Players[i]); 3941 break; 3942 } 3943 } 3944 } 3945 3946 /*------------------------------------------------------------------------ 3947 NET_MESSAGE: Someone is sending us a message 3948 ------------------------------------------------------------------------*/ 3949 else if (GPacket.Command==NET_MESSAGE) { 3950 sprintf(txt,Text_String (TXT_FROM), GPacket.Name, GPacket.Message.Buf); 3951 magic_number = *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-4)); 3952 crc = *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-2)); 3953 color = MPlayerID_To_ColorIndex(GPacket.Message.ID); 3954 Messages.Add_Message (txt, MPlayerTColors[color], 3955 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 1200, magic_number, crc); 3956 retval = EV_MESSAGE; 3957 } 3958 3959 return(retval); 3960 } 3961 3962 3963 3964 /*************************************************************************** 3965 * Compute_Name_CRC -- computes CRC from char string * 3966 * * 3967 * INPUT: * 3968 * name string to create CRC for * 3969 * * 3970 * OUTPUT: * 3971 * CRC * 3972 * * 3973 * WARNINGS: * 3974 * none. * 3975 * * 3976 * HISTORY: * 3977 * 06/29/1995 BRR : Created. * 3978 *=========================================================================*/ 3979 unsigned long Compute_Name_CRC(char *name) 3980 { 3981 char buf[80]; 3982 unsigned long crc = 0L; 3983 int i; 3984 3985 strcpy (buf, name); 3986 strupr (buf); 3987 3988 for (i = 0; i < (int)strlen(buf); i++) { 3989 Add_CRC (&crc, (unsigned long)buf[i]); 3990 } 3991 3992 return (crc); 3993 } 3994 3995 /*************************************************************************** 3996 * Net_Reconnect_Dialog -- Draws/updates the network reconnect dialog * 3997 * * 3998 * INPUT: * 3999 * reconn 1 = reconnect, 0 = waiting for first-time connection * 4000 * fresh 1 = draw from scratch, 0 = only update time counter * 4001 * oldest_index IPX connection index of oldest connection * 4002 * (only used for reconnection) * 4003 * timeval value to print in the countdown field * 4004 * * 4005 * OUTPUT: * 4006 * none. * 4007 * * 4008 * WARNINGS: * 4009 * none. * 4010 * * 4011 * HISTORY: * 4012 * 07/08/1995 BRR : Created. * 4013 *=========================================================================*/ 4014 void Net_Reconnect_Dialog(int reconn, int fresh, int oldest_index, 4015 unsigned long timeval) 4016 { 4017 static int x,y,w,h; 4018 int id; 4019 char buf1[40] = {0}; 4020 char buf2[40] = {0}; 4021 char const *buf3 = ""; 4022 4023 int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2; 4024 4025 int d_txt6_h = 6*factor+1; 4026 int d_margin = 5*factor; 4027 4028 4029 /*------------------------------------------------------------------------ 4030 Draw the dialog from scratch 4031 ------------------------------------------------------------------------*/ 4032 if (fresh) { 4033 Fancy_Text_Print ("", 0, 0, CC_GREEN, TBLACK, 4034 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 4035 if (reconn) { 4036 id = Ipx.Connection_ID(oldest_index); 4037 sprintf(buf1,Text_String(TXT_RECONNECTING_TO), 4038 Ipx.Connection_Name(id)); 4039 } else { 4040 sprintf(buf1,Text_String(TXT_WAITING_FOR_CONNECTIONS)); 4041 } 4042 sprintf(buf2,Text_String(TXT_TIME_ALLOWED), timeval + 1); 4043 buf3 = Text_String(TXT_PRESS_ESC); 4044 4045 w = MAX(String_Pixel_Width(buf1),String_Pixel_Width(buf2)); 4046 w = MAX(String_Pixel_Width(buf3), (unsigned)w); 4047 w += (d_margin * 4); 4048 h = (d_txt6_h * 3) + (d_margin * 6); 4049 x = 160*factor - (w / 2); 4050 y = 100*factor - (h / 2); 4051 4052 Hide_Mouse(); 4053 Set_Logic_Page(SeenBuff); 4054 Dialog_Box(x, y, w, h); 4055 4056 Fancy_Text_Print (buf1, 160*factor, y + (d_margin * 2), CC_GREEN, BLACK, 4057 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 4058 4059 Fancy_Text_Print (buf2, 160*factor, y + (d_margin * 2) + d_txt6_h + d_margin, 4060 CC_GREEN, BLACK, 4061 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 4062 4063 Fancy_Text_Print (buf3, 160*factor, y + (d_margin * 2) + (d_txt6_h + d_margin) * 2, 4064 CC_GREEN, BLACK, 4065 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 4066 4067 Show_Mouse(); 4068 4069 } else { 4070 4071 /*------------------------------------------------------------------------ 4072 Just update the timeout value on the dialog 4073 ------------------------------------------------------------------------*/ 4074 Hide_Mouse(); 4075 Set_Logic_Page(SeenBuff); 4076 4077 sprintf(buf2,Text_String(TXT_TIME_ALLOWED), timeval + 1); 4078 int pixwidth = String_Pixel_Width (buf2); 4079 LogicPage->Fill_Rect (160*factor - (pixwidth/2) - 12, y+(d_margin*2) + d_txt6_h + d_margin, 4080 160*factor + (pixwidth/2) + 12, y+(d_margin*2) + d_txt6_h*2 + d_margin, 4081 TBLACK); 4082 Fancy_Text_Print (buf2, 160*factor, y + (d_margin * 2) + d_txt6_h + d_margin, 4083 CC_GREEN, BLACK, 4084 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 4085 4086 Show_Mouse(); 4087 } 4088 } 4089 4090 4091 4092 4093 4094 4095 /*********************************************************************************************** 4096 * Wait_For_Focus -- Wait for game to be in focus before proceeding * 4097 * * 4098 * * 4099 * * 4100 * INPUT: Nothing * 4101 * * 4102 * OUTPUT: Nothing * 4103 * * 4104 * WARNINGS: None * 4105 * * 4106 * HISTORY: * 4107 * 1/6/97 3:23PM ST : Created * 4108 *=============================================================================================*/ 4109 void Wait_For_Focus (void) 4110 { 4111 CountDownTimerClass focus_timer; 4112 focus_timer.Set(5*60); 4113 ShowWindow ( MainWindow, SW_SHOWMAXIMIZED ); 4114 4115 /* 4116 ** Process the message loop until we are in focus. 4117 */ 4118 if (!GameInFocus){ 4119 CCDebugString ("C&C95 - Waiting for game to come into focus."); 4120 do { 4121 CCDebugString ("."); 4122 Keyboard::Check(); 4123 if (!focus_timer.Time()){ 4124 CCDebugString ("C&C95 - Calling SetForgroundWindow.\n"); 4125 SetForegroundWindow ( MainWindow ); 4126 CCDebugString ("C&C95 - Calling ShowWindow.\n"); 4127 ShowWindow ( MainWindow, SW_SHOWMAXIMIZED ); 4128 focus_timer.Set(5*60); 4129 } 4130 4131 }while (!GameInFocus); 4132 CCDebugString ("\n"); 4133 AllSurfaces.SurfacesRestored=FALSE; 4134 } 4135 } 4136 4137 4138 4139 4140 4141 extern bool Spawn_WChat(bool can_launch); 4142 4143 /*********************************************************************************************** 4144 * Net_Fake_New_Dialog -- Just like Net_New_Dialog but without the Dialog. For internet play * 4145 * * 4146 * This 'dialog' does all the non-dialog game set up stuff that is done in the normal * 4147 * network game set up dialog. The only visible button is 'cancel' * 4148 * * 4149 * INPUT: Nothing * 4150 * * 4151 * OUTPUT: true if successfully connected * 4152 * * 4153 * WARNINGS: None * 4154 * * 4155 * HISTORY: * 4156 * 5/24/96 10:34AM ST : Created * 4157 *=============================================================================================*/ 4158 static int Net_Fake_New_Dialog(void) 4159 { 4160 int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2; 4161 4162 int d_dialog_w = 120*factor; // dialog width 4163 int d_dialog_h = 80*factor; // dialog height 4164 int d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord 4165 int d_dialog_y = ((200*factor - d_dialog_h) / 2); // centered y-coord 4166 int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord 4167 4168 //d_playerlist_w = 100; 4169 int d_playerlist_w = 106*factor; 4170 int d_playerlist_h = 27*factor; 4171 //int d_playerlist_x = 10 * factor; //off screen 4172 int d_playerlist_x = 500*factor; //10 * factor; //off screen 4173 int d_playerlist_y = d_dialog_y + 20; 4174 4175 #if (GERMAN | FRENCH) 4176 int d_cancel_w = 50*factor; 4177 #else 4178 int d_cancel_w = 45*factor; 4179 #endif 4180 int d_cancel_h = 9*factor; 4181 int d_cancel_x = d_dialog_cx - (d_cancel_w / 2); 4182 int d_cancel_y = d_dialog_y + d_dialog_h - 20*factor; 4183 4184 #if (GERMAN | FRENCH) 4185 int width=160*factor; 4186 int height=80*factor; 4187 #else 4188 int width=120*factor; 4189 int height=80*factor; 4190 #endif //GERMAN | FRENCH 4191 4192 bool player_joined = false; 4193 CountDownTimerClass join_timer; 4194 4195 Fancy_Text_Print(TXT_NONE,0,0,TBLACK,TBLACK,TPF_6PT_GRAD | TPF_NOSHADOW); 4196 Format_Window_String((char*)Text_String(TXT_CONNECTING), SeenBuff.Get_Height(), width, height); 4197 4198 #if (GERMAN | FRENCH) 4199 d_dialog_w = width + 25*factor; 4200 d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord 4201 d_cancel_x = d_dialog_cx - (d_cancel_w / 2); 4202 #endif 4203 4204 4205 /*........................................................................ 4206 Button Enumerations 4207 ........................................................................*/ 4208 enum { 4209 BUTTON_CANCEL = 100, 4210 BUTTON_PLAYERLIST, 4211 }; 4212 4213 /*........................................................................ 4214 Redraw values: in order from "top" to "bottom" layer of the dialog 4215 ........................................................................*/ 4216 typedef enum { 4217 REDRAW_NONE = 0, 4218 REDRAW_MESSAGE, 4219 REDRAW_BUTTONS, 4220 REDRAW_BACKGROUND, 4221 REDRAW_ALL = REDRAW_BACKGROUND 4222 } RedrawType; 4223 4224 /*........................................................................ 4225 Dialog variables 4226 ........................................................................*/ 4227 RedrawType display = REDRAW_ALL; // redraw level 4228 bool process = true; // process while true 4229 KeyNumType input; 4230 4231 char credbuf[CREDITSBUF_MAX]; // for credit edit box 4232 int old_cred; // old value in credits buffer 4233 int transmit; // 1 = re-transmit new game options 4234 4235 long ok_timer = 0; // for timing OK button 4236 int rc; 4237 int i,j; 4238 char *item; 4239 int tabs[] = {77*factor}; // tabs for player list box 4240 4241 long ping_timer = 0; // for sending Ping packets 4242 4243 unsigned char tmp_id[MAX_PLAYERS]; // temp storage for sorting player ID's 4244 int min_index; // for sorting player ID's 4245 unsigned char min_id; // for sorting player ID's 4246 unsigned char id; // connection ID 4247 JoinEventType whahoppa; // event generated by received packets 4248 4249 void const *up_button; 4250 void const *down_button; 4251 4252 if (InMainLoop){ 4253 up_button = Hires_Retrieve("BTN-UP.SHP"); 4254 down_button = Hires_Retrieve("BTN-DN.SHP"); 4255 }else{ 4256 up_button = Hires_Retrieve("BTN-UP2.SHP"); 4257 down_button = Hires_Retrieve("BTN-DN2.SHP"); 4258 } 4259 4260 /*........................................................................ 4261 Buttons 4262 ........................................................................*/ 4263 GadgetClass *commands; // button list 4264 4265 ColorListClass playerlist(BUTTON_PLAYERLIST, 4266 d_playerlist_x, d_playerlist_y, d_playerlist_w, d_playerlist_h, 4267 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 4268 up_button, 4269 down_button); 4270 4271 TextButtonClass cancelbtn(BUTTON_CANCEL, TXT_CANCEL, 4272 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 4273 //#if (GERMAN | FRENCH) 4274 // d_cancel_x, d_cancel_y); 4275 //#else 4276 d_cancel_x, d_cancel_y, d_cancel_w, d_cancel_h); 4277 //#endif 4278 4279 4280 CCDebugString ("C&C95 - In new game dialog - initialising lists.\n"); 4281 /* 4282 ------------------------- Build the button list -------------------------- 4283 */ 4284 commands = &playerlist; 4285 cancelbtn.Add_Tail(*commands); 4286 4287 playerlist.Set_Tabs(tabs); 4288 4289 /* 4290 ----------------------------- Various Inits ------------------------------ 4291 */ 4292 4293 sprintf(credbuf, "%d", MPlayerCredits); 4294 old_cred = MPlayerCredits; 4295 4296 /*........................................................................ 4297 Init other scenario parameters 4298 ........................................................................*/ 4299 Special.IsTGrowth = MPlayerTiberium; 4300 Special.IsTSpread = MPlayerTiberium; 4301 transmit = 0; 4302 4303 /*........................................................................ 4304 Init player color-used flags 4305 ........................................................................*/ 4306 for (i = 0; i < MAX_MPLAYER_COLORS; i++) { 4307 ColorUsed[i] = 0; // init all colors to available 4308 } 4309 ColorUsed[MPlayerColorIdx] = 1; // set my color to used 4310 playerlist.Set_Selected_Style(ColorListClass::SELECT_BAR, CC_GREEN_SHADOW); 4311 4312 /*........................................................................ 4313 Init random-number generator, & create a seed to be used for all random 4314 numbers from here on out 4315 ........................................................................*/ 4316 //ST - 12/18/2018 11:37AM 4317 //randomize(); 4318 //Seed = rand(); 4319 4320 /*------------------------------------------------------------------------ 4321 Add myself to the list. Note that since I'm not in the Players Vector, 4322 the Vector & listbox are now 1 out of sync. 4323 ------------------------------------------------------------------------*/ 4324 item = new char [MPLAYER_NAME_MAX + 4]; 4325 if (MPlayerHouse==HOUSE_GOOD) { 4326 sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_G_D_I)); 4327 } else { 4328 sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_N_O_D)); 4329 } 4330 playerlist.Add_Item(item, MPlayerTColors[MPlayerColorIdx]); 4331 4332 Wait_For_Focus(); 4333 4334 CCDebugString ("C&C95 - About to uncompress title page.\n"); 4335 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 4336 Blit_Hid_Page_To_Seen_Buff(); 4337 CCDebugString ("C&C95 - About to set the palette.\n"); 4338 Set_Palette(Palette); 4339 CCDebugString ("C&C95 - Palette was set OK.\n"); 4340 4341 if (LogicPage != &SeenBuff && LogicPage!= &HidPage){ 4342 CCDebugString ("C&C95 - Logic page invalid"); 4343 Set_Logic_Page (SeenBuff); 4344 } 4345 4346 char a_buffer [128]; 4347 sprintf (a_buffer, "Number of players:%d", Players.Count()); 4348 CCDebugString (a_buffer); 4349 4350 4351 #ifdef VIRTUAL_SUBNET_SERVER 4352 /* 4353 ** Send a bogus packet to wake up the VSS 4354 */ 4355 memset (&GPacket, 0, sizeof(GlobalPacketType)); 4356 4357 GPacket.Command = (NetCommandType)50; //Invalid command 4358 strcpy (GPacket.Name, MPlayerName); 4359 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 0, NULL); 4360 #endif //VIRTUAL_SUBNET_SERVER 4361 4362 4363 CCDebugString ("C&C95 - About to reveal mouse\n"); 4364 while (Get_Mouse_State() > 0) Show_Mouse(); 4365 4366 /* 4367 ---------------------------- Processing loop ----------------------------- 4368 */ 4369 CCDebugString ("C&C95 - Entering join dialogue loop\n"); 4370 while (process) { 4371 4372 /* 4373 ** If we have just received input focus again after running in the background then 4374 ** we need to redraw. 4375 */ 4376 if (AllSurfaces.SurfacesRestored){ 4377 AllSurfaces.SurfacesRestored=FALSE; 4378 display=REDRAW_ALL; 4379 } 4380 4381 /* 4382 ...................... Refresh display if needed ...................... 4383 */ 4384 if (display) { 4385 Hide_Mouse(); 4386 /* 4387 .................. Redraw backgound & dialog box ................... 4388 */ 4389 if (display >= REDRAW_BACKGROUND) { 4390 4391 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 4392 Blit_Hid_Page_To_Seen_Buff(); 4393 Set_Palette(Palette); 4394 4395 Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h); 4396 4397 /*............................................................... 4398 Dialog & Field labels 4399 ...............................................................*/ 4400 Draw_Caption (TXT_NONE, d_dialog_x, d_dialog_y, d_dialog_w); 4401 4402 Fancy_Text_Print(TXT_CONNECTING, d_dialog_cx-width/2, d_dialog_y + 25*factor, CC_GREEN, TBLACK, 4403 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 4404 } 4405 4406 /* 4407 .......................... Redraw buttons .......................... 4408 */ 4409 if (display >= REDRAW_BUTTONS) { 4410 commands->Draw_All(); 4411 } 4412 4413 Show_Mouse(); 4414 display = REDRAW_NONE; 4415 } 4416 4417 /* 4418 ........................... Get user input ............................ 4419 */ 4420 input = commands->Input(); 4421 4422 /* 4423 ---------------------------- Process input ---------------------------- 4424 */ 4425 switch (input) { 4426 4427 /*------------------------------------------------------------------ 4428 CANCEL: send a SIGN_OFF, bail out with error code 4429 ------------------------------------------------------------------*/ 4430 case (KN_ESC): 4431 case (BUTTON_CANCEL | KN_BUTTON): 4432 memset (&GPacket, 0, sizeof(GlobalPacketType)); 4433 4434 GPacket.Command = NET_SIGN_OFF; 4435 strcpy (GPacket.Name, MPlayerName); 4436 4437 /*............................................................... 4438 Broadcast my sign-off over my network 4439 ...............................................................*/ 4440 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 4441 0, NULL); 4442 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 4443 0, NULL); 4444 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 4445 4446 /*............................................................... 4447 Broadcast my sign-off over a bridged network if there is one 4448 ...............................................................*/ 4449 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 4450 4451 /*............................................................... 4452 And now, just be absolutely sure, send my sign-off to each 4453 player in my game. (If there's a bridge between us, the other 4454 player will have specified my address, so he can cross the 4455 bridge; but I may not have specified a bridge address, so the 4456 only way I have of crossing the bridge is to send a packet 4457 directly to him.) 4458 ...............................................................*/ 4459 for (i = 0; i < Players.Count(); i++) { 4460 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1, 4461 &(Players[i]->Address)); 4462 Ipx.Service(); 4463 } 4464 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 4465 MPlayerGameName[0] = 0; 4466 process = false; 4467 rc = false; 4468 Send_Data_To_DDE_Server ("Hello", strlen("Hello"), DDEServerClass::DDE_CONNECTION_FAILED); 4469 GameStatisticsPacketSent = false; 4470 Spawn_WChat(false); 4471 break; 4472 4473 /*------------------------------------------------------------------ 4474 default: exit loop with TRUE status 4475 ------------------------------------------------------------------*/ 4476 default: 4477 #ifdef VIRTUAL_SUBNET_SERVER 4478 if (Players.Count() == InternetMaxPlayers-1){ 4479 4480 4481 #else //VIRTUAL_SUBNET_SERVER 4482 if (Players.Count() > 0){ 4483 #endif // VIRTUAL_SUBNET_SERVER 4484 4485 //char ddkks[128]; 4486 //sprintf (ddkks, "C&C95 - Players.Count() = %d\n", Players.Count()); 4487 //CCDebugString (ddkks); 4488 4489 /* 4490 ** Wait for several secs after receiving request to join before sending 4491 ** start game packet 4492 */ 4493 if (!player_joined){ 4494 player_joined = true; 4495 join_timer.Set (3*60, true); 4496 break; 4497 }else{ 4498 if (join_timer.Time()) break; 4499 } 4500 4501 CCDebugString ("C&C95 - Join timer expired\n"); 4502 4503 /*............................................................... 4504 If a new player has joined in the last second, don't allow 4505 an OK; force a wait longer than 2 seconds (to give all players 4506 a chance to know about this new guy) 4507 ...............................................................*/ 4508 i = MAX(Ipx.Global_Response_Time() * 2, (unsigned long)120); 4509 while (TickCount.Time() - ok_timer < i) 4510 Ipx.Service(); 4511 4512 /*............................................................... 4513 If there are at least 2 players, go ahead & play; error otherwise 4514 ...............................................................*/ 4515 if (MPlayerSolo || Players.Count() > 0) { 4516 rc = TRUE; 4517 process = FALSE; 4518 } else { 4519 CCMessageBox().Process (TXT_ONLY_ONE,TXT_OOPS,NULL); 4520 display = REDRAW_ALL; 4521 } 4522 } 4523 break; 4524 } 4525 4526 /*--------------------------------------------------------------------- 4527 Process incoming packets 4528 ---------------------------------------------------------------------*/ 4529 whahoppa = Get_NewGame_Responses(&playerlist); 4530 if (whahoppa == EV_NEW_PLAYER) { 4531 ok_timer = TickCount.Time(); 4532 transmit = 1; 4533 } else { 4534 if (whahoppa == EV_MESSAGE) { 4535 display = REDRAW_MESSAGE; 4536 } 4537 } 4538 4539 /*--------------------------------------------------------------------- 4540 If our Transmit flag is set, we need to send out a game option packet 4541 ---------------------------------------------------------------------*/ 4542 if (transmit) { 4543 for (i = 0; i < Players.Count(); i++) { 4544 memset (&GPacket, 0, sizeof(GlobalPacketType)); 4545 4546 GPacket.Command = NET_GAME_OPTIONS; 4547 GPacket.ScenarioInfo.Scenario = ScenarioIdx; //MPlayerFilenum[ScenarioIdx]; 4548 GPacket.ScenarioInfo.Credits = MPlayerCredits; 4549 GPacket.ScenarioInfo.IsBases = MPlayerBases; 4550 GPacket.ScenarioInfo.IsTiberium = MPlayerTiberium; 4551 GPacket.ScenarioInfo.IsGoodies = MPlayerGoodies; 4552 GPacket.ScenarioInfo.IsGhosties = MPlayerGhosts; 4553 GPacket.ScenarioInfo.BuildLevel = BuildLevel; 4554 GPacket.ScenarioInfo.UnitCount = MPlayerUnitCount; 4555 GPacket.ScenarioInfo.Seed = Seed; 4556 GPacket.ScenarioInfo.Special = Special; 4557 GPacket.ScenarioInfo.GameSpeed = Options.GameSpeed; 4558 4559 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 4560 1, &(Players[i]->Address) ); 4561 } 4562 transmit = 0; 4563 } 4564 4565 /*--------------------------------------------------------------------- 4566 Ping every player in my game, to force the Global Channel to measure 4567 the connection response time. 4568 ---------------------------------------------------------------------*/ 4569 if (TickCount.Time() - ping_timer > 15) { 4570 memset (&GPacket, 0, sizeof(GlobalPacketType)); 4571 GPacket.Command = NET_PING; 4572 for (i = 0; i < Players.Count(); i++) { 4573 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 4574 1, &(Players[i]->Address) ); 4575 } 4576 ping_timer = TickCount.Time(); 4577 } 4578 4579 /*--------------------------------------------------------------------- 4580 Service the Ipx connections 4581 ---------------------------------------------------------------------*/ 4582 Ipx.Service(); 4583 4584 /*--------------------------------------------------------------------- 4585 Service the sounds & score; GameActive must be false at this point, 4586 so Call_Back() doesn't intercept global messages from me! 4587 ---------------------------------------------------------------------*/ 4588 Call_Back(); 4589 4590 } /* end of while */ 4591 4592 CCDebugString ("C&C95 - Exited process loop\n"); 4593 4594 /*------------------------------------------------------------------------ 4595 Establish connections with all other players. 4596 ------------------------------------------------------------------------*/ 4597 if (rc) { 4598 /*..................................................................... 4599 Set the number of players in this game, and my ID 4600 .....................................................................*/ 4601 MPlayerCount = Players.Count() + 1; 4602 MPlayerLocalID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse); 4603 4604 /*..................................................................... 4605 Get the scenario filename 4606 .....................................................................*/ 4607 Scenario = ScenarioIdx; //PlayerFilenum[ScenarioIdx]; We are passed actual number now from wchat not index from 4608 //Scenario = MPlayerFilenum[ScenarioIdx]; 4609 4610 /*..................................................................... 4611 Compute frame delay value for packet transmissions: 4612 - Divide global channel's response time by 8 (2 to convert to 1-way 4613 value, 4 more to convert from ticks to frames) 4614 .....................................................................*/ 4615 MPlayerMaxAhead = MAX( (Ipx.Global_Response_Time() / 8), (unsigned long)2); 4616 4617 /*..................................................................... 4618 Send all players the NET_GO packet. Wait until all ACK's have been 4619 received. 4620 .....................................................................*/ 4621 CCDebugString ("C&C95 - Sending the 'GO' packet\n"); 4622 memset (&GPacket, 0, sizeof(GlobalPacketType)); 4623 GPacket.Command = NET_GO; 4624 GPacket.ResponseTime.OneWay = MPlayerMaxAhead; 4625 for (i = 0; i < Players.Count(); i++) { 4626 char flopbuf [128]; 4627 sprintf (flopbuf, "Sending 'GO' packet to address %d\n", *((unsigned short*)&(Players[i]->Address))); 4628 CCDebugString (flopbuf); 4629 4630 4631 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 4632 1, &(Players[i]->Address) ); 4633 /*.................................................................. 4634 Wait for all the ACK's to come in. 4635 ..................................................................*/ 4636 while (Ipx.Global_Num_Send() > 0) 4637 Ipx.Service(); 4638 } 4639 4640 /*..................................................................... 4641 Form connections with all other players. Form the IPX Connection ID 4642 from the player's Color (high byte) and House (low byte). This 4643 will let us extract any player's color & house at any time. 4644 Fill in 'tmp_id' while we're doing this. 4645 .....................................................................*/ 4646 for (i = 0; i < Players.Count(); i++) { 4647 id = Build_MPlayerID (Players[i]->Player.Color, 4648 Players[i]->Player.House); 4649 4650 tmp_id[i] = id; 4651 4652 Ipx.Create_Connection(id, Players[i]->Name, &(Players[i]->Address) ); 4653 } 4654 4655 #ifdef VIRTUAL_SUBNET_SERVER 4656 CCDebugString ("C&C95 - Creating connection to the VSS\n"); 4657 /* 4658 ** Create an additional connection to the VSS 4659 */ 4660 if (UseVirtualSubnetServer){ 4661 IPXAddressClass vss_global_address; 4662 NetNodeType vss_node; 4663 NetNumType vss_net; 4664 memset (vss_net, 1, sizeof (vss_net)); 4665 memset (vss_node, 0, sizeof (vss_node)); 4666 vss_global_address.Set_Address(vss_net, vss_node); 4667 Ipx.Create_Connection( VSS_ID, "VSS", &vss_global_address); 4668 } 4669 #endif //VIRTUAL_SUBNET_SERVER 4670 tmp_id[i] = MPlayerLocalID; 4671 4672 /*..................................................................... 4673 Store every player's ID in the MPlayerID[] array. This array will 4674 determine the order of event execution, so the ID's must be stored 4675 in the same order on all systems. 4676 .....................................................................*/ 4677 for (i = 0; i < MPlayerCount; i++) { 4678 min_index = 0; 4679 min_id = 0xff; 4680 for (j = 0; j < MPlayerCount; j++) { 4681 if (tmp_id[j] < min_id) { 4682 min_id = tmp_id[j]; 4683 min_index = j; 4684 } 4685 } 4686 MPlayerID[i] = tmp_id[min_index]; 4687 tmp_id[min_index] = 0xff; 4688 } 4689 /*..................................................................... 4690 Fill in the array of player names, including my own. 4691 .....................................................................*/ 4692 for (i = 0; i < MPlayerCount; i++) { 4693 if (MPlayerID[i] == MPlayerLocalID) { 4694 strcpy (MPlayerNames[i], MPlayerName); 4695 } else { 4696 strcpy (MPlayerNames[i], Ipx.Connection_Name(MPlayerID[i])); 4697 } 4698 } 4699 } 4700 4701 /*------------------------------------------------------------------------ 4702 Init network timing values, using previous response times as a measure 4703 of what our retry delta & timeout should be. 4704 ------------------------------------------------------------------------*/ 4705 Ipx.Set_Timing (Ipx.Global_Response_Time() + 2, -1, 4706 Ipx.Global_Response_Time() * 4); 4707 4708 /*------------------------------------------------------------------------ 4709 Clear all lists 4710 ------------------------------------------------------------------------*/ 4711 Clear_Player_List(&playerlist); 4712 4713 /*------------------------------------------------------------------------ 4714 Restore screen 4715 ------------------------------------------------------------------------*/ 4716 Hide_Mouse(); 4717 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 4718 Blit_Hid_Page_To_Seen_Buff(); 4719 Show_Mouse(); 4720 4721 if (rc){ 4722 Wait_For_Focus(); 4723 } 4724 4725 return(rc); 4726 } 4727 4728 4729 4730 4731 4732 4733 /*********************************************************************************************** 4734 * Net_Fake_Join_Dialog -- Like Net_Join_Dialog but with no dialogs. For Internet Play. * 4735 * * 4736 * This 'dialog' does all the non-dialog game set up stuff that is done in the normal * 4737 * network game set up dialog. The only visible button is 'cancel' * 4738 * * 4739 * * 4740 * INPUT: Nothing * 4741 * * 4742 * OUTPUT: 0 = good, -1 = bad * 4743 * * 4744 * WARNINGS: None * 4745 * * 4746 * HISTORY: * 4747 * 5/24/96 11:07AM ST : Created * 4748 *=============================================================================================*/ 4749 4750 static int Net_Fake_Join_Dialog(void) 4751 { 4752 int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2; 4753 /*........................................................................ 4754 Dialog & button dimensions 4755 ........................................................................*/ 4756 /* ###Change collision detected! C:\PROJECTS\CODE\NETDLG.CPP... */ 4757 int d_dialog_w = 120 *factor; // dialog width 4758 int d_dialog_h = 80*factor; // dialog height 4759 int d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord 4760 int d_dialog_y = ((200*factor - d_dialog_h) / 2); // centered y-coord 4761 int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord 4762 4763 int d_margin1=10; 4764 int d_txt6_h=15; 4765 4766 int d_gamelist_w = 160*factor; 4767 int d_gamelist_h = 27*factor; 4768 int d_gamelist_x = 500*factor; //230*factor; //Off screen 4769 //int d_gamelist_x = 230*factor; //Off screen 4770 int d_gamelist_y = d_dialog_y + 20; 4771 4772 int d_playerlist_w = 106*factor; 4773 int d_playerlist_h = 27*factor; 4774 //int d_playerlist_x = 10 * factor; //Off screen 4775 int d_playerlist_x = 500*factor; //10 * factor; //Off screen 4776 int d_playerlist_y = d_gamelist_y + 20; 4777 4778 #if (GERMAN | FRENCH) 4779 int d_cancel_w = 50*factor; 4780 #else 4781 int d_cancel_w = 45*factor; 4782 #endif 4783 int d_cancel_h = 9*factor; 4784 int d_cancel_x = d_dialog_cx - d_cancel_w / 2; 4785 int d_cancel_y = d_dialog_y + d_dialog_h - 20*factor; 4786 4787 bool ready_to_go = false; 4788 4789 #if (GERMAN | FRENCH) 4790 int width=160*factor; 4791 int height=80*factor; 4792 #else 4793 int width=120*factor; 4794 int height=80*factor; 4795 #endif //GERMAN | FRENCH 4796 4797 Fancy_Text_Print(TXT_NONE,0,0,TBLACK,TBLACK,TPF_6PT_GRAD | TPF_NOSHADOW); 4798 Format_Window_String((char*)Text_String(TXT_CONNECTING), SeenBuff.Get_Height(), width, height); 4799 4800 #if (GERMAN | FRENCH) 4801 d_dialog_w = width + 25*factor; 4802 d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord 4803 d_cancel_x = d_dialog_cx - (d_cancel_w / 2); 4804 #endif 4805 4806 /*........................................................................ 4807 Button Enumerations 4808 ........................................................................*/ 4809 enum { 4810 BUTTON_CANCEL = 100, 4811 BUTTON_GAMELIST, 4812 BUTTON_PLAYERLIST, 4813 }; 4814 4815 /*........................................................................ 4816 Redraw values: in order from "top" to "bottom" layer of the dialog 4817 ........................................................................*/ 4818 typedef enum { 4819 REDRAW_NONE = 0, 4820 REDRAW_MESSAGE, 4821 REDRAW_COLORS, 4822 REDRAW_BUTTONS, 4823 REDRAW_BACKGROUND, 4824 REDRAW_ALL = REDRAW_BACKGROUND 4825 } RedrawType; 4826 4827 /*........................................................................ 4828 Dialog variables 4829 ........................................................................*/ 4830 RedrawType display = REDRAW_ALL; // redraw level 4831 bool process = true; // process while true 4832 KeyNumType input; 4833 4834 JoinStateType joinstate = JOIN_NOTHING; // current "state" of this dialog 4835 char namebuf[MPLAYER_NAME_MAX] = {0}; // buffer for player's name 4836 int game_index = -1; // index of currently-selected game 4837 int join_index = -1; // index of game we're joining 4838 int rc = 0; // -1 = user cancelled, 1 = New 4839 JoinEventType event; // event from incoming packet 4840 int i,j; // loop counter 4841 int parms_received; // 1 = game options received 4842 4843 unsigned char tmp_id[MAX_PLAYERS]; // temp storage for sorting player ID's 4844 int min_index; // for sorting player ID's 4845 unsigned char min_id; // for sorting player ID's 4846 unsigned char id; // connection ID 4847 char * item; 4848 unsigned long starttime; 4849 4850 NodeNameType *who; 4851 4852 void const *up_button; 4853 void const *down_button; 4854 4855 if (InMainLoop){ 4856 up_button = Hires_Retrieve("BTN-UP.SHP"); 4857 down_button = Hires_Retrieve("BTN-DN.SHP"); 4858 }else{ 4859 up_button = Hires_Retrieve("BTN-UP2.SHP"); 4860 down_button = Hires_Retrieve("BTN-DN2.SHP"); 4861 } 4862 4863 /*........................................................................ 4864 Buttons 4865 ........................................................................*/ 4866 GadgetClass *commands; // button list 4867 4868 ColorListClass playerlist(BUTTON_PLAYERLIST, 4869 d_playerlist_x, d_playerlist_y, d_playerlist_w, d_playerlist_h, 4870 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 4871 up_button, 4872 down_button); 4873 4874 ListClass gamelist(BUTTON_GAMELIST, 4875 d_gamelist_x, d_gamelist_y, d_gamelist_w, d_gamelist_h, 4876 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 4877 up_button, 4878 down_button); 4879 4880 TextButtonClass cancelbtn(BUTTON_CANCEL, TXT_CANCEL, 4881 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, 4882 //#if (GERMAN | FRENCH) 4883 // d_cancel_x, d_cancel_y); 4884 //#else 4885 d_cancel_x, d_cancel_y, d_cancel_w, d_cancel_h); 4886 //#endif 4887 4888 /* 4889 ----------------------------- Various Inits ------------------------------ 4890 */ 4891 //MPlayerColorIdx = MPlayerPrefColor; // init my preferred color 4892 4893 playerlist.Set_Selected_Style(ColorListClass::SELECT_NONE); 4894 4895 Fancy_Text_Print("", 0, 0, CC_GREEN, TBLACK, 4896 TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 4897 4898 /* 4899 --------------------------- Send network query --------------------------- 4900 */ 4901 CCDebugString ("C&C95 - About to call Send_Join_Queries.\n"); 4902 Send_Join_Queries (game_index, 1, 0); 4903 4904 Wait_For_Focus(); 4905 4906 CCDebugString ("C&C95 - About to uncompress title page.\n"); 4907 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 4908 Blit_Hid_Page_To_Seen_Buff(); 4909 CCDebugString ("C&C95 - About to set the palette.\n"); 4910 Set_Palette(Palette); 4911 CCDebugString ("C&C95 - Palette was set OK.\n"); 4912 4913 if (LogicPage != &SeenBuff && LogicPage!= &HidPage){ 4914 CCDebugString ("C&C95 - Logic page invalid\n"); 4915 Set_Logic_Page (SeenBuff); 4916 } 4917 4918 4919 char a_buffer [128]; 4920 sprintf (a_buffer, "C&C95 - Number of players:%d\n", Players.Count()); 4921 CCDebugString (a_buffer); 4922 4923 /* 4924 ---------------------------- Init Mono Output ---------------------------- 4925 */ 4926 CCDebugString ("C&C95 - About to reveal mouse\n"); 4927 while (Get_Mouse_State() > 0) Show_Mouse(); 4928 4929 /* 4930 ---------------------------- Processing loop ----------------------------- 4931 */ 4932 CCDebugString ("C&C95 - Entering join dialogue loop\n"); 4933 while (process) { 4934 4935 /* 4936 ** If we have just received input focus again after running in the background then 4937 ** we need to redraw. 4938 */ 4939 if (AllSurfaces.SurfacesRestored){ 4940 AllSurfaces.SurfacesRestored=FALSE; 4941 display=REDRAW_ALL; 4942 } 4943 4944 /* 4945 ...................... Refresh display if needed ...................... 4946 */ 4947 if (display) { 4948 Hide_Mouse(); 4949 /* 4950 .................. Redraw backgound & dialog box ................... 4951 */ 4952 if (display >= REDRAW_BACKGROUND) { 4953 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 4954 Blit_Hid_Page_To_Seen_Buff(); 4955 Set_Palette(Palette); 4956 4957 Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h); 4958 4959 /*............................................................... 4960 Dialog & Field labels 4961 ...............................................................*/ 4962 Draw_Caption (TXT_NONE, d_dialog_x, d_dialog_y, d_dialog_w); 4963 4964 Fancy_Text_Print(TXT_CONNECTING, d_dialog_cx-width/2, d_dialog_y + 25*factor, CC_GREEN, TBLACK, 4965 TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW); 4966 4967 /* 4968 .................... Rebuild the button list .................... 4969 */ 4970 cancelbtn.Zap(); 4971 gamelist.Zap(); 4972 playerlist.Zap(); 4973 4974 commands = &cancelbtn; 4975 gamelist.Add_Tail(*commands); 4976 playerlist.Add_Tail(*commands); 4977 } 4978 /* 4979 .......................... Redraw buttons .......................... 4980 */ 4981 if (display >= REDRAW_BUTTONS) { 4982 commands->Draw_All(); 4983 } 4984 4985 Show_Mouse(); 4986 display = REDRAW_NONE; 4987 } 4988 4989 /* 4990 ........................... Get user input ............................ 4991 */ 4992 input = commands->Input(); 4993 4994 /* 4995 ---------------------------- Process input ---------------------------- 4996 */ 4997 switch (input) { 4998 4999 /*------------------------------------------------------------------ 5000 CANCEL: send a SIGN_OFF 5001 - If we're part of a game, stay in this dialog; otherwise, exit 5002 ------------------------------------------------------------------*/ 5003 case (KN_ESC): 5004 case (BUTTON_CANCEL | KN_BUTTON): 5005 memset (&GPacket, 0, sizeof(GlobalPacketType)); 5006 5007 GPacket.Command = NET_SIGN_OFF; 5008 strcpy(GPacket.Name,MPlayerName); 5009 5010 /*............................................................... 5011 If we're joined to a game, make extra sure the other players in 5012 that game know I'm exiting; send my SIGN_OFF as an ack-required 5013 packet. Do not send this packet to myself (index 0). 5014 ...............................................................*/ 5015 if (joinstate == JOIN_CONFIRMED) { 5016 // 5017 // Remove myself from the player list box 5018 // 5019 item = (char *)(playerlist.Get_Item(0)); 5020 playerlist.Remove_Item(item); 5021 delete [] item; 5022 playerlist.Flag_To_Redraw(); 5023 5024 // 5025 // Remove myself from the Players list 5026 // 5027 who = Players[0]; 5028 Players.Delete(0); 5029 delete who; 5030 5031 for (i = 0; i < Players.Count(); i++) { 5032 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1, 5033 &(Players[i]->Address)); 5034 Ipx.Service(); 5035 } 5036 } 5037 5038 /*............................................................... 5039 Now broadcast my SIGN_OFF so other players looking at this game 5040 know I'm leaving. 5041 ...............................................................*/ 5042 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 5043 0, NULL); 5044 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 5045 0, NULL); 5046 5047 if (IsBridge) { 5048 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 5049 &BridgeNet); 5050 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 5051 &BridgeNet); 5052 } 5053 5054 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 5055 5056 Send_Data_To_DDE_Server ("Hello", strlen("Hello"), DDEServerClass::DDE_CONNECTION_FAILED); 5057 GameStatisticsPacketSent = false; 5058 Spawn_WChat(false); 5059 process = false; 5060 rc = -1; 5061 #if (0) 5062 if (joinstate != JOIN_CONFIRMED) { 5063 process = false; 5064 rc = -1; 5065 } else { 5066 MPlayerGameName[0] = 0; 5067 joinstate = JOIN_NOTHING; 5068 display = REDRAW_ALL; 5069 } 5070 #endif //(0) 5071 break; 5072 5073 /*------------------------------------------------------------------ 5074 JOIN: send a join request packet & switch to waiting-for-confirmation 5075 mode. (Request_To_Join fills in MPlayerName with my namebuf.) 5076 ------------------------------------------------------------------*/ 5077 default: 5078 if (joinstate == JOIN_NOTHING && Games.Count()!=0){ 5079 gamelist.Set_Selected_Index(0); 5080 join_index = gamelist.Current_Index(); 5081 parms_received = 0; 5082 if (Request_To_Join (MPlayerName, join_index, &playerlist, MPlayerHouse, 5083 MPlayerColorIdx)) { 5084 joinstate = JOIN_WAIT_CONFIRM; 5085 } else { 5086 display = REDRAW_ALL; 5087 } 5088 } 5089 break; 5090 5091 } 5092 5093 /*--------------------------------------------------------------------- 5094 Resend our query packets 5095 ---------------------------------------------------------------------*/ 5096 Send_Join_Queries(game_index, 0, 0); 5097 5098 /*--------------------------------------------------------------------- 5099 Process incoming packets 5100 ---------------------------------------------------------------------*/ 5101 event = Get_Join_Responses(&joinstate, &gamelist, &playerlist, 5102 join_index); 5103 /*..................................................................... 5104 If we've changed state, redraw everything; if we're starting the game, 5105 break out of the loop. If we've just joined, send out a player query 5106 so I'll get added to the list instantly. 5107 .....................................................................*/ 5108 if (event == EV_STATE_CHANGE) { 5109 display = REDRAW_ALL; 5110 if (joinstate==JOIN_GAME_START) { 5111 CCDebugString ("C&C95 - Received 'GO' packet\n"); 5112 5113 ready_to_go = true; 5114 } else { 5115 5116 /*.................................................................. 5117 If we're newly-confirmed, immediately send out a player query 5118 ..................................................................*/ 5119 if (joinstate==JOIN_CONFIRMED) { 5120 5121 Clear_Player_List(&playerlist); 5122 5123 item = new char [MPLAYER_NAME_MAX + 4]; 5124 if (MPlayerHouse==HOUSE_GOOD) { 5125 sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_G_D_I)); 5126 } else { 5127 sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_N_O_D)); 5128 } 5129 playerlist.Add_Item (item, MPlayerTColors[MPlayerColorIdx]); 5130 5131 who = new NodeNameType; 5132 strcpy(who->Name, MPlayerName); 5133 who->Address = IPXAddressClass(); 5134 who->Player.House = MPlayerHouse; 5135 who->Player.Color = MPlayerColorIdx; 5136 Players.Add (who); 5137 5138 Send_Join_Queries (game_index, 0, 1); 5139 } else { 5140 5141 /*.................................................................. 5142 If we've been rejected, clear any messages we may have been typing. 5143 ..................................................................*/ 5144 if (joinstate==JOIN_REJECTED) { 5145 5146 // 5147 // Remove myself from the player list box 5148 // 5149 item = (char *)(playerlist.Get_Item(0)); 5150 if (item){ 5151 playerlist.Remove_Item(item); 5152 delete [] item; 5153 playerlist.Flag_To_Redraw(); 5154 } 5155 5156 // 5157 // Remove myself from the Players list 5158 // 5159 if (Players.Count()){ 5160 who = Players[0]; 5161 Players.Delete(0); 5162 delete who; 5163 } 5164 } 5165 } 5166 } 5167 } else 5168 5169 /*..................................................................... 5170 If a new game is detected, and it's the first game on our list, 5171 automatically send out a player query for that game. 5172 .....................................................................*/ 5173 if (event == EV_NEW_GAME && gamelist.Count()==1) { 5174 gamelist.Set_Selected_Index(0); 5175 game_index = gamelist.Current_Index(); 5176 Send_Join_Queries (game_index, 0, 1); 5177 } else 5178 5179 /*..................................................................... 5180 If the game options have changed, print them. 5181 .....................................................................*/ 5182 if (event == EV_GAME_OPTIONS) { 5183 parms_received = 1; 5184 display = REDRAW_MESSAGE; 5185 } else 5186 5187 /*..................................................................... 5188 Draw an incoming message 5189 .....................................................................*/ 5190 if (event == EV_MESSAGE) { 5191 display = REDRAW_MESSAGE; 5192 } else 5193 5194 /*..................................................................... 5195 A game before the one I've selected is gone, so we have a new index now. 5196 'game_index' must be kept set to the currently-selected list item, so 5197 we send out queries for the currently-selected game. It's therefore 5198 imperative that we detect any changes to the game list. 5199 If we're joined in a game, we must decrement our game_index to keep 5200 it aligned with the game we're joined to. 5201 .....................................................................*/ 5202 if (event == EV_GAME_SIGNOFF) { 5203 if (joinstate==JOIN_CONFIRMED) { 5204 game_index--; 5205 join_index--; 5206 gamelist.Set_Selected_Index(join_index); 5207 } else { 5208 gamelist.Flag_To_Redraw(); 5209 Clear_Player_List(&playerlist); 5210 game_index = gamelist.Current_Index(); 5211 Send_Join_Queries (game_index, 0, 1); 5212 } 5213 } 5214 5215 /*--------------------------------------------------------------------- 5216 Service the Ipx connections 5217 ---------------------------------------------------------------------*/ 5218 Ipx.Service(); 5219 5220 /*--------------------------------------------------------------------- 5221 Clean out the Game List; if an old entry is found: 5222 - Remove it 5223 - Clear the player list 5224 - Send queries for the new selected game, if there is one 5225 ---------------------------------------------------------------------*/ 5226 for (i = 0; i < Games.Count(); i++) { 5227 if (TickCount.Time() - Games[i]->Game.LastTime > 400) { 5228 Games.Delete(Games[i]); 5229 item = (char *)(gamelist.Get_Item (i)); 5230 gamelist.Remove_Item (item); 5231 delete [] item; 5232 if (i <= game_index) { 5233 gamelist.Flag_To_Redraw(); 5234 Clear_Player_List(&playerlist); 5235 game_index = gamelist.Current_Index(); 5236 Send_Join_Queries (game_index, 0, 1); 5237 } 5238 } 5239 } 5240 5241 /* 5242 ** If we were flagged to start the game and we recognise both players then quit the loop 5243 */ 5244 5245 //char ddkks[128]; 5246 //sprintf (ddkks, "C&C95 - Players.Count() = %d\n", Players.Count()); 5247 //CCDebugString (ddkks); 5248 if (ready_to_go){ // && Players.Count() == InternetMaxPlayers){ 5249 rc = 0; 5250 process = false; 5251 } 5252 5253 /*--------------------------------------------------------------------- 5254 Service the sounds & score; GameActive must be false at this point, 5255 so Call_Back() doesn't intercept global messages from me! 5256 ---------------------------------------------------------------------*/ 5257 Call_Back(); 5258 } 5259 5260 /*------------------------------------------------------------------------ 5261 Establish connections with all other players. 5262 ------------------------------------------------------------------------*/ 5263 if (rc == 0) { 5264 /*..................................................................... 5265 If the other guys are playing a scenario I don't have (sniff), I can't 5266 play. Try to bail gracefully. 5267 .....................................................................*/ 5268 if (ScenarioIdx==-1) { 5269 CCMessageBox().Process (TXT_UNABLE_PLAY_WAAUGH); 5270 5271 // 5272 // Remove myself from the player list box 5273 // 5274 item = (char *)(playerlist.Get_Item(0)); 5275 playerlist.Remove_Item(item); 5276 delete [] item; 5277 playerlist.Flag_To_Redraw(); 5278 5279 // 5280 // Remove myself from the Players list 5281 // 5282 who = Players[0]; 5283 Players.Delete(0); 5284 delete who; 5285 5286 memset (&GPacket, 0, sizeof(GlobalPacketType)); 5287 5288 GPacket.Command = NET_SIGN_OFF; 5289 strcpy (GPacket.Name, MPlayerName); 5290 5291 for (i = 0; i < Players.Count(); i++) { 5292 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1, 5293 &(Players[i]->Address)); 5294 Ipx.Service(); 5295 } 5296 5297 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 5298 0, NULL); 5299 Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 5300 0, NULL); 5301 5302 if (IsBridge) { 5303 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 5304 &BridgeNet); 5305 Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, 5306 &BridgeNet); 5307 } 5308 5309 while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ; 5310 5311 rc = -1; 5312 5313 } else { 5314 5315 /*.................................................................. 5316 Set the number of players in this game, and my ID 5317 ..................................................................*/ 5318 MPlayerCount = Players.Count(); 5319 MPlayerLocalID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse); 5320 5321 /*.................................................................. 5322 Get the scenario number 5323 ..................................................................*/ 5324 Scenario = ScenarioIdx; //PlayerFilenum[ScenarioIdx]; We are passed actual number now from wchat not index from 5325 5326 /*.................................................................. 5327 Form connections with all other players. Form the IPX Connection ID 5328 from the player's Color and House. This will let us extract any 5329 player's color & house at any time. Fill in 'tmp_id' while we're 5330 doing this. 5331 ..................................................................*/ 5332 for (i = 0; i < Players.Count(); i++) { 5333 5334 /*............................................................... 5335 Only create the connection if it's not myself! 5336 ...............................................................*/ 5337 if (strcmp (MPlayerName, Players[i]->Name)) { 5338 id = Build_MPlayerID(Players[i]->Player.Color, 5339 Players[i]->Player.House); 5340 5341 tmp_id[i] = id; 5342 5343 Ipx.Create_Connection((int)id, Players[i]->Name, &(Players[i]->Address) ); 5344 } else { 5345 tmp_id[i] = MPlayerLocalID; 5346 } 5347 } 5348 5349 #ifdef VIRTUAL_SUBNET_SERVER 5350 /* 5351 ** Create an additional connection to the VSS 5352 */ 5353 if (UseVirtualSubnetServer){ 5354 IPXAddressClass vss_global_address; 5355 NetNodeType vss_node; 5356 NetNumType vss_net; 5357 memset (vss_net, 1, sizeof (vss_net)); 5358 memset (vss_node, 0, sizeof (vss_node)); 5359 vss_global_address.Set_Address(vss_net, vss_node); 5360 Ipx.Create_Connection( VSS_ID, "VSS", &vss_global_address); 5361 } 5362 #endif //VIRTUAL_SUBNET_SERVER 5363 5364 /*.................................................................. 5365 Store every player's ID in the MPlayerID[] array. This array will 5366 determine the order of event execution, so the ID's must be stored 5367 in the same order on all systems. 5368 ..................................................................*/ 5369 for (i = 0; i < MPlayerCount; i++) { 5370 min_index = 0; 5371 min_id = 0xff; 5372 for (j = 0; j < MPlayerCount; j++) { 5373 if (tmp_id[j] < min_id) { 5374 min_id = tmp_id[j]; 5375 min_index = j; 5376 } 5377 } 5378 MPlayerID[i] = tmp_id[min_index]; 5379 tmp_id[min_index] = 0xff; 5380 } 5381 /*.................................................................. 5382 Fill in the array of player names, including my own. 5383 ..................................................................*/ 5384 for (i = 0; i < MPlayerCount; i++) { 5385 if (MPlayerID[i] == MPlayerLocalID) { 5386 strcpy (MPlayerNames[i], MPlayerName); 5387 } else { 5388 strcpy (MPlayerNames[i], Ipx.Connection_Name(MPlayerID[i])); 5389 } 5390 } 5391 } 5392 /*--------------------------------------------------------------------- 5393 Wait a while, polling the IPX service routines, to give our ACK 5394 a chance to get to the other system. If he doesn't get our ACK, he'll 5395 be waiting the whole time we load MIX files. 5396 ---------------------------------------------------------------------*/ 5397 i = MAX(Ipx.Global_Response_Time() * 2, (unsigned long)120); 5398 starttime = TickCount.Time(); 5399 while (TickCount.Time() - starttime < (unsigned)i) { 5400 Ipx.Service(); 5401 } 5402 } 5403 5404 /*------------------------------------------------------------------------ 5405 Init network timing values, using previous response times as a measure 5406 of what our retry delta & timeout should be. 5407 ------------------------------------------------------------------------*/ 5408 Ipx.Set_Timing (Ipx.Global_Response_Time() + 2, -1, 5409 Ipx.Global_Response_Time() * 4); 5410 5411 /*------------------------------------------------------------------------ 5412 Clear all lists 5413 ------------------------------------------------------------------------*/ 5414 Clear_Game_List(&gamelist); 5415 Clear_Player_List(&playerlist); 5416 5417 /*------------------------------------------------------------------------ 5418 Restore screen 5419 ------------------------------------------------------------------------*/ 5420 Hide_Mouse(); 5421 Load_Title_Screen("HTITLE.PCX", &HidPage, Palette); 5422 Blit_Hid_Page_To_Seen_Buff(); 5423 Show_Mouse(); 5424 5425 if (rc != -1){ 5426 Wait_For_Focus(); 5427 } 5428 5429 return(rc); 5430 } 5431 5432 5433 5434 #endif