mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 05:51:20 +00:00
- fixed the 'frozen level' handling and did some cleanup on the session data in savegames.
The handling for the two frozen flags was totally inconsistent. Furthermore, these need to be session data, not level data. The old exported variables for this still exist and shadow the real state, but are deprecated now. Frozen state should only be checked with "currentSession.isFrozen()" now. The session data in the savegame was grouped and separated from the global state, which onl consists of server CVARs and RNG state now.
This commit is contained in:
parent
9f1aedd135
commit
9099dc600f
34 changed files with 379 additions and 353 deletions
|
@ -1487,6 +1487,7 @@ public:
|
|||
void DeleteAttachedLights();
|
||||
static void DeleteAllAttachedLights();
|
||||
static void RecreateAllAttachedLights();
|
||||
bool isFrozen();
|
||||
|
||||
bool hasmodel;
|
||||
};
|
||||
|
|
|
@ -96,6 +96,28 @@ inline double AActor::AttackOffset(double offset)
|
|||
|
||||
}
|
||||
|
||||
inline bool AActor::isFrozen()
|
||||
{
|
||||
if (!(flags5 & MF5_NOTIMEFREEZE))
|
||||
{
|
||||
auto state = currentSession->isFrozen();
|
||||
if (state)
|
||||
{
|
||||
if (player == nullptr || player->Bot != nullptr) return true;
|
||||
|
||||
// This is the only place in the entire game where the two freeze flags need different treatment.
|
||||
// The time freezer flag also freezes other players, the global setting does not.
|
||||
|
||||
if ((state & 1) && player->timefreezer == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
class FActorIterator
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -139,7 +139,7 @@ void DBot::Tick ()
|
|||
{
|
||||
Super::Tick ();
|
||||
|
||||
if (player->mo == nullptr || Level->freeze)
|
||||
if (player->mo == nullptr || currentSession->isFrozen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@ void FCajunMaster::Main(FLevelLocals *Level)
|
|||
return;
|
||||
|
||||
//Add new bots?
|
||||
if (wanted_botnum > botnum && !Level->freeze)
|
||||
if (wanted_botnum > botnum && !currentSession->isFrozen())
|
||||
{
|
||||
if (t_join == ((wanted_botnum - botnum) * SPAWN_DELAY))
|
||||
{
|
||||
|
|
|
@ -1178,7 +1178,7 @@ void DDecalFader::Tick ()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (Level->maptime < TimeToStartDecay || Level->freeze)
|
||||
if (Level->maptime < TimeToStartDecay || currentSession->isFrozen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1265,7 +1265,7 @@ void DDecalStretcher::Tick ()
|
|||
Destroy ();
|
||||
return;
|
||||
}
|
||||
if (Level->maptime < TimeToStart || Level->freeze)
|
||||
if (Level->maptime < TimeToStart || currentSession->isFrozen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1333,7 +1333,7 @@ void DDecalSlider::Tick ()
|
|||
Destroy ();
|
||||
return;
|
||||
}
|
||||
if (Level->maptime < TimeToStart || Level->freeze)
|
||||
if (Level->maptime < TimeToStart || currentSession->isFrozen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1401,7 +1401,7 @@ void DDecalColorer::Tick ()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (Level->maptime < TimeToStartDecay || Level->freeze)
|
||||
if (Level->maptime < TimeToStartDecay || currentSession->isFrozen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -67,10 +67,6 @@ CUSTOM_CVAR (String, language, "auto", CVAR_ARCHIVE)
|
|||
// [RH] Network arbitrator
|
||||
int Net_Arbitrator = 0;
|
||||
|
||||
int NextSkill = -1;
|
||||
|
||||
int SinglePlayerClass[MAXPLAYERS];
|
||||
|
||||
bool ToggleFullscreen;
|
||||
|
||||
FString LumpFilterIWAD;
|
||||
|
|
|
@ -68,7 +68,6 @@ extern FString StoredWarp; // [RH] +warp at the command line
|
|||
|
||||
// Selected by user.
|
||||
EXTERN_CVAR (Int, gameskill);
|
||||
extern int NextSkill; // [RH] Skill to use at next level load
|
||||
|
||||
// Netgame? Only true if >1 player.
|
||||
extern bool netgame;
|
||||
|
@ -91,10 +90,6 @@ EXTERN_CVAR (Bool, teamplay)
|
|||
// [RH] Friendly fire amount
|
||||
EXTERN_CVAR (Float, teamdamage)
|
||||
|
||||
// [RH] The class the player will spawn as in single player,
|
||||
// in case using a random class with Hexen.
|
||||
extern int SinglePlayerClass[/*MAXPLAYERS*/];
|
||||
|
||||
// -------------------------
|
||||
// Internal parameters for sound rendering.
|
||||
|
||||
|
|
|
@ -73,7 +73,6 @@
|
|||
#include "dobjgc.h"
|
||||
#include "gi.h"
|
||||
|
||||
#include "g_hub.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "events.h"
|
||||
|
||||
|
@ -95,7 +94,6 @@ void G_DoWorldDone (void);
|
|||
void G_DoSaveGame (bool okForQuicksave, FString filename, const char *description);
|
||||
void G_DoAutoSave ();
|
||||
|
||||
void STAT_Serialize(FSerializer &file);
|
||||
bool WriteZip(const char *filename, TArray<FString> &filenames, TArray<FCompressedBuffer> &content);
|
||||
|
||||
FIntCVar gameskill ("skill", 2, CVAR_SERVERINFO|CVAR_LATCH);
|
||||
|
@ -1886,12 +1884,9 @@ void G_DoLoadGame ()
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
// Read intermission data for hubs
|
||||
G_SerializeHub(arc);
|
||||
|
||||
bglobal.RemoveAllBots(true);
|
||||
|
||||
// read the global state
|
||||
FString cvar;
|
||||
arc("importantcvars", cvar);
|
||||
if (!cvar.IsEmpty())
|
||||
|
@ -1899,17 +1894,13 @@ void G_DoLoadGame ()
|
|||
uint8_t *vars_p = (uint8_t *)cvar.GetChars();
|
||||
C_ReadCVars(&vars_p);
|
||||
}
|
||||
FRandom::StaticReadRNGState(arc);
|
||||
|
||||
uint32_t time[2] = { 1,0 };
|
||||
|
||||
arc("ticrate", time[0])
|
||||
("leveltime", time[1]);
|
||||
// dearchive all the modifications
|
||||
currentSession->time = Scale(time[1], TICRATE, time[0]);
|
||||
// Read the session data
|
||||
currentSession->SerializeSession(arc);
|
||||
|
||||
G_ReadSnapshots(resfile.get());
|
||||
resfile.reset(nullptr); // we no longer need the resource file below this point
|
||||
G_ReadVisited(arc);
|
||||
|
||||
// load a base level
|
||||
savegamerestore = true; // Use the player actors in the savegame
|
||||
|
@ -1918,13 +1909,6 @@ void G_DoLoadGame ()
|
|||
demoplayback = demoplaybacksave;
|
||||
savegamerestore = false;
|
||||
|
||||
STAT_Serialize(arc);
|
||||
FRandom::StaticReadRNGState(arc);
|
||||
P_ReadACSDefereds(arc);
|
||||
P_ReadACSVars(arc);
|
||||
|
||||
NextSkill = -1;
|
||||
arc("nextskill", NextSkill);
|
||||
|
||||
// Delete all snapshots that were created for the currently active levels.
|
||||
ForAllLevels([](FLevelLocals *Level)
|
||||
|
@ -2113,7 +2097,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
|||
|
||||
char buf[100];
|
||||
|
||||
bool checkok = gamestate != GS_LEVEL;
|
||||
bool checkok = gamestate == GS_LEVEL;
|
||||
|
||||
ForAllLevels([&](FLevelLocals *Level) {
|
||||
|
||||
|
@ -2124,6 +2108,12 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
|||
}
|
||||
});
|
||||
|
||||
if (!checkok)
|
||||
{
|
||||
Printf("Cannot save outside a level\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (demoplayback)
|
||||
{
|
||||
filename = G_BuildSaveName ("demosave." SAVEGAME_EXT, -1);
|
||||
|
@ -2194,33 +2184,15 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
|||
PutSaveWads (savegameinfo);
|
||||
PutSaveComment (savegameinfo);
|
||||
|
||||
// Intermission stats for hubs
|
||||
G_SerializeHub(savegameglobals);
|
||||
|
||||
{
|
||||
FString vars = C_GetMassCVarString(CVAR_SERVERINFO);
|
||||
savegameglobals.AddString("importantcvars", vars.GetChars());
|
||||
}
|
||||
|
||||
if (currentSession->time != 0)
|
||||
{
|
||||
int tic = TICRATE;
|
||||
savegameglobals("ticrate", tic);
|
||||
savegameglobals("leveltime", currentSession->time);
|
||||
}
|
||||
|
||||
STAT_Serialize(savegameglobals);
|
||||
FRandom::StaticWriteRNGState(savegameglobals);
|
||||
P_WriteACSDefereds(savegameglobals);
|
||||
P_WriteACSVars(savegameglobals);
|
||||
G_WriteVisited(savegameglobals);
|
||||
currentSession->SerializeSession(savegameglobals);
|
||||
|
||||
|
||||
if (NextSkill != -1)
|
||||
{
|
||||
savegameglobals("nextskill", NextSkill);
|
||||
}
|
||||
|
||||
auto picdata = savepic.GetBuffer();
|
||||
FCompressedBuffer bufpng = { picdata->Size(), picdata->Size(), METHOD_STORED, 0, static_cast<unsigned int>(crc32(0, &(*picdata)[0], picdata->Size())), (char*)&(*picdata)[0] };
|
||||
|
||||
|
@ -2238,6 +2210,13 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio
|
|||
|
||||
savegameManager.NotifyNewSave (filename, description, okForQuicksave);
|
||||
|
||||
|
||||
// delete the JSON buffers we created just above. Everything else will
|
||||
// either still be needed or taken care of automatically.
|
||||
savegame_content[1].Clean();
|
||||
savegame_content[2].Clean();
|
||||
|
||||
|
||||
// Check whether the file is ok by trying to open it.
|
||||
FResourceFile *test = FResourceFile::OpenResourceFile(filename, true);
|
||||
if (test != nullptr)
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
*/
|
||||
|
||||
#include "doomstat.h"
|
||||
#include "g_hub.h"
|
||||
#include "g_level.h"
|
||||
#include "g_game.h"
|
||||
#include "m_png.h"
|
||||
|
@ -44,39 +43,7 @@
|
|||
#include "g_levellocals.h"
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Player is leaving the current level
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FHubInfo
|
||||
{
|
||||
int levelnum;
|
||||
|
||||
int maxkills;
|
||||
int maxitems;
|
||||
int maxsecret;
|
||||
int maxfrags;
|
||||
|
||||
wbplayerstruct_t plyr[MAXPLAYERS];
|
||||
|
||||
FHubInfo &operator=(const wbstartstruct_t &wbs)
|
||||
{
|
||||
levelnum = wbs.finished_ep;
|
||||
maxkills = wbs.maxkills;
|
||||
maxsecret= wbs.maxsecret;
|
||||
maxitems = wbs.maxitems;
|
||||
maxfrags = wbs.maxfrags;
|
||||
memcpy(plyr, wbs.plyr, sizeof(plyr));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static TArray<FHubInfo> hubdata;
|
||||
|
||||
void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs, FLevelLocals *Level)
|
||||
void FGameSession::LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs, FLevelLocals *Level)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
|
@ -176,13 +143,3 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FHubInfo &h, FHubInfo
|
|||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
void G_SerializeHub(FSerializer &arc)
|
||||
{
|
||||
arc("hubinfo", hubdata);
|
||||
}
|
||||
|
||||
void G_ClearHubInfo()
|
||||
{
|
||||
hubdata.Clear();
|
||||
}
|
13
src/g_hub.h
13
src/g_hub.h
|
@ -1,13 +0,0 @@
|
|||
#ifndef __G_HUB_H
|
||||
#define __G_HUB_H
|
||||
|
||||
struct cluster_info_t;
|
||||
struct wbstartstruct_t;
|
||||
class FSerializer;
|
||||
struct FLevelLocals;
|
||||
|
||||
void G_SerializeHub (FSerializer &file);
|
||||
void G_LeavingHub(int mode, cluster_info_t * cluster, struct wbstartstruct_t * wbs, FLevelLocals *Level);
|
||||
|
||||
#endif
|
||||
|
312
src/g_level.cpp
312
src/g_level.cpp
|
@ -84,14 +84,17 @@
|
|||
|
||||
#include "gi.h"
|
||||
|
||||
#include "g_hub.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "actorinlines.h"
|
||||
#include "i_time.h"
|
||||
#include "p_maputl.h"
|
||||
|
||||
void STAT_StartNewGame(const char *lev);
|
||||
void STAT_ChangeLevel(const char *newl, FLevelLocals *Level);
|
||||
bool globalfreeze;
|
||||
DEFINE_GLOBAL(globalfreeze);
|
||||
|
||||
void STAT_StartNewGame(TArray<OneLevel> &LevelData, const char *lev);
|
||||
void STAT_ChangeLevel(TArray<OneLevel> &LevelData, const char *newl, FLevelLocals *Level);
|
||||
void STAT_Serialize(TArray<OneLevel> &LevelData, FSerializer &file);
|
||||
|
||||
EXTERN_CVAR(Bool, save_formatted)
|
||||
EXTERN_CVAR (Float, sv_gravity)
|
||||
|
@ -411,7 +414,7 @@ void G_NewInit ()
|
|||
}
|
||||
BackupSaveName = "";
|
||||
consoleplayer = 0;
|
||||
NextSkill = -1;
|
||||
currentSession->NextSkill = -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -440,21 +443,17 @@ void G_DoNewGame (void)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
static void InitPlayerClasses ()
|
||||
void FGameSession::InitPlayerClasses ()
|
||||
{
|
||||
if (!savegamerestore)
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
SinglePlayerClass[i] = players[i].userinfo.GetPlayerClassNum();
|
||||
if (SinglePlayerClass[i] < 0 || !playeringame[i])
|
||||
{
|
||||
SinglePlayerClass[i] = players[i].userinfo.GetPlayerClassNum();
|
||||
if (SinglePlayerClass[i] < 0 || !playeringame[i])
|
||||
{
|
||||
SinglePlayerClass[i] = (pr_classchoice()) % PlayerClasses.Size ();
|
||||
}
|
||||
players[i].cls = NULL;
|
||||
players[i].CurrentPlayerClass = SinglePlayerClass[i];
|
||||
SinglePlayerClass[i] = (pr_classchoice()) % PlayerClasses.Size ();
|
||||
}
|
||||
players[i].cls = nullptr;
|
||||
players[i].CurrentPlayerClass = SinglePlayerClass[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,12 +473,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
|
|||
|
||||
if (!savegamerestore)
|
||||
{
|
||||
G_ClearHubInfo();
|
||||
G_ClearSnapshots ();
|
||||
P_RemoveDefereds ();
|
||||
|
||||
// [RH] Mark all levels as not visited
|
||||
currentSession->Visited.Clear();
|
||||
currentSession->Reset();
|
||||
}
|
||||
|
||||
UnlatchCVars ();
|
||||
|
@ -530,14 +524,14 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
|
|||
|
||||
if (!multiplayer || !deathmatch)
|
||||
{
|
||||
InitPlayerClasses ();
|
||||
currentSession->InitPlayerClasses ();
|
||||
}
|
||||
|
||||
// force players to be initialized upon first level load
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
players[i].playerstate = PST_ENTER; // [BC]
|
||||
|
||||
STAT_StartNewGame(mapname);
|
||||
STAT_StartNewGame(currentSession->Statistics, mapname);
|
||||
}
|
||||
|
||||
usergame = !bTitleLevel; // will be set false if a demo
|
||||
|
@ -639,7 +633,7 @@ void G_ChangeLevel(FLevelLocals *OldLevel, const char *levelname, int position,
|
|||
}
|
||||
|
||||
if (nextSkill != -1)
|
||||
NextSkill = nextSkill;
|
||||
currentSession->NextSkill = nextSkill;
|
||||
|
||||
if (flags & CHANGELEVEL_NOINTERMISSION)
|
||||
{
|
||||
|
@ -681,7 +675,7 @@ void G_ChangeLevel(FLevelLocals *OldLevel, const char *levelname, int position,
|
|||
E_WorldUnloadedUnsafe();
|
||||
unloading = false;
|
||||
|
||||
STAT_ChangeLevel(nextlevel, OldLevel);
|
||||
STAT_ChangeLevel(currentSession->Statistics, nextlevel, OldLevel);
|
||||
|
||||
if (thiscluster && (thiscluster->flags & CLUSTER_HUB))
|
||||
{
|
||||
|
@ -877,7 +871,7 @@ void G_DoCompleted ()
|
|||
}
|
||||
|
||||
// Intermission stats for entire hubs
|
||||
G_LeavingHub(mode, thiscluster, &wminfo, Level);
|
||||
currentSession->LeavingHub(mode, thiscluster, &wminfo, Level);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
|
@ -1012,12 +1006,12 @@ void G_DoLoadLevel (const FString &nextlevel, int position, bool autosave, bool
|
|||
gamestate_t oldgs = gamestate;
|
||||
int i;
|
||||
|
||||
if (NextSkill >= 0)
|
||||
if (currentSession->NextSkill >= 0)
|
||||
{
|
||||
UCVarValue val;
|
||||
val.Int = NextSkill;
|
||||
val.Int = currentSession->NextSkill;
|
||||
gameskill.ForceSet (val, CVAR_Int);
|
||||
NextSkill = -1;
|
||||
currentSession->NextSkill = -1;
|
||||
}
|
||||
|
||||
if (position == -1)
|
||||
|
@ -1071,6 +1065,8 @@ void G_DoLoadLevel (const FString &nextlevel, int position, bool autosave, bool
|
|||
players[i].fragcount = 0;
|
||||
}
|
||||
|
||||
globalfreeze = false;
|
||||
|
||||
// Set up all needed levels.
|
||||
for(auto &linfo : MapSet)
|
||||
{
|
||||
|
@ -1115,6 +1111,8 @@ void G_DoLoadLevel (const FString &nextlevel, int position, bool autosave, bool
|
|||
|
||||
// Restore the state of the levels
|
||||
G_UnSnapshotLevel (currentSession->Levelinfo, !savegamerestore);
|
||||
|
||||
globalfreeze = !!(currentSession->isFrozen() & 2);
|
||||
|
||||
int pnumerr = G_FinishTravel (currentSession->Levelinfo[0]);
|
||||
|
||||
|
@ -1785,15 +1783,146 @@ void G_ClearSnapshots (void)
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
// Remove any existing defereds
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void P_RemoveDefereds (void)
|
||||
void FGameSession::SerializeACSDefereds(FSerializer &arc)
|
||||
{
|
||||
currentSession->ClearDefered();
|
||||
if (arc.isWriting())
|
||||
{
|
||||
if (DeferredScripts.CountUsed() == 0) return;
|
||||
decltype(DeferredScripts)::Iterator it(DeferredScripts);
|
||||
decltype(DeferredScripts)::Pair *pair;
|
||||
|
||||
if (arc.BeginObject("deferred"))
|
||||
{
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
arc(pair->Key, pair->Value);
|
||||
}
|
||||
}
|
||||
arc.EndObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
FString MapName;
|
||||
|
||||
DeferredScripts.Clear();
|
||||
|
||||
if (arc.BeginObject("deferred"))
|
||||
{
|
||||
const char *key;
|
||||
|
||||
while ((key = arc.GetKey()))
|
||||
{
|
||||
TArray<acsdefered_t> deferred;
|
||||
arc(nullptr, deferred);
|
||||
DeferredScripts.Insert(key, std::move(deferred));
|
||||
}
|
||||
arc.EndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGameSession::SerializeVisited(FSerializer &arc)
|
||||
{
|
||||
if (arc.isWriting())
|
||||
{
|
||||
decltype(Visited)::Iterator it(Visited);
|
||||
decltype(Visited)::Pair *pair;
|
||||
|
||||
if (arc.BeginArray("visited"))
|
||||
{
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
// Write out which levels have been visited
|
||||
arc.AddString(nullptr, pair->Key);
|
||||
}
|
||||
arc.EndArray();
|
||||
}
|
||||
|
||||
// Store player classes to be used when spawning a random class
|
||||
if (multiplayer)
|
||||
{
|
||||
arc.Array("randomclasses", SinglePlayerClass, MAXPLAYERS);
|
||||
}
|
||||
|
||||
if (arc.BeginObject("playerclasses"))
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
FString key;
|
||||
key.Format("%d", i);
|
||||
arc(key, players[i].cls);
|
||||
}
|
||||
}
|
||||
arc.EndObject();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arc.BeginArray("visited"))
|
||||
{
|
||||
for (int s = arc.ArraySize(); s > 0; s--)
|
||||
{
|
||||
FString str;
|
||||
arc(nullptr, str);
|
||||
Visited.Insert(str, true);
|
||||
}
|
||||
arc.EndArray();
|
||||
}
|
||||
|
||||
arc.Array("randomclasses", SinglePlayerClass, MAXPLAYERS);
|
||||
|
||||
if (arc.BeginObject("playerclasses"))
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
FString key;
|
||||
key.Format("%d", i);
|
||||
arc(key, players[i].cls);
|
||||
}
|
||||
arc.EndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGameSession::SerializeSession(FSerializer &arc)
|
||||
{
|
||||
if (arc.BeginObject("session"))
|
||||
{
|
||||
arc("f1pic", F1Pic)
|
||||
("musicvolume", MusicVolume)
|
||||
("totaltime", totaltime)
|
||||
("time", time)
|
||||
("frozenstate", frozenstate)
|
||||
("hubinfo", hubdata)
|
||||
("nextskill", NextSkill);
|
||||
|
||||
SerializeACSDefereds(arc);
|
||||
SerializeVisited(arc);
|
||||
STAT_Serialize(Statistics, arc);
|
||||
if (arc.isReading()) P_ReadACSVars(arc);
|
||||
else P_WriteACSVars(arc);
|
||||
arc.EndObject();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Archives the current level
|
||||
|
@ -1910,47 +2039,6 @@ void G_WriteSnapshots(TArray<FString> &filenames, TArray<FCompressedBuffer> &buf
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void G_WriteVisited(FSerializer &arc)
|
||||
{
|
||||
decltype(currentSession->Visited)::Iterator it(currentSession->Visited);
|
||||
decltype(currentSession->Visited)::Pair *pair;
|
||||
|
||||
if (arc.BeginArray("visited"))
|
||||
{
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
// Write out which levels have been visited
|
||||
arc.AddString(nullptr, pair->Key);
|
||||
}
|
||||
arc.EndArray();
|
||||
}
|
||||
|
||||
// Store player classes to be used when spawning a random class
|
||||
if (multiplayer)
|
||||
{
|
||||
arc.Array("randomclasses", SinglePlayerClass, MAXPLAYERS);
|
||||
}
|
||||
|
||||
if (arc.BeginObject("playerclasses"))
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
FString key;
|
||||
key.Format("%d", i);
|
||||
arc(key, players[i].cls);
|
||||
}
|
||||
}
|
||||
arc.EndObject();
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void G_ReadSnapshots(FResourceFile *resf)
|
||||
{
|
||||
G_ClearSnapshots();
|
||||
|
@ -1976,38 +2064,6 @@ void G_ReadSnapshots(FResourceFile *resf)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void G_ReadVisited(FSerializer &arc)
|
||||
{
|
||||
if (arc.BeginArray("visited"))
|
||||
{
|
||||
for (int s = arc.ArraySize(); s > 0; s--)
|
||||
{
|
||||
FString str;
|
||||
arc(nullptr, str);
|
||||
currentSession->Visited.Insert(str, true);
|
||||
}
|
||||
arc.EndArray();
|
||||
}
|
||||
|
||||
arc.Array("randomclasses", SinglePlayerClass, MAXPLAYERS);
|
||||
|
||||
if (arc.BeginObject("playerclasses"))
|
||||
{
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
FString key;
|
||||
key.Format("%d", i);
|
||||
arc(key, players[i].cls);
|
||||
}
|
||||
arc.EndObject();
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD(listsnapshots)
|
||||
{
|
||||
decltype(currentSession->Snapshots)::Iterator it(currentSession->Snapshots);
|
||||
|
@ -2023,52 +2079,6 @@ CCMD(listsnapshots)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void P_WriteACSDefereds (FSerializer &arc)
|
||||
{
|
||||
if (currentSession->DeferredScripts.CountUsed() == 0) return;
|
||||
decltype(currentSession->DeferredScripts)::Iterator it(currentSession->DeferredScripts);
|
||||
decltype(currentSession->DeferredScripts)::Pair *pair;
|
||||
|
||||
if (arc.BeginObject("deferred"))
|
||||
{
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
arc(pair->Key, pair->Value);
|
||||
}
|
||||
}
|
||||
arc.EndObject();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void P_ReadACSDefereds (FSerializer &arc)
|
||||
{
|
||||
FString MapName;
|
||||
|
||||
P_RemoveDefereds ();
|
||||
|
||||
if (arc.BeginObject("deferred"))
|
||||
{
|
||||
const char *key;
|
||||
|
||||
while ((key = arc.GetKey()))
|
||||
{
|
||||
TArray<acsdefered_t> deferred;
|
||||
arc(nullptr, deferred);
|
||||
currentSession->DeferredScripts.Insert(key, std::move(deferred));
|
||||
}
|
||||
arc.EndObject();
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// This object is responsible for marking sectors during the propagate
|
||||
|
|
|
@ -481,14 +481,12 @@ FString CalcMapName (int episode, int level);
|
|||
void G_ParseMapInfo (FString basemapinfo);
|
||||
|
||||
void G_ClearSnapshots (void);
|
||||
void P_RemoveDefereds ();
|
||||
void G_SnapshotLevel (void);
|
||||
void G_UnSnapshotLevel(const TArray<FLevelLocals *> &levels, bool hubLoad);
|
||||
void G_ReadSnapshots (FResourceFile *);
|
||||
void G_WriteSnapshots (TArray<FString> &, TArray<FCompressedBuffer> &);
|
||||
void G_WriteVisited(FSerializer &arc);
|
||||
void G_ReadVisited(FSerializer &arc);
|
||||
void G_ClearHubInfo();
|
||||
|
||||
enum ESkillProperty
|
||||
{
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "p_acs.h"
|
||||
#include "p_tags.h"
|
||||
#include "p_effect.h"
|
||||
#include "wi_stuff.h"
|
||||
#include "p_destructible.h"
|
||||
#include "p_conversation.h"
|
||||
#include "r_data/r_interpolate.h"
|
||||
|
@ -340,6 +341,46 @@ struct FLevelLocals : public FLevelData
|
|||
}
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Player is leaving the current level
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
struct FHubInfo
|
||||
{
|
||||
int levelnum;
|
||||
|
||||
int maxkills;
|
||||
int maxitems;
|
||||
int maxsecret;
|
||||
int maxfrags;
|
||||
|
||||
wbplayerstruct_t plyr[MAXPLAYERS];
|
||||
|
||||
FHubInfo &operator=(const wbstartstruct_t &wbs)
|
||||
{
|
||||
levelnum = wbs.finished_ep;
|
||||
maxkills = wbs.maxkills;
|
||||
maxsecret = wbs.maxsecret;
|
||||
maxitems = wbs.maxitems;
|
||||
maxfrags = wbs.maxfrags;
|
||||
memcpy(plyr, wbs.plyr, sizeof(plyr));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// This struct is used to track statistics data in game
|
||||
struct OneLevel
|
||||
{
|
||||
int totalkills, killcount;
|
||||
int totalitems, itemcount;
|
||||
int totalsecrets, secretcount;
|
||||
int leveltime;
|
||||
FString Levelname;
|
||||
};
|
||||
|
||||
|
||||
class FGameSession
|
||||
{
|
||||
|
@ -349,25 +390,50 @@ public:
|
|||
TMap<FName, FCompressedBuffer> Snapshots;
|
||||
TMap<FName, TArray<acsdefered_t>> DeferredScripts;
|
||||
TMap<FName, bool> Visited;
|
||||
|
||||
TArray<FHubInfo> hubdata;
|
||||
TArray<OneLevel> Statistics;// Current game's statistics
|
||||
int SinglePlayerClass[MAXPLAYERS];
|
||||
|
||||
FString F1Pic;
|
||||
float MusicVolume;
|
||||
int time; // time in the hub
|
||||
int totaltime; // time in the game
|
||||
|
||||
float MusicVolume = 1.0f;
|
||||
int time = 0; // time in the hub
|
||||
int totaltime = 0; // time in the game
|
||||
int frozenstate = 0;
|
||||
int changefreeze = 0;
|
||||
int NextSkill = -1;
|
||||
|
||||
FString nextlevel; // Level to go to on exit
|
||||
int nextstartpos; // [RH] Support for multiple starts per level
|
||||
int nextstartpos = 0; // [RH] Support for multiple starts per level
|
||||
|
||||
|
||||
void SetMusicVolume(float vol);
|
||||
|
||||
void Reset();
|
||||
void LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs, FLevelLocals *Level);
|
||||
void InitPlayerClasses();
|
||||
|
||||
void Reset()
|
||||
{
|
||||
Levelinfo.DeleteAndClear();
|
||||
ClearSnapshots();
|
||||
DeferredScripts.Clear();
|
||||
Visited.Clear();
|
||||
hubdata.Clear();
|
||||
Statistics.Clear();
|
||||
|
||||
MusicVolume = 1.0f;
|
||||
time = 0;
|
||||
totaltime = 0;
|
||||
frozenstate = 0;
|
||||
changefreeze = 0;
|
||||
|
||||
nextlevel = "";
|
||||
nextstartpos = 0;
|
||||
}
|
||||
int isFrozen() const
|
||||
{
|
||||
return frozenstate;
|
||||
}
|
||||
bool isValid();
|
||||
FString LookupLevelName ();
|
||||
void ClearDefered()
|
||||
{
|
||||
DeferredScripts.Clear();
|
||||
}
|
||||
void ClearSnapshots()
|
||||
{
|
||||
decltype(Snapshots)::Iterator it(Snapshots);
|
||||
|
@ -388,6 +454,9 @@ public:
|
|||
}
|
||||
Snapshots.Remove(mapname);
|
||||
}
|
||||
void SerializeSession(FSerializer &arc);
|
||||
void SerializeACSDefereds(FSerializer &arc);
|
||||
void SerializeVisited(FSerializer &arc);
|
||||
|
||||
};
|
||||
|
||||
|
@ -499,3 +568,6 @@ inline void ForAllLevels(T func)
|
|||
for (auto Level : currentSession->Levelinfo) func(Level);
|
||||
}
|
||||
}
|
||||
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, wbplayerstruct_t &h, wbplayerstruct_t *def);
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, FHubInfo &h, FHubInfo *def);
|
|
@ -1198,7 +1198,7 @@ void GLSprite::ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *
|
|||
|
||||
const auto &vp = di->Viewpoint;
|
||||
double timefrac = vp.TicFrac;
|
||||
if (paused || di->Level->freeze || (di->Level->flags2 & LEVEL2_FROZEN))
|
||||
if (paused || currentSession->isFrozen())
|
||||
timefrac = 0.;
|
||||
float xvf = (particle->Vel.X) * timefrac;
|
||||
float yvf = (particle->Vel.Y) * timefrac;
|
||||
|
|
|
@ -515,9 +515,8 @@ void cht_DoCheat (player_t *player, int cheat)
|
|||
|
||||
case CHT_FREEZE:
|
||||
{
|
||||
auto Level = player->mo->Level;
|
||||
Level->changefreeze ^= 1;
|
||||
if (Level->freeze ^ Level->changefreeze)
|
||||
currentSession->changefreeze ^= 2;
|
||||
if (currentSession->isFrozen() ^ currentSession->changefreeze)
|
||||
{
|
||||
msg = GStrings("TXT_FREEZEON");
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@ void P_ThinkParticles (FLevelLocals *Level)
|
|||
{
|
||||
particle = &Level->Particles[i];
|
||||
i = particle->tnext;
|
||||
if (!particle->notimefreeze && ((Level->freeze) || (Level->flags2 & LEVEL2_FROZEN)))
|
||||
if (!particle->notimefreeze && currentSession->isFrozen())
|
||||
{
|
||||
prev = particle;
|
||||
continue;
|
||||
|
|
|
@ -3140,11 +3140,11 @@ FUNC(LS_ChangeSkill)
|
|||
{
|
||||
if ((unsigned)arg0 >= AllSkills.Size())
|
||||
{
|
||||
NextSkill = -1;
|
||||
currentSession->NextSkill = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
NextSkill = arg0;
|
||||
currentSession->NextSkill = arg0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3522,7 +3522,7 @@ void AActor::Tick ()
|
|||
if (!(flags5 & MF5_NOTIMEFREEZE))
|
||||
{
|
||||
//Added by MC: Freeze mode.
|
||||
if (Level->freeze || Level->flags2 & LEVEL2_FROZEN)
|
||||
if (isFrozen())
|
||||
{
|
||||
// Boss cubes shouldn't be accelerated by timefreeze
|
||||
if (flags6 & MF6_BOSSCUBE)
|
||||
|
@ -3569,27 +3569,16 @@ void AActor::Tick ()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!(flags5 & MF5_NOTIMEFREEZE))
|
||||
if (isFrozen())
|
||||
{
|
||||
// Boss cubes shouldn't be accelerated by timefreeze
|
||||
if (flags6 & MF6_BOSSCUBE)
|
||||
{
|
||||
special2++;
|
||||
}
|
||||
//Added by MC: Freeze mode.
|
||||
if (Level->freeze && !(player && player->Bot == NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply freeze mode.
|
||||
if ((Level->flags2 & LEVEL2_FROZEN) && (player == NULL || player->timefreezer == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (effects & FX_ROCKET)
|
||||
{
|
||||
if (++smokecounter == 4)
|
||||
|
@ -4934,7 +4923,7 @@ AActor *P_SpawnPlayer (FLevelLocals *Level, FPlayerStart *mthing, int playernum,
|
|||
|
||||
if (!deathmatch || !multiplayer)
|
||||
{
|
||||
type = SinglePlayerClass[playernum];
|
||||
type = currentSession->SinglePlayerClass[playernum];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -950,14 +950,11 @@ void G_SerializeLevel(FSerializer &arc, FLevelLocals *Level, bool hubload)
|
|||
("fragglethinker", Level->FraggleScriptThinker)
|
||||
("acsthinker", Level->ACSThinker)
|
||||
("impactdecalcount", Level->ImpactDecalCount)
|
||||
("freeze", Level->freeze)
|
||||
("changefreeze", Level->changefreeze)
|
||||
("sndseqlisthead", Level->SequenceListHead)
|
||||
("am_markpointnum", Level->am_markpointnum)
|
||||
.Array("am_markpoints", &Level->am_markpoints[0].x, Level->AM_NUMMARKPOINTS * 2) // write as a double array.
|
||||
("am_scale_mtof", Level->am_scale_mtof)
|
||||
("am_scale_ftom", Level->am_scale_ftom)
|
||||
.EndObject();
|
||||
("am_scale_ftom", Level->am_scale_ftom);
|
||||
|
||||
|
||||
|
||||
|
@ -1026,5 +1023,4 @@ void G_SerializeLevel(FSerializer &arc, FLevelLocals *Level, bool hubload)
|
|||
}
|
||||
AActor::RecreateAllAttachedLights();
|
||||
InitPortalGroups(Level);
|
||||
|
||||
}
|
||||
|
|
|
@ -41,9 +41,6 @@ class FSerializer;
|
|||
// Also see farchive.(h|cpp)
|
||||
void P_DestroyThinkers(bool hubLoad);
|
||||
|
||||
void P_ReadACSDefereds (FSerializer &);
|
||||
void P_WriteACSDefereds (FSerializer &);
|
||||
|
||||
void G_SerializeLevel(FSerializer &arc, FLevelLocals *Level, bool hubLoad);
|
||||
|
||||
#endif // __P_SAVEG_H__
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "actorinlines.h"
|
||||
|
||||
extern gamestate_t wipegamestate;
|
||||
extern bool globalfreeze;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -110,10 +111,11 @@ void P_Ticker (void)
|
|||
// [RH] Frozen mode is only changed every 4 tics, to make it work with A_Tracer().
|
||||
if ((Level->maptime & 3) == 0)
|
||||
{
|
||||
if (Level->changefreeze)
|
||||
if (currentSession->changefreeze)
|
||||
{
|
||||
Level->freeze ^= 1;
|
||||
Level->changefreeze = 0;
|
||||
currentSession->frozenstate ^= currentSession->changefreeze;
|
||||
currentSession->changefreeze = 0;
|
||||
globalfreeze = !!(currentSession->isFrozen() & 2); // for ZScript backwards compatibiity.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,7 +155,7 @@ void P_Ticker (void)
|
|||
DThinker::RunThinkers(Level);
|
||||
|
||||
//if added by MC: Freeze mode.
|
||||
if (!Level->freeze && !(Level->flags2 & LEVEL2_FROZEN))
|
||||
if (!currentSession->isFrozen())
|
||||
{
|
||||
P_UpdateSpecials(Level);
|
||||
P_RunEffects(Level); // [RH] Run particle effects
|
||||
|
|
|
@ -1226,7 +1226,7 @@ void P_PlayerThink (player_t *player)
|
|||
}
|
||||
|
||||
// Bots do not think in freeze mode.
|
||||
if (player->mo->Level->freeze && player->Bot != nullptr)
|
||||
if (currentSession->isFrozen() && player->Bot != nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1695,7 +1695,7 @@ bool P_IsPlayerTotallyFrozen(const player_t *player)
|
|||
return
|
||||
gamestate == GS_TITLELEVEL ||
|
||||
player->cheats & CF_TOTALLYFROZEN ||
|
||||
((player->mo->Level->flags2 & LEVEL2_FROZEN) && player->timefreezer == 0);
|
||||
player->mo->isFrozen();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ EXTERN_CVAR(Int, gl_particles_style)
|
|||
void RenderPolyParticle::Render(PolyRenderThread *thread, particle_t *particle, subsector_t *sub, uint32_t stencilValue)
|
||||
{
|
||||
double timefrac = r_viewpoint.TicFrac;
|
||||
if (paused || PolyRenderer::Instance()->Level->freeze || (PolyRenderer::Instance()->Level->flags2 & LEVEL2_FROZEN))
|
||||
if (paused || currentSession->isFrozen())
|
||||
timefrac = 0.;
|
||||
DVector3 pos = particle->Pos + (particle->Vel * timefrac);
|
||||
double psize = particle->size / 8.0;
|
||||
|
|
|
@ -230,7 +230,7 @@ void FModelRenderer::RenderFrameModels(FLevelLocals *Level, const FSpriteModelFr
|
|||
// [BB] To interpolate at more than 35 fps we take tic fractions into account.
|
||||
float ticFraction = 0.;
|
||||
// [BB] In case the tic counter is frozen we have to leave ticFraction at zero.
|
||||
if (ConsoleState == c_up && menuactive != MENU_On && !(Level->flags2 & LEVEL2_FROZEN))
|
||||
if (ConsoleState == c_up && menuactive != MENU_On && !currentSession->isFrozen())
|
||||
{
|
||||
ticFraction = I_GetTimeFrac();
|
||||
}
|
||||
|
|
|
@ -2667,7 +2667,32 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, Vec3Offset, Vec3Offset)
|
|||
ACTION_RETURN_VEC3(result);
|
||||
}
|
||||
|
||||
static int isFrozen(FGameSession *self)
|
||||
{
|
||||
return self->isFrozen();
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(FGameSession, isFrozen, isFrozen)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FGameSession);
|
||||
return isFrozen(self);
|
||||
}
|
||||
|
||||
void setFrozen(FGameSession *self, int on)
|
||||
{
|
||||
self->frozenstate = (self->frozenstate & ~1) | on;
|
||||
// For compatibility. The engine itself never checks this.
|
||||
if (on) self->Levelinfo[0]->flags2 |= LEVEL2_FROZEN;
|
||||
else self->Levelinfo[0]->flags2 &= ~LEVEL2_FROZEN;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(FGameSession, setFrozen, setFrozen)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FGameSession);
|
||||
PARAM_BOOL(on);
|
||||
setFrozen(self, on);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
//
|
||||
|
@ -2744,7 +2769,6 @@ DEFINE_FIELD(FLevelLocals, outsidefogdensity)
|
|||
DEFINE_FIELD(FLevelLocals, skyfog)
|
||||
DEFINE_FIELD(FLevelLocals, pixelstretch)
|
||||
DEFINE_FIELD(FLevelLocals, deathsequence)
|
||||
DEFINE_FIELD(FLevelLocals, freeze)
|
||||
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags, noinventorybar, LEVEL_NOINVENTORYBAR)
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags, monsterstelefrag, LEVEL_MONSTERSTELEFRAG)
|
||||
|
@ -2872,4 +2896,4 @@ DEFINE_FIELD(DHUDFont, mFont);
|
|||
|
||||
DEFINE_GLOBAL(StatusBar);
|
||||
|
||||
DEFINE_FIELD(DThinker, Level);
|
||||
DEFINE_FIELD(DThinker, Level);
|
||||
|
|
|
@ -1680,6 +1680,18 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, compat_mushroom, compat_mushroom_)
|
|||
ACTION_RETURN_INT(compat_mushroom_(self));
|
||||
}
|
||||
|
||||
static int isFrozen(AActor *self)
|
||||
{
|
||||
return self->isFrozen();
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION_NATIVE(AActor, isFrozen, isFrozen)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(AActor);
|
||||
return isFrozen(self);
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// PlayerPawn functions
|
||||
|
|
|
@ -68,18 +68,6 @@ CVAR(String, statfile, "zdoomstat.txt", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
// This struct is used to track statistics data in game
|
||||
struct OneLevel
|
||||
{
|
||||
int totalkills, killcount;
|
||||
int totalitems, itemcount;
|
||||
int totalsecrets, secretcount;
|
||||
int leveltime;
|
||||
FString Levelname;
|
||||
};
|
||||
|
||||
// Current game's statistics
|
||||
static TArray<OneLevel> LevelData;
|
||||
static FEpisode *StartEpisode;
|
||||
|
||||
// The statistics for one level
|
||||
|
@ -363,7 +351,7 @@ static void LevelStatEntry(FSessionStatistics *es, const char *level, const char
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void STAT_StartNewGame(const char *mapname)
|
||||
void STAT_StartNewGame(TArray<OneLevel> &LevelData, const char *mapname)
|
||||
{
|
||||
LevelData.Clear();
|
||||
if (!deathmatch && !multiplayer)
|
||||
|
@ -386,7 +374,7 @@ void STAT_StartNewGame(const char *mapname)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
static void StoreLevelStats(FLevelLocals *Level)
|
||||
static void StoreLevelStats(TArray<OneLevel> &LevelData, FLevelLocals *Level)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
@ -432,10 +420,10 @@ static void StoreLevelStats(FLevelLocals *Level)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void STAT_ChangeLevel(const char *newl, FLevelLocals *Level)
|
||||
void STAT_ChangeLevel(TArray<OneLevel> &LevelData, const char *newl, FLevelLocals *Level)
|
||||
{
|
||||
// record the current level's stats.
|
||||
StoreLevelStats(Level);
|
||||
StoreLevelStats(LevelData, Level);
|
||||
|
||||
const level_info_t *thisinfo = Level->info;
|
||||
level_info_t *nextinfo = NULL;
|
||||
|
@ -524,7 +512,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, OneLevel &l, OneLevel
|
|||
return arc;
|
||||
}
|
||||
|
||||
void STAT_Serialize(FSerializer &arc)
|
||||
void STAT_Serialize(TArray<OneLevel> &LevelData, FSerializer &arc)
|
||||
{
|
||||
FString startlevel;
|
||||
int i = LevelData.Size();
|
||||
|
@ -564,6 +552,7 @@ void STAT_Serialize(FSerializer &arc)
|
|||
|
||||
FString GetStatString()
|
||||
{
|
||||
auto &LevelData = currentSession->Statistics;
|
||||
FString compose;
|
||||
for(unsigned i = 0; i < LevelData.Size(); i++)
|
||||
{
|
||||
|
@ -577,7 +566,7 @@ FString GetStatString()
|
|||
|
||||
CCMD(printstats)
|
||||
{
|
||||
if (currentSession) StoreLevelStats(currentSession->Levelinfo[0]); // Refresh the current level's results.
|
||||
if (currentSession) StoreLevelStats(currentSession->Statistics, currentSession->Levelinfo[0]); // Refresh the current level's results.
|
||||
Printf("%s", GetStatString().GetChars());
|
||||
}
|
||||
|
||||
|
@ -596,6 +585,6 @@ CCMD(finishgame)
|
|||
|
||||
ADD_STAT(statistics)
|
||||
{
|
||||
if (currentSession) StoreLevelStats(currentSession->Levelinfo[0]); // Refresh the current level's results.
|
||||
if (currentSession) StoreLevelStats(currentSession->Statistics, currentSession->Levelinfo[0]); // Refresh the current level's results.
|
||||
return GetStatString();
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace swrenderer
|
|||
sector_t* heightsec = NULL;
|
||||
|
||||
double timefrac = r_viewpoint.TicFrac;
|
||||
if (paused || sector->Level->freeze || (sector->Level->flags2 & LEVEL2_FROZEN))
|
||||
if (paused || currentSession->isFrozen())
|
||||
timefrac = 0.;
|
||||
|
||||
double ippx = particle->Pos.X + particle->Vel.X * timefrac;
|
||||
|
|
|
@ -448,6 +448,7 @@ class Actor : Thinker native
|
|||
return sin(fb * (180./32)) * 8;
|
||||
}
|
||||
|
||||
native bool isFrozen();
|
||||
virtual native void BeginPlay();
|
||||
virtual native void Activate(Actor activator);
|
||||
virtual native void Deactivate(Actor activator);
|
||||
|
|
|
@ -7,7 +7,6 @@ struct _ native // These are the global variables, the struct is only here to av
|
|||
native readonly Array<@Team> Teams;
|
||||
native int validcount;
|
||||
native readonly bool multiplayer;
|
||||
//native play @LevelLocals level;
|
||||
native @KeyBindings Bindings;
|
||||
native @KeyBindings AutomapBindings;
|
||||
native play @DehInfo deh;
|
||||
|
@ -46,6 +45,9 @@ struct _ native // These are the global variables, the struct is only here to av
|
|||
native int LocalViewPitch;
|
||||
native GameSession currentSession;
|
||||
|
||||
//native play @LevelLocals level;
|
||||
deprecated("3.8") native readonly bool globalfreeze;
|
||||
|
||||
}
|
||||
|
||||
struct TexMan
|
||||
|
@ -633,6 +635,10 @@ struct GameSession native
|
|||
native readonly String F1Pic;
|
||||
native readonly int time;
|
||||
native readonly int totaltime;
|
||||
|
||||
native bool isFrozen();
|
||||
native void setFrozen(bool on);
|
||||
|
||||
}
|
||||
|
||||
struct LevelLocals native
|
||||
|
@ -709,7 +715,7 @@ struct LevelLocals native
|
|||
native readonly bool polygrind;
|
||||
native readonly bool nomonsters;
|
||||
native readonly bool allowrespawn;
|
||||
native bool frozen;
|
||||
deprecated("3.8") native bool frozen;
|
||||
native readonly bool infinite_flight;
|
||||
native readonly bool no_dlg_freeze;
|
||||
native readonly bool keepfullinventory;
|
||||
|
@ -719,7 +725,6 @@ struct LevelLocals native
|
|||
native readonly int skyfog;
|
||||
native readonly float pixelstretch;
|
||||
native name deathsequence;
|
||||
native readonly uint8 freeze;
|
||||
// level_info_t *info cannot be done yet.
|
||||
|
||||
native String GetUDMFString(int type, int index, Name key);
|
||||
|
@ -769,6 +774,7 @@ struct LevelLocals native
|
|||
int sec = Thinker.Tics2Seconds(totals? currentSession.totaltime : currentSession.time);
|
||||
return String.Format("%02d:%02d:%02d", sec / 3600, (sec % 3600) / 60, sec % 60);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct StringTable native
|
||||
|
|
|
@ -1531,7 +1531,7 @@ class PowerTimeFreezer : Powerup
|
|||
// Make sure the effect starts and ends on an even tic.
|
||||
if ((Level.maptime & 1) == 0)
|
||||
{
|
||||
Level.frozen = true;;
|
||||
currentSession.SetFrozen(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1560,7 +1560,7 @@ class PowerTimeFreezer : Powerup
|
|||
// [RH] The "blinking" can't check against EffectTics exactly or it will
|
||||
// never happen, because InitEffect ensures that EffectTics will always
|
||||
// be odd when Level.maptime is even.
|
||||
Level.frozen = ( EffectTics > 4*32
|
||||
currentSession.SetFrozen ( EffectTics > 4*32
|
||||
|| (( EffectTics > 3*32 && EffectTics <= 4*32 ) && ((EffectTics + 1) & 15) != 0 )
|
||||
|| (( EffectTics > 2*32 && EffectTics <= 3*32 ) && ((EffectTics + 1) & 7) != 0 )
|
||||
|| (( EffectTics > 32 && EffectTics <= 2*32 ) && ((EffectTics + 1) & 3) != 0 )
|
||||
|
@ -1598,7 +1598,7 @@ class PowerTimeFreezer : Powerup
|
|||
}
|
||||
|
||||
// No, so allow other actors to move about freely once again.
|
||||
Level.frozen = false;
|
||||
currentSession.SetFrozen(false);
|
||||
|
||||
// Also, turn the music back on.
|
||||
S_ResumeSound(false);
|
||||
|
|
|
@ -50,14 +50,8 @@ class FastProjectile : Actor
|
|||
ClearInterpolation();
|
||||
double oldz = pos.Z;
|
||||
|
||||
if (!bNoTimeFreeze)
|
||||
{
|
||||
//Added by MC: Freeze mode.
|
||||
if (Level.freeze || Level.Frozen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isFrozen())
|
||||
return;
|
||||
|
||||
// [RH] Ripping is a little different than it was in Hexen
|
||||
FCheckPosition tm;
|
||||
|
|
|
@ -2764,7 +2764,7 @@ struct PlayerInfo native play // self is what internally is known as player_t
|
|||
return
|
||||
gamestate == GS_TITLELEVEL ||
|
||||
(cheats & CF_TOTALLYFROZEN) ||
|
||||
(mo.Level.frozen && timefreezer == 0);
|
||||
mo.isFrozen();
|
||||
}
|
||||
|
||||
void Uncrouch()
|
||||
|
|
|
@ -210,7 +210,7 @@ extend class PlayerPawn
|
|||
{ // You can't use items if you're totally frozen
|
||||
return false;
|
||||
}
|
||||
if ((Level.FROZEN) && (player == NULL || player.timefreezer == 0))
|
||||
if (isFrozen())
|
||||
{
|
||||
// Time frozen
|
||||
return false;
|
||||
|
|
Loading…
Reference in a new issue