Skip to content

Commit

Permalink
libcommon: Ensure game rule changes are fully applied when staring a …
Browse files Browse the repository at this point in the history
…new game
  • Loading branch information
danij-deng committed Feb 4, 2014
1 parent aea3395 commit 638f51d
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 116 deletions.
6 changes: 4 additions & 2 deletions doomsday/plugins/common/include/g_common.h
Expand Up @@ -69,11 +69,13 @@ void G_EndGame(void);
dd_bool G_QuitInProgress(void);

/**
* @param episode Logical episode number.
* @param map Logical map number (i.e., not a warp/translated number).
* @param mapEntrance Logical map entry point number.
* @param rules Game rules to apply.
*/
void G_NewGame(skillmode_t skill, uint episode, uint map, uint mapEntrance);
void G_DeferredNewGame(skillmode_t skill, uint episode, uint map, uint mapEntrance);
void G_NewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rules);
void G_DeferredNewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rules);

/**
* Signal that play on the current map may now begin.
Expand Down
5 changes: 4 additions & 1 deletion doomsday/plugins/common/src/d_net.c
Expand Up @@ -127,6 +127,7 @@ void NetSv_ApplyGameRulesFromConfig(void)
int D_NetServerStarted(int before)
{
uint netMap, netEpisode;
GameRuleset netRules = gameRules; // Make a copy of the current rules.

if(before) return true;

Expand Down Expand Up @@ -156,7 +157,9 @@ int D_NetServerStarted(int before)
netEpisode = cfg.netEpisode;
#endif

G_NewGame(cfg.netSkill, netEpisode, netMap, 0/*default*/);
netRules.skill = cfg.netSkill;

G_NewGame(netEpisode, netMap, 0/*default*/, &netRules);

/// @todo Necessary?
G_SetGameAction(GA_NONE);
Expand Down
58 changes: 26 additions & 32 deletions doomsday/plugins/common/src/d_netcl.c
Expand Up @@ -47,12 +47,13 @@ void NetCl_UpdateGameState(Reader* msg)
byte gsMap = 0;
byte gsMapEntrance = 0;
byte configFlags = 0;
byte gsDeathmatch = 0;
byte gsMonsters = 0;
byte gsRespawn = 0;
//byte gsDeathmatch = 0;
//byte gsMonsters = 0;
//byte gsRespawn = 0;
byte gsJumping = 0;
byte gsSkill = 0;
//byte gsSkill = 0;
coord_t gsGravity = 0;
GameRuleset gsRules = gameRules; // Make a copy of the current rules.

BusyMode_FreezeGameForBusyMode();

Expand All @@ -73,15 +74,17 @@ void NetCl_UpdateGameState(Reader* msg)
//gsMapEntryPoint = ??;

configFlags = Reader_ReadByte(msg);
gsDeathmatch = configFlags & 0x3;
gsMonsters = (configFlags & 0x4? true : false);
gsRespawn = (configFlags & 0x8? true : false);
gsRules.deathmatch = configFlags & 0x3;
gsRules.noMonsters = !(configFlags & 0x4? true : false);
#if !__JHEXEN__
gsRules.respawnMonsters = (configFlags & 0x8? true : false);
#endif
gsJumping = (configFlags & 0x10? true : false);
gsSkill = Reader_ReadByte(msg);
gsRules.skill = Reader_ReadByte(msg);

// Interpret skill modes outside the normal range as "spawn no things".
if(gsSkill < SM_BABY || gsSkill >= NUM_SKILL_MODES)
gsSkill = SM_NOTHINGS;
if(gsRules.skill < SM_BABY || gsRules.skill >= NUM_SKILL_MODES)
gsRules.skill = SM_NOTHINGS;

gsGravity = Reader_ReadFloat(msg);

Expand Down Expand Up @@ -109,39 +112,33 @@ void NetCl_UpdateGameState(Reader* msg)
}
}

gameRules.deathmatch = gsDeathmatch;
gameRules.noMonsters = !gsMonsters;
#if !__JHEXEN__
gameRules.respawnMonsters = gsRespawn;
#endif

