diff --git a/src/d_main.c b/src/d_main.c index e25ef998e..0654e0927 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1462,7 +1462,7 @@ void D_SRB2Main(void) { levelstarttic = gametic; G_SetGamestate(GS_LEVEL); - if (!P_SetupLevel(false)) + if (!P_LoadLevel(false)) I_Quit(); // fail so reset game stuff } } diff --git a/src/g_game.c b/src/g_game.c index 19b18ef8c..e6a28aa41 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1847,7 +1847,7 @@ void G_DoLoadLevel(boolean resetplayer) } // Setup the level. - if (!P_SetupLevel(false)) // this never returns false? + if (!P_LoadLevel(false)) // this never returns false? { // fail so reset game stuff Command_ExitGame_f(); diff --git a/src/p_saveg.c b/src/p_saveg.c index 85efacf88..4cfeab6f8 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -4064,7 +4064,7 @@ static inline boolean P_NetUnArchiveMisc(void) tokenlist = READUINT32(save_p); - if (!P_SetupLevel(true)) + if (!P_LoadLevel(true)) return false; // get the time diff --git a/src/p_setup.c b/src/p_setup.c index ce6027c4e..2605faa0d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -971,7 +971,7 @@ static void P_SpawnEmeraldHunt(void) mobjinfo[MT_EMERHUNT].spawnstate+2); } -static void P_LoadThings(boolean loademblems) +static void P_SpawnMapThings(boolean spawnemblems) { size_t i; mapthing_t *mt; @@ -1001,7 +1001,7 @@ static void P_LoadThings(boolean loademblems) || mt->type == 1702) // MT_AXISTRANSFERLINE continue; // These were already spawned - if (!loademblems && mt->type == mobjinfo[MT_EMBLEM].doomednum) + if (!spawnemblems && mt->type == mobjinfo[MT_EMBLEM].doomednum) continue; mt->mobj = NULL; @@ -2016,6 +2016,75 @@ static void P_LoadMapData(const virtres_t* virt) memcpy(spawnsides, sides, numsides * sizeof (*sides)); } +/** Compute MD5 message digest for bytes read from memory source + * + * The resulting message digest number will be written into the 16 bytes + * beginning at RESBLOCK. + * + * \param filename path of file + * \param resblock resulting MD5 checksum + * \return 0 if MD5 checksum was made, and is at resblock, 1 if error was found + */ +static INT32 P_MakeBufferMD5(const char* buffer, size_t len, void* resblock) +{ +#ifdef NOMD5 + (void)buffer; + (void)len; + memset(resblock, 0x00, 16); + return 1; +#else + tic_t t = I_GetTime(); + CONS_Debug(DBG_SETUP, "Making MD5\n"); + if (md5_buffer(buffer, len, resblock) == NULL) + return 1; + CONS_Debug(DBG_SETUP, "MD5 calc took %f seconds\n", (float)(I_GetTime() - t)/NEWTICRATE); + return 0; +#endif +} + +static void P_MakeMapMD5(virtres_t* virt, void* dest) +{ + unsigned char linemd5[16]; + unsigned char sectormd5[16]; + unsigned char thingmd5[16]; + unsigned char sidedefmd5[16]; + unsigned char resmd5[16]; + UINT8 i; + + // Create a hash for the current map + // get the actual lumps! + virtlump_t *virtlines = vres_Find(virt, "LINEDEFS"); + virtlump_t *virtsectors = vres_Find(virt, "SECTORS"); + virtlump_t *virtmthings = vres_Find(virt, "THINGS"); + virtlump_t *virtsides = vres_Find(virt, "SIDEDEFS"); + + P_MakeBufferMD5((char*)virtlines->data, virtlines->size, linemd5); + P_MakeBufferMD5((char*)virtsectors->data, virtsectors->size, sectormd5); + P_MakeBufferMD5((char*)virtmthings->data, virtmthings->size, thingmd5); + P_MakeBufferMD5((char*)virtsides->data, virtsides->size, sidedefmd5); + + for (i = 0; i < 16; i++) + resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF; + + M_Memcpy(dest, &resmd5, 16); +} + +static void P_LoadMapFromFile(void) +{ + virtres_t *virt = vres_GetMap(lastloadedmaplumpnum); + + P_LoadMapData(virt); + P_LoadMapBSP(virt); + P_LoadMapLUT(virt); + + P_LoadLineDefs2(); + P_GroupLines(); + + P_MakeMapMD5(virt, &mapmd5); + + vres_Free(virt); +} + #if 0 static char *levellumps[] = { @@ -2084,7 +2153,7 @@ lumpnum_t lastloadedmaplumpnum; // for comparative savegame // // Some player initialization for map start. // -static void P_LevelInitStuff(void) +static void P_InitLevelSettings(void) { INT32 i; boolean canresetlives = true; @@ -2209,68 +2278,15 @@ void P_LoadThingsOnly(void) P_RemoveMobj((mobj_t *)think); } - P_LevelInitStuff(); + P_InitLevelSettings(); - P_LoadThings(true); + P_SpawnMapThings(true); // restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0]; skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0]; } -/** Compute MD5 message digest for bytes read from memory source - * - * The resulting message digest number will be written into the 16 bytes - * beginning at RESBLOCK. - * - * \param filename path of file - * \param resblock resulting MD5 checksum - * \return 0 if MD5 checksum was made, and is at resblock, 1 if error was found - */ -static INT32 P_MakeBufferMD5(const char *buffer, size_t len, void *resblock) -{ -#ifdef NOMD5 - (void)buffer; - (void)len; - memset(resblock, 0x00, 16); - return 1; -#else - tic_t t = I_GetTime(); - CONS_Debug(DBG_SETUP, "Making MD5\n"); - if (md5_buffer(buffer, len, resblock) == NULL) - return 1; - CONS_Debug(DBG_SETUP, "MD5 calc took %f seconds\n", (float)(I_GetTime() - t)/NEWTICRATE); - return 0; -#endif -} - -static void P_MakeMapMD5(virtres_t* virt, void *dest) -{ - unsigned char linemd5[16]; - unsigned char sectormd5[16]; - unsigned char thingmd5[16]; - unsigned char sidedefmd5[16]; - unsigned char resmd5[16]; - UINT8 i; - - // Create a hash for the current map - // get the actual lumps! - virtlump_t* virtlines = vres_Find(virt, "LINEDEFS"); - virtlump_t* virtsectors = vres_Find(virt, "SECTORS"); - virtlump_t* virtmthings = vres_Find(virt, "THINGS"); - virtlump_t* virtsides = vres_Find(virt, "SIDEDEFS"); - - P_MakeBufferMD5((char*)virtlines->data, virtlines->size, linemd5); - P_MakeBufferMD5((char*)virtsectors->data, virtsectors->size, sectormd5); - P_MakeBufferMD5((char*)virtmthings->data, virtmthings->size, thingmd5); - P_MakeBufferMD5((char*)virtsides->data, virtsides->size, sidedefmd5); - - for (i = 0; i < 16; i++) - resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF; - - M_Memcpy(dest, &resmd5, 16); -} - static void P_RunLevelScript(const char *scriptname) { if (!(mapheaderinfo[gamemap-1]->levelflags & LF_SCRIPTISFILE)) @@ -2335,6 +2351,26 @@ static void P_ForceCharacter(const char *forcecharskin) } } +static void P_ResetSpawnpoints(void) +{ + UINT8 i; + + numdmstarts = numredctfstarts = numbluectfstarts = 0; + + // reset the player starts + for (i = 0; i < MAXPLAYERS; i++) + playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL; + + for (i = 0; i < MAX_DM_STARTS; i++) + deathmatchstarts[i] = NULL; + + for (i = 0; i < 2; i++) + skyboxmo[i] = NULL; + + for (i = 0; i < 16; i++) + skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; +} + static void P_LoadRecordGhosts(void) { const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1; @@ -2434,6 +2470,45 @@ static void P_LoadNightsGhosts(void) free(gpath); } +static void P_InitTagGametype(void) +{ + UINT8 i; + INT32 realnumplayers = 0; + INT32 playersactive[MAXPLAYERS]; + + //I just realized how problematic this code can be. + //D_NumPlayers() will not always cover the scope of the netgame. + //What if one player is node 0 and the other node 31? + //The solution? Make a temp array of all players that are currently playing and pick from them. + //Future todo? When a player leaves, shift all nodes down so D_NumPlayers() can be used as intended? + //Also, you'd never have to loop through all 32 players slots to find anything ever again. + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator) + { + playersactive[realnumplayers] = i; //stores the player's node in the array. + realnumplayers++; + } + } + + if (!realnumplayers) //this should also fix the dedicated crash bug. You only pick a player if one exists to be picked. + { + CONS_Printf(M_GetText("No player currently available to become IT. Awaiting available players.\n")); + return; + } + + i = P_RandomKey(realnumplayers); + players[playersactive[i]].pflags |= PF_TAGIT; //choose our initial tagger before map starts. + + // Taken and modified from G_DoReborn() + // Remove the player so he can respawn elsewhere. + // first disassociate the corpse + if (players[playersactive[i]].mo) + P_RemoveMobj(players[playersactive[i]].mo); + + G_SpawnPlayer(playersactive[i], false); //respawn the lucky player in his dedicated spawn location. +} + static void P_SetupCamera(void) { if (players[displayplayer].mo && (server || addedtogame)) @@ -2471,6 +2546,52 @@ static void P_SetupCamera(void) } } +static void P_InitCamera(void) +{ + if (!dedicated) + { + P_SetupCamera(); + + // Salt: CV_ClearChangedFlags() messes with your settings :( + /*if (!cv_cam_height.changed) + CV_Set(&cv_cam_height, cv_cam_height.defaultvalue); + if (!cv_cam2_height.changed) + CV_Set(&cv_cam2_height, cv_cam2_height.defaultvalue); + + if (!cv_cam_dist.changed) + CV_Set(&cv_cam_dist, cv_cam_dist.defaultvalue); + if (!cv_cam2_dist.changed) + CV_Set(&cv_cam2_dist, cv_cam2_dist.defaultvalue);*/ + + // Though, I don't think anyone would care about cam_rotate being reset back to the only value that makes sense :P + if (!cv_cam_rotate.changed) + CV_Set(&cv_cam_rotate, cv_cam_rotate.defaultvalue); + if (!cv_cam2_rotate.changed) + CV_Set(&cv_cam2_rotate, cv_cam2_rotate.defaultvalue); + + if (!cv_analog.changed) + CV_SetValue(&cv_analog, 0); + if (!cv_analog2.changed) + CV_SetValue(&cv_analog2, 0); + + displayplayer = consoleplayer; // Start with your OWN view, please! + } + + if (twodlevel) + { + CV_SetValue(&cv_analog, false); + CV_SetValue(&cv_analog2, false); + } + else + { + if (cv_useranalog.value) + CV_SetValue(&cv_analog, true); + + if ((splitscreen && cv_useranalog2.value) || botingame) + CV_SetValue(&cv_analog2, true); + } +} + static boolean CanSaveLevel(INT32 mapnum) { if (ultimatemode) // never save in ultimate (probably redundant with cursaveslot also being checked) @@ -2486,21 +2607,187 @@ static boolean CanSaveLevel(INT32 mapnum) return (mapheaderinfo[mapnum-1]->levelflags & LF_SAVEGAME || gamecomplete || !lastmaploaded); } +static void P_RunSpecialStageWipe(void) +{ + tic_t starttime = I_GetTime(); + tic_t endtime = starttime + (3*TICRATE)/2; + tic_t nowtime; + + S_StartSound(NULL, sfx_s3kaf); + + // Fade music! Time it to S3KAF: 0.25 seconds is snappy. + if (RESETMUSIC || + strnicmp(S_MusicName(), + (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap - 1]->musname : mapmusname, 7)) + S_FadeOutStopMusic(MUSICRATE/4); //FixedMul(FixedDiv(F_GetWipeLength(wipedefs[wipe_speclevel_towhite])*NEWTICRATERATIO, NEWTICRATE), MUSICRATE) + + F_WipeStartScreen(); + wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE); + +#ifdef HWRENDER + // uh.......... + if (rendermode == render_opengl) + F_WipeColorFill(0); +#endif + + F_WipeEndScreen(); + F_RunWipe(wipedefs[wipe_speclevel_towhite], false); + + I_OsPolling(); + I_FinishUpdate(); // page flip or blit buffer + if (moviemode) + M_SaveFrame(); + + nowtime = lastwipetic; + + // Hold on white for extra effect. + while (nowtime < endtime) + { + // wait loop + while (!((nowtime = I_GetTime()) - lastwipetic)) + I_Sleep(); + lastwipetic = nowtime; + if (moviemode) // make sure we save frames for the white hold too + M_SaveFrame(); + } +} + +static void P_RunLevelWipe(void) +{ + F_WipeStartScreen(); + wipestyleflags |= WSF_FADEOUT; + +#ifdef HWRENDER + // uh.......... + if (rendermode == render_opengl) + F_WipeColorFill(31); +#endif + + F_WipeEndScreen(); + // for titlemap: run a specific wipe if specified + // needed for exiting time attack + if (wipetypepre != INT16_MAX) + F_RunWipe( + (wipetypepre >= 0 && F_WipeExists(wipetypepre)) ? wipetypepre : wipedefs[wipe_level_toblack], + false); + wipetypepre = -1; +} + +static void P_InitPlayers(void) +{ + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + // Start players with pity shields if possible + players[i].pity = -1; + + players[i].mo = NULL; + + if (!G_PlatformGametype()) + G_DoReborn(i); + else // gametype is GT_COOP or GT_RACE + { + G_SpawnPlayer(i, players[i].starposttime); + if (players[i].starposttime) + P_ClearStarPost(players[i].starpostnum); + } + } +} + +static void P_WriteLetter(void) +{ + char *buf, *b; + + if (!unlockables[27].unlocked) // pandora's box + return; + + if (modeattacking) + return; + +#ifndef DEVELOP + if (modifiedgame) + return; +#endif + + if (netgame || multiplayer) + return; + + if (gamemap != 0x1d35 - 016464) + return; + + P_SpawnMobj(0640370000, 0x11000000, 0x3180000, MT_LETTER)->angle = ANGLE_90; + + if (textprompts[199]->page[1].backcolor == 259) + return; + + buf = W_CacheLumpName("WATERMAP", PU_STATIC); + b = buf; + + while ((*b != 65) && (b - buf < 256)) + { + *b = (*b - 65) & 255; + b++; + } + *b = '\0'; + + Z_Free(textprompts[199]->page[1].text); + textprompts[199]->page[1].text = Z_StrDup(buf); + textprompts[199]->page[1].lines = 4; + textprompts[199]->page[1].backcolor = 259; + Z_Free(buf); +} + +static void P_InitGametype(void) +{ + UINT8 i; + + P_InitPlayers(); + + // restore time in netgame (see also g_game.c) + if ((netgame || multiplayer) && gametype == GT_COOP && cv_coopstarposts.value == 2) + { + // is this a hack? maybe + tic_t maxstarposttime = 0; + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && players[i].starposttime > maxstarposttime) + maxstarposttime = players[i].starposttime; + } + leveltime = maxstarposttime; + } + + P_WriteLetter(); + + if (modeattacking == ATTACKING_RECORD && !demoplayback) + P_LoadRecordGhosts(); + else if (modeattacking == ATTACKING_NIGHTS && !demoplayback) + P_LoadNightsGhosts(); + + if (G_TagGametype()) + P_InitTagGametype(); + else if (gametype == GT_RACE && server) + CV_StealthSetValue(&cv_numlaps, + (cv_basenumlaps.value) + ? cv_basenumlaps.value + : mapheaderinfo[gamemap - 1]->numlaps); +} + /** Loads a level from a lump or external wad. * - * \param skipprecip If true, don't spawn precipitation. + * \param fromnetsave If true, skip some stuff because we're loading a netgame snapshot. * \todo Clean up, refactor, split up; get rid of the bloat. */ -boolean P_SetupLevel(boolean skipprecip) +boolean P_LoadLevel(boolean fromnetsave) { // use gamemap to get map number. // 99% of the things already did, so. // Map header should always be in place at this point - INT32 i, loadprecip = 1, ranspecialwipe = 0; - INT32 loademblems = 1; - INT32 fromnetsave = 0; + INT32 i, ranspecialwipe = 0; sector_t *ss; - boolean chase; levelloading = true; // This is needed. Don't touch. @@ -2531,19 +2818,18 @@ boolean P_SetupLevel(boolean skipprecip) if (cv_runscripts.value && mapheaderinfo[gamemap-1]->scriptname[0] != '#') P_RunLevelScript(mapheaderinfo[gamemap-1]->scriptname); - P_LevelInitStuff(); + P_InitLevelSettings(); postimgtype = postimgtype2 = postimg_none; if (mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0') P_ForceCharacter(mapheaderinfo[gamemap-1]->forcecharacter); - // chasecam on in chaos, race, coop - // chasecam off in match, tag, capture the flag - chase = (!(gametyperules & GTR_FIRSTPERSON)) || (maptol & TOL_2D); - if (!dedicated) { + // chasecam on in first-person gametypes and 2D + boolean chase = (!(gametyperules & GTR_FIRSTPERSON)) || (maptol & TOL_2D); + // Salt: CV_ClearChangedFlags() messes with your settings :( /*if (!cv_cam_speed.changed) CV_Set(&cv_cam_speed, cv_cam_speed.defaultvalue);*/ @@ -2570,48 +2856,7 @@ boolean P_SetupLevel(boolean skipprecip) ranspecialwipe = 2; else if (rendermode != render_none && G_IsSpecialStage(gamemap)) { - tic_t starttime = I_GetTime(); - tic_t endtime = starttime + (3*TICRATE)/2; - tic_t nowtime; - - S_StartSound(NULL, sfx_s3kaf); - - // Fade music! Time it to S3KAF: 0.25 seconds is snappy. - if (RESETMUSIC || - strnicmp(S_MusicName(), - (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7)) - S_FadeOutStopMusic(MUSICRATE/4); //FixedMul(FixedDiv(F_GetWipeLength(wipedefs[wipe_speclevel_towhite])*NEWTICRATERATIO, NEWTICRATE), MUSICRATE) - - F_WipeStartScreen(); - wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE); - -#ifdef HWRENDER - // uh.......... - if (rendermode == render_opengl) - F_WipeColorFill(0); -#endif - - F_WipeEndScreen(); - F_RunWipe(wipedefs[wipe_speclevel_towhite], false); - - I_OsPolling(); - I_FinishUpdate(); // page flip or blit buffer - if (moviemode) - M_SaveFrame(); - - nowtime = lastwipetic; - - // Hold on white for extra effect. - while (nowtime < endtime) - { - // wait loop - while (!((nowtime = I_GetTime()) - lastwipetic)) - I_Sleep(); - lastwipetic = nowtime; - if (moviemode) // make sure we save frames for the white hold too - M_SaveFrame(); - } - + P_RunSpecialStageWipe(); ranspecialwipe = 1; } @@ -2637,25 +2882,7 @@ boolean P_SetupLevel(boolean skipprecip) // Let's fade to black here // But only if we didn't do the special stage wipe if (rendermode != render_none && !ranspecialwipe) - { - F_WipeStartScreen(); - wipestyleflags |= WSF_FADEOUT; - -#ifdef HWRENDER - // uh.......... - if (rendermode == render_opengl) - F_WipeColorFill(31); -#endif - - F_WipeEndScreen(); - // for titlemap: run a specific wipe if specified - // needed for exiting time attack - if (wipetypepre != INT16_MAX) - F_RunWipe( - (wipetypepre >= 0 && F_WipeExists(wipetypepre)) ? wipetypepre : wipedefs[wipe_level_toblack], - false); - wipetypepre = -1; - } + P_RunLevelWipe(); if (!titlemapinaction) { @@ -2713,14 +2940,7 @@ boolean P_SetupLevel(boolean skipprecip) P_InitThinkers(); P_InitCachedActions(); - /// \note for not spawning precipitation, etc. when loading netgame snapshots - if (skipprecip) - { - fromnetsave = 1; - loadprecip = 0; - loademblems = 0; - } - else if (savedata.lives > 0) + if (!fromnetsave && savedata.lives > 0) { numgameovers = savedata.numgameovers; players[consoleplayer].continues = savedata.continues; @@ -2734,9 +2954,7 @@ boolean P_SetupLevel(boolean skipprecip) // internal game map maplumpname = G_BuildMapName(gamemap); - //lastloadedmaplumpnum = LUMPERROR; lastloadedmaplumpnum = W_CheckNumForName(maplumpname); - if (lastloadedmaplumpnum == INT16_MAX) I_Error("Map %s not found.\n", maplumpname); @@ -2746,38 +2964,12 @@ boolean P_SetupLevel(boolean skipprecip) // SRB2 determines the sky texture to be used depending on the map header. P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); - numdmstarts = numredctfstarts = numbluectfstarts = 0; - - // reset the player starts - for (i = 0; i < MAXPLAYERS; i++) - playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL; - - for (i = 0; i < MAX_DM_STARTS; i++) - deathmatchstarts[i] = NULL; - - for (i = 0; i < 2; i++) - skyboxmo[i] = NULL; - - for (i = 0; i < 16; i++) - skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; + P_ResetSpawnpoints(); P_MapStart(); if (lastloadedmaplumpnum) - { - virtres_t* virt = vres_GetMap(lastloadedmaplumpnum); - - P_LoadMapData(virt); - P_LoadMapBSP(virt); - P_LoadMapLUT(virt); - - P_LoadLineDefs2(); - P_GroupLines(); - - P_MakeMapMD5(virt, &mapmd5); - - vres_Free(virt); - } + P_LoadMapFromFile(); // init gravity, tag lists, // anything that P_ResetDynamicSlopes/P_LoadThings needs to know @@ -2787,7 +2979,7 @@ boolean P_SetupLevel(boolean skipprecip) P_ResetDynamicSlopes(fromnetsave); #endif - P_LoadThings(loademblems); + P_SpawnMapThings(!fromnetsave); skyboxmo[0] = skyboxviewpnts[0]; skyboxmo[1] = skyboxcenterpnts[0]; @@ -2798,7 +2990,7 @@ boolean P_SetupLevel(boolean skipprecip) // set up world state P_SpawnSpecials(fromnetsave); - if (loadprecip) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame) + if (!fromnetsave) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame) P_SpawnPrecipitation(); #ifdef HWRENDER // not win32 only 19990829 by Kin @@ -2826,161 +3018,10 @@ boolean P_SetupLevel(boolean skipprecip) // none of this needs to be done because it's not the beginning of the map when // a netgame save is being loaded, and could actively be harmful by messing with // the client's view of the data.) - if (fromnetsave) - goto netgameskip; - // ========== + if (!fromnetsave) + P_InitGametype(); - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - { - // Start players with pity shields if possible - players[i].pity = -1; - - if (!G_PlatformGametype()) - { - players[i].mo = NULL; - G_DoReborn(i); - } - else // gametype is GT_COOP or GT_RACE - { - players[i].mo = NULL; - - if (players[i].starposttime) - { - G_SpawnPlayer(i, true); - P_ClearStarPost(players[i].starpostnum); - } - else - G_SpawnPlayer(i, false); - } - } - - // restore time in netgame (see also g_game.c) - if ((netgame || multiplayer) && gametype == GT_COOP && cv_coopstarposts.value == 2) - { - // is this a hack? maybe - tic_t maxstarposttime = 0; - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && players[i].starposttime > maxstarposttime) - maxstarposttime = players[i].starposttime; - } - leveltime = maxstarposttime; - } - - if (unlockables[27].unlocked && !modeattacking // pandora's box -#ifndef DEVELOP - && !modifiedgame -#endif - && !(netgame || multiplayer) && gamemap == 0x1d35-016464) - { - P_SpawnMobj(0640370000, 0x11000000, 0x3180000, MT_LETTER)->angle = ANGLE_90; - if (textprompts[199]->page[1].backcolor != 259) - { - char *buf = W_CacheLumpName("WATERMAP", PU_STATIC), *b = buf; - while ((*b != 65) && (b-buf < 256)) { *b = (*b - 65)&255; b++; } *b = '\0'; - Z_Free(textprompts[199]->page[1].text); - textprompts[199]->page[1].text = Z_StrDup(buf); - textprompts[199]->page[1].lines = 4; - textprompts[199]->page[1].backcolor = 259; - Z_Free(buf); - } - } - - if (modeattacking == ATTACKING_RECORD && !demoplayback) - P_LoadRecordGhosts(); - else if (modeattacking == ATTACKING_NIGHTS && !demoplayback) - P_LoadNightsGhosts(); - - if (G_TagGametype()) - { - INT32 realnumplayers = 0; - INT32 playersactive[MAXPLAYERS]; - - //I just realized how problematic this code can be. - //D_NumPlayers() will not always cover the scope of the netgame. - //What if one player is node 0 and the other node 31? - //The solution? Make a temp array of all players that are currently playing and pick from them. - //Future todo? When a player leaves, shift all nodes down so D_NumPlayers() can be used as intended? - //Also, you'd never have to loop through all 32 players slots to find anything ever again. - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].spectator) - { - playersactive[realnumplayers] = i; //stores the player's node in the array. - realnumplayers++; - } - } - - if (realnumplayers) //this should also fix the dedicated crash bug. You only pick a player if one exists to be picked. - { - i = P_RandomKey(realnumplayers); - players[playersactive[i]].pflags |= PF_TAGIT; //choose our initial tagger before map starts. - - // Taken and modified from G_DoReborn() - // Remove the player so he can respawn elsewhere. - // first dissasociate the corpse - if (players[playersactive[i]].mo) - P_RemoveMobj(players[playersactive[i]].mo); - - G_SpawnPlayer(playersactive[i], false); //respawn the lucky player in his dedicated spawn location. - } - else - CONS_Printf(M_GetText("No player currently available to become IT. Awaiting available players.\n")); - - } - else if (gametype == GT_RACE && server) - CV_StealthSetValue(&cv_numlaps, - (cv_basenumlaps.value) - ? cv_basenumlaps.value - : mapheaderinfo[gamemap - 1]->numlaps); - - // =========== - // landing point for netgames. - netgameskip: - - if (!dedicated) - { - P_SetupCamera(); - - // Salt: CV_ClearChangedFlags() messes with your settings :( - /*if (!cv_cam_height.changed) - CV_Set(&cv_cam_height, cv_cam_height.defaultvalue); - if (!cv_cam2_height.changed) - CV_Set(&cv_cam2_height, cv_cam2_height.defaultvalue); - - if (!cv_cam_dist.changed) - CV_Set(&cv_cam_dist, cv_cam_dist.defaultvalue); - if (!cv_cam2_dist.changed) - CV_Set(&cv_cam2_dist, cv_cam2_dist.defaultvalue);*/ - - // Though, I don't think anyone would care about cam_rotate being reset back to the only value that makes sense :P - if (!cv_cam_rotate.changed) - CV_Set(&cv_cam_rotate, cv_cam_rotate.defaultvalue); - if (!cv_cam2_rotate.changed) - CV_Set(&cv_cam2_rotate, cv_cam2_rotate.defaultvalue); - - if (!cv_analog.changed) - CV_SetValue(&cv_analog, 0); - if (!cv_analog2.changed) - CV_SetValue(&cv_analog2, 0); - - displayplayer = consoleplayer; // Start with your OWN view, please! - } - - if (cv_useranalog.value) - CV_SetValue(&cv_analog, true); - - if (splitscreen && cv_useranalog2.value) - CV_SetValue(&cv_analog2, true); - else if (botingame) - CV_SetValue(&cv_analog2, true); - - if (twodlevel) - { - CV_SetValue(&cv_analog2, false); - CV_SetValue(&cv_analog, false); - } + P_InitCamera(); // clear special respawning que iquehead = iquetail = 0; @@ -3015,7 +3056,7 @@ boolean P_SetupLevel(boolean skipprecip) lastmaploaded = gamemap; // HAS to be set after saving!! - if (loadprecip) // uglier hack + if (!fromnetsave) // uglier hack { // to make a newly loaded level start on the second frame. INT32 buf = gametic % BACKUPTICS; for (i = 0; i < MAXPLAYERS; i++) diff --git a/src/p_setup.h b/src/p_setup.h index c95dd0f63..de791677c 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -97,7 +97,7 @@ void P_SetupLevelSky(INT32 skynum, boolean global); void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); #endif void P_LoadThingsOnly(void); -boolean P_SetupLevel(boolean skipprecip); +boolean P_LoadLevel(boolean fromnetsave); boolean P_AddWadFile(const char *wadfilename); boolean P_RunSOC(const char *socfilename); void P_LoadSoundsRange(UINT16 wadnum, UINT16 first, UINT16 num); diff --git a/src/p_slopes.c b/src/p_slopes.c index 89d265fa4..f35e7d732 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -553,11 +553,8 @@ pslope_t *P_SlopeById(UINT16 id) } /// Reset slopes and read them from special lines. -void P_ResetDynamicSlopes(const UINT32 fromsave) { +void P_ResetDynamicSlopes(const boolean fromsave) { size_t i; - - boolean spawnthinkers = !(boolean)fromsave; - slopelist = NULL; slopecount = 0; @@ -574,14 +571,14 @@ void P_ResetDynamicSlopes(const UINT32 fromsave) { case 711: case 712: case 713: - line_SpawnViaLine(i, spawnthinkers); + line_SpawnViaLine(i, !fromsave); break; case 704: case 705: case 714: case 715: - line_SpawnViaVertexes(i, spawnthinkers); + line_SpawnViaVertexes(i, !fromsave); break; default: diff --git a/src/p_slopes.h b/src/p_slopes.h index 076fd8796..96764051b 100644 --- a/src/p_slopes.h +++ b/src/p_slopes.h @@ -23,7 +23,7 @@ extern UINT16 slopecount; void P_LinkSlopeThinkers (void); void P_CalculateSlopeNormal(pslope_t *slope); -void P_ResetDynamicSlopes(const UINT32 fromsave); +void P_ResetDynamicSlopes(const boolean fromsave); // // P_CopySectorSlope diff --git a/src/p_spec.c b/src/p_spec.c index 0b0ba940d..20f1c8278 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -6426,7 +6426,7 @@ static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flata * as they'll just be erased by UnArchiveThinkers. * \sa P_SpawnPrecipitation, P_SpawnFriction, P_SpawnPushers, P_SpawnScrollers */ -void P_SpawnSpecials(INT32 fromnetsave) +void P_SpawnSpecials(boolean fromnetsave) { sector_t *sector; size_t i; diff --git a/src/p_spec.h b/src/p_spec.h index 14d3ebb59..630bcb3de 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -35,7 +35,7 @@ void P_SetupLevelFlatAnims(void); // at map load void P_InitSpecials(void); -void P_SpawnSpecials(INT32 fromnetsave); +void P_SpawnSpecials(boolean fromnetsave); // every tic void P_UpdateSpecials(void);