CCTEN.CPP (22497B)
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 /*************************************************************************** 17 * * 18 * Project Name : Command & Conquer * 19 * * 20 * File Name : CCTEN.CPP * 21 * * 22 * Programmer : Bill R. Randolph * 23 * * 24 * Start Date : 01/09/96 * 25 * * 26 * Last Update : November 27, 1996 [BRR] * 27 * * 28 *-------------------------------------------------------------------------* 29 * Functions: * 30 * Init_TEN -- Performs TEN-specific initialization * 31 * Shutdown_TEN -- Shuts down TEN connections * 32 * Connect_TEN -- Waits for connections to other players * 33 * Destroy_TEN_Connection -- Destroys the given connection * 34 * Debug_Mono -- Custom mono prints * 35 * Send_TEN_Win_Packet -- Sends a win packet to server * 36 * Send_TEN_Alliance -- Sends an ally/enemy packet to server * 37 * Send_TEN_Out_Of_Sync -- Announces this game out of sync * 38 * Send_TEN_Packet_Too_Late -- Announces packet-received-too-late * 39 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 40 #include "function.h" 41 42 #if(TEN) 43 #ifdef WIN32 44 #define WINDOWS 45 #endif 46 #include "ten.h" 47 #endif 48 49 void Connect_TEN(void); 50 void Debug_Mono(void); 51 52 /*************************************************************************** 53 * Init_TEN -- Performs TEN-specific initialization * 54 * * 55 * INPUT: * 56 * none. * 57 * * 58 * OUTPUT: * 59 * 1 = OK, 0 = error * 60 * * 61 * WARNINGS: * 62 * none. * 63 * * 64 * HISTORY: * 65 * 01/09/1996 BRR : Created. * 66 *=========================================================================*/ 67 int Init_TEN(void) 68 { 69 #if(TEN) 70 //------------------------------------------------------------------------ 71 // Allocate a packet buffer for TEN's use 72 //------------------------------------------------------------------------ 73 Session.TenPacket = new char[Session.TenSize]; 74 75 //------------------------------------------------------------------------ 76 // Read the multiplayer settings from the CONQUER.INI file, and the game 77 // options from the options file. 78 //------------------------------------------------------------------------ 79 Session.Read_MultiPlayer_Settings(); 80 81 if (!Read_TEN_Game_Options()) { 82 WWMessageBox().Process("Unable to load game settings!"); 83 //Prog_End(); 84 Emergency_Exit(0); 85 } 86 87 //------------------------------------------------------------------------ 88 // Flush all incoming packets 89 //------------------------------------------------------------------------ 90 Ten->Flush_All(); 91 92 //------------------------------------------------------------------------ 93 // Form connections to all other players 94 //------------------------------------------------------------------------ 95 Connect_TEN(); 96 97 //------------------------------------------------------------------------ 98 // Set multiplayer values for the local system, and timing values. 99 //------------------------------------------------------------------------ 100 Session.CommProtocol = COMM_PROTOCOL_MULTI_E_COMP; 101 102 return (1); 103 #else 104 return (1); 105 #endif 106 107 } // end of Init_TEN 108 109 110 /*************************************************************************** 111 * Shutdown_TEN -- Shuts down TEN connections * 112 * * 113 * INPUT: * 114 * none. * 115 * * 116 * OUTPUT: * 117 * none. * 118 * * 119 * WARNINGS: * 120 * none. * 121 * * 122 * HISTORY: * 123 * 01/09/1996 BRR : Created. * 124 *=========================================================================*/ 125 void Shutdown_TEN(void) 126 { 127 #if(TEN) 128 CDTimerClass<SystemTimerClass> timer; 129 130 //------------------------------------------------------------------------ 131 // Wait a full second before exiting, to ensure all packets get sent. 132 //------------------------------------------------------------------------ 133 timer = 60; 134 while (timer) ; 135 136 //------------------------------------------------------------------------ 137 // Free memory 138 //------------------------------------------------------------------------ 139 if (Session.TenPacket) { 140 delete [] Session.TenPacket; 141 Session.TenPacket = NULL; 142 } 143 144 if (Ten) { 145 delete Ten; 146 Ten = NULL; 147 } 148 149 return; 150 151 #endif 152 } // end of Shutdown_TEN 153 154 155 /*************************************************************************** 156 * Connect_TEN -- Waits for connections to other players * 157 * * 158 * INPUT: * 159 * none. * 160 * * 161 * OUTPUT: * 162 * none. * 163 * * 164 * WARNINGS: * 165 * MPlayerCount must have been initialized at this point. * 166 * * 167 * HISTORY: * 168 * 01/10/1996 BRR : Created. * 169 *=========================================================================*/ 170 void Connect_TEN(void) 171 { 172 #if(TEN) 173 typedef struct ConnectPacketTag { 174 NetCommandType Dummy; // packet type; set to PING 175 char Name[MPLAYER_NAME_MAX]; // player's name 176 HousesType House; // player's ActLike 177 unsigned char Color; // player's Color 178 } ConnectPacketType; 179 int num_players; 180 int num_found; 181 ConnectPacketType send_packet; 182 ConnectPacketType receive_packet; 183 int address; 184 int found; 185 int size; 186 int i; 187 CDTimerClass<SystemTimerClass> send_timer; 188 NodeNameType *who; 189 190 enum { 191 D_TXT6_H = 7, 192 D_MARGIN = 5, 193 }; 194 static int x,y,w,h; 195 char const *buf1; 196 char const *buf2; 197 198 int display = 0; 199 RemapControlType * scheme = GadgetClass::Get_Color_Scheme(); 200 201 // 202 // Clear the Players list 203 // 204 while (Session.Players.Count() > 0) { 205 delete Session.Players[0]; 206 Session.Players.Delete(Session.Players[0]); 207 } 208 209 // 210 // Add myself to the list first thing 211 // 212 who = new NodeNameType; 213 strcpy(who->Name, Session.Handle); 214 who->Player.House = Session.House; 215 who->Player.Color = Session.ColorIdx; 216 Session.Players.Add (who); 217 218 // 219 // Find out how many players to wait for 220 // 221 num_players = Session.NumPlayers - 1; 222 num_found = 0; 223 224 // 225 // Send out a packet announcing my presence 226 // 227 send_packet.Dummy = NET_PING; 228 strcpy(send_packet.Name, Session.Handle); 229 send_packet.House = Session.House; 230 send_packet.Color = Session.ColorIdx; 231 Ten->Send_Global_Message(&send_packet, sizeof(send_packet), 0, -1); 232 233 // 234 // Start our packet-sending timer 235 // 236 send_timer = 240; 237 238 // 239 // Wait for all players to enter the game 240 // 241 display = 1; 242 while (num_found < num_players) { 243 244 #ifdef WIN32 245 /* 246 ** If we have just received input focus again after running in the background then 247 ** we need to redraw. 248 */ 249 if (AllSurfaces.SurfacesRestored) { 250 AllSurfaces.SurfacesRestored=FALSE; 251 display = 1; 252 } 253 #endif 254 255 if (display) { 256 Fancy_Text_Print("", 0, 0, 0, 0, TPF_TEXT); 257 buf1 = Text_String(TXT_WAITING_FOR_CONNECTIONS); 258 buf2 = Text_String(TXT_PRESS_ESC); 259 w = MAX(String_Pixel_Width(buf1),String_Pixel_Width(buf2)); 260 w += (D_MARGIN * 2); 261 h = (D_TXT6_H * 2) + (D_MARGIN * 7); 262 x = 160 - (w / 2); 263 y = 100 - (h / 2); 264 Hide_Mouse(); 265 //Set_Logic_Page(SeenBuff); 266 Dialog_Box(x * RESFACTOR, y * RESFACTOR, w * RESFACTOR, h * RESFACTOR); 267 268 Fancy_Text_Print(buf1, 269 160 * RESFACTOR, 270 (y + (D_MARGIN * 2)) * RESFACTOR, 271 scheme, TBLACK, TPF_CENTER | TPF_TEXT); 272 Fancy_Text_Print(buf2, 273 160 * RESFACTOR, 274 (y + (D_MARGIN * 2) + D_TXT6_H + D_MARGIN) * RESFACTOR, 275 scheme, TBLACK, TPF_CENTER | TPF_TEXT); 276 Show_Mouse(); 277 display = 0; 278 } 279 280 Ten->Service(); 281 282 // 283 // Check for an incoming packet; if a PING comes in, see if we already 284 // have this player in our Players list. If not, add him. 285 // 286 if (Ten->Get_Global_Message (&receive_packet, &size, &address) && 287 receive_packet.Dummy == NET_PING) { 288 found = 0; 289 for (i = 1; i < Session.Players.Count(); i++) { 290 if (Session.Players[i]->TenAddress == address) { 291 found = 1; 292 break; 293 } 294 } 295 296 // 297 // Create a new connection and a new node in the list. 298 // 299 if (!found) { 300 301 who = new NodeNameType; 302 strcpy(who->Name, receive_packet.Name); 303 who->TenAddress = address; 304 who->Player.House = receive_packet.House; 305 who->Player.Color = (PlayerColorType)receive_packet.Color; 306 Session.Players.Add (who); 307 308 num_found++; 309 310 Ten->Send_Global_Message(&send_packet, sizeof(send_packet), 1, 311 address); 312 } 313 } 314 315 // 316 // If the user hits ESC, bail out. 317 // 318 if (Keyboard->Check()) { 319 if (Keyboard->Get() == KN_ESC) { 320 //Prog_End(); 321 Emergency_Exit(0); 322 } 323 } 324 325 // 326 // When our timer expires, re-send the packet. 327 // 328 if (!send_timer) { 329 send_packet.Dummy = NET_PING; 330 Ten->Send_Global_Message(&send_packet, sizeof(send_packet), 0, -1); 331 send_timer = 240; 332 } 333 } 334 335 #else 336 return; 337 #endif 338 } 339 340 341 /*************************************************************************** 342 * Destroy_TEN_Connection -- Destroys the given connection * 343 * * 344 * INPUT: * 345 * id connection ID to destroy (must be a HousesType) * 346 * error 0 = user signed off; 1 = connection error; otherwise, * 347 * no error is shown. * 348 * * 349 * OUTPUT: * 350 * none. * 351 * * 352 * WARNINGS: * 353 * none. * 354 * * 355 * HISTORY: * 356 * 01/11/1996 BRR : Created. * 357 *=========================================================================*/ 358 void Destroy_TEN_Connection(int id, int error) 359 { 360 #if(TEN) 361 int i; 362 HouseClass *housep; 363 char txt[80]; 364 365 //------------------------------------------------------------------------ 366 // Do nothing if the house isn't human. 367 //------------------------------------------------------------------------ 368 housep = HouseClass::As_Pointer((HousesType)id); 369 if (!housep || !housep->IsHuman) 370 return; 371 372 /*------------------------------------------------------------------------ 373 Create a message to display to the user 374 ------------------------------------------------------------------------*/ 375 txt[0] = '\0'; 376 if (error==1) { 377 sprintf(txt,Text_String(TXT_CONNECTION_LOST),Ten->Connection_Name(id)); 378 } else if (error==0) { 379 sprintf(txt,Text_String(TXT_LEFT_GAME),Ten->Connection_Name(id)); 380 } 381 382 if (strlen(txt)) { 383 Session.Messages.Add_Message (NULL,0, txt, housep->RemapColor, 384 TPF_TEXT, Rule.MessageDelay * TICKS_PER_MINUTE); 385 Map.Flag_To_Redraw(false); 386 } 387 388 //------------------------------------------------------------------------ 389 // Remove this player from the Players vector 390 //------------------------------------------------------------------------ 391 for (i = 0; i < Session.Players.Count(); i++) { 392 if (!stricmp(Session.Players[i]->Name,housep->IniName)) { 393 delete Session.Players[i]; 394 Session.Players.Delete(Session.Players[i]); 395 break; 396 } 397 } 398 399 /*------------------------------------------------------------------------ 400 Delete the TEN connection 401 ------------------------------------------------------------------------*/ 402 Ten->Delete_Connection(id); 403 404 //------------------------------------------------------------------------ 405 // Turn the player's house over to the computer's AI 406 //------------------------------------------------------------------------ 407 housep->IsHuman = false; 408 housep->IQ = Rule.MaxIQ; 409 strcpy (housep->IniName,Text_String(TXT_COMPUTER)); 410 411 Session.NumPlayers--; 412 413 /*------------------------------------------------------------------------ 414 If we're the last player left, tell the user. 415 ------------------------------------------------------------------------*/ 416 if (Session.NumPlayers == 1) { 417 sprintf(txt,"%s",Text_String(TXT_JUST_YOU_AND_ME)); 418 Session.Messages.Add_Message (NULL, 0, txt, housep->RemapColor, 419 TPF_TEXT, Rule.MessageDelay * TICKS_PER_MINUTE); 420 Map.Flag_To_Redraw(false); 421 } 422 423 #else 424 id = id; 425 error = error; 426 427 #endif 428 } // end of Destroy_TEN_Connection 429 430 431 /*************************************************************************** 432 * Debug_Mono -- Custom mono prints * 433 * * 434 * INPUT: * 435 * none. * 436 * * 437 * OUTPUT: * 438 * none. * 439 * * 440 * WARNINGS: * 441 * none. * 442 * * 443 * HISTORY: * 444 * 11/27/1996 BRR : Created. * 445 *=========================================================================*/ 446 void Debug_Mono(void) 447 { 448 #if(TEN) 449 int i; 450 int id; 451 452 Mono_Printf("STATE: # Connections:%d\n",Ten->Num_Connections()); 453 for (i=0;i<Ten->Num_Connections();i++) { 454 id = Ten->Connection_ID(i); 455 Mono_Printf("Connection %d: Name:%s, ID:%d, Address:%d\n", 456 i, 457 Ten->Connection_Name(id), 458 Ten->Connection_ID(i), 459 Ten->Connection_Address(id)); 460 } 461 462 #endif 463 } 464 465 466 /*************************************************************************** 467 * Send_TEN_Win_Packet -- Sends a win packet to server * 468 * * 469 * INPUT: * 470 * none. * 471 * * 472 * OUTPUT: * 473 * none. * 474 * * 475 * WARNINGS: * 476 * none. * 477 * * 478 * HISTORY: * 479 * 11/27/1996 BRR : Created. * 480 *=========================================================================*/ 481 void Send_TEN_Win_Packet(void) 482 { 483 #if(TEN) 484 char winbuf[80]; 485 char idbuf[20]; 486 int first = 1; 487 HouseClass *hptr; 488 int i; 489 490 // 491 // Build a special text buffer to send to the TEN server. Format: 492 // "winner 'id id'", where 'id' is the Ten Player ID of each player 493 // on the winning team. (For TEN, the color index is the player ID.) 494 // 495 sprintf(winbuf,"winner '"); 496 for (i = 0; i < Session.Players.Count(); i++) { 497 hptr = HouseClass::As_Pointer(Session.Players[i]->Player.ID); 498 if (!hptr->IsDefeated) { 499 if (!first) { 500 strcat(winbuf," "); 501 } else { 502 first = 0; 503 } 504 sprintf(idbuf,"%d", Session.Players[i]->Player.Color); 505 strcat (winbuf, idbuf); 506 } 507 } 508 strcat (winbuf,"' "); 509 tenArSetPlayerState(winbuf); 510 #endif // TEN 511 512 } // end of Send_TEN_Win_Packet 513 514 515 /*************************************************************************** 516 * Send_TEN_Alliance -- Sends an ally/enemy packet to server * 517 * * 518 * INPUT: * 519 * whom name of player we're allying / enemying with * 520 * ally 1 = we're allying; 0 = we're breaking the alliance * 521 * * 522 * OUTPUT: * 523 * none. * 524 * * 525 * WARNINGS: * 526 * none. * 527 * * 528 * HISTORY: * 529 * 11/27/1996 BRR : Created. * 530 *=========================================================================*/ 531 void Send_TEN_Alliance(char *whom, int ally) 532 { 533 #if(TEN) 534 char buf[80]; 535 536 if (ally) { 537 sprintf(buf,"ally '%s' ",whom); 538 } else { 539 sprintf(buf,"enemy '%s' ",whom); 540 } 541 542 tenArSetPlayerState(buf); 543 544 #else 545 whom = whom; 546 ally = ally; 547 #endif // TEN 548 549 } // end of Send_TEN_Alliance 550 551 552 /*************************************************************************** 553 * Send_TEN_Out_Of_Sync -- Announces this game out of sync * 554 * * 555 * INPUT: * 556 * none. * 557 * * 558 * OUTPUT: * 559 * none. * 560 * * 561 * WARNINGS: * 562 * none. * 563 * * 564 * HISTORY: * 565 * 11/27/1996 BRR : Created. * 566 *=========================================================================*/ 567 void Send_TEN_Out_Of_Sync(void) 568 { 569 #if(TEN) 570 tenArSetPlayerState("sync '1' "); 571 #endif // TEN 572 573 } // end of Send_TEN_Out_Of_Sync 574 575 576 /*************************************************************************** 577 * Send_TEN_Packet_Too_Late -- Announces packet-received-too-late * 578 * * 579 * INPUT: * 580 * none. * 581 * * 582 * OUTPUT: * 583 * none. * 584 * * 585 * WARNINGS: * 586 * none. * 587 * * 588 * HISTORY: * 589 * 11/27/1996 BRR : Created. * 590 *=========================================================================*/ 591 void Send_TEN_Packet_Too_Late(void) 592 { 593 #if(TEN) 594 tenArSetPlayerState("toolate '1' "); 595 #endif // TEN 596 597 } // end of Send_TEN_Packet_Too_Late 598 599 600 /***************************** end of ccten.cpp *****************************/