From e9b67ff184d5b40cccbe11df2198a15d1b56bade Mon Sep 17 00:00:00 2001 From: danij Date: Thu, 12 Jul 2012 18:29:28 +0100 Subject: [PATCH] libcommon|Refactor: Began commonizing G_DoWorldDone() --- doomsday/plugins/common/include/p_actor.h | 11 + doomsday/plugins/common/include/p_map.h | 2 + doomsday/plugins/common/include/p_saveg.h | 17 +- doomsday/plugins/common/src/g_game.c | 91 +++++++- doomsday/plugins/common/src/p_actor.c | 22 +- doomsday/plugins/common/src/p_map.c | 13 ++ doomsday/plugins/common/src/p_saveg.c | 265 ++++++++++------------ doomsday/plugins/jdoom/include/p_local.h | 1 - 8 files changed, 257 insertions(+), 165 deletions(-) diff --git a/doomsday/plugins/common/include/p_actor.h b/doomsday/plugins/common/include/p_actor.h index a26d4afb31..8abc6612a9 100644 --- a/doomsday/plugins/common/include/p_actor.h +++ b/doomsday/plugins/common/include/p_actor.h @@ -29,8 +29,19 @@ #ifndef LIBCOMMON_P_ACTOR_H #define LIBCOMMON_P_ACTOR_H +/** + * Removes the given mobj from the world. + * + * @param mo The mobj to be removed. + * @param noRespawn Disable the automatical respawn which occurs + * with mobjs of certain type(s) (also dependant on + * the current gamemode). + * Generally this should be @c false. + */ void P_MobjRemove(mobj_t* mo, boolean noRespawn); +void P_RemoveAllPlayerMobjs(void); + void P_MobjUnsetOrigin(mobj_t* mo); void P_MobjSetOrigin(mobj_t* mo); diff --git a/doomsday/plugins/common/include/p_map.h b/doomsday/plugins/common/include/p_map.h index 1e6f430ed5..fe0a7c657d 100644 --- a/doomsday/plugins/common/include/p_map.h +++ b/doomsday/plugins/common/include/p_map.h @@ -72,6 +72,8 @@ boolean P_TryMoveXY(mobj_t* thing, coord_t x, coord_t y); boolean P_TeleportMove(mobj_t* thing, coord_t x, coord_t y, boolean alwaysStomp); +void P_TelefragMobjsTouchingPlayers(void); + void P_SlideMove(mobj_t* mo); void P_UseLines(player_t* player); diff --git a/doomsday/plugins/common/include/p_saveg.h b/doomsday/plugins/common/include/p_saveg.h index 7ab8e6716c..e9b5d6579f 100644 --- a/doomsday/plugins/common/include/p_saveg.h +++ b/doomsday/plugins/common/include/p_saveg.h @@ -143,7 +143,22 @@ boolean SV_LoadGame(int slot); #if __JHEXEN__ void SV_HxInitBaseSlot(void); -void SV_HxMapTeleport(uint map, uint position); +void SV_HxSaveClusterMap(void); +void SV_HxLoadClusterMap(void); + +typedef struct { + player_t player; + uint numInventoryItems[NUM_INVENTORYITEM_TYPES]; + inventoryitemtype_t readyItem; +} playerbackup_t; + +void SV_HxBackupPlayersInCluster(playerbackup_t playerBackup[MAXPLAYERS]); + +/** + * @param playerBackup Player state backup. + * @param entryPoint Logical identifier for the entry point used to enter the map. + */ +void SV_HxRestorePlayersInCluster(playerbackup_t playerBackup[MAXPLAYERS], uint entryPoint); #endif #if !__JHEXEN__ diff --git a/doomsday/plugins/common/src/g_game.c b/doomsday/plugins/common/src/g_game.c index 26bc8cfbb3..04fbb7c745 100644 --- a/doomsday/plugins/common/src/g_game.c +++ b/doomsday/plugins/common/src/g_game.c @@ -73,6 +73,7 @@ #include "x_hair.h" #include "p_player.h" #include "r_common.h" +#include "p_map.h" #include "p_mapspec.h" #include "p_start.h" #include "p_inventory.h" @@ -1291,12 +1292,13 @@ static void initFogForMap(ddmapinfo_t* mapInfo) #endif } -static int G_LoadMapWorker(void* params) +static int G_LoadMap(loadmap_params_t* p) { - loadmap_params_t* p = (loadmap_params_t*) params; boolean hasMapInfo = false; ddmapinfo_t mapInfo; + DENG_ASSERT(p); + // Is MapInfo data available for this map? { ddstring_t* mapUriStr = Uri_Compose(p->mapUri); if(mapUriStr) @@ -1307,18 +1309,21 @@ static int G_LoadMapWorker(void* params) P_SetupMap(p->mapUri, p->episode, p->map); initFogForMap(hasMapInfo? &mapInfo : 0); - - BusyMode_WorkerEnd(); /// @todo Fixme: Do not assume! return 0; // Assume success. } -void G_DoLoadMap(loadmap_params_t* p) +static int G_LoadMapWorker(void* params) { - DENG_ASSERT(p); - - G_LoadMapWorker(p); + loadmap_params_t* p = (loadmap_params_t*) params; + int result = G_LoadMap(p); + BusyMode_WorkerEnd(); + return result; +} +void G_DoLoadMap(loadmap_params_t* p) +{ + G_LoadMap(p); // Wrap up, map loading is now complete. G_SetGameAction(GA_NONE); } @@ -1334,7 +1339,6 @@ int G_DoLoadMapAndMaybeStartBriefing(void* parameters) hasBrief = G_BriefingEnabled(p->episode, p->map, &fin); G_LoadMapWorker(p); - // Wrap up, map loading is now complete. G_SetGameAction(GA_NONE); @@ -2482,11 +2486,76 @@ static int G_SaveStateWorker(void* parameters) return result; } +#if __JHEXEN__ +static void mapTeleport(uint map, uint entryPoint) +{ + playerbackup_t playerBackup[MAXPLAYERS]; + boolean revisit; + boolean oldRandomClassParm; + + /** + * First, determine whether we've been to this map previously and if so, + * whether we need to load the archived map state. + */ + revisit = SV_HxHaveMapSaveForSlot(BASE_SLOT, map+1); + if(deathmatch) revisit = false; + + if(!deathmatch) + { + if(P_GetMapCluster(gameMap) == P_GetMapCluster(map)) + { + // Same cluster; save current map. + SV_HxSaveClusterMap(); + } + else + { + // Entering new cluster - clear base slot. + SV_ClearSlot(BASE_SLOT); + } + } + + // Take a copy of the player objects (they will be cleared in the process + // of calling G_InitNew() and we need to restore them after). + SV_HxBackupPlayersInCluster(playerBackup); + + // Disable class randomization (all players must spawn as their existing class). + oldRandomClassParm = randomClassParm; + randomClassParm = false; + + // We don't want to see a briefing if we've already visited this map. + if(revisit) briefDisabled = true; + + G_InitNew(gameSkill, gameEpisode, map); + + if(revisit) + { + SV_HxLoadClusterMap(); + } + else // First visit. + { + // Destroy all freshly spawned players. + P_RemoveAllPlayerMobjs(); + } + + SV_HxRestorePlayersInCluster(playerBackup, entryPoint); + + // Restore the random class option. + randomClassParm = oldRandomClassParm; + + // Launch waiting scripts. + if(!deathmatch) + { + P_CheckACSStore(gameMap); + } + + rebornPosition = entryPoint; +} +#endif + void G_DoWorldDone(void) { #if __JHEXEN__ - SV_HxMapTeleport(nextMap, nextMapEntryPoint); - rebornPosition = nextMapEntryPoint; + mapTeleport(nextMap, nextMapEntryPoint); #else loadmap_params_t p; boolean hasBrief; diff --git a/doomsday/plugins/common/src/p_actor.c b/doomsday/plugins/common/src/p_actor.c index 760488a9ec..a4eeb32f48 100644 --- a/doomsday/plugins/common/src/p_actor.c +++ b/doomsday/plugins/common/src/p_actor.c @@ -107,15 +107,6 @@ void P_SpawnTelefog(mobj_t* mo, void* context) # endif } -/** - * Removes the given mobj from the world. - * - * @param mo The mobj to be removed. - * @param noRespawn Disable the automatical respawn which occurs - * with mobjs of certain type(s) (also dependant on - * the current gamemode). - * Generally this should be @c false. - */ void P_MobjRemove(mobj_t* mo, boolean noRespawn) { if(mo->ddFlags & DDMF_REMOTE) goto justDoIt; @@ -157,6 +148,19 @@ void P_MobjRemove(mobj_t* mo, boolean noRespawn) P_MobjDestroy(mo); } +void P_RemoveAllPlayerMobjs(void) +{ + uint i; + for(i = 0; i < MAXPLAYERS; ++i) + { + player_t* plr = players + i; + ddplayer_t* ddplr = plr->plr; + if(!ddplr->inGame) continue; + + P_MobjRemove(ddplr->mo, true); + } +} + /** * Called after a move to link the mobj back into the world. */ diff --git a/doomsday/plugins/common/src/p_map.c b/doomsday/plugins/common/src/p_map.c index 37ac61be67..37db109ce0 100644 --- a/doomsday/plugins/common/src/p_map.c +++ b/doomsday/plugins/common/src/p_map.c @@ -350,6 +350,19 @@ boolean P_TeleportMove(mobj_t* thing, coord_t x, coord_t y, boolean alwaysStomp) return true; } +void P_TelefragMobjsTouchingPlayers(void) +{ + uint i; + for(i = 0; i < MAXPLAYERS; ++i) + { + player_t* plr = players + i; + ddplayer_t* ddplr = plr->plr; + if(!ddplr->inGame) continue; + + P_TeleportMove(ddplr->mo, ddplr->mo->origin[VX], ddplr->mo->origin[VY], true); + } +} + /** * Checks to see if a start->end trajectory line crosses a blocking line. * Returns false if it does. diff --git a/doomsday/plugins/common/src/p_saveg.c b/doomsday/plugins/common/src/p_saveg.c index baec09f642..f07c2b324b 100644 --- a/doomsday/plugins/common/src/p_saveg.c +++ b/doomsday/plugins/common/src/p_saveg.c @@ -5530,166 +5530,145 @@ boolean SV_SaveGame(int slot, const char* name) } #if __JHEXEN__ -void SV_HxMapTeleport(uint map, uint position) +void SV_HxSaveClusterMap(void) { - int i, oldKeys = 0, oldPieces = 0, bestWeapon; - player_t playerBackup[MAXPLAYERS]; - uint numInventoryItems[MAXPLAYERS][NUM_INVENTORYITEM_TYPES]; - inventoryitemtype_t readyItem[MAXPLAYERS]; - mobj_t* targetPlayerMobj; - boolean rClass, playerWasReborn, revisit; - boolean oldWeaponOwned[NUM_WEAPON_TYPES]; + AutoStr* mapFilePath; - errorIfNotInited("SV_MapTeleport"); + errorIfNotInited("SV_HxSaveClusterMap"); playerHeaderOK = false; // Uninitialized. - /** - * First, determine whether we've been to this map previously and if so, - * whether we need to load the archived map state. - */ - if(!deathmatch && SV_HxHaveMapSaveForSlot(BASE_SLOT, map+1)) - revisit = true; - else - revisit = false; + // Set the mobj archive numbers + SV_InitThingArchive(false, false); - if(!deathmatch) - { - if(P_GetMapCluster(gameMap) == P_GetMapCluster(map)) - { - /** - * Same cluster - save current map without saving player mobjs. - */ - // Compose the full path name to the saved map file. - AutoStr* mapFilePath = SV_ComposeSavePathForMapSlot(gameMap+1, BASE_SLOT); - - // Set the mobj archive numbers - SV_InitThingArchive(false, false); + // Create and populate the MaterialArchive. + materialArchive = MaterialArchive_New(true); - // Create and populate the MaterialArchive. - materialArchive = MaterialArchive_New(true); + // Compose the full path name to the saved map file. + mapFilePath = SV_ComposeSavePathForMapSlot(gameMap+1, BASE_SLOT); + SV_OpenFile(Str_Text(mapFilePath), "wp"); + P_ArchiveMap(false); - SV_OpenFile(Str_Text(mapFilePath), "wp"); - P_ArchiveMap(false); + // We are done with the MaterialArchive. + MaterialArchive_Delete(materialArchive); + materialArchive = NULL; - // We are done with the MaterialArchive. - MaterialArchive_Delete(materialArchive); - materialArchive = NULL; + // Close the output file + SV_CloseFile(); +} - // Close the output file - SV_CloseFile(); - } - else - { - // Entering new cluster - clear base slot - SV_ClearSlot(BASE_SLOT); - } - } +void SV_HxLoadClusterMap(void) +{ + // Only unarchiveMap() uses targetPlayerAddrs, so it's NULLed here for the + // following check (player mobj redirection). + targetPlayerAddrs = NULL; - // Store player structs for later - rClass = randomClassParm; - randomClassParm = false; - for(i = 0; i < MAXPLAYERS; ++i) - { - uint j; + playerHeaderOK = false; // Uninitialized. - memcpy(&playerBackup[i], &players[i], sizeof(player_t)); + // Been here before, load the previous map state. + // Create the MaterialArchive. + materialArchive = MaterialArchive_NewEmpty(true); - for(j = 0; j < NUM_INVENTORYITEM_TYPES; ++j) - numInventoryItems[i][j] = P_InventoryCount(i, j); - readyItem[i] = P_InventoryReadyItem(i); - } + unarchiveMap(); - // Only unarchiveMap() uses targetPlayerAddrs, so it's NULLed here - // for the following check (player mobj redirection) - targetPlayerAddrs = NULL; + // We are done with the MaterialArchive. + MaterialArchive_Delete(materialArchive); + materialArchive = NULL; +} - // We don't want to see a briefing if we're loading a save game. - if(revisit) - briefDisabled = true; +void SV_HxBackupPlayersInCluster(playerbackup_t playerBackup[MAXPLAYERS]) +{ + uint i; - G_InitNew(gameSkill, gameEpisode, map); + DENG_ASSERT(playerBackup); - if(revisit) - { // Been here before, load the previous map state. - // Create the MaterialArchive. - materialArchive = MaterialArchive_NewEmpty(true); + for(i = 0; i < MAXPLAYERS; ++i) + { + playerbackup_t* pb = playerBackup + i; + player_t* plr = players + i; + uint j; - unarchiveMap(); + memcpy(&pb->player, plr, sizeof(player_t)); - // We are done with the MaterialArchive. - MaterialArchive_Delete(materialArchive); - materialArchive = NULL; - } - else - { // First visit. - // Destroy all freshly spawned players - for(i = 0; i < MAXPLAYERS; ++i) + // Make a copy of the inventory states also. + for(j = 0; j < NUM_INVENTORYITEM_TYPES; ++j) { - if(players[i].plr->inGame) - { - P_MobjRemove(players[i].plr->mo, true); - } + pb->numInventoryItems[j] = P_InventoryCount(i, j); } + pb->readyItem = P_InventoryReadyItem(i); } +} + +void SV_HxRestorePlayersInCluster(playerbackup_t playerBackup[MAXPLAYERS], + uint entryPoint) +{ + uint i, j, k; + mobj_t* targetPlayerMobj; + + DENG_ASSERT(playerBackup); - // Restore player structs. - targetPlayerMobj = NULL; for(i = 0; i < MAXPLAYERS; ++i) { - uint j; + playerbackup_t* pb = playerBackup + i; + player_t* plr = players + i; + ddplayer_t* ddplr = plr->plr; + int oldKeys = 0, oldPieces = 0; + boolean oldWeaponOwned[NUM_WEAPON_TYPES]; + boolean wasReborn; - if(!players[i].plr->inGame) - { - continue; - } + if(!ddplr->inGame) continue; - memcpy(&players[i], &playerBackup[i], sizeof(player_t)); + memcpy(plr, &pb->player, sizeof(player_t)); for(j = 0; j < NUM_INVENTORYITEM_TYPES; ++j) { - uint k; - // Don't give back the wings of wrath if reborn. - if(j == IIT_FLY && players[i].playerState == PST_REBORN) + if(j == IIT_FLY && plr->playerState == PST_REBORN) continue; - for(k = 0; k < numInventoryItems[i][j]; ++k) + for(k = 0; k < pb->numInventoryItems[j]; ++k) + { P_InventoryGive(i, j, true); + } } - P_InventorySetReadyItem(i, readyItem[i]); + P_InventorySetReadyItem(i, pb->readyItem); ST_LogEmpty(i); - players[i].attacker = NULL; - players[i].poisoner = NULL; + plr->attacker = NULL; + plr->poisoner = NULL; if(IS_NETGAME || deathmatch) { - if(players[i].playerState == PST_DEAD) - { // In a network game, force all players to be alive - players[i].playerState = PST_REBORN; + // In a network game, force all players to be alive + if(plr->playerState == PST_DEAD) + { + plr->playerState = PST_REBORN; } + if(!deathmatch) - { // Cooperative net-play, retain keys and weapons - oldKeys = players[i].keys; - oldPieces = players[i].pieces; + { + // Cooperative net-play; retain keys and weapons. + oldKeys = plr->keys; + oldPieces = plr->pieces; for(j = 0; j < NUM_WEAPON_TYPES; j++) { - oldWeaponOwned[j] = players[i].weapons[j].owned; + oldWeaponOwned[j] = plr->weapons[j].owned; } } } - playerWasReborn = (players[i].playerState == PST_REBORN); + + wasReborn = (plr->playerState == PST_REBORN); + if(deathmatch) { - memset(players[i].frags, 0, sizeof(players[i].frags)); - players[i].plr->mo = NULL; + memset(plr->frags, 0, sizeof(plr->frags)); + ddplr->mo = NULL; G_DeathMatchSpawnPlayer(i); } else { const playerstart_t* start; - if((start = P_GetPlayerStart(position, i, false))) + if((start = P_GetPlayerStart(entryPoint, i, false))) { const mapspot_t* spot = &mapSpots[start->spot]; P_SpawnPlayer(i, cfg.playerClass[i], spot->origin[VX], @@ -5703,69 +5682,69 @@ void SV_HxMapTeleport(uint map, uint position) } } - if(playerWasReborn && IS_NETGAME && !deathmatch) + if(wasReborn && IS_NETGAME && !deathmatch) { - // Restore keys and weapons when reborn in co-op - players[i].keys = oldKeys; - players[i].pieces = oldPieces; + int bestWeapon; + + // Restore keys and weapons when reborn in co-op. + plr->keys = oldKeys; + plr->pieces = oldPieces; + for(bestWeapon = 0, j = 0; j < NUM_WEAPON_TYPES; ++j) { if(oldWeaponOwned[j]) { bestWeapon = j; - players[i].weapons[j].owned = true; + plr->weapons[j].owned = true; } } - players[i].ammo[AT_BLUEMANA].owned = 25; //// @todo values.ded - players[i].ammo[AT_GREENMANA].owned = 25; //// @todo values.ded + + plr->ammo[AT_BLUEMANA].owned = 25; /// @todo values.ded + plr->ammo[AT_GREENMANA].owned = 25; /// @todo values.ded + + // Bring up the best weapon. if(bestWeapon) - { // Bring up the best weapon - players[i].pendingWeapon = bestWeapon; + { + plr->pendingWeapon = bestWeapon; } } + } - if(targetPlayerMobj == NULL) - { // The poor sap. - targetPlayerMobj = players[i].plr->mo; + targetPlayerMobj = NULL; + { uint i; + for(i = 0; i < MAXPLAYERS; ++i) + { + player_t* plr = players + i; + ddplayer_t* ddplr = plr->plr; + + if(!ddplr->inGame) continue; + + if(!targetPlayerMobj) + { + targetPlayerMobj = ddplr->mo; } - } - randomClassParm = rClass; + }} - //// @todo Redirect anything targeting a player mobj - //// FIXME! This only supports single player games!! + /// @todo Redirect anything targeting a player mobj + /// FIXME! This only supports single player games!! if(targetPlayerAddrs) { - targetplraddress_t *p; + targetplraddress_t* p; - p = targetPlayerAddrs; - while(p != NULL) + for(p = targetPlayerAddrs; p; p = p->next) { *(p->address) = targetPlayerMobj; - p = p->next; } SV_FreeTargetPlayerList(); - /* dj: - When XG is available in jHexen, call this after updating - target player references (after a load). + /* dj: - When XG is available in Hexen, call this after updating + target player references (after a load). // The activator mobjs must be set. XL_UpdateActivators(); */ } - // Destroy all things touching players - for(i = 0; i < MAXPLAYERS; ++i) - { - if(players[i].plr->inGame) - { - P_TeleportMove(players[i].plr->mo, players[i].plr->mo->origin[VX], - players[i].plr->mo->origin[VY], true); - } - } - - // Launch waiting scripts - if(!deathmatch) - { - P_CheckACSStore(gameMap); - } + // Destroy all things touching players. + P_TelefragMobjsTouchingPlayers(); } #endif diff --git a/doomsday/plugins/jdoom/include/p_local.h b/doomsday/plugins/jdoom/include/p_local.h index 86de8ab41f..0e5de4753e 100644 --- a/doomsday/plugins/jdoom/include/p_local.h +++ b/doomsday/plugins/jdoom/include/p_local.h @@ -86,7 +86,6 @@ void P_MovePsprites(player_t* plr); void P_DropWeapon(player_t* plr); void P_SetPsprite(player_t* plr, int position, statenum_t stnum); -void P_MobjRemove(mobj_t* mo, boolean noRespawn); boolean P_MobjChangeState(mobj_t* mo, statenum_t state); void P_MobjThinker(mobj_t* mo); void P_RipperBlood(mobj_t* mo);