// Some statistics.
#if __JHEXEN__
App_Log(DE2_LOG_NOTE,
"Game state: Map=%u Skill=%i %s", gsMap+1, gsSkill,
gameRules.deathmatch == 1 ? "Deathmatch" :
gameRules.deathmatch == 2 ? "Deathmatch2" : "Co-op");
"Game state: Map=%u Skill=%i %s", gsMap+1, gsRules.skill,
gsRules.deathmatch == 1 ? "Deathmatch" :
gsRules.deathmatch == 2 ? "Deathmatch2" : "Co-op");
#else
App_Log(DE2_LOG_NOTE,
"Game state: Map=%u Episode=%u Skill=%i %s", gsMap+1,
gsEpisode+1, gsSkill,
gameRules.deathmatch == 1 ? "Deathmatch" :
gameRules.deathmatch == 2 ? "Deathmatch2" : "Co-op");
gsEpisode+1, gsRules.skill,
gsRules.deathmatch == 1 ? "Deathmatch" :
gsRules.deathmatch == 2 ? "Deathmatch2" : "Co-op");
#endif
#if !__JHEXEN__
App_Log(DE2_LOG_NOTE, " Respawn=%s Monsters=%s Jumping=%s Gravity=%.1f",
gameRules.respawnMonsters ? "yes" : "no", !gameRules.noMonsters ? "yes" : "no",
gsRules.respawnMonsters ? "yes" : "no", !gsRules.noMonsters ? "yes" : "no",
gsJumping ? "yes" : "no", gsGravity);
#else
App_Log(DE2_NET_NOTE, " Monsters=%s Jumping=%s Gravity=%.1f",
!gameRules.noMonsters ? "yes" : "no",
!gsRules.noMonsters ? "yes" : "no",
gsJumping ? "yes" : "no", gsGravity);
#endif

// Do we need to change the map?
if(gsFlags & GSF_CHANGE_MAP)
{
G_NewGame(gsSkill, gsEpisode, gsMap, gameMapEntrance /*gsMapEntrance*/);
G_NewGame(gsEpisode, gsMap, gameMapEntrance /*gsMapEntrance*/, &gsRules);

/// @todo Necessary?
G_SetGameAction(GA_NONE);
Expand All @@ -150,11 +147,8 @@ void NetCl_UpdateGameState(Reader* msg)
{
gameEpisode = gsEpisode;
gameMap = gsMap;

gameRules.skill = gsSkill;

/// @todo Not communicated to clients??
//gameMapEntrance = gsMapEntrance;
//gameMapEntrance = gsMapEntrance; /// @todo Not communicated to clients??
gameRules = gsRules;
}

// Set gravity.
Expand All @@ -164,8 +158,8 @@ void NetCl_UpdateGameState(Reader* msg)
// Camera init included?
if(gsFlags & GSF_CAMERA_INIT)
{
player_t* pl = &players[CONSOLEPLAYER];
mobj_t* mo;
player_t *pl = &players[CONSOLEPLAYER];
mobj_t *mo;

mo = pl->plr->mo;
if(mo)
Expand Down
43 changes: 24 additions & 19 deletions doomsday/plugins/common/src/g_game.c
Expand Up @@ -402,10 +402,10 @@ ccmdtemplate_t gameCmds[] = {
};

// Deferred new game arguments:
static skillmode_t dSkill;
static uint dEpisode;
static uint dMap;
static uint dMapEntrance;
static GameRuleset dRules;

static gameaction_t gameAction;
static dd_bool quitInProgress;
Expand Down Expand Up @@ -1545,7 +1545,7 @@ static void runGameAction(void)
{
case GA_NEWGAME:
G_InitNewGame();
G_NewGame(dSkill, dEpisode, dMap, dMapEntrance);
G_NewGame(dEpisode, dMap, dMapEntrance, &dRules);
G_SetGameAction(GA_NONE);
break;

Expand Down Expand Up @@ -2220,13 +2220,16 @@ static void G_ApplyGameRuleFastMissiles(dd_bool fast)
}
#endif

static void G_ApplyGameRules(skillmode_t skill)
/**
* To be called when a new game begins to effect the game rules. Note that some
* of the rules may be overridden here (e.g., in a networked game).
*/
static void G_ApplyNewGameRules()
{
if(skill < SM_NOTHINGS)
skill = SM_NOTHINGS;
if(skill > NUM_SKILL_MODES - 1)
skill = NUM_SKILL_MODES - 1;
gameRules.skill = skill;
if(gameRules.skill < SM_NOTHINGS)
gameRules.skill = SM_NOTHINGS;
if(gameRules.skill > NUM_SKILL_MODES - 1)
gameRules.skill = NUM_SKILL_MODES - 1;

#if __JDOOM__ || __JHERETIC__ || __JDOOM64__
if(!IS_NETGAME)
Expand Down Expand Up @@ -2625,10 +2628,6 @@ void G_DoLeaveMap(void)
{
SV_ClearSlot(BASE_SLOT);
}

// Re-apply the game rules.
/// @todo Necessary?
G_ApplyGameRules(gameRules.skill);
}

Uri_Delete(nextMapUri);
Expand Down Expand Up @@ -2746,7 +2745,7 @@ void G_DoRestartMap(void)

// Restart the game session entirely.
G_InitNewGame();
G_NewGame(dSkill, dEpisode, dMap, dMapEntrance);
G_NewGame(dEpisode, dMap, dMapEntrance, &dRules);
#else
loadmap_params_t p;

Expand Down Expand Up @@ -2957,20 +2956,24 @@ void G_DoSaveGame(void)
G_SetGameAction(GA_NONE);
}

void G_DeferredNewGame(skillmode_t skill, uint episode, uint map, uint mapEntrance)
void G_DeferredNewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rules)
{
dSkill = skill;
DENG_ASSERT(rules != 0);

dEpisode = episode;
dMap = map;
dMapEntrance = mapEntrance;
dRules = *rules; // make a copy.

G_SetGameAction(GA_NEWGAME);
}

