doomlib.cpp (16575B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #include "Precompiled.h" 30 #include "globaldata.h" 31 #include "doomlib.h" 32 #include <assert.h> 33 #include "Main.h" 34 #include "sys/sys_session.h" 35 #include "idlib/Thread.h" 36 37 38 #include <sys/types.h> 39 40 // Store master volume settings in archived cvars, becausue we want them to apply 41 // even if a user isn't signed in. 42 // The range is from 0 to 15, which matches the setting in vanilla DOOM. 43 idCVar s_volume_sound( "s_volume_sound", "8", CVAR_ARCHIVE | CVAR_INTEGER, "sound volume", 0, 15 ); 44 idCVar s_volume_midi( "s_volume_midi", "8", CVAR_ARCHIVE | CVAR_INTEGER, "music volume", 0, 15 ); 45 idCVar m_show_messages( "m_show_messages", "1", CVAR_ARCHIVE | CVAR_INTEGER, "show messages", 0, 1 ); 46 idCVar m_inDemoMode( "m_inDemoMode", "1", CVAR_INTEGER, "in demo mode", 0, 1 ); 47 48 bool globalNetworking = false; 49 bool globalPauseTime = false; 50 int PLAYERCOUNT = 1; 51 52 #ifdef _DEBUG 53 bool debugOutput = true; 54 #else 55 bool debugOutput = false; 56 #endif 57 58 namespace DoomLib 59 { 60 static const char * Expansion_Names[] = { 61 "Ultimate DOOM", "DOOM II: Hell On Earth", "Final DOOM: TNT Evilution", "Final DOOM: Plutonia Experiment", "DOOM II: Master Levels", "DOOM II: No Rest For The Living" 62 }; 63 64 static const char* Skill_Names[] = { 65 "I'm Too Young To Die!", "Hey, Not Too Rough!", "Hurt Me Plenty!", "Ultra-Violence", "Nightmare" 66 }; 67 68 static const char* Filter_Names[] = { 69 "#str_friends", "#str_around", "#str_top15" 70 }; 71 72 // Game-specific setup values. 73 static const char * Doom_MapNames[] = { 74 "E1M1: Hangar", "E1M2: Nuclear Plant", "E1M3: Toxin Refinery", "E1M4: Command Control", "E1M5: Phobos Lab", "E1M6: Central Processing", "E1M7: Computer Station", "E1M8: Phobos Anomaly", "E1M9: Military Base", 75 "E2M1: Deimos Anomaly", "E2M2: Containment Area", "E2M3: Refinery", "E2M4: Deimos Lab", "E2M5: Command Center", "E2M6: Halls of the Damned", "E2M7: Spawning Vats", "E2M8: Tower of Babel", "E2M9: Fortress of Mystery", 76 "E3M1: Hell Keep", "E3M2: Slough of Despair", "E3M3: Pandemonium", "E3M4: House of Pain", "E3M5: Unholy Cathedral", "E3M6: MT. Erebus", "E3M7: Gate to Limbo", "E3M8: DIS", "E3M9: Warrens", 77 "E4M1: Hell Beneath", "E4M2: Perfect Hatred", "E4M3: Sever The Wicked", "E4M4: Unruly Evil", "E4M5: They Will Repent", "E4M6: Against Thee Wickedly", "E4M7: And Hell Followed", "E4M8: Unto The Cruel", "E4M9: Fear" 78 }; 79 80 static const char * Doom2_MapNames[] = { 81 "1: Entryway", "2: Underhalls", "3: The Gantlet", "4: The Focus", "5: The Waste Tunnels", "6: The Crusher", "7: Dead Simple", "8: Tricks and Traps", "9: The Pit", "10: Refueling Base", 82 "11: Circle of Death", "12: The Factory", "13: Downtown", "14: The Inmost Dens", "15: Industrial Zone", "16: Suburbs", "17: Tenements", "18: The Courtyard", "19: The Citadel", "20: Gotcha!", 83 "21: Nirvana", "22: The Catacombs", "23: Barrels O' Fun", "24: The Chasm", "25: Bloodfalls", "26: The Abandoned Mines", "27: Monster Condo", "28: The Spirit World", "29: The Living End", 84 "30: Icon of Sin", "31: IDKFA", "32: Keen" 85 }; 86 87 static const char * TNT_MapNames[] = { 88 "1: System Control", "2: Human BBQ", "3: Power Control", "4: Wormhole", "5: Hangar", "6: Open Season", "7: Prison", "8: Metal", "9: Stronghold", "10: Redemption", "11: Storage Facility", 89 "12: Crater", "13: Nukage Processing", "14: Steel Works", "15: Dead Zone", "16: Deepest Reaches", "17: Processing Area", "18: Mill", "19: Shipping & Respawning", "20: Central Processing", 90 "21: Administration Center", "22: Habitat", "23: Lunar Mining Project", "24: Quarry", "25: Baron's Den", "26: Ballistyx", "27: Mount Pain", "28: Heck", "29: River Styx", "30: Last Call", "31: Pharaoh", "32: Caribbean" 91 }; 92 93 static const char * Plut_MapNames[] = { 94 "1: Congo", "2: Well of Souls", "3: Aztec", "4: Caged", "5: Ghost Town", "6: Baron's Lair", "7: Caughtyard", "8: Realm", "9: Abattoire", "10: Onslaught", "11: Hunted", "12: Speed", "13: The Crypt", "14: Genesis", 95 "15: The Twilight", "16: The Omen", "17: Compound", "18: Neurosphere", "19: NME", "20: The Death Domain", "21: Slayer", "22: Impossible Mission", "23: Tombstone", "24: The Final Frontier", "25: The Temple of Darkness", 96 "26: Bunker", "27: Anti-Christ", "28: The Sewers", "29: Odyssey of Noises", "30: The Gateway of Hell", "31: Cyberden", "32: Go 2 It" 97 }; 98 99 static const char * Mast_MapNames[] = { 100 "1: Attack", "2: Canyon","3: The Catwalk", "4: The Combine", "5: The Fistula", "6: The Garrison", "7: Titan Manor", "8: Paradox", "9: Subspace", "10: Subterra", "11: Trapped On Titan", "12: Virgil's Lead", "13: Minos' Judgement", 101 "14: Bloodsea Keep", "15: Mephisto's Maosoleum", "16: Nessus", "17: Geryon", "18: Vesperas", "19: Black Tower", "20: The Express Elevator To Hell", "21: Bad Dream" 102 }; 103 104 static const char * Nerve_MapNames[] = { 105 "1: The Earth Base", "2: The Pain Labs", "3: Canyon of the Dead", "4: Hell Mountain", "5: Vivisection", "6: Inferno of Blood", "7: Baron's Banquet", "8: Tomb of Malevolence", "9: March of Demons" 106 }; 107 108 const ExpansionData App_Expansion_Data_Local[] = { 109 { ExpansionData::IWAD, retail, doom, "DOOM", DOOMWADDIR"DOOM.WAD", NULL, "base/textures/DOOMICON.PNG" , Doom_MapNames }, 110 { ExpansionData::IWAD, commercial, doom2, "DOOM 2", DOOMWADDIR"DOOM2.WAD", NULL, "base/textures/DOOM2ICON.PNG" , Doom2_MapNames }, 111 { ExpansionData::IWAD, commercial, pack_tnt, "FINAL DOOM: TNT EVILUTION", DOOMWADDIR"TNT.WAD", NULL, "base/textures/TNTICON.PNG" , TNT_MapNames }, 112 { ExpansionData::IWAD, commercial, pack_plut, "FINAL DOOM: PLUTONIA EXPERIMENT", DOOMWADDIR"PLUTONIA.WAD", NULL, "base/textures/PLUTICON.PNG" , Plut_MapNames }, 113 { ExpansionData::PWAD, commercial, pack_master, "DOOM 2: MASTER LEVELS", DOOMWADDIR"DOOM2.WAD", DOOMWADDIR"MASTERLEVELS.WAD", "base/textures/MASTICON.PNG" , Mast_MapNames }, 114 { ExpansionData::PWAD, commercial, pack_nerve, "DOOM 2: NO REST FOR THE LIVING", DOOMWADDIR"DOOM2.WAD", DOOMWADDIR"NERVE.WAD", "base/textures/NERVEICON.PNG" , Nerve_MapNames }, 115 }; 116 117 int classicRemap[K_LAST_KEY]; 118 119 const ExpansionData * GetCurrentExpansion() { 120 return &App_Expansion_Data_Local[ DoomLib::expansionSelected ]; 121 } 122 123 void SetCurrentExpansion( int expansion ) { 124 expansionDirty = true; 125 expansionSelected = expansion; 126 } 127 128 void SetIdealExpansion( int expansion ) { 129 idealExpansion = expansion; 130 } 131 132 idStr currentMapName; 133 idStr currentDifficulty; 134 135 void SetCurrentMapName( idStr name ) { currentMapName = name; } 136 const idStr & GetCurrentMapName() { return currentMapName; } 137 void SetCurrentDifficulty( idStr name ) { currentDifficulty = name; } 138 const idStr & GetCurrentDifficulty() { return currentDifficulty; } 139 140 int currentplayer = -1; 141 142 Globals *globaldata[4]; 143 144 RecvFunc Recv; 145 SendFunc Send; 146 SendRemoteFunc SendRemote; 147 148 149 bool Active = true; 150 DoomInterface Interface; 151 152 int idealExpansion = 0; 153 int expansionSelected = 0; 154 bool expansionDirty = true; 155 156 bool skipToLoad = false; 157 char loadGamePath[MAX_PATH]; 158 159 bool skipToNew = false; 160 int chosenSkill = 0; 161 int chosenEpisode = 1; 162 163 idMatchParameters matchParms; 164 165 void * (*Z_Malloc)( int size, int tag, void* user ) = NULL; 166 void (*Z_FreeTag)(int lowtag ); 167 168 idArray< idSysMutex, 4 > playerScreenMutexes; 169 170 void ExitGame() { 171 // TODO: If we ever support splitscreen and online, 172 // we'll have to call D_QuitNetGame for all local players. 173 DoomLib::SetPlayer( 0 ); 174 D_QuitNetGame(); 175 176 session->QuitMatch(); 177 } 178 179 void ShowXToContinue( bool activate ) { 180 } 181 182 /* 183 ======================== 184 DoomLib::GetGameSKU 185 ======================== 186 */ 187 gameSKU_t GetGameSKU() { 188 189 if ( common->GetCurrentGame() == DOOM_CLASSIC ) { 190 return GAME_SKU_DOOM1_BFG; 191 } else if ( common->GetCurrentGame() == DOOM2_CLASSIC ) { 192 return GAME_SKU_DOOM2_BFG; 193 } 194 195 assert( false && "Invalid basepath" ); 196 return GAME_SKU_DCC; 197 } 198 199 /* 200 ======================== 201 DoomLib::ActivateGame 202 ======================== 203 */ 204 void ActivateGame() { 205 Active = true; 206 207 // Turn off menu toggler 208 int originalPlayer = DoomLib::GetPlayer(); 209 210 for ( int i = 0; i < Interface.GetNumPlayers(); i++ ) { 211 DoomLib::SetPlayer(i); 212 ::g->menuactive = false; 213 } 214 215 globalPauseTime = false; 216 217 DoomLib::SetPlayer( originalPlayer ); 218 } 219 220 /* 221 ======================== 222 DoomLib::HandleEndMatch 223 ======================== 224 */ 225 void HandleEndMatch() { 226 if ( session->GetGameLobbyBase().IsHost() ) { 227 ShowXToContinue( false ); 228 session->EndMatch(); 229 } 230 } 231 }; 232 233 234 extern void I_InitGraphics(); 235 extern void D_DoomMain(); 236 extern bool D_DoomMainPoll(); 237 extern void I_InitInput(); 238 extern void D_RunFrame( bool ); 239 extern void I_ShutdownSound(); 240 extern void I_ShutdownMusic(); 241 extern void I_ShutdownGraphics(); 242 extern void I_ProcessSoundEvents( void ); 243 244 245 void DoomLib::InitGlobals( void *ptr /* = NULL */ ) 246 { 247 if (ptr == NULL) 248 ptr = new Globals; 249 250 globaldata[currentplayer] = static_cast<Globals*>(ptr); 251 252 memset( globaldata[currentplayer], 0, sizeof(Globals) ); 253 g = globaldata[currentplayer]; 254 g->InitGlobals(); 255 256 } 257 258 void *DoomLib::GetGlobalData( int player ) { 259 return globaldata[player]; 260 } 261 262 void DoomLib::InitControlRemap() { 263 264 memset( classicRemap, K_NONE, sizeof( classicRemap ) ); 265 266 classicRemap[K_JOY3] = KEY_TAB ; 267 classicRemap[K_JOY4] = K_MINUS; 268 classicRemap[K_JOY2] = K_EQUALS; 269 classicRemap[K_JOY9] = K_ESCAPE ; 270 classicRemap[K_JOY_STICK1_UP] = K_UPARROW ; 271 classicRemap[K_JOY_DPAD_UP] = K_UPARROW ; 272 classicRemap[K_JOY_STICK1_DOWN] = K_DOWNARROW ; 273 classicRemap[K_JOY_DPAD_DOWN] = K_DOWNARROW ; 274 classicRemap[K_JOY_STICK1_LEFT] = K_LEFTARROW ; 275 classicRemap[K_JOY_DPAD_LEFT] = K_LEFTARROW ; 276 classicRemap[K_JOY_STICK1_RIGHT] = K_RIGHTARROW ; 277 classicRemap[K_JOY_DPAD_RIGHT] = K_RIGHTARROW ; 278 classicRemap[K_JOY1] = K_ENTER; 279 280 281 } 282 283 keyNum_t DoomLib::RemapControl( keyNum_t key ) { 284 285 if( classicRemap[ key ] == K_NONE ) { 286 return key; 287 } else { 288 289 if( ::g->menuactive && key == K_JOY2 ) { 290 return K_BACKSPACE; 291 } 292 293 return (keyNum_t)classicRemap[ key ]; 294 } 295 296 } 297 298 void DoomLib::InitGame( int argc, char** argv ) 299 { 300 ::g->myargc = argc; 301 ::g->myargv = argv; 302 303 InitControlRemap(); 304 305 306 307 D_DoomMain(); 308 } 309 310 bool DoomLib::Poll() 311 { 312 return D_DoomMainPoll(); 313 } 314 315 bool TryRunTics( idUserCmdMgr * userCmdMgr ); 316 bool DoomLib::Tic( idUserCmdMgr * userCmdMgr ) 317 { 318 return TryRunTics( userCmdMgr ); 319 } 320 321 void D_Wipe(); 322 void DoomLib::Wipe() 323 { 324 D_Wipe(); 325 } 326 327 void DoomLib::Frame( int realoffset, int buffer ) 328 { 329 ::g->realoffset = realoffset; 330 331 // The render thread needs to read the player's screens[0] array, 332 // so updating it needs to be in a critical section. 333 // This may seem like a really broad mutex (which it is), and if performance 334 // suffers too much, we can try to narrow the scope. 335 // Just be careful, because the player's screen data is updated in many different 336 // places. 337 if ( 0 <= currentplayer && currentplayer <= 4 ) { 338 idScopedCriticalSection crit( playerScreenMutexes[currentplayer] ); 339 340 D_RunFrame( true ); 341 } 342 } 343 344 void DoomLib::Draw() 345 { 346 R_RenderPlayerView (&::g->players[::g->displayplayer]); 347 } 348 349 angle_t GetViewAngle() 350 { 351 return g->viewangle; 352 } 353 354 void SetViewAngle( angle_t ang ) 355 { 356 g->viewangle = ang; 357 ::g->viewxoffset = (finesine[g->viewangle>>ANGLETOFINESHIFT]*::g->realoffset) >> 8; 358 ::g->viewyoffset = (finecosine[g->viewangle>>ANGLETOFINESHIFT]*::g->realoffset) >> 8; 359 360 } 361 362 363 void SetViewX( fixed_t x ) 364 { 365 ::g->viewx = x; 366 } 367 368 void SetViewY( fixed_t y ) 369 { 370 ::g->viewy = y; 371 } 372 373 374 fixed_t GetViewX() 375 { 376 return ::g->viewx + ::g->viewxoffset; 377 } 378 379 fixed_t GetViewY() 380 { 381 return ::g->viewy + ::g->viewyoffset; 382 } 383 384 void DoomLib::Shutdown() { 385 //D_QuitNetGame (); 386 I_ShutdownSound(); 387 I_ShutdownGraphics(); 388 389 W_Shutdown(); 390 391 // De-allocate the zone memory (never happened in original doom, until quit) 392 if ( ::g->mainzone ) { 393 free( ::g->mainzone ); 394 } 395 396 // Delete the globals 397 if ( globaldata[currentplayer] ) { 398 delete globaldata[currentplayer]; 399 globaldata[currentplayer] = NULL; 400 } 401 } 402 403 // static 404 void DoomLib::SetPlayer( int id ) 405 { 406 currentplayer = id; 407 408 if ( id < 0 || id >= MAX_PLAYERS ) { 409 g = NULL; 410 } 411 else { 412 413 // Big Fucking hack. 414 if( globalNetworking && session->GetGameLobbyBase().GetMatchParms().matchFlags | MATCH_ONLINE ) { 415 currentplayer = 0; 416 } 417 418 g = globaldata[currentplayer]; 419 } 420 } 421 422 void DoomLib::SetNetworking( RecvFunc rf, SendFunc sf, SendRemoteFunc sendRemote ) 423 { 424 Recv = rf; 425 Send = sf; 426 SendRemote = sendRemote; 427 } 428 429 int DoomLib::GetPlayer() 430 { 431 return currentplayer; 432 } 433 434 byte DoomLib::BuildSourceDest( int toNode ) { 435 byte sourceDest = 0; 436 sourceDest |= ::g->consoleplayer << 2; 437 sourceDest |= RemoteNodeToPlayerIndex( toNode ); 438 return sourceDest; 439 } 440 441 void I_Printf(char *error, ...); 442 443 void DoomLib::GetSourceDest( byte sourceDest, int* source, int* dest ) { 444 445 int src = (sourceDest & 12) >> 2; 446 int dst = sourceDest & 3; 447 448 *source = PlayerIndexToRemoteNode( src ); 449 450 //I_Printf( "GetSourceDest Current Player(%d) %d --> %d\n", GetPlayer(), src, *source ); 451 *dest = PlayerIndexToRemoteNode( dst ); 452 } 453 454 int nodeMap[4][4] = { 455 {0, 1, 2, 3}, //Player 0 456 {1, 0, 2, 3}, //Player 1 457 {2, 0, 1, 3}, //Player 2 458 {3, 0, 1, 2} //Player 3 459 }; 460 461 int DoomLib::RemoteNodeToPlayerIndex( int node ) { 462 //This needs to be called with the proper doom globals set so this calculation will work properly 463 464 /* 465 int player = ::g->consoleplayer; 466 if (player == 2 && node == 2 ) { 467 int suck = 0; 468 } 469 if( node == player ) { 470 return 0; 471 } 472 if( node - player <= 0 ) { 473 return node+1; 474 } 475 return node;*/ 476 return nodeMap[::g->consoleplayer][node]; 477 478 } 479 480 int indexMap[4][4] = { 481 {0, 1, 2, 3}, //Player 0 482 {1, 0, 2, 3}, //Player 1 483 {1, 2, 0, 3}, //Player 2 484 {1, 2, 3, 0} //Player 3 485 }; 486 487 int DoomLib::PlayerIndexToRemoteNode( int index ) { 488 /*int player = ::g->consoleplayer; 489 if( index == 0 ) { 490 return player; 491 } 492 if( index <= player ) { 493 return index-1; 494 } 495 return index;*/ 496 return indexMap[::g->consoleplayer][index]; 497 } 498 499 void I_Error (char *error, ...); 500 extern bool useTech5Packets; 501 502 void DoomLib::PollNetwork() { 503 #if 0 504 if ( !useTech5Packets ) { 505 506 if ( !globalNetworking ) { 507 return; 508 } 509 510 int c; 511 struct sockaddr fromaddress; 512 socklen_t fromlen; 513 doomdata_t sw; 514 515 while(1) { 516 int receivedSize = recvfrom( ::g->insocket, &sw, sizeof( doomdata_t ), MSG_DONTWAIT, &fromaddress, &fromlen ); 517 //c = WSARecvFrom(::g->insocket, &buffer, 1, &num_recieved, &flags, (struct sockaddr*)&fromaddress, &fromlen, 0, 0); 518 519 if ( receivedSize < 0 ) 520 { 521 int err = sys_net_errno; 522 if (err != SYS_NET_EWOULDBLOCK ) { 523 I_Error ("GetPacket: %d", err ); 524 //I_Printf ("GetPacket: %s",strerror(errno)); 525 } 526 return; 527 } 528 529 printf( "RECEIVED PACKET!!\n" ); 530 531 int source; 532 int dest; 533 GetSourceDest( sw.sourceDest, &source, &dest ); 534 535 //Push the packet onto the network stack to be processed. 536 DoomLib::Send( (char*)&sw, receivedSize, NULL, dest ); 537 } 538 } 539 #endif 540 } 541 542 void DoomLib::SendNetwork() { 543 544 if ( !globalNetworking ) { 545 return; 546 } 547 DoomLib::SendRemote(); 548 } 549 550 void DoomLib::RunSound() { 551 552 I_ProcessSoundEvents(); 553 } 554