diff --git a/src/d_clisrv.c b/src/d_clisrv.c index b1a128b9d12b7abfb7f7aa2d46ac1a398b2bfd9b..e92341a664ee2cf250e5ecd9800db4e768eda01d 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2041,7 +2041,7 @@ static boolean SV_SendServerConfig(INT32 node) } #ifndef NONET -#define SAVEGAMESIZE (768*1024) +#define SAVEGAMESIZE (2048*1024) //(768*1024) static void SV_SendSaveGame(INT32 node) { @@ -3037,6 +3037,9 @@ static void CL_RemovePlayer(INT32 playernum, kickreason_t reason) } } + if (players[playernum].world) + ((world_t *)players[playernum].world)->players--; + if (gametyperules & GTR_TEAMFLAGS) P_PlayerFlagBurst(&players[playernum], false); // Don't take the flag with you! @@ -3903,8 +3906,6 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) D_SendPlayerConfig(); addedtogame = true; - P_SwitchPlayerWorld(newplayer, world); - if (rejoined) { if (newplayer->mo) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 936e57bc8d7393e5e26c087951e8b5283640ad1b..1490784e171d2f42c3f9e772c5a702cad962168d 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -62,6 +62,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum); static void Got_WeaponPref(UINT8 **cp, INT32 playernum); static void Got_Mapcmd(UINT8 **cp, INT32 playernum); static void Got_ExitLevelcmd(UINT8 **cp, INT32 playernum); +static void Got_Switchworld(UINT8 **cp, INT32 playernum); static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum); static void Got_Addfilecmd(UINT8 **cp, INT32 playernum); static void Got_Pause(UINT8 **cp, INT32 playernum); @@ -406,7 +407,7 @@ const char *netxcmdnames[MAXNETXCMD - 1] = "ADDPLAYER", "TEAMCHANGE", "CLEARSCORES", - "LOGIN", + "SWITCHWORLD", "VERIFIED", "RANDOMSEED", "RUNSOC", @@ -444,6 +445,7 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_WEAPONPREF, Got_WeaponPref); RegisterNetXCmd(XD_MAP, Got_Mapcmd); RegisterNetXCmd(XD_EXITLEVEL, Got_ExitLevelcmd); + RegisterNetXCmd(XD_SWITCHWORLD, Got_Switchworld); RegisterNetXCmd(XD_ADDFILE, Got_Addfilecmd); RegisterNetXCmd(XD_REQADDFILE, Got_RequestAddfilecmd); RegisterNetXCmd(XD_PAUSE, Got_Pause); @@ -1783,9 +1785,10 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean addworld, boolean pult else { mapchangepending = false; + // spawn the server if needed // reset players if there is a new one - if (!IsPlayerAdmin(consoleplayer)) + if (!IsPlayerAdmin(consoleplayer) && !addworld) { if (SV_SpawnServer()) buf[0] &= ~(1<<1); @@ -1848,7 +1851,6 @@ static void Command_Map_f(void) size_t option_gametype; const char *gametypename; boolean newresetplayers; - boolean addworld; boolean mustmodifygame; @@ -1861,7 +1863,9 @@ static void Command_Map_f(void) INT32 d; - if (client && !IsPlayerAdmin(consoleplayer)) + boolean addworld = COM_CheckParm("-addworld"); + + if (client && !addworld && !IsPlayerAdmin(consoleplayer)) { CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n")); return; @@ -1870,7 +1874,6 @@ static void Command_Map_f(void) option_force = COM_CheckPartialParm("-f"); option_gametype = COM_CheckPartialParm("-g"); newresetplayers = ! COM_CheckParm("-noresetplayers"); - addworld = COM_CheckParm("-addworld"); mustmodifygame = !( netgame || multiplayer ) && @@ -2094,7 +2097,8 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) { DEBFILE(va("Warping to %s [resetplayer=%d lastgametype=%d gametype=%d cpnd=%d]\n", mapname, resetplayer, lastgametype, gametype, chmappending)); - CONS_Printf(M_GetText("Speeding off to level...\n")); + if (!addworld || (addworld && playernum == consoleplayer)) + CONS_Printf(M_GetText("Speeding off to level...\n")); } if (demoplayback && !timingdemo) @@ -2129,6 +2133,44 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) demo_start = true; } +void SendWorldSwitch(INT32 worldnum, boolean nodetach) +{ + UINT8 buf[sizeof(INT32) + sizeof(UINT8)]; + UINT8 *p = buf; + + WRITEINT32(p, worldnum); + WRITEUINT8(p, nodetach ? 1 : 0); + + SendNetXCmd(XD_SWITCHWORLD, buf, sizeof(buf)); +} + +static void Got_Switchworld(UINT8 **cp, INT32 playernum) +{ + player_t *player = &players[playernum]; + + INT32 worldnum = READINT32(*cp); + UINT8 nodetach = READUINT8(*cp); + + if (worldnum > numworlds) + { + CONS_Alert(CONS_WARNING, M_GetText("Illegal world switch command received from %s\n"), player_names[playernum]); + if (server) + SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY); + return; + } + + if (nodetach) // Don't detach from the current world, if any + { +#if 1 + if (player->world) + ((world_t *)player->world)->players--; +#endif + player->world = NULL; + } + + P_SwitchWorld(player, worldlist[worldnum]); +} + static void Command_Pause(void) { UINT8 buf[2]; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index a7de0237676a67d57b92b07d82a94a839776b099..674c59d7898d3c56026041f88a05428906e67d00 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -133,8 +133,8 @@ typedef enum XD_ADDPLAYER, // 10 XD_TEAMCHANGE, // 11 XD_CLEARSCORES, // 12 - // UNUSED 13 (Because I don't want to change these comments) - XD_VERIFIED = 14,//14 + XD_SWITCHWORLD, // 13 + XD_VERIFIED, // 14 XD_RANDOMSEED, // 15 XD_RUNSOC, // 16 XD_REQADDFILE, // 17 @@ -206,6 +206,7 @@ void ClearAdminPlayers(void); void RemoveAdminPlayer(INT32 playernum); void ItemFinder_OnChange(void); void D_SetPassword(const char *pw); +void SendWorldSwitch(INT32 worldnum, boolean nodetach); // used for the player setup menu UINT8 CanChangeSkin(INT32 playernum); diff --git a/src/d_player.h b/src/d_player.h index 9ea4d5970c4c2a9e883336a5019b500c37aae8b0..86a375fe91ae08aca88d99115286dc30cc03310f 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -323,6 +323,7 @@ typedef struct player_s playerstate_t playerstate; void *world; + INT32 worldnum; // Lactozilla: for unarchiving purposes only, just like mobjnum // Determine POV, including viewpoint bobbing during movement. fixed_t camerascale; diff --git a/src/doomdef.h b/src/doomdef.h index 6cfaba8a1148d073908734dddcd8f45feb4e2ad9..c46e458e122c61fab3b075b82d9d07301548aa95 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -392,6 +392,10 @@ extern skincolor_t skincolors[MAXSKINCOLORS]; #define PUSHACCEL (2*FRACUNIT) // Acceleration for MF2_SLIDEPUSH items. +// Time interval for item respawning. +// WARNING MUST be a power of 2 +#define ITEMQUESIZE 1024 + // Special linedef executor tag numbers! enum { LE_PINCHPHASE = -2, // A boss entered pinch phase (and, in most cases, is preparing their pinch phase attack!) diff --git a/src/doomstat.h b/src/doomstat.h index d48978042283caef1f8a2c20d20ff10905dffc74..aef9541221799f62f9d49c0ee3f030748efabeae 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -40,7 +40,6 @@ extern UINT32 mapmusposition; // Use other bits if necessary. extern UINT32 maptol; -extern UINT8 globalweather; extern INT32 curWeather; extern INT32 cursaveslot; //extern INT16 lastmapsaved; diff --git a/src/f_finale.c b/src/f_finale.c index 50cd5e8d19fd329293663946912874cdf8ae2b1c..477c6373c5470c5cf19ed482770f17fbeac8bc67 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2541,7 +2541,6 @@ void F_StartTitleScreen(void) P_UnloadWorldList(); maptol = mapheaderinfo[gamemap-1]->typeoflevel; - globalweather = mapheaderinfo[gamemap-1]->weather; G_DoLoadLevel(&players[displayplayer], false, true); if (!titlemap) diff --git a/src/g_game.c b/src/g_game.c index 1238e5aa2610546913515ed6375546e8c39b6356..405df674e4f2f4e5d77a3a70eedabddf535252e1 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -51,6 +51,7 @@ gameaction_t gameaction; gamestate_t gamestate = GS_NULL; UINT8 ultimatemode = false; +boolean roaming = false; boolean botingame; UINT8 botskin; @@ -77,7 +78,6 @@ UINT32 mapmusposition; // Position to jump to INT16 gamemap = 1; UINT32 maptol; -UINT8 globalweather = 0; INT32 curWeather = PRECIP_NONE; INT32 cursaveslot = 0; // Auto-save 1p savegame slot //INT16 lastmapsaved = 0; // Last map we auto-saved at @@ -1779,6 +1779,14 @@ static void AutoBrake2_OnChange(void) SendWeaponPref2(); } +static void G_ResetCamera(INT32 playernum) +{ + if (playernum == consoleplayer && camera.chase) + P_ResetCamera(&players[displayplayer], &camera); + if (playernum == 1 && camera2.chase && splitscreen) + P_ResetCamera(&players[secondarydisplayplayer], &camera2); +} + // // G_DoLoadLevel // @@ -1849,13 +1857,8 @@ void G_DoLoadLevel(player_t *player, boolean addworld, boolean resetplayer) Z_CheckHeap(-2); #endif - if (player == &players[consoleplayer]) + if (!addworld) { - if (camera.chase) - P_ResetCamera(&players[displayplayer], &camera); - if (camera2.chase && splitscreen) - P_ResetCamera(&players[secondarydisplayplayer], &camera2); - // clear cmd building stuff memset(gamekeydown, 0, sizeof (gamekeydown)); for (i = 0;i < JOYAXISSET; i++) @@ -1866,6 +1869,14 @@ void G_DoLoadLevel(player_t *player, boolean addworld, boolean resetplayer) mousex = mousey = 0; mouse2x = mouse2y = 0; + if (splitscreen) + G_ResetCamera(1); + } + + if (player == &players[consoleplayer]) + { + G_ResetCamera(consoleplayer); + // clear hud messages remains (usually from game startup) CON_ClearHUD(); } @@ -2365,7 +2376,7 @@ void G_Ticker(boolean run) // G_PlayerFinishLevel // Called when a player completes a level. // -static inline void G_PlayerFinishLevel(INT32 player) +void G_PlayerFinishLevel(INT32 player) { player_t *p; @@ -2707,9 +2718,6 @@ void G_MovePlayerToSpawnOrStarpost(INT32 playernum) P_MovePlayerToStarpost(playernum); else P_MovePlayerToSpawn(playernum, G_FindMapStart(playernum)); - - if (players[playernum].world) - P_MarkWorldVisited(&players[playernum], players[playernum].world); } mapthing_t *G_FindCTFStart(INT32 playernum) @@ -3150,9 +3158,8 @@ void G_AddPlayer(INT32 playernum) } } - p->world = world; - if (p->world) - ((world_t *)p->world)->players++; + if (worldlist) // Assume the player is on the first world + p->world = worldlist[0]; p->playerstate = PST_REBORN; @@ -3779,34 +3786,9 @@ static void G_HandleSaveLevel(void) G_SaveGame((UINT32)cursaveslot, lastmap+1); // not nextmap+1 to route around special stages } -// -// G_DoCompleted -// -static void G_DoCompleted(void) +void G_SetNextMap(boolean usespec, boolean inspec) { INT32 i; - boolean spec = G_IsSpecialStage(gamemap); - - tokenlist = 0; // Reset the list - - if (modeattacking && pausedelay) - pausedelay = 0; - - gameaction = ga_nothing; - - if (metalplayback) - G_StopMetalDemo(); - if (metalrecording) - G_StopMetalRecording(false); - - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - G_PlayerFinishLevel(i); // take away cards and stuff - - if (automapactive) - AM_Stop(); - - S_StopSounds(); prevmap = (INT16)(gamemap-1); @@ -3827,7 +3809,7 @@ static void G_DoCompleted(void) // a map of the proper gametype -- skip levels that don't support // the current gametype. (Helps avoid playing boss levels in Race, // for instance). - if (!spec) + if (!inspec) { if (nextmap >= 0 && nextmap < NUMMAPS) { @@ -3882,7 +3864,7 @@ static void G_DoCompleted(void) lastmap = nextmap; // Remember last map for when you come out of the special stage. } - if ((gottoken = ((gametyperules & GTR_SPECIALSTAGES) && token))) + if ((gottoken = (usespec && token))) { token--; @@ -3900,8 +3882,39 @@ static void G_DoCompleted(void) } } - if (spec && !gottoken) + if (inspec && !gottoken) nextmap = lastmap; // Exiting from a special stage? Go back to the game. Tails 08-11-2001 +} + +// +// G_DoCompleted +// +static void G_DoCompleted(void) +{ + INT32 i; + boolean spec = G_IsSpecialStage(gamemap); + + tokenlist = 0; // Reset the list + + if (modeattacking && pausedelay) + pausedelay = 0; + + gameaction = ga_nothing; + + if (metalplayback) + G_StopMetalDemo(); + if (metalrecording) + G_StopMetalRecording(false); + + for (i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + G_PlayerFinishLevel(i); // take away cards and stuff + + if (automapactive) + AM_Stop(); + + S_StopSounds(); + G_SetNextMap(gametyperules & GTR_SPECIALSTAGES, spec); automapactive = false; @@ -4755,6 +4768,7 @@ void G_InitNew(player_t *player, if (addworld) { P_DetachPlayerWorld(player); + P_UnloadWorldPlayer(player); G_ResetPlayer(player, pultmode, FLS); } else @@ -4789,7 +4803,6 @@ void G_InitNew(player_t *player, P_AllocMapHeader(gamemap-1); maptol = mapheaderinfo[gamemap-1]->typeoflevel; - globalweather = mapheaderinfo[gamemap-1]->weather; // Don't carry over custom music change to another map. mapmusflags |= MUSIC_RELOADRESET; diff --git a/src/g_game.h b/src/g_game.h index 3b47593c375ea4317325cbd7c3b8994921f1e708..f77630c4014cb0481a3600d8b5141a7032d576e2 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -198,6 +198,8 @@ boolean G_CompetitionGametype(void); boolean G_EnoughPlayersFinished(void); void G_ExitLevel(void); void G_NextLevel(void); +void G_SetNextMap(boolean usespec, boolean inspec); +void G_PlayerFinishLevel(INT32 player); void G_Continue(void); void G_UseContinue(void); void G_AfterIntermission(void); diff --git a/src/g_state.h b/src/g_state.h index e364c5a35b62c323464783d518bf266b2abe4185..6fb2bd872c88cf00e8592a590e1b9a4f7ccc247b 100644 --- a/src/g_state.h +++ b/src/g_state.h @@ -54,6 +54,7 @@ typedef enum extern gamestate_t gamestate; extern UINT8 titlemapinaction; extern UINT8 ultimatemode; // was sk_insane +extern boolean roaming; extern gameaction_t gameaction; extern boolean botingame; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index c4937a54d2e9b086d6e2d13cb02b21a43af9d6a1..ffa676e329e525119e0089f63332b3e02481ebff 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5061,8 +5061,8 @@ static void HWR_DrawSkyBackground(player_t *player) } dometransform.splitscreen = splitscreen; - HWR_GetTexture(texturetranslation[viewworld->skytexture]); - HWD.pfnRenderSkyDome(viewworld->skytexture, textures[viewworld->skytexture]->width, textures[viewworld->skytexture]->height, dometransform); + HWR_GetTexture(texturetranslation[skytexture]); + HWD.pfnRenderSkyDome(skytexture, textures[skytexture]->width, textures[skytexture]->height, dometransform); } else { @@ -5072,7 +5072,7 @@ static void HWR_DrawSkyBackground(player_t *player) float aspectratio; float angleturn; - HWR_GetTexture(texturetranslation[viewworld->skytexture]); + HWR_GetTexture(texturetranslation[skytexture]); aspectratio = (float)vid.width/(float)vid.height; //Hurdler: the sky is the only texture who need 4.0f instead of 1.0 @@ -5099,7 +5099,7 @@ static void HWR_DrawSkyBackground(player_t *player) angle = (dup_viewangle + gr_xtoviewangle[0]); - dimensionmultiply = ((float)textures[texturetranslation[viewworld->skytexture]]->width/256.0f); + dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->width/256.0f); v[0].s = v[3].s = (-1.0f * angle) / ((ANGLE_90-1)*dimensionmultiply); // left v[2].s = v[1].s = v[0].s + (1.0f/dimensionmultiply); // right (or left + 1.0f) @@ -5107,7 +5107,7 @@ static void HWR_DrawSkyBackground(player_t *player) // Y angle = aimingangle; - dimensionmultiply = ((float)textures[texturetranslation[viewworld->skytexture]]->height/(128.0f*aspectratio)); + dimensionmultiply = ((float)textures[texturetranslation[skytexture]]->height/(128.0f*aspectratio)); if (splitscreen) { diff --git a/src/lua_baselib.c b/src/lua_baselib.c index b1187f5437762f7ecf51e8ea1bcaed39444303f3..b537d47da4eecdc1f62e5469be7882445dfc10ae 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -2000,7 +2000,7 @@ static int lib_pSwitchWeather(lua_State *L) if (!lua_isnone(L, 2) && lua_isuserdata(L, 2)) // if a player, setup weather for only the player, otherwise setup weather for all players user = *((player_t **)luaL_checkudata(L, 2, META_PLAYER)); if (!user) // global - globalweather = weathernum; + world->weather = weathernum; if (!user || P_IsLocalPlayer(user)) P_SwitchWeather(weathernum); return 0; diff --git a/src/lua_script.c b/src/lua_script.c index ecd369e91290c43026429b6ab62e3e7975f57543..0fe26b1bee192ed4116083499a039d7b065d68fe 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -293,13 +293,13 @@ int LUA_PushGlobals(lua_State *L, const char *word) lua_pushinteger(L, curWeather); return 1; } else if (fastcmp(word,"globalweather")) { - lua_pushinteger(L, globalweather); + lua_pushinteger(L, (localworld ? localworld->weather : PRECIP_NONE)); return 1; } else if (fastcmp(word,"levelskynum")) { lua_pushinteger(L, levelskynum); return 1; } else if (fastcmp(word,"globallevelskynum")) { - lua_pushinteger(L, globallevelskynum); + lua_pushinteger(L, (localworld ? localworld->skynum : 0)); return 1; } else if (fastcmp(word,"mapmusname")) { lua_pushstring(L, mapmusname); @@ -1338,40 +1338,40 @@ static UINT8 UnArchiveValue(int TABLESINDEX) LUA_PushUserdata(gL, &states[READUINT16(save_p)], META_STATE); break; case ARCH_MOBJ: - LUA_PushUserdata(gL, P_FindNewPosition(READUINT32(save_p)), META_MOBJ); + LUA_PushUserdata(gL, P_FindNewPosition(archiveworld, READUINT32(save_p)), META_MOBJ); break; case ARCH_PLAYER: LUA_PushUserdata(gL, &players[READUINT8(save_p)], META_PLAYER); break; case ARCH_MAPTHING: - LUA_PushUserdata(gL, &mapthings[READUINT16(save_p)], META_MAPTHING); + LUA_PushUserdata(gL, &archiveworld->mapthings[READUINT16(save_p)], META_MAPTHING); break; case ARCH_VERTEX: - LUA_PushUserdata(gL, &vertexes[READUINT16(save_p)], META_VERTEX); + LUA_PushUserdata(gL, &archiveworld->vertexes[READUINT16(save_p)], META_VERTEX); break; case ARCH_LINE: - LUA_PushUserdata(gL, &lines[READUINT16(save_p)], META_LINE); + LUA_PushUserdata(gL, &archiveworld->lines[READUINT16(save_p)], META_LINE); break; case ARCH_SIDE: - LUA_PushUserdata(gL, &sides[READUINT16(save_p)], META_SIDE); + LUA_PushUserdata(gL, &archiveworld->sides[READUINT16(save_p)], META_SIDE); break; case ARCH_SUBSECTOR: - LUA_PushUserdata(gL, &subsectors[READUINT16(save_p)], META_SUBSECTOR); + LUA_PushUserdata(gL, &archiveworld->subsectors[READUINT16(save_p)], META_SUBSECTOR); break; case ARCH_SECTOR: - LUA_PushUserdata(gL, §ors[READUINT16(save_p)], META_SECTOR); + LUA_PushUserdata(gL, &archiveworld->sectors[READUINT16(save_p)], META_SECTOR); break; #ifdef HAVE_LUA_SEGS case ARCH_SEG: - LUA_PushUserdata(gL, &segs[READUINT16(save_p)], META_SEG); + LUA_PushUserdata(gL, &archiveworld->segs[READUINT16(save_p)], META_SEG); break; case ARCH_NODE: - LUA_PushUserdata(gL, &nodes[READUINT16(save_p)], META_NODE); + LUA_PushUserdata(gL, &archiveworld->nodes[READUINT16(save_p)], META_NODE); break; #endif case ARCH_FFLOOR: { - sector_t *sector = §ors[READUINT16(save_p)]; + sector_t *sector = &archiveworld->sectors[READUINT16(save_p)]; UINT16 id = READUINT16(save_p); ffloor_t *rover = P_GetFFloorByID(sector, id); if (rover) diff --git a/src/p_enemy.c b/src/p_enemy.c index bb4e8eca97e854a5f318882a84769ead4aba2edf..6ec021ef08a45e29d31f59c555452650c26b3d65 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -749,6 +749,9 @@ boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed if (player->quittime) continue; // Ignore uncontrolled bodies + if (player->world != actor->world) + continue; // Different world + if (dist > 0 && P_AproxDistance(P_AproxDistance(player->mo->x - actor->x, player->mo->y - actor->y), player->mo->z - actor->z) > dist) continue; // Too far away diff --git a/src/p_local.h b/src/p_local.h index ce60cc66b5121ab8069d2c28a5a6211afef68d32..1f053800f0b98499ea9d5f83e643dc4995c3c58a 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -266,13 +266,6 @@ void P_PlayJingleMusic(player_t *player, const char *musname, UINT16 musflags, b #define ONFLOORZ INT32_MIN #define ONCEILINGZ INT32_MAX -// Time interval for item respawning. -// WARNING MUST be a power of 2 -#define ITEMQUESIZE 1024 - -extern mapthing_t *itemrespawnque[ITEMQUESIZE]; -extern tic_t itemrespawntime[ITEMQUESIZE]; -extern size_t iquehead, iquetail; extern consvar_t cv_gravity, cv_movebob; void P_RespawnSpecials(void); @@ -280,7 +273,7 @@ void P_RespawnSpecials(void); mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type); void P_RecalcPrecipInSector(sector_t *sector); -void P_PrecipitationEffects(void); +void P_PrecipitationEffects(world_t *w); void P_RemoveMobj(mobj_t *th); boolean P_MobjWasRemoved(mobj_t *th); diff --git a/src/p_mobj.c b/src/p_mobj.c index c6d65510bb6690b0737e4499fb372d21f7a81380..f9467708244b2d3d1388c9c126327c4ed01c5410 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4205,6 +4205,9 @@ boolean P_SupermanLook4Players(mobj_t *actor) if (players[c].mo->health <= 0) continue; // dead + if (players[c].world != actor->world) + continue; // Different world + playersinthegame[stop] = &players[c]; stop++; } @@ -10028,13 +10031,13 @@ void P_MobjThinker(mobj_t *mobj) return; // Remove dead target/tracer. - if (mobj->target && P_MobjWasRemoved(mobj->target)) + if (!P_MobjIsConnected(mobj, mobj->target)) P_SetTarget(&mobj->target, NULL); - if (mobj->tracer && P_MobjWasRemoved(mobj->tracer)) + if (!P_MobjIsConnected(mobj, mobj->tracer)) P_SetTarget(&mobj->tracer, NULL); - if (mobj->hnext && P_MobjWasRemoved(mobj->hnext)) + if (!P_MobjIsConnected(mobj, mobj->hnext)) P_SetTarget(&mobj->hnext, NULL); - if (mobj->hprev && P_MobjWasRemoved(mobj->hprev)) + if (!P_MobjIsConnected(mobj, mobj->hprev)) P_SetTarget(&mobj->hprev, NULL); mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG); @@ -10906,9 +10909,6 @@ static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mob // // P_RemoveMobj // -mapthing_t *itemrespawnque[ITEMQUESIZE]; -tic_t itemrespawntime[ITEMQUESIZE]; -size_t iquehead, iquetail; #ifdef PARANOIA #define SCRAMBLE_REMOVED // Force debug build to crash when Removed mobj is accessed @@ -10933,12 +10933,12 @@ void P_RemoveMobj(mobj_t *mobj) || P_WeaponOrPanel(mobj->type)) && !(mobj->flags2 & MF2_DONTRESPAWN)) { - itemrespawnque[iquehead] = mobj->spawnpoint; - itemrespawntime[iquehead] = leveltime; - iquehead = (iquehead+1)&(ITEMQUESIZE-1); + world->itemrespawnque[world->iquehead] = mobj->spawnpoint; + world->itemrespawntime[world->iquehead] = leveltime; + world->iquehead = (world->iquehead+1)&(ITEMQUESIZE-1); // lose one off the end? - if (iquehead == iquetail) - iquetail = (iquetail+1)&(ITEMQUESIZE-1); + if (world->iquehead == world->iquetail) + world->iquetail = (world->iquetail+1)&(ITEMQUESIZE-1); } if (mobj->type == MT_OVERLAY) @@ -11127,7 +11127,7 @@ void P_SpawnPrecipitation(void) // // P_PrecipitationEffects // -void P_PrecipitationEffects(void) +void P_PrecipitationEffects(world_t *w) { INT16 thunderchance = INT16_MAX; INT32 volume; @@ -11144,8 +11144,8 @@ void P_PrecipitationEffects(void) // with global rain and switched players to anything else ... // If the global weather has lightning strikes, // EVERYONE gets them at the SAME time! - else if (globalweather == PRECIP_STORM - || globalweather == PRECIP_STORM_NORAIN) + else if (w->weather == PRECIP_STORM + || w->weather == PRECIP_STORM_NORAIN) thunderchance = (P_RandomKey(8192)); // But on the other hand, if the global weather is ANYTHING ELSE, // don't sync lightning strikes. @@ -11180,8 +11180,8 @@ void P_PrecipitationEffects(void) { sector_t *ss = sectors; - for (i = 0; i < numsectors; i++, ss++) - if (ss->ceilingpic == world->skyflatnum) // Only for the sky. + for (i = 0; i < w->numsectors; i++, ss++) + if (ss->ceilingpic == w->skyflatnum) // Only for the sky. P_SpawnLightningFlash(ss); // Spawn a quick flash thinker } @@ -11193,7 +11193,7 @@ void P_PrecipitationEffects(void) if (sound_disabled) return; // Sound off? D'aw, no fun. - if (players[displayplayer].mo->subsector->sector->ceilingpic == world->skyflatnum) + if (players[displayplayer].mo->subsector->sector->ceilingpic == w->skyflatnum) volume = 255; // Sky above? We get it full blast. else { @@ -11209,7 +11209,7 @@ void P_PrecipitationEffects(void) for (y = yl; y <= yh; y += FRACUNIT*64) for (x = xl; x <= xh; x += FRACUNIT*64) { - if (R_PointInSubsector(x, y)->sector->ceilingpic == world->skyflatnum) // Found the outdoors! + if (R_PointInWorldSubsector(w, x, y)->sector->ceilingpic == w->skyflatnum) // Found the outdoors! { newdist = S_CalculateSoundDistance(players[displayplayer].mo->x, players[displayplayer].mo->y, 0, x, y, 0); if (newdist < closedist) @@ -11277,15 +11277,15 @@ void P_RespawnSpecials(void) return; // nothing left to respawn? - if (iquehead == iquetail) + if (world->iquehead == world->iquetail) return; // the first item in the queue is the first to respawn // wait at least 30 seconds - if (leveltime - itemrespawntime[iquetail] < (tic_t)cv_itemrespawntime.value*TICRATE) + if (leveltime - world->itemrespawntime[world->iquetail] < (tic_t)cv_itemrespawntime.value*TICRATE) return; - mthing = itemrespawnque[iquetail]; + mthing = world->itemrespawnque[world->iquetail]; #ifdef PARANOIA if (!mthing) @@ -11296,7 +11296,7 @@ void P_RespawnSpecials(void) P_SpawnMapThing(mthing); // pull it from the que - iquetail = (iquetail+1)&(ITEMQUESIZE-1); + world->iquetail = (world->iquetail+1)&(ITEMQUESIZE-1); } // diff --git a/src/p_mobj.h b/src/p_mobj.h index 6182d108401d74d6eff59af5ccf9c046de228d69..9e769ce4cc83bec4b5ba741d347e710ef81bd226 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -357,7 +357,9 @@ typedef struct mobj_s fixed_t watertop; // top of the water FOF the mobj is in fixed_t waterbottom; // bottom of the water FOF the mobj is in - UINT32 mobjnum; // A unique number for this mobj. Used for restoring pointers on save games. + // Used for restoring pointers on save games. + UINT32 mobjnum; // A unique number for this mobj. + UINT32 worldnum; // The world number for this mobj. fixed_t scale; fixed_t destscale; diff --git a/src/p_saveg.c b/src/p_saveg.c index ba0730da477d0bfe90248dd7b6ca27e61f5d82b3..9c13a242c65cc7fa4f6806543d1d7ac855bc2804 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -37,11 +37,15 @@ savedata_t savedata; UINT8 *save_p; +world_t *archiveworld; +world_t *unarchiveworld; + // Block UINT32s to attempt to ensure that the correct data is // being sent and received #define ARCHIVEBLOCK_MISC 0x7FEEDEED #define ARCHIVEBLOCK_PLAYERS 0x7F448008 -#define ARCHIVEBLOCK_WORLD 0x7F8C08C0 +#define ARCHIVEBLOCK_MAP 0x7F8C08C0 +#define ARCHIVEBLOCK_WORLD 0x7F9F47A3 #define ARCHIVEBLOCK_POBJS 0x7F928546 #define ARCHIVEBLOCK_THINKERS 0x7F37037C #define ARCHIVEBLOCK_SPECIALS 0x7F228378 @@ -104,6 +108,7 @@ static void P_NetArchivePlayers(void) // no longer send ticcmds, player name, skin, or color + WRITEINT32(save_p, players[i].worldnum); WRITEINT16(save_p, players[i].angleturn); WRITEINT16(save_p, players[i].oldrelangleturn); WRITEANGLE(save_p, players[i].aiming); @@ -314,6 +319,7 @@ static void P_NetUnArchivePlayers(void) // sending player names, skin and color should not be necessary at all! // (that data is handled in the server config now) + players[i].worldnum = READINT32(save_p); players[i].angleturn = READINT16(save_p); players[i].oldrelangleturn = READINT16(save_p); players[i].aiming = READANGLE(save_p); @@ -728,9 +734,9 @@ static void P_NetArchiveWaypoints(void) for (i = 0; i < NUMWAYPOINTSEQUENCES; i++) { - WRITEUINT16(save_p, world->numwaypoints[i]); - for (j = 0; j < world->numwaypoints[i]; j++) - WRITEUINT32(save_p, world->waypoints[i][j] ? world->waypoints[i][j]->mobjnum : 0); + WRITEUINT16(save_p, archiveworld->numwaypoints[i]); + for (j = 0; j < archiveworld->numwaypoints[i]; j++) + WRITEUINT32(save_p, archiveworld->waypoints[i][j] ? archiveworld->waypoints[i][j]->mobjnum : 0); } } @@ -741,11 +747,11 @@ static void P_NetUnArchiveWaypoints(void) for (i = 0; i < NUMWAYPOINTSEQUENCES; i++) { - world->numwaypoints[i] = READUINT16(save_p); - for (j = 0; j < world->numwaypoints[i]; j++) + unarchiveworld->numwaypoints[i] = READUINT16(save_p); + for (j = 0; j < unarchiveworld->numwaypoints[i]; j++) { mobjnum = READUINT32(save_p); - world->waypoints[i][j] = (mobjnum == 0) ? NULL : P_FindNewPosition(mobjnum); + unarchiveworld->waypoints[i][j] = (mobjnum == 0) ? NULL : P_FindNewPosition(unarchiveworld, mobjnum); } } } @@ -885,11 +891,11 @@ static void UnArchiveFFloors(const sector_t *ss) static void ArchiveSectors(void) { size_t i; - const sector_t *ss = sectors; - const sector_t *spawnss = spawnsectors; + const sector_t *ss = archiveworld->sectors; + const sector_t *spawnss = archiveworld->spawnsectors; UINT8 diff, diff2, diff3; - for (i = 0; i < numsectors; i++, ss++, spawnss++) + for (i = 0; i < archiveworld->numsectors; i++, ss++, spawnss++) { diff = diff2 = diff3 = 0; if (ss->floorheight != spawnss->floorheight) @@ -954,9 +960,9 @@ static void ArchiveSectors(void) if (diff & SD_CEILHT) WRITEFIXED(save_p, ss->ceilingheight); if (diff & SD_FLOORPIC) - WRITEMEM(save_p, world->flats[ss->floorpic].name, 8); + WRITEMEM(save_p, archiveworld->flats[ss->floorpic].name, 8); if (diff & SD_CEILPIC) - WRITEMEM(save_p, world->flats[ss->ceilingpic].name, 8); + WRITEMEM(save_p, archiveworld->flats[ss->ceilingpic].name, 8); if (diff & SD_LIGHT) WRITEINT16(save_p, ss->lightlevel); if (diff & SD_SPECIAL) @@ -1005,8 +1011,8 @@ static void UnArchiveSectors(void) if (i == 0xffff) break; - if (i > numsectors) - I_Error("Invalid sector number %u from server (expected end at %s)", i, sizeu1(numsectors)); + if (i > unarchiveworld->numsectors) + I_Error("Invalid sector number %u from server (expected end at %s)", i, sizeu1(unarchiveworld->numsectors)); diff = READUINT8(save_p); if (diff & SD_DIFF2) @@ -1019,64 +1025,64 @@ static void UnArchiveSectors(void) diff3 = 0; if (diff & SD_FLOORHT) - sectors[i].floorheight = READFIXED(save_p); + unarchiveworld->sectors[i].floorheight = READFIXED(save_p); if (diff & SD_CEILHT) - sectors[i].ceilingheight = READFIXED(save_p); + unarchiveworld->sectors[i].ceilingheight = READFIXED(save_p); if (diff & SD_FLOORPIC) { - sectors[i].floorpic = P_AddLevelFlatRuntime((char *)save_p); + unarchiveworld->sectors[i].floorpic = P_AddLevelFlatForWorld(unarchiveworld, (char *)save_p); save_p += 8; } if (diff & SD_CEILPIC) { - sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)save_p); + unarchiveworld->sectors[i].ceilingpic = P_AddLevelFlatForWorld(unarchiveworld, (char *)save_p); save_p += 8; } if (diff & SD_LIGHT) - sectors[i].lightlevel = READINT16(save_p); + unarchiveworld->sectors[i].lightlevel = READINT16(save_p); if (diff & SD_SPECIAL) - sectors[i].special = READINT16(save_p); + unarchiveworld->sectors[i].special = READINT16(save_p); if (diff2 & SD_FXOFFS) - sectors[i].floor_xoffs = READFIXED(save_p); + unarchiveworld->sectors[i].floor_xoffs = READFIXED(save_p); if (diff2 & SD_FYOFFS) - sectors[i].floor_yoffs = READFIXED(save_p); + unarchiveworld->sectors[i].floor_yoffs = READFIXED(save_p); if (diff2 & SD_CXOFFS) - sectors[i].ceiling_xoffs = READFIXED(save_p); + unarchiveworld->sectors[i].ceiling_xoffs = READFIXED(save_p); if (diff2 & SD_CYOFFS) - sectors[i].ceiling_yoffs = READFIXED(save_p); + unarchiveworld->sectors[i].ceiling_yoffs = READFIXED(save_p); if (diff2 & SD_FLOORANG) - sectors[i].floorpic_angle = READANGLE(save_p); + unarchiveworld->sectors[i].floorpic_angle = READANGLE(save_p); if (diff2 & SD_CEILANG) - sectors[i].ceilingpic_angle = READANGLE(save_p); + unarchiveworld->sectors[i].ceilingpic_angle = READANGLE(save_p); if (diff2 & SD_TAG) - sectors[i].tag = READINT16(save_p); // DON'T use P_ChangeSectorTag + unarchiveworld->sectors[i].tag = READINT16(save_p); // DON'T use P_ChangeSectorTag if (diff3 & SD_TAGLIST) { - sectors[i].firsttag = READINT32(save_p); - sectors[i].nexttag = READINT32(save_p); + unarchiveworld->sectors[i].firsttag = READINT32(save_p); + unarchiveworld->sectors[i].nexttag = READINT32(save_p); } if (diff3 & SD_COLORMAP) - sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(save_p)); + unarchiveworld->sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(save_p)); if (diff3 & SD_CRUMBLESTATE) - sectors[i].crumblestate = READINT32(save_p); + unarchiveworld->sectors[i].crumblestate = READINT32(save_p); if (diff & SD_FFLOORS) - UnArchiveFFloors(§ors[i]); + UnArchiveFFloors(&unarchiveworld->sectors[i]); } } static void ArchiveLines(void) { size_t i; - const line_t *li = lines; - const line_t *spawnli = spawnlines; + const line_t *li = archiveworld->lines; + const line_t *spawnli = archiveworld->spawnlines; const side_t *si; const side_t *spawnsi; UINT8 diff, diff2; // no diff3 - for (i = 0; i < numlines; i++, spawnli++, li++) + for (i = 0; i < archiveworld->numlines; i++, spawnli++, li++) { diff = diff2 = 0; @@ -1088,8 +1094,8 @@ static void ArchiveLines(void) if (li->sidenum[0] != 0xffff) { - si = &sides[li->sidenum[0]]; - spawnsi = &spawnsides[li->sidenum[0]]; + si = &archiveworld->sides[li->sidenum[0]]; + spawnsi = &archiveworld->spawnsides[li->sidenum[0]]; if (si->textureoffset != spawnsi->textureoffset) diff |= LD_S1TEXOFF; //SoM: 4/1/2000: Some textures are colormaps. Don't worry about invalid textures. @@ -1102,8 +1108,8 @@ static void ArchiveLines(void) } if (li->sidenum[1] != 0xffff) { - si = &sides[li->sidenum[1]]; - spawnsi = &spawnsides[li->sidenum[1]]; + si = &archiveworld->sides[li->sidenum[1]]; + spawnsi = &archiveworld->spawnsides[li->sidenum[1]]; if (si->textureoffset != spawnsi->textureoffset) diff2 |= LD_S2TEXOFF; if (si->toptexture != spawnsi->toptexture) @@ -1129,7 +1135,7 @@ static void ArchiveLines(void) if (diff & LD_CLLCOUNT) WRITEINT16(save_p, li->callcount); - si = &sides[li->sidenum[0]]; + si = &archiveworld->sides[li->sidenum[0]]; if (diff & LD_S1TEXOFF) WRITEFIXED(save_p, si->textureoffset); if (diff & LD_S1TOPTEX) @@ -1139,7 +1145,7 @@ static void ArchiveLines(void) if (diff & LD_S1MIDTEX) WRITEINT32(save_p, si->midtexture); - si = &sides[li->sidenum[1]]; + si = &archiveworld->sides[li->sidenum[1]]; if (diff2 & LD_S2TEXOFF) WRITEFIXED(save_p, si->textureoffset); if (diff2 & LD_S2TOPTEX) @@ -1166,11 +1172,11 @@ static void UnArchiveLines(void) if (i == 0xffff) break; - if (i > numlines) + if (i > unarchiveworld->numlines) I_Error("Invalid line number %u from server", i); diff = READUINT8(save_p); - li = &lines[i]; + li = &unarchiveworld->lines[i]; if (diff & LD_DIFF2) diff2 = READUINT8(save_p); @@ -1206,27 +1212,19 @@ static void UnArchiveLines(void) } } -static void P_NetArchiveWorld(void) +static void P_NetArchiveMap(void) { - // initialize colormap vars because paranoia - ClearNetColormaps(); - - WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); - + WRITEUINT32(save_p, ARCHIVEBLOCK_MAP); ArchiveSectors(); ArchiveLines(); - R_ClearTextureNumCache(false); } -static void P_NetUnArchiveWorld(void) +static void P_NetUnArchiveMap(void) { UINT16 i; - if (READUINT32(save_p) != ARCHIVEBLOCK_WORLD) - I_Error("Bad $$$.sav at archive block World"); - - // initialize colormap vars because paranoia - ClearNetColormaps(); + if (READUINT32(save_p) != ARCHIVEBLOCK_MAP) + I_Error("Bad $$$.sav at archive block Map"); // count the level's ffloors so that colormap loading can have an upper limit for (i = 0; i < numsectors; i++) @@ -1354,13 +1352,13 @@ static inline UINT32 SaveMobjnum(const mobj_t *mobj) static UINT32 SaveSector(const sector_t *sector) { - if (sector) return (UINT32)(sector - sectors); + if (sector) return (UINT32)(sector - archiveworld->sectors); return 0xFFFFFFFF; } static UINT32 SaveLine(const line_t *line) { - if (line) return (UINT32)(line - lines); + if (line) return (UINT32)(line - archiveworld->lines); return 0xFFFFFFFF; } @@ -1543,8 +1541,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) { size_t z; - for (z = 0; z < nummapthings; z++) - if (&mapthings[z] == mobj->spawnpoint) + for (z = 0; z < archiveworld->nummapthings; z++) + if (&archiveworld->mapthings[z] == mobj->spawnpoint) WRITEUINT16(save_p, z); if (mobj->type == MT_HOOPCENTER) return; @@ -1650,6 +1648,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) WRITEFIXED(save_p, mobj->shadowscale); WRITEUINT32(save_p, mobj->mobjnum); + WRITEUINT32(save_p, mobj->worldnum); } static void SaveNoEnemiesThinker(const thinker_t *th, const UINT8 type) @@ -2142,7 +2141,7 @@ static void P_NetArchiveThinkers(void) { UINT32 numsaved = 0; // save off the current thinkers - for (th = thlist[i].next; th != &thlist[i]; th = th->next) + for (th = archiveworld->thlist[i].next; th != &archiveworld->thlist[i]; th = th->next) { if (!(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed || th->function.acp1 == (actionf_p1)P_NullPrecipThinker)) @@ -2372,12 +2371,12 @@ static void P_NetArchiveThinkers(void) // relink to this; the savegame contains the old position in the pointer // field copyed in the info field temporarily, but finally we just search // for the old position and relink to it. -mobj_t *P_FindNewPosition(UINT32 oldposition) +mobj_t *P_FindNewPosition(world_t *w, UINT32 oldposition) { thinker_t *th; mobj_t *mobj; - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + for (th = w->thlist[THINK_MOBJ].next; th != &w->thlist[THINK_MOBJ]; th = th->next) { if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) continue; @@ -2400,14 +2399,14 @@ static inline mobj_t *LoadMobj(UINT32 mobjnum) static sector_t *LoadSector(UINT32 sector) { - if (sector >= numsectors) return NULL; - return §ors[sector]; + if (sector >= unarchiveworld->numsectors) return NULL; + return &unarchiveworld->sectors[sector]; } static line_t *LoadLine(UINT32 line) { - if (line >= numlines) return NULL; - return &lines[line]; + if (line >= unarchiveworld->numlines) return NULL; + return &unarchiveworld->lines[line]; } static inline player_t *LoadPlayer(UINT32 player) @@ -2418,8 +2417,8 @@ static inline player_t *LoadPlayer(UINT32 player) static inline pslope_t *LoadSlope(UINT32 slopeid) { - pslope_t *p = world->slopelist; - if (slopeid > world->slopecount) return NULL; + pslope_t *p = unarchiveworld->slopelist; + if (slopeid > unarchiveworld->slopecount) return NULL; do { if (p->id == slopeid) @@ -2468,16 +2467,17 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) { UINT16 spawnpointnum = READUINT16(save_p); - if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case + if (unarchiveworld->mapthings[spawnpointnum].type == 1705 + || unarchiveworld->mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case { - P_SpawnHoop(&mapthings[spawnpointnum]); + P_SpawnHoop(&unarchiveworld->mapthings[spawnpointnum]); return NULL; } mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); - mobj->spawnpoint = &mapthings[spawnpointnum]; - mapthings[spawnpointnum].mobj = mobj; + mobj->spawnpoint = &unarchiveworld->mapthings[spawnpointnum]; + unarchiveworld->mapthings[spawnpointnum].mobj = mobj; } else mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); @@ -2670,6 +2670,11 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->mobjnum = READUINT32(save_p); + // Lactozilla: Unarchive world number + mobj->worldnum = READUINT32(save_p); + if (mobj->worldnum == 0xFFFFFFFF) + I_Error("Unknown world"); + if (mobj->player) { if (mobj->eflags & MFE_VERTICALFLIP) @@ -3284,8 +3289,8 @@ static void P_NetUnArchiveThinkers(void) // remove all the current thinkers for (i = 0; i < NUM_THINKERLISTS; i++) { - currentthinker = thlist[i].next; - for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = next) + currentthinker = unarchiveworld->thlist[i].next; + for (currentthinker = unarchiveworld->thlist[i].next; currentthinker != &unarchiveworld->thlist[i]; currentthinker = next) { next = currentthinker->next; @@ -3297,7 +3302,7 @@ static void P_NetUnArchiveThinkers(void) } // we don't want the removed mobjs to come back - iquetail = iquehead = 0; + unarchiveworld->iquetail = unarchiveworld->iquehead = 0; P_InitThinkers(); // clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity @@ -3505,7 +3510,7 @@ static void P_NetUnArchiveThinkers(void) delay = (void *)currentthinker; if (!(mobjnum = (UINT32)(size_t)delay->caller)) continue; - delay->caller = P_FindNewPosition(mobjnum); + delay->caller = P_FindNewPosition(unarchiveworld, mobjnum); } } } @@ -3574,20 +3579,20 @@ static inline void P_UnArchivePolyObj(polyobj_t *po) Polyobj_MoveOnLoad(po, angle, x, y); } -static inline void P_ArchivePolyObjects(void) +static inline void P_NetArchivePolyObjects(void) { INT32 i; WRITEUINT32(save_p, ARCHIVEBLOCK_POBJS); // save number of polyobjects - WRITEINT32(save_p, world->numPolyObjects); + WRITEINT32(save_p, archiveworld->numPolyObjects); - for (i = 0; i < world->numPolyObjects; ++i) - P_ArchivePolyObj(&world->PolyObjects[i]); + for (i = 0; i < archiveworld->numPolyObjects; ++i) + P_ArchivePolyObj(&archiveworld->PolyObjects[i]); } -static inline void P_UnArchivePolyObjects(void) +static inline void P_NetUnArchivePolyObjects(void) { INT32 i, numSavedPolys; @@ -3597,7 +3602,7 @@ static inline void P_UnArchivePolyObjects(void) numSavedPolys = READINT32(save_p); if (numSavedPolys != world->numPolyObjects) - I_Error("P_UnArchivePolyObjects: polyobj count inconsistency\n"); + I_Error("P_NetUnArchivePolyObjects: polyobj count inconsistency\n"); for (i = 0; i < numSavedPolys; ++i) P_UnArchivePolyObj(&world->PolyObjects[i]); @@ -3627,7 +3632,8 @@ static void P_RelinkPointers(void) UINT32 temp; // use info field (value = oldposition) to relink mobjs - for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ]; + for (currentthinker = unarchiveworld->thlist[THINK_MOBJ].next; + currentthinker != &unarchiveworld->thlist[THINK_MOBJ]; currentthinker = currentthinker->next) { if (currentthinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) @@ -3642,70 +3648,70 @@ static void P_RelinkPointers(void) { temp = (UINT32)(size_t)mobj->tracer; mobj->tracer = NULL; - if (!P_SetTarget(&mobj->tracer, P_FindNewPosition(temp))) + if (!P_SetTarget(&mobj->tracer, P_FindNewPosition(unarchiveworld, temp))) CONS_Debug(DBG_GAMELOGIC, "tracer not found on %d\n", mobj->type); } if (mobj->target) { temp = (UINT32)(size_t)mobj->target; mobj->target = NULL; - if (!P_SetTarget(&mobj->target, P_FindNewPosition(temp))) + if (!P_SetTarget(&mobj->target, P_FindNewPosition(unarchiveworld, temp))) CONS_Debug(DBG_GAMELOGIC, "target not found on %d\n", mobj->type); } if (mobj->hnext) { temp = (UINT32)(size_t)mobj->hnext; mobj->hnext = NULL; - if (!(mobj->hnext = P_FindNewPosition(temp))) + if (!(mobj->hnext = P_FindNewPosition(unarchiveworld, temp))) CONS_Debug(DBG_GAMELOGIC, "hnext not found on %d\n", mobj->type); } if (mobj->hprev) { temp = (UINT32)(size_t)mobj->hprev; mobj->hprev = NULL; - if (!(mobj->hprev = P_FindNewPosition(temp))) + if (!(mobj->hprev = P_FindNewPosition(unarchiveworld, temp))) CONS_Debug(DBG_GAMELOGIC, "hprev not found on %d\n", mobj->type); } if (mobj->player && mobj->player->capsule) { temp = (UINT32)(size_t)mobj->player->capsule; mobj->player->capsule = NULL; - if (!P_SetTarget(&mobj->player->capsule, P_FindNewPosition(temp))) + if (!P_SetTarget(&mobj->player->capsule, P_FindNewPosition(unarchiveworld, temp))) CONS_Debug(DBG_GAMELOGIC, "capsule not found on %d\n", mobj->type); } if (mobj->player && mobj->player->axis1) { temp = (UINT32)(size_t)mobj->player->axis1; mobj->player->axis1 = NULL; - if (!P_SetTarget(&mobj->player->axis1, P_FindNewPosition(temp))) + if (!P_SetTarget(&mobj->player->axis1, P_FindNewPosition(unarchiveworld, temp))) CONS_Debug(DBG_GAMELOGIC, "axis1 not found on %d\n", mobj->type); } if (mobj->player && mobj->player->axis2) { temp = (UINT32)(size_t)mobj->player->axis2; mobj->player->axis2 = NULL; - if (!P_SetTarget(&mobj->player->axis2, P_FindNewPosition(temp))) + if (!P_SetTarget(&mobj->player->axis2, P_FindNewPosition(unarchiveworld, temp))) CONS_Debug(DBG_GAMELOGIC, "axis2 not found on %d\n", mobj->type); } if (mobj->player && mobj->player->awayviewmobj) { temp = (UINT32)(size_t)mobj->player->awayviewmobj; mobj->player->awayviewmobj = NULL; - if (!P_SetTarget(&mobj->player->awayviewmobj, P_FindNewPosition(temp))) + if (!P_SetTarget(&mobj->player->awayviewmobj, P_FindNewPosition(unarchiveworld, temp))) CONS_Debug(DBG_GAMELOGIC, "awayviewmobj not found on %d\n", mobj->type); } if (mobj->player && mobj->player->followmobj) { temp = (UINT32)(size_t)mobj->player->followmobj; mobj->player->followmobj = NULL; - if (!P_SetTarget(&mobj->player->followmobj, P_FindNewPosition(temp))) + if (!P_SetTarget(&mobj->player->followmobj, P_FindNewPosition(unarchiveworld, temp))) CONS_Debug(DBG_GAMELOGIC, "followmobj not found on %d\n", mobj->type); } if (mobj->player && mobj->player->drone) { temp = (UINT32)(size_t)mobj->player->drone; mobj->player->drone = NULL; - if (!P_SetTarget(&mobj->player->drone, P_FindNewPosition(temp))) + if (!P_SetTarget(&mobj->player->drone, P_FindNewPosition(unarchiveworld, temp))) CONS_Debug(DBG_GAMELOGIC, "drone not found on %d\n", mobj->type); } } @@ -3718,18 +3724,18 @@ static inline void P_NetArchiveSpecials(void) WRITEUINT32(save_p, ARCHIVEBLOCK_SPECIALS); // itemrespawn queue for deathmatch - i = iquetail; - while (iquehead != i) + i = archiveworld->iquetail; + while (archiveworld->iquehead != i) { - for (z = 0; z < nummapthings; z++) + for (z = 0; z < archiveworld->nummapthings; z++) { - if (&mapthings[z] == itemrespawnque[i]) + if (&archiveworld->mapthings[z] == archiveworld->itemrespawnque[i]) { WRITEUINT32(save_p, z); break; } } - WRITEUINT32(save_p, itemrespawntime[i]); + WRITEUINT32(save_p, archiveworld->itemrespawntime[i]); i = (i + 1) & (ITEMQUESIZE-1); } @@ -3737,10 +3743,10 @@ static inline void P_NetArchiveSpecials(void) WRITEUINT32(save_p, 0xffffffff); // Sky number - WRITEINT32(save_p, globallevelskynum); + WRITEINT32(save_p, archiveworld->skynum); // Current global weather type - WRITEUINT8(save_p, globalweather); + WRITEUINT8(save_p, archiveworld->weather); if (metalplayback) // Is metal sonic running? { @@ -3760,30 +3766,30 @@ static void P_NetUnArchiveSpecials(void) I_Error("Bad $$$.sav at archive block Specials"); // BP: added save itemrespawn queue for deathmatch - iquetail = iquehead = 0; + unarchiveworld->iquetail = unarchiveworld->iquehead = 0; while ((i = READUINT32(save_p)) != 0xffffffff) { - itemrespawnque[iquehead] = &mapthings[i]; - itemrespawntime[iquehead++] = READINT32(save_p); + unarchiveworld->itemrespawnque[unarchiveworld->iquehead] = &unarchiveworld->mapthings[i]; + unarchiveworld->itemrespawntime[unarchiveworld->iquehead++] = READINT32(save_p); } j = READINT32(save_p); - if (j != globallevelskynum) - P_SetupLevelSky(j, true); + P_SetupLevelSky(j, false); // Don't call P_SetupWorldSky from there + P_SetupWorldSky(j, unarchiveworld); - globalweather = READUINT8(save_p); + unarchiveworld->weather = READUINT8(save_p); - if (globalweather) + if (world->weather) { - if (curWeather == globalweather) + if (curWeather == world->weather) curWeather = PRECIP_NONE; - P_SwitchWeather(globalweather); + P_SwitchWeather(world->weather); } else // PRECIP_NONE { if (curWeather != PRECIP_NONE) - P_SwitchWeather(globalweather); + P_SwitchWeather(world->weather); } if (READUINT8(save_p) == 0x01) // metal sonic @@ -3853,7 +3859,7 @@ static void P_NetArchiveMisc(void) WRITEUINT32(save_p, ARCHIVEBLOCK_MISC); - WRITEINT16(save_p, gamemap); + WRITEINT16(save_p, baseworld->gamemap); WRITEINT16(save_p, gamestate); { @@ -3903,7 +3909,7 @@ static void P_NetArchiveMisc(void) WRITEUINT32(save_p, countdown); WRITEUINT32(save_p, countdown2); - WRITEFIXED(save_p, gravity); + WRITEFIXED(save_p, baseworld->gravity); WRITEUINT32(save_p, countdowntimer); WRITEUINT8(save_p, countdowntimeup); @@ -3924,6 +3930,8 @@ static inline boolean P_NetUnArchiveMisc(void) if (READUINT32(save_p) != ARCHIVEBLOCK_MISC) I_Error("Bad $$$.sav at archive block Misc"); + P_UnloadWorldList(); + gamemap = READINT16(save_p); // gamemap changed; we assume that its map header is always valid, @@ -4049,37 +4057,87 @@ void P_SaveGame(INT16 mapnum) P_ArchiveLuabanksAndConsistency(); } +static void P_NetArchiveWorlds(void) +{ + INT32 i; + + // initialize colormap vars because paranoia + ClearNetColormaps(); + R_ClearTextureNumCache(false); + + WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); + WRITEINT32(save_p, numworlds); + + for (i = 0; i < numworlds; i++) + { + archiveworld = worldlist[i]; + + WRITEINT16(save_p, archiveworld->gamemap); + WRITEUINT8(save_p, archiveworld->players); + + P_NetArchiveMap(); + P_NetArchivePolyObjects(); + P_NetArchiveThinkers(); + P_NetArchiveSpecials(); + P_NetArchiveWaypoints(); + } + + P_NetArchiveColormaps(); +} + void P_SaveNetGame(void) { thinker_t *th; mobj_t *mobj; - INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise + INT32 i; CV_SaveNetVars(&save_p); P_NetArchiveMisc(); // Assign the mobjnumber for pointer tracking - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + for (i = 0; i < numworlds; i++) { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; + world_t *w = worldlist[i]; + INT32 mobjnum = 1; // don't start from 0, it'd be confused with a blank pointer otherwise - mobj = (mobj_t *)th; - if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER) + for (th = w->thlist[THINK_MOBJ].next; th != &w->thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + mobj = (mobj_t *)th; + if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER) + continue; + mobj->mobjnum = mobjnum++; + mobj->worldnum = (UINT32)i; + } + } + + // Lactozilla: Assign world numbers to players + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *player; + INT32 w; + + if (!playeringame[i]) continue; - mobj->mobjnum = i++; + + player = &players[i]; + player->worldnum = -1; + + for (w = 0; w < numworlds; w++) + { + if (player->world == worldlist[w]) + { + player->worldnum = w; + break; + } + } } P_NetArchivePlayers(); if (gamestate == GS_LEVEL) - { - P_NetArchiveWorld(); - P_ArchivePolyObjects(); - P_NetArchiveThinkers(); - P_NetArchiveSpecials(); - P_NetArchiveColormaps(); - P_NetArchiveWaypoints(); - } + P_NetArchiveWorlds(); LUA_Archive(); P_ArchiveLuabanksAndConsistency(); @@ -4104,6 +4162,108 @@ boolean P_LoadGame(INT16 mapoverride) return true; } +static void UnArchiveWorld(void) +{ + unarchiveworld->players = READUINT8(save_p); + P_NetUnArchiveMap(); + P_NetUnArchivePolyObjects(); + P_NetUnArchiveThinkers(); + P_NetUnArchiveSpecials(); + P_NetUnArchiveWaypoints(); + P_RelinkPointers(); + P_FinishMobjs(); +} + +static void RelinkWorldsToEntities(void) +{ + thinker_t *th; + mobj_t *mo; + INT32 i; + + for (i = 0; i < numworlds; i++) + { + world_t *w = worldlist[i]; + + for (th = w->thlist[THINK_MOBJ].next; th != &w->thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + mo = (mobj_t *)th; + + if ((INT32)mo->worldnum >= numworlds) + I_Error("RelinkWorldsToEntities: Mobj type %d has unknown world %d", mo->type, mo->worldnum); + + if ((INT32)mo->worldnum != i) + I_Error("RelinkWorldsToEntities: Mobj type %d has a world mismatch (mobj: %d, set: %d)", mo->type, mo->worldnum, i); + + mo->world = worldlist[mo->worldnum]; + } + } + + // Relink players to their worlds + // This is also done for their mobjs. + for (i = 0; i < MAXPLAYERS; i++) + { + world_t *w; + player_t *player; + + if (!playeringame[i]) + continue; + + player = &players[i]; + + if (player->worldnum == -1 || player->worldnum >= numworlds) + I_Error("RelinkWorldsToEntities: Player %d (%s) has unknown world %d", i, player_names[i], player->worldnum); + + w = worldlist[player->worldnum]; + player->world = w; + if (player->mo) + player->mo->world = w; + } +} + +static void SetUnArchiveWorld(world_t *w) +{ + unarchiveworld = world = baseworld = localworld = w; +} + +static void P_NetUnArchiveWorlds(void) +{ + player_t *player = &players[consoleplayer]; + INT32 worldcount, i; + + if (READUINT32(save_p) != ARCHIVEBLOCK_WORLD) + I_Error("Bad $$$.sav at archive block World"); + + worldcount = READINT32(save_p); + + // initialize colormap vars because paranoia + ClearNetColormaps(); + + // Unarchive the first world + gamemap = READINT16(save_p); + SetUnArchiveWorld(worldlist[0]); + UnArchiveWorld(); + + for (i = 1; i < worldcount; i++) + { + gamemap = READINT16(save_p); + if (!P_LoadLevel(player, true, true)) + I_Error("P_NetUnArchiveWorlds: failed loading world"); + SetUnArchiveWorld(worldlist[i]); + UnArchiveWorld(); + } + + P_NetUnArchiveColormaps(); + RelinkWorldsToEntities(); + + // Send a command to switch this player to the first world + // For every other client, the player is on that world, but not for the joiner + if (worldcount > 1) + SendWorldSwitch(0, true); +} + boolean P_LoadNetGame(void) { CV_LoadNetVars(&save_p); @@ -4111,16 +4271,7 @@ boolean P_LoadNetGame(void) return false; P_NetUnArchivePlayers(); if (gamestate == GS_LEVEL) - { - P_NetUnArchiveWorld(); - P_UnArchivePolyObjects(); - P_NetUnArchiveThinkers(); - P_NetUnArchiveSpecials(); - P_NetUnArchiveColormaps(); - P_NetUnArchiveWaypoints(); - P_RelinkPointers(); - P_FinishMobjs(); - } + P_NetUnArchiveWorlds(); LUA_UnArchive(); // This is stupid and hacky, but maybe it'll work! diff --git a/src/p_saveg.h b/src/p_saveg.h index d8756a7a9b955e4520e46849c3d76313329b1623..bf2f45175365bc1e770b0494bdc991f8403b8dae 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -18,6 +18,8 @@ #pragma interface #endif +#include "p_world.h" + // Persistent storage/archiving. // These are the load / save game routines. @@ -26,7 +28,7 @@ void P_SaveNetGame(void); boolean P_LoadGame(INT16 mapoverride); boolean P_LoadNetGame(void); -mobj_t *P_FindNewPosition(UINT32 oldposition); +mobj_t *P_FindNewPosition(world_t *w, UINT32 oldposition); typedef struct { @@ -42,4 +44,7 @@ typedef struct extern savedata_t savedata; extern UINT8 *save_p; +extern world_t *archiveworld; +extern world_t *unarchiveworld; + #endif diff --git a/src/p_setup.c b/src/p_setup.c index 02241bbf7c6d15ef60c1111b6cf1307e7fe3e0f3..6706f796c46807f134f10aed795c1e4daf6eefc4 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2832,27 +2832,50 @@ static boolean P_LoadMapFromFile(void) // LEVEL INITIALIZATION FUNCTIONS // +static void P_InitLevelSky(INT32 skynum, player_t *player) +{ + if (player == &players[consoleplayer]) + P_SetupSkyTexture(skynum); + + P_SetupWorldSky(skynum, world); + levelskynum = skynum; + + // scale up the old skies, if needed + if (!dedicated) + R_SetupSkyDraw(); +} + /** Sets up a sky texture to use for the level. * The sky texture is used instead of F_SKY1. */ void P_SetupLevelSky(INT32 skynum, boolean global) { - char skytexname[12]; - - sprintf(skytexname, "SKY%d", skynum); - world->skytexture = R_TextureNumForName(skytexname); + P_SetupSkyTexture(skynum); levelskynum = skynum; // Global change if (global) - globallevelskynum = levelskynum; + P_SetupWorldSky(skynum, world); - // Don't go beyond for dedicated servers - if (dedicated) - return; + // scale up the old skies, if needed + if (!dedicated) + R_SetupSkyDraw(); +} + +void P_SetupWorldSky(INT32 skynum, world_t *w) +{ + w->skynum = skynum; // scale up the old skies, if needed - R_SetupSkyDraw(world); + if (!dedicated) + R_SetupSkyDraw(); +} + +void P_SetupSkyTexture(INT32 skynum) +{ + char skytexname[12]; + sprintf(skytexname, "SKY%d", skynum); + skytexture = R_TextureNumForName(skytexname); } static const char *maplumpname; @@ -2934,7 +2957,7 @@ static void P_InitWorldSettings(void) stagefailed = true; // assume failed unless proven otherwise - P_GiveEmerald or emerald touchspecial } -static void P_InitLevelSettings(player_t *player, boolean addworld) +static void P_InitLevelSettings(player_t *player, boolean addworld, boolean fromnetsave) { INT32 i; boolean canresetlives = true; @@ -2963,10 +2986,18 @@ static void P_InitLevelSettings(player_t *player, boolean addworld) if (!addworld) countdown = countdown2 = exitfadestarted = 0; - if (!addworld) + if (!addworld || fromnetsave) { for (i = 0; i < MAXPLAYERS; i++) - P_InitPlayerSettings(i, canresetlives); + { + if (fromnetsave) + { + players[i].followmobj = NULL; + players[i].mo = NULL; + } + else + P_InitPlayerSettings(i, canresetlives); + } } else if (player) { @@ -3002,7 +3033,7 @@ void P_RespawnThings(void) P_RemoveMobj((mobj_t *)think); } - P_InitLevelSettings(NULL, false); + P_InitLevelSettings(NULL, false, false); P_SpawnMapThings(true); @@ -3476,11 +3507,11 @@ static void P_WriteLetter(void) Z_Free(buf); } -static void P_InitGametype(player_t *player, boolean addplayer) +static void P_InitGametype(player_t *player, boolean addworld) { UINT8 i; - if (!addplayer) + if (!addworld) { P_InitGametypePlayers(); @@ -3527,6 +3558,7 @@ boolean P_LoadLevel(player_t *player, boolean addworld, boolean fromnetsave) // 99% of the things already did, so. // Map header should always be in place at this point INT32 i, ranspecialwipe = 0; + boolean runforself = (!addworld || (addworld && player == &players[consoleplayer])); levelloading = true; @@ -3541,9 +3573,6 @@ boolean P_LoadLevel(player_t *player, boolean addworld, boolean fromnetsave) if (rendermode != render_none) V_SetPaletteLump("PLAYPAL"); - if (player && !titlemapinaction && player->world) - P_MarkWorldVisited(player, player->world); - // Initialize sector node list. P_Initsecnode(); @@ -3562,7 +3591,7 @@ boolean P_LoadLevel(player_t *player, boolean addworld, boolean fromnetsave) if (cv_runscripts.value && mapheaderinfo[gamemap-1]->scriptname[0] != '#') P_RunLevelScript(mapheaderinfo[gamemap-1]->scriptname); - P_InitLevelSettings(player, addworld); + P_InitLevelSettings(player, addworld, fromnetsave); postimgtype = postimgtype2 = postimg_none; @@ -3597,102 +3626,107 @@ boolean P_LoadLevel(player_t *player, boolean addworld, boolean fromnetsave) wipegamestate = FORCEWIPEOFF; wipestyleflags = 0; - // Special stage fade to white - // This is handled BEFORE sounds are stopped. - if (modeattacking && !demoplayback && (pausedelay == INT32_MIN)) - ranspecialwipe = 2; - else if (rendermode != render_none && G_IsSpecialStage(gamemap)) + if (!addworld) { - P_RunSpecialStageWipe(); - ranspecialwipe = 1; - } + // Special stage fade to white + // This is handled BEFORE sounds are stopped. + if (modeattacking && !demoplayback && (pausedelay == INT32_MIN)) + ranspecialwipe = 2; + else if (rendermode != render_none && G_IsSpecialStage(gamemap)) + { + P_RunSpecialStageWipe(); + ranspecialwipe = 1; + } - if (G_GetModeAttackRetryFlag()) - { - if (modeattacking) - wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE); - G_ClearModeAttackRetryFlag(); - } + if (G_GetModeAttackRetryFlag()) + { + if (modeattacking) + wipestyleflags |= (WSF_FADEOUT|WSF_TOWHITE); + G_ClearModeAttackRetryFlag(); + } - // Make sure all sounds are stopped before Z_FreeTags. - S_StopSounds(); - S_ClearSfx(); + // Make sure all sounds are stopped before Z_FreeTags. + S_StopSounds(); + S_ClearSfx(); - // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. - // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. - if (!titlemapinaction && (RESETMUSIC || - strnicmp(S_MusicName(), - (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7))) - S_FadeMusic(0, FixedMul( - FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); + // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. + // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. + if (!titlemapinaction && (RESETMUSIC || + strnicmp(S_MusicName(), + (mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7))) + S_FadeMusic(0, FixedMul( + FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); - // Let's fade to black here - // But only if we didn't do the special stage wipe - if (rendermode != render_none && !ranspecialwipe) - P_RunLevelWipe(); + // Let's fade to black here + // But only if we didn't do the special stage wipe + if (rendermode != render_none && !ranspecialwipe) + P_RunLevelWipe(); - if (!titlemapinaction) - { - if (ranspecialwipe == 2) + if (!titlemapinaction) { - pausedelay = -3; // preticker plus one - S_StartSound(NULL, sfx_s3k73); - } + if (ranspecialwipe == 2) + { + pausedelay = -3; // preticker plus one + S_StartSound(NULL, sfx_s3k73); + } - // Print "SPEEDING OFF TO [ZONE] [ACT 1]..." - if (rendermode != render_none) - { - // Don't include these in the fade! - char tx[64]; - V_DrawSmallString(1, 191, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Speeding off to...")); - snprintf(tx, 63, "%s%s%s", - mapheaderinfo[gamemap-1]->lvlttl, - (mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " Zone", - (mapheaderinfo[gamemap-1]->actnum > 0) ? va(" %d",mapheaderinfo[gamemap-1]->actnum) : ""); - V_DrawSmallString(1, 195, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, tx); - I_UpdateNoVsync(); - } + // Print "SPEEDING OFF TO [ZONE] [ACT 1]..." + if (rendermode != render_none) + { + // Don't include these in the fade! + char tx[64]; + V_DrawSmallString(1, 191, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Speeding off to...")); + snprintf(tx, 63, "%s%s%s", + mapheaderinfo[gamemap-1]->lvlttl, + (mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " Zone", + (mapheaderinfo[gamemap-1]->actnum > 0) ? va(" %d",mapheaderinfo[gamemap-1]->actnum) : ""); + V_DrawSmallString(1, 195, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, tx); + I_UpdateNoVsync(); + } - // As oddly named as this is, this handles music only. - // We should be fine starting it here. - // Don't do this during titlemap, because the menu code handles music by itself. - S_Start(); - } + // As oddly named as this is, this handles music only. + // We should be fine starting it here. + // Don't do this during titlemap, because the menu code handles music by itself. + S_Start(); + } - levelfadecol = (ranspecialwipe) ? 0 : 31; + levelfadecol = (ranspecialwipe) ? 0 : 31; - // Close text prompt before freeing the old level - F_EndTextPrompt(false, true); + // Close text prompt before freeing the old level + F_EndTextPrompt(false, true); + } + else + wipegamestate = gamestate; if (player && (!titlemapinaction)) - { P_UnloadWorldPlayer(player); - //P_UnloadWorld(world); - } world = P_InitNewWorld(); thlist = world->thlist; - if (addworld) - P_SwitchPlayerWorld(player, world); - else + if (!fromnetsave) { - for (i = 0; i < MAXPLAYERS; i++) + if (addworld) + P_SwitchPlayerWorld(player, world); + else { - player_t *p; + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *p; - if (!playeringame[i]) - continue; + if (!playeringame[i]) + continue; - p = &players[i]; - p->world = NULL; - P_SwitchPlayerWorld(p, world); - } + p = &players[i]; + p->world = NULL; + P_SwitchPlayerWorld(p, world); + } - world->players = D_NumPlayers(); + world->players = D_NumPlayers(); + } } - if (player == &players[consoleplayer]) + if (!addworld || player == &players[consoleplayer]) localworld = world; #if defined (WALLSPLATS) || defined (FLOORSPLATS) @@ -3722,10 +3756,15 @@ boolean P_LoadLevel(player_t *player, boolean addworld, boolean fromnetsave) I_Error("Map %s not found.\n", maplumpname); R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette); + if (!addworld) + { + // Init Boom colormaps. + R_ClearColormaps(); + } CON_SetupBackColormap(); // SRB2 determines the sky texture to be used depending on the map header. - P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); + P_InitLevelSky(mapheaderinfo[gamemap-1]->skynum, player); P_ResetSpawnpoints(); @@ -3756,7 +3795,8 @@ boolean P_LoadLevel(player_t *player, boolean addworld, boolean fromnetsave) // set up world state P_SpawnSpecials(fromnetsave); - if (!fromnetsave) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame) + // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame) + if (!fromnetsave && runforself) P_SpawnPrecipitation(); #ifdef HWRENDER // not win32 only 19990829 by Kin @@ -3778,10 +3818,11 @@ boolean P_LoadLevel(player_t *player, boolean addworld, boolean fromnetsave) if (!fromnetsave) P_InitGametype(player, addworld); - P_InitCamera(); + if (runforself) + P_InitCamera(); // clear special respawning que - iquehead = iquetail = 0; + world->iquehead = world->iquetail = 0; // Fab : 19-07-98 : start cd music for this level (note: can be remapped) I_PlayCD((UINT8)(gamemap), false); @@ -3789,7 +3830,7 @@ boolean P_LoadLevel(player_t *player, boolean addworld, boolean fromnetsave) P_MapEnd(); // Remove the loading shit from the screen - if (rendermode != render_none && !titlemapinaction) + if (rendermode != render_none && !titlemapinaction && runforself) F_WipeColorFill(levelfadecol); if (precache || dedicated) @@ -3837,6 +3878,10 @@ boolean P_LoadLevel(player_t *player, boolean addworld, boolean fromnetsave) if (rendermode == render_none) return true; + //if (!runforself || (addworld && splitscreen)) + if (addworld) + return true; + // Title card! G_StartTitleCard(); diff --git a/src/p_setup.h b/src/p_setup.h index 893b19f096c57caf294bac2017ccd2c3e00dc7ec..c3828aa3f63a60d67b1720c08de2b358ca23856c 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -86,6 +86,7 @@ extern size_t nummapthings; extern mapthing_t *mapthings; void P_SetupLevelSky(INT32 skynum, boolean global); +void P_SetupSkyTexture(INT32 skynum); #ifdef SCANTHINGS void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum); #endif diff --git a/src/p_sight.c b/src/p_sight.c index 8ddec3999bcf915aebd0f06ebd8e644716ddea78..7ce4d0357e799afdad3956cce609a4768567de2e 100644 --- a/src/p_sight.c +++ b/src/p_sight.c @@ -397,14 +397,17 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2) s2 = t2->subsector->sector; // Check in REJECT table. - //CONS_Printf("P_CheckSight: %d %p %d %p\n", t1->type, t1->world, t2->type, t2->world); - if (t1->world == t2->world) + if (s1->world == s2->world + && t1->world == t2->world + && t1->world == s1->world + && t2->world == s2->world) { - size_t pnum = (s1-sectors)*numsectors + (s2-sectors); + world_t *w = s1->world; + size_t pnum = (s1-w->sectors)*w->numsectors + (s2-w->sectors); - if (rejectmatrix != NULL) + if (w->rejectmatrix != NULL) { - if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected + if (w->rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected return false; } } diff --git a/src/p_spec.c b/src/p_spec.c index ba77c835cc3f235edf64f397398fbab59dec3f37..ee039ceab4c30fc22a6b4bd7b41b4d33207ca3ed 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2987,8 +2987,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) case 424: // Change Weather if (line->flags & ML_NOCLIMB) { - globalweather = (UINT8)(sides[line->sidenum[0]].textureoffset>>FRACBITS); - P_SwitchWeather(globalweather); + world->weather = (UINT8)(sides[line->sidenum[0]].textureoffset>>FRACBITS); + P_SwitchWeather(world->weather); } else if (mo && mo->player && P_IsLocalPlayer(mo->player)) P_SwitchWeather(sides[line->sidenum[0]].textureoffset>>FRACBITS); @@ -6136,7 +6136,7 @@ static void P_RunLevelLoadExecutors(void) void P_InitSpecials(void) { // Set the default gravity. Custom gravity overrides this setting. - gravity = mapheaderinfo[gamemap-1]->gravity; + world->gravity = gravity = mapheaderinfo[gamemap-1]->gravity; // Defaults in case levels don't have them set. sstimer = mapheaderinfo[gamemap-1]->sstimer*TICRATE + 6; @@ -6161,7 +6161,7 @@ void P_InitSpecials(void) } // Set globalweather - globalweather = mapheaderinfo[gamemap-1]->weather; + world->weather = mapheaderinfo[gamemap-1]->weather; } static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs) @@ -6236,7 +6236,7 @@ void P_SpawnSpecials(boolean fromnetsave) break; case 11: // Custom global gravity! - gravity = sector->floorheight/1000; + world->gravity = gravity = sector->floorheight/1000; break; } diff --git a/src/p_tick.c b/src/p_tick.c index 74cb8255b3ca60e068605743d3acaf2d91415c77..0d71dd58f41856ebc388115c08bd4c196af07b09 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -651,6 +651,27 @@ static inline void P_RunWorldSpecials(void) } } +static inline void P_WorldPrecipitationEffects(void) +{ + INT32 i; + + if (!(netgame || multiplayer) || (numworlds < 2)) + { + P_PrecipitationEffects(baseworld); + return; + } + + for (i = 0; i < numworlds; i++) + { + world_t *w = worldlist[i]; + + if (!w->players) + continue; + + P_PrecipitationEffects(w); + } +} + static inline void P_WorldRunVoid(void (*func)(void)) { INT32 i; @@ -781,7 +802,7 @@ void P_Ticker(boolean run) P_RunWorldSpecials(); // Lightning, rain sounds, etc. - P_PrecipitationEffects(); + P_WorldPrecipitationEffects(); if (run) leveltime++; diff --git a/src/p_user.c b/src/p_user.c index c4a3ec0678bb8e86e2efc26e636226b5e855b890..8d8dcd3e7c0aa3dd8f90aca1092423eda0d75b07 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2213,7 +2213,9 @@ void P_DoPlayerExit(player_t *player) if (player->exiting) return; - if (cv_allowexitlevel.value == 0 && !G_PlatformGametype()) + if (roaming) + player->exiting = (3*TICRATE) - 1; + else if (cv_allowexitlevel.value == 0 && !G_PlatformGametype()) return; else if (gametyperules & GTR_RACE) // If in Race Mode, allow { @@ -9457,6 +9459,30 @@ void P_RestoreMultiMusic(player_t *player) } } +static void P_PlayerSetRaceRealTime(player_t *player) +{ + if (leveltime >= 4*TICRATE) + { + player->realtime = leveltime - 4*TICRATE; + + if (roaming) + { + INT32 i; + + for (i = 0; i < numworlds; i++) + { + if (player->world == worldlist[i]) + break; + } + + if (i > 0 && i < numworlds) + player->realtime -= (i * (3*TICRATE)-1); + } + } + else + player->realtime = 0; +} + // // P_DeathThink // Fall on your face when dying. @@ -9584,12 +9610,7 @@ static void P_DeathThink(player_t *player) if (!(countdown2 && !countdown) && !player->exiting && !(player->pflags & PF_GAMETYPEOVER) && !stoppedclock) { if (gametyperules & GTR_RACE) - { - if (leveltime >= 4*TICRATE) - player->realtime = leveltime - 4*TICRATE; - else - player->realtime = 0; - } + P_PlayerSetRaceRealTime(player); else player->realtime = leveltime; } @@ -11608,43 +11629,52 @@ void P_PlayerThink(player_t *player) if (player->exiting == 2 || countdown2 == 2) { - UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value); - if (numneeded) // Count to be sure everyone's exited + if (roaming) { - INT32 i, total = 0, exiting = 0; - - for (i = 0; i < MAXPLAYERS; i++) + G_PlayerFinishLevel(playeri); + G_SetNextMap(false, false); + P_RoamIntoWorld(player, nextmap+1); + } + else + { + UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value); + if (numneeded) // Count to be sure everyone's exited { - if (!playeringame[i] || players[i].spectator || players[i].bot) - continue; - if (players[i].quittime > 30 * TICRATE) - continue; - if (players[i].lives <= 0) - continue; + INT32 i, total = 0, exiting = 0; - total++; - if (players[i].exiting && players[i].exiting < 4) - exiting++; - } + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i] || players[i].spectator || players[i].bot) + continue; + if (players[i].quittime > 30 * TICRATE) + continue; + if (players[i].lives <= 0) + continue; + + total++; + if (players[i].exiting && players[i].exiting < 4) + exiting++; + } - if (!total || ((4*exiting)/total) >= numneeded) + if (!total || ((4*exiting)/total) >= numneeded) + { + if (server) + SendNetXCmd(XD_EXITLEVEL, NULL, 0); + } + else + player->exiting = 3; + } + else { if (server) SendNetXCmd(XD_EXITLEVEL, NULL, 0); } - else - player->exiting = 3; - } - else - { - if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); } } if (player->pflags & PF_FINISHED) { - if (((gametyperules & GTR_FRIENDLY) && cv_exitmove.value) && !G_EnoughPlayersFinished()) + if (((gametyperules & GTR_FRIENDLY) && cv_exitmove.value) && !G_EnoughPlayersFinished() && (!roaming)) player->exiting = 0; else P_DoPlayerExit(player); @@ -11699,12 +11729,7 @@ void P_PlayerThink(player_t *player) if (!player->exiting && !stoppedclock) { if (gametyperules & GTR_RACE) - { - if (leveltime >= 4*TICRATE) - player->realtime = leveltime - 4*TICRATE; - else - player->realtime = 0; - } + P_PlayerSetRaceRealTime(player); else player->realtime = leveltime; } diff --git a/src/p_world.c b/src/p_world.c index 074214282912d658eb97b41725976edd7db55f3d..cd58d4124723b038f3b92dcad66cfd3db07d58ca 100644 --- a/src/p_world.c +++ b/src/p_world.c @@ -38,6 +38,7 @@ #include "lua_hook.h" world_t *world = NULL; +world_t *baseworld = NULL; world_t *localworld = NULL; world_t *viewworld = NULL; @@ -66,13 +67,15 @@ world_t *P_InitNewWorld(void) worldlist[numworlds] = P_InitWorld(); w = worldlist[numworlds]; + if (!numworlds) + baseworld = w; + numworlds++; return w; } // // Sets the current world structures for physics simulation. -// (This was easier than referencing world-> in every part of gamelogic.) // void P_SetGameWorld(world_t *w) { @@ -120,26 +123,6 @@ void P_SetViewWorld(world_t *w) viewworld = w; } -// -// Sets a world as visited by a player. -// -void P_MarkWorldVisited(player_t *player, world_t *w) -{ - size_t playernum = (size_t)(player - players); - worldplayerinfo_t *playerinfo = &w->playerinfo[playernum]; - vector3_t *pos = &playerinfo->pos; - - if (!playeringame[playernum] || !player->mo || P_MobjWasRemoved(player->mo)) - return; - - pos->x = player->mo->x; - pos->y = player->mo->y; - pos->z = player->mo->z; - playerinfo->angle = player->mo->angle; - - playerinfo->visited = true; -} - // // Sets the current world. // @@ -150,10 +133,9 @@ void P_SetWorld(world_t *w) P_SetGameWorld(w); - thlist = world->thlist; + thlist = w->thlist; gamemap = w->gamemap; - - P_InitSpecials(); + gravity = w->gravity; } // @@ -183,21 +165,94 @@ void P_SwitchPlayerWorld(player_t *player, world_t *newworld) newworld->players++; } +// +// Loads a new world, or switches to one. +// +void P_RoamIntoWorld(player_t *player, INT32 mapnum) +{ + world_t *w = NULL; + INT32 i; + + for (i = 0; i < numworlds; i++) + { + if (worldlist[i]->gamemap == mapnum) + { + w = worldlist[i]; + break; + } + } + + if (w == player->world) + return; + else if (w) + P_SwitchWorld(player, w); + else + D_MapChange(mapnum, gametype, true, false, false, 0, false, false); +} + +boolean P_TransferCarriedPlayers(player_t *player, world_t *w) +{ + boolean anycarried = false; + INT32 i; + + // Lactozilla: Transfer carried players + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *carry; + + if (!playeringame[i]) + continue; + + carry = &players[i]; + if (carry == player) + continue; + + if (carry->powers[pw_carry] == CR_PLAYER + && carry->mo->tracer && !P_MobjWasRemoved(carry->mo->tracer) + && carry->mo->tracer == player->mo) + { + mobj_t *tails = player->mo; + + P_SwitchWorld(carry, w); + + tails->z += tails->height*3*P_MobjFlip(tails); + + // Set player position + P_UnsetThingPosition(carry->mo); + carry->mo->x = tails->x; + carry->mo->y = tails->y; + if (carry->mo->eflags & MFE_VERTICALFLIP) + carry->mo->z = tails->z + tails->height + 12*carry->mo->scale; + else + carry->mo->z = tails->z - carry->mo->height - 12*carry->mo->scale; + P_SetThingPosition(carry->mo); + + anycarried = true; + } + } + + return anycarried; +} + // // Switches a player to a world. // void P_SwitchWorld(player_t *player, world_t *w) { size_t playernum = (size_t)(player - players); - worldplayerinfo_t *playerinfo = &w->playerinfo[playernum]; + boolean local = ((INT32)playernum == consoleplayer); + boolean resetplayer = (player->powers[pw_carry] != CR_PLAYER); +#if 0 if (w == player->world) return; +#endif if (!playeringame[playernum] || !player->mo || P_MobjWasRemoved(player->mo)) return; - P_MarkWorldVisited(player, player->world); + if (player->world) + P_RemoveMobjConnections(player->mo, player->world); if (player->followmobj) { @@ -206,32 +261,38 @@ void P_SwitchWorld(player_t *player, world_t *w) } P_SwitchPlayerWorld(player, w); + if (!splitscreen) + { P_SetWorld(w); + if (local) + P_InitSpecials(); + } P_UnsetThingPosition(player->mo); P_MoveThinkerToWorld(w, THINK_MAIN, (thinker_t *)(player->mo)); + G_MovePlayerToSpawnOrStarpost(playernum); - if (playerinfo->visited) - { - vector3_t *pos = &playerinfo->pos; - P_TeleportMove(player->mo, pos->x, pos->y, pos->z); - P_SetPlayerAngle(player, playerinfo->angle); - } - else - G_MovePlayerToSpawnOrStarpost(playernum); - - P_MapEnd(); - - if ((INT32)playernum == consoleplayer) + if (local) { localworld = world; S_Start(); + if (!dedicated) + { + P_SetupSkyTexture(w->skynum); + R_SetupSkyDraw(); + } } - if (!dedicated) - R_SetupSkyDraw(world); - P_ResetCamera(player, &camera); + if (player == &players[displayplayer]) + P_ResetCamera(player, (splitscreen && playernum == 1) ? &camera2 : &camera); + + if (P_TransferCarriedPlayers(player, w)) + resetplayer = false; + + if (resetplayer) + P_ResetPlayer(player); + P_MapEnd(); } void Command_Switchworld_f(void) @@ -248,32 +309,27 @@ void Command_Switchworld_f(void) w = worldlist[worldnum]; CONS_Printf("Switching to world %d (%p)\n", worldnum, w); - P_SwitchWorld(&players[consoleplayer], w); + + if (netgame) + SendWorldSwitch(worldnum, false); + else + P_SwitchWorld(&players[consoleplayer], w); } void Command_Listworlds_f(void) { INT32 worldnum; world_t *w; - worldplayerinfo_t *playerinfo; for (worldnum = 0; worldnum < numworlds; worldnum++) { w = worldlist[worldnum]; - playerinfo = &w->playerinfo[consoleplayer]; CONS_Printf("World %d (%p)\n", worldnum, w); CONS_Printf("Gamemap: %d\n", w->gamemap); CONS_Printf("vt %d sg %d sc %d ss %d nd %d ld %d sd %d mt %d\n", w->numvertexes, w->numsegs, w->numsectors, w->numsubsectors, w->numnodes, w->numlines, w->numsides, w->nummapthings); - - CONS_Printf("Player has visited: %d\n", playerinfo->visited); CONS_Printf("Player count: %d\n", w->players); - CONS_Printf("Player position: %d %d %d %d\n", - playerinfo->pos.x>>FRACBITS, - playerinfo->pos.y>>FRACBITS, - playerinfo->pos.z>>FRACBITS, - AngleFixed(playerinfo->angle)>>FRACBITS); } } @@ -380,3 +436,31 @@ void P_UnloadWorldPlayer(player_t *player) P_SetTarget(&player->mo, NULL); } } + +boolean P_MobjIsConnected(mobj_t *mobj1, mobj_t *mobj2) +{ + return (mobj2 && !P_MobjWasRemoved(mobj2) && mobj1->world == mobj2->world); +} + +void P_RemoveMobjConnections(mobj_t *mobj, world_t *w) +{ + thinker_t *th; + mobj_t *check; + + for (th = w->thlist[THINK_MOBJ].next; th != &w->thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + + check = (mobj_t *)th; + + if (check->target == mobj) + P_SetTarget(&mobj->target, NULL); + if (check->tracer == mobj) + P_SetTarget(&mobj->tracer, NULL); + if (check->hnext == mobj) + P_SetTarget(&mobj->hnext, NULL); + if (check->hprev == mobj) + P_SetTarget(&mobj->hprev, NULL); + } +} diff --git a/src/p_world.h b/src/p_world.h index afe2a541e6fa33f588995d5e8bb2ac8569ef40b3..a5a8f2787a6e5b7c84dab2fcd9394068991f8fba 100644 --- a/src/p_world.h +++ b/src/p_world.h @@ -25,13 +25,6 @@ #define WAYPOINTSEQUENCESIZE 256 #define NUMWAYPOINTSEQUENCES 256 -typedef struct -{ - boolean visited; - vector3_t pos; - angle_t angle; -} worldplayerinfo_t; - // // Lactozilla: A "world" is the environment that players interact with. // A "map" is what defines how the world is built (what you edit in a level editor.) @@ -41,7 +34,6 @@ typedef struct typedef struct { INT32 gamemap; - worldplayerinfo_t playerinfo[MAXPLAYERS]; thinker_t *thlist; INT32 players; @@ -71,9 +63,10 @@ typedef struct mobj_t *overlaycap; - INT32 skytexture; // the lump number of the sky texture - INT32 skytexturemid; // the horizon line in a 256x128 sky texture - fixed_t skyscale; // the scale of the sky + fixed_t gravity; + + INT32 skynum; // used for keeping track of the current sky + UINT8 weather; // Needed to store the number of the dummy sky flat. // Used for rendering, as well as tracking projectiles etc. @@ -95,6 +88,10 @@ typedef struct mobj_t *waypoints[NUMWAYPOINTSEQUENCES][WAYPOINTSEQUENCESIZE]; UINT16 numwaypoints[NUMWAYPOINTSEQUENCES]; + mapthing_t *itemrespawnque[ITEMQUESIZE]; + tic_t itemrespawntime[ITEMQUESIZE]; + size_t iquehead, iquetail; + UINT8 *rejectmatrix; // for fast sight rejection INT32 *blockmaplump; // offsets in blockmap are from here INT32 *blockmap; // Big blockmap @@ -112,6 +109,7 @@ typedef struct } world_t; extern world_t *world; +extern world_t *baseworld; extern world_t *localworld; extern world_t *viewworld; @@ -129,15 +127,21 @@ void P_SetGameWorld(world_t *w); void P_SetViewWorld(world_t *w); void P_SetWorld(world_t *w); -void P_MarkWorldVisited(player_t *player, world_t *w); +void P_RoamIntoWorld(player_t *player, INT32 mapnum); void P_SwitchWorld(player_t *player, world_t *w); + void P_DetachPlayerWorld(player_t *player); void P_SwitchPlayerWorld(player_t *player, world_t *newworld); +boolean P_TransferCarriedPlayers(player_t *player, world_t *w); +boolean P_MobjIsConnected(mobj_t *mobj1, mobj_t *mobj2); +void P_RemoveMobjConnections(mobj_t *mobj, world_t *w); + void Command_Switchworld_f(void); void Command_Listworlds_f(void); +void P_SetupWorldSky(INT32 skynum, world_t *w); INT32 P_AddLevelFlatForWorld(world_t *w, const char *flatname); #endif diff --git a/src/r_data.c b/src/r_data.c index 698015cd53578d3543ede65144dca36098a178ee..b48888a1fe027f2a7ef0334692a295f1bc02659a 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -1772,9 +1772,6 @@ void R_ReInitColormaps(UINT16 num) if (fadecolormap) Z_Free(fadecolormap); R_CreateFadeColormaps(); - - // Init Boom colormaps. - R_ClearColormaps(); } // @@ -2694,7 +2691,7 @@ void R_PrecacheLevel(void) // Sky texture is always present. // Note that F_SKY1 is the name used to indicate a sky floor/ceiling as a flat, // while the sky texture is stored like a wall texture, with a skynum dependent name. - texturepresent[world->skytexture] = 1; + texturepresent[skytexture] = 1; texturememory = 0; for (j = 0; j < (unsigned)numtextures; j++) diff --git a/src/r_main.c b/src/r_main.c index 39e7529a43f19456d947dff3e9f96fa7e43728cb..ed45514ce44fff72e5ae7d725e7be046ed391550 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -927,11 +927,7 @@ void R_ExecuteSetViewSize(void) screenheightarray[i] = (INT16)viewheight; // setup sky scaling - for (i = 0; i < numworlds; i++) - { - if (worldlist[i]) - R_SetSkyScale(worldlist[i]); - } + R_SetSkyScale(); // planes if (rendermode == render_soft) @@ -1229,7 +1225,7 @@ void R_SkyboxFrame(player_t *player) thiscam = &camera; // cut-away view stuff - r_viewmobj = world->skyboxmo[0]; + r_viewmobj = viewworld->skyboxmo[0]; #ifdef PARANOIA if (!r_viewmobj) { @@ -1298,18 +1294,18 @@ void R_SkyboxFrame(player_t *player) campos.y += quake.y; campos.z += quake.z; - if (world->skyboxmo[1]) // Is there a viewpoint? + if (viewworld->skyboxmo[1]) // Is there a viewpoint? { fixed_t x = 0, y = 0; if (mh->skybox_scalex > 0) - x = (campos.x - world->skyboxmo[1]->x) / mh->skybox_scalex; + x = (campos.x - viewworld->skyboxmo[1]->x) / mh->skybox_scalex; else if (mh->skybox_scalex < 0) - x = (campos.x - world->skyboxmo[1]->x) * -mh->skybox_scalex; + x = (campos.x - viewworld->skyboxmo[1]->x) * -mh->skybox_scalex; if (mh->skybox_scaley > 0) - y = (campos.y - world->skyboxmo[1]->y) / mh->skybox_scaley; + y = (campos.y - viewworld->skyboxmo[1]->y) / mh->skybox_scaley; else if (mh->skybox_scaley < 0) - y = (campos.y - world->skyboxmo[1]->y) * -mh->skybox_scaley; + y = (campos.y - viewworld->skyboxmo[1]->y) * -mh->skybox_scaley; if (r_viewmobj->angle == 0) { @@ -1525,7 +1521,7 @@ void R_RenderPlayerView(player_t *player) // Add skybox portals caused by sky visplanes. - if (cv_skybox.value && world->skyboxmo[0]) + if (cv_skybox.value && viewworld->skyboxmo[0]) Portal_AddSkyboxPortals(); // Portal rendering. Hijacks the BSP traversal. diff --git a/src/r_plane.c b/src/r_plane.c index 4655500e385704103b70fb63b084b6fbf66d28dc..d7c861aa1fa73b7dd77fe401a02134a07401b74d 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -616,15 +616,15 @@ static void R_DrawSkyPlane(visplane_t *pl) colfunc = colfuncs[BASEDRAWFUNC]; // use correct aspect ratio scale - dc_iscale = world->skyscale; + dc_iscale = skyscale; // Sky is always drawn full bright, // i.e. colormaps[0] is used. // Because of this hack, sky is not affected // by sector colormaps (INVUL inverse mapping is not implemented in SRB2 so is irrelevant). dc_colormap = colormaps; - dc_texturemid = viewworld->skytexturemid; - dc_texheight = textureheight[viewworld->skytexture] + dc_texturemid = skytexturemid; + dc_texheight = textureheight[skytexture] >>FRACBITS; for (x = pl->minx; x <= pl->maxx; x++) { @@ -634,10 +634,10 @@ static void R_DrawSkyPlane(visplane_t *pl) if (dc_yl <= dc_yh) { angle = (pl->viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT; - dc_iscale = FixedMul(viewworld->skyscale, FINECOSINE(xtoviewangle[x]>>ANGLETOFINESHIFT)); + dc_iscale = FixedMul(skyscale, FINECOSINE(xtoviewangle[x]>>ANGLETOFINESHIFT)); dc_x = x; dc_source = - R_GetColumn(texturetranslation[viewworld->skytexture], + R_GetColumn(texturetranslation[skytexture], -angle); // get negative of angle for each column to display sky correct way round! --Monster Iestyn 27/01/18 colfunc(); } diff --git a/src/r_sky.c b/src/r_sky.c index 789882457cfb7aa3c302ec95ee314933db00bcc4..f559fbccb228cd2998fb78b3b9c8b5f20d88c594 100644 --- a/src/r_sky.c +++ b/src/r_sky.c @@ -31,7 +31,18 @@ /** \brief used for keeping track of the current sky */ INT32 levelskynum; -INT32 globallevelskynum; + +/** \brief the lump number of the sky texture +*/ +INT32 skytexture; + +/** \brief the horizon line in a 256x128 sky texture +*/ +INT32 skytexturemid; + +/** \brief the scale of the sky +*/ +fixed_t skyscale; /** \brief The R_SetupSkyDraw function @@ -42,11 +53,11 @@ INT32 globallevelskynum; \return void */ -void R_SetupSkyDraw(world_t *w) +void R_SetupSkyDraw(void) { // the horizon line in a 256x128 sky texture - w->skytexturemid = (textures[world->skytexture]->height/2)<<FRACBITS; - R_SetSkyScale(w); + skytexturemid = (textures[skytexture]->height/2)<<FRACBITS; + R_SetSkyScale(); } /** \brief The R_SetSkyScale function @@ -55,8 +66,8 @@ void R_SetupSkyDraw(world_t *w) \return void */ -void R_SetSkyScale(world_t *w) +void R_SetSkyScale(void) { fixed_t difference = vid.fdupx-(vid.dupx<<FRACBITS); - w->skyscale = FixedDiv(fovtan, vid.fdupx+difference); + skyscale = FixedDiv(fovtan, vid.fdupx+difference); } diff --git a/src/r_sky.h b/src/r_sky.h index ab3923d91625b4b78762abb9d20a722238dad2f0..b74d9257dd2f2b0a6276ea5fd67bb0cd8ba06c3f 100644 --- a/src/r_sky.h +++ b/src/r_sky.h @@ -27,11 +27,13 @@ /// \brief The sky map is 256*128*4 maps. #define ANGLETOSKYSHIFT 22 +extern INT32 skytexture, skytexturemid; +extern fixed_t skyscale; + extern INT32 levelskynum; -extern INT32 globallevelskynum; // call after skytexture is set to adapt for old/new skies -void R_SetupSkyDraw(world_t *w); -void R_SetSkyScale(world_t *w); +void R_SetupSkyDraw(void); +void R_SetSkyScale(void); #endif