void G_NewGame(skillmode_t skill, uint episode, uint map, uint mapEntrance)
void G_NewGame(uint episode, uint map, uint mapEntrance, GameRuleset const *rules)
{
uint i;

DENG_ASSERT(rules != 0);

G_StopDemo();

// Clear the menu if open.
Expand Down Expand Up @@ -3017,8 +3020,10 @@ void G_NewGame(skillmode_t skill, uint episode, uint map, uint mapEntrance)
gameEpisode = episode;
gameMap = map;
gameMapEntrance = mapEntrance;
gameRules = *rules;

G_ApplyNewGameRules();

G_ApplyGameRules(skill);
M_ResetRandom();

NetSv_UpdateGameConfigDescription();
Expand Down Expand Up @@ -4001,12 +4006,12 @@ D_CMD(WarpMap)
nextMapEntrance = 0;
G_SetGameAction(GA_LEAVEMAP);
#else
G_DeferredNewGame(gameRules.skill, epsd, map, 0/*default*/);
G_DeferredNewGame(epsd, map, 0/*default*/, &gameRules);
#endif
}
else
{
G_DeferredNewGame(IS_SERVER? cfg.netSkill : gameRules.skill, epsd, map, 0/*default*/);
G_DeferredNewGame(epsd, map, 0/*default*/, &gameRules);
}

// If the command source was "us" the game library then it was probably in
Expand Down
7 changes: 5 additions & 2 deletions doomsday/plugins/common/src/hu_menu.c
Expand Up @@ -6441,6 +6441,8 @@ int Hu_MenuConfirmInitNewGame(msgresponse_t response, int userValue, void* userP

void Hu_MenuInitNewGame(dd_bool confirmed)
{
GameRuleset newRules = gameRules;

#if __JDOOM__
if(!confirmed && SM_NIGHTMARE == mnSkillmode)
{
Expand All @@ -6455,10 +6457,11 @@ void Hu_MenuInitNewGame(dd_bool confirmed)
cfg.playerClass[CONSOLEPLAYER] = mnPlrClass;
#endif

newRules.skill = mnSkillmode;
#if __JHEXEN__
G_DeferredNewGame(mnSkillmode, mnEpisode, P_TranslateMap(0), 0/*default*/);
G_DeferredNewGame(mnEpisode, P_TranslateMap(0), 0/*default*/, &newRules);
#else
G_DeferredNewGame(mnSkillmode, mnEpisode, 0, 0/*default*/);
G_DeferredNewGame(mnEpisode, 0, 0/*default*/, &newRules);
#endif
}

Expand Down
41 changes: 16 additions & 25 deletions doomsday/plugins/common/src/p_saveg.cpp
Expand Up @@ -3646,9 +3646,9 @@ static bool openGameSaveFile(Str const *fileName, bool write)
return SV_File() != 0;
}

static int SV_LoadState(Str const *path, SaveInfo *saveInfo)
static int SV_LoadState(Str const *path, SaveInfo *info)
{
DENG_ASSERT(path != 0 && saveInfo != 0);
DENG_ASSERT(path != 0 && info != 0);

playerHeaderOK = false; // Uninitialized.

Expand All @@ -3665,35 +3665,26 @@ static int SV_LoadState(Str const *path, SaveInfo *saveInfo)
delete tmp;
}

/*
* Configure global game state:
*/
curInfo = saveInfo;

gameEpisode = saveInfo->episode();
gameMap = saveInfo->map();
gameMapEntrance = 0; /// @todo Not saved??
gameRules = saveInfo->gameRules();
curInfo = info;

#if __JHEXEN__
Game_ACScriptInterpreter().readWorldScriptData(reader, saveInfo->version());
Game_ACScriptInterpreter().readWorldScriptData(reader, info->version());
#endif

/*
* Load the map and configure some game settings.
*/
briefDisabled = true;
G_NewGame(gameRules.skill, gameEpisode, gameMap, gameMapEntrance);

G_SetGameAction(GA_NONE); /// @todo Necessary?
G_NewGame(info->episode(), info->map(), 0/*not saved??*/, &info->gameRules());

#if !__JHEXEN__
// Set the time.
mapTime = saveInfo->mapTime();
mapTime = info->mapTime();
#endif

G_SetGameAction(GA_NONE); /// @todo Necessary?

#if !__JHEXEN__
initThingArchiveForLoad(saveInfo->version() >= 5? Reader_ReadInt32(reader) : 1024 /* num elements */);
initThingArchiveForLoad(info->version() >= 5? Reader_ReadInt32(reader) : 1024 /* num elements */);
#endif

readPlayerHeader(reader);
Expand Down Expand Up @@ -3797,7 +3788,7 @@ static int SV_LoadState(Str const *path, SaveInfo *saveInfo)

#if !__JHEXEN__
// In netgames, the server tells the clients about this.
NetSv_LoadGame(saveInfo->gameId());
NetSv_LoadGame(info->gameId());
#endif

Reader_Delete(reader);
Expand Down Expand Up @@ -3996,18 +3987,18 @@ void SV_LoadGameClient(uint gameId)
return;
}

gameRules = saveInfo->gameRules();

// Do we need to change the map?
if(gameMap != saveInfo->map() || gameEpisode != saveInfo->episode())
{
gameEpisode = saveInfo->episode();
gameMap = saveInfo->map();
gameMapEntrance = 0;
G_NewGame(gameRules.skill, gameEpisode, gameMap, gameMapEntrance);
G_NewGame(saveInfo->episode(), saveInfo->map(), 0/*default*/, &saveInfo->gameRules());
/// @todo Necessary?
G_SetGameAction(GA_NONE);
}
else
{
/// @todo Necessary?
gameRules = saveInfo->gameRules();
}
mapTime = saveInfo->mapTime();

P_MobjUnlink(mo);
Expand Down

0 comments on commit 638f51d

Please sign in to comment.