mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-12-27 20:20:40 +00:00
- get load and save game menus and related CCMDs working again.
This commit is contained in:
parent
53c3a6fc9b
commit
2bb38f7d67
23 changed files with 806 additions and 750 deletions
|
@ -932,6 +932,7 @@ set (PCH_SOURCES
|
|||
common/menu/optionmenu.cpp
|
||||
common/menu/resolutionmenu.cpp
|
||||
common/menu/menudef.cpp
|
||||
common/menu/savegamemanager.cpp
|
||||
|
||||
common/rendering/v_framebuffer.cpp
|
||||
common/rendering/v_video.cpp
|
||||
|
|
|
@ -80,8 +80,8 @@ struct GameInterface : ::GameInterface
|
|||
void MenuClosed() override;
|
||||
bool CanSave() override;
|
||||
bool StartGame(FNewGameStartup& gs) override;
|
||||
bool SaveGame(FSaveGameNode*) override;
|
||||
bool LoadGame(FSaveGameNode*) override;
|
||||
bool SaveGame() override;
|
||||
bool LoadGame() override;
|
||||
void QuitToTitle() override;
|
||||
FString GetCoordString() override;
|
||||
ReservedSpace GetReservedScreenSpace(int viewsize) override;
|
||||
|
|
|
@ -474,7 +474,7 @@ void LoadSave::Write(void *pData, int nSize)
|
|||
ThrowError("File error #%d writing save file.", errno);
|
||||
}
|
||||
|
||||
bool GameInterface::LoadGame(FSaveGameNode* node)
|
||||
bool GameInterface::LoadGame()
|
||||
{
|
||||
sndKillAllSounds();
|
||||
sfxKillAllSounds();
|
||||
|
@ -534,7 +534,7 @@ bool GameInterface::LoadGame(FSaveGameNode* node)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GameInterface::SaveGame(FSaveGameNode* node)
|
||||
bool GameInterface::SaveGame()
|
||||
{
|
||||
LoadSave::hSFile = WriteSavegameChunk("snapshot.bld");
|
||||
|
||||
|
|
|
@ -41,8 +41,6 @@ public:
|
|||
virtual void Load(void);
|
||||
void Read(void *, int);
|
||||
void Write(void *, int);
|
||||
static void LoadGame(FSavegameNode *);
|
||||
static void SaveGame(FSavegameNode*);
|
||||
};
|
||||
|
||||
void LoadSaveSetup(void);
|
||||
|
|
|
@ -1529,6 +1529,19 @@ void DrawFrame(F2DDrawer* twod, PalEntry color, int left, int top, int width, in
|
|||
twod->AddColorOnlyQuad(right, top - offset, offset, height + 2 * offset, color);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Screen, DrawLineFrame)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_COLOR(color);
|
||||
PARAM_INT(left);
|
||||
PARAM_INT(top);
|
||||
PARAM_INT(width);
|
||||
PARAM_INT(height);
|
||||
PARAM_INT(thickness);
|
||||
DrawFrame(twod, color, left, top, width, height, thickness);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void V_CalcCleanFacs(int designwidth, int designheight, int realwidth, int realheight, int* cleanx, int* cleany, int* _cx1, int* _cx2)
|
||||
{
|
||||
if (designheight < 240 && realheight >= 480) designheight = 240;
|
||||
|
|
541
source/common/menu/savegamemanager.cpp
Normal file
541
source/common/menu/savegamemanager.cpp
Normal file
|
@ -0,0 +1,541 @@
|
|||
/*
|
||||
** loadsavemenu.cpp
|
||||
** The load game and save game menus
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2001-2010 Randy Heit
|
||||
** Copyright 2010-2020 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include "menu.h"
|
||||
#include "version.h"
|
||||
#include "m_png.h"
|
||||
#include "filesystem.h"
|
||||
#include "v_text.h"
|
||||
#include "gstrings.h"
|
||||
#include "serializer.h"
|
||||
#include "vm.h"
|
||||
#include "i_system.h"
|
||||
#include "v_video.h"
|
||||
#include "findfile.h"
|
||||
#include "v_draw.h"
|
||||
#include "savegamemanager.h"
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Save data maintenance
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManagerBase::ClearSaveGames()
|
||||
{
|
||||
for (unsigned i = 0; i<SaveGames.Size(); i++)
|
||||
{
|
||||
if (!SaveGames[i]->bNoDelete)
|
||||
delete SaveGames[i];
|
||||
}
|
||||
SaveGames.Clear();
|
||||
}
|
||||
|
||||
FSavegameManagerBase::~FSavegameManagerBase()
|
||||
{
|
||||
ClearSaveGames();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Save data maintenance
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
int FSavegameManagerBase::RemoveSaveSlot(int index)
|
||||
{
|
||||
int listindex = SaveGames[0]->bNoDelete ? index - 1 : index;
|
||||
if (listindex < 0) return index;
|
||||
|
||||
remove(SaveGames[index]->Filename.GetChars());
|
||||
UnloadSaveData();
|
||||
|
||||
FSaveGameNode *file = SaveGames[index];
|
||||
|
||||
if (quickSaveSlot == SaveGames[index])
|
||||
{
|
||||
quickSaveSlot = nullptr;
|
||||
}
|
||||
if (!file->bNoDelete) delete file;
|
||||
|
||||
if (LastSaved == listindex) LastSaved = -1;
|
||||
else if (LastSaved > listindex) LastSaved--;
|
||||
if (LastAccessed == listindex) LastAccessed = -1;
|
||||
else if (LastAccessed > listindex) LastAccessed--;
|
||||
|
||||
SaveGames.Delete(index);
|
||||
if ((unsigned)index >= SaveGames.Size()) index--;
|
||||
ExtractSaveData(index);
|
||||
return index;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveSaveSlot)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
PARAM_INT(sel);
|
||||
ACTION_RETURN_INT(self->RemoveSaveSlot(sel));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
int FSavegameManagerBase::InsertSaveNode(FSaveGameNode *node)
|
||||
{
|
||||
if (SaveGames.Size() == 0)
|
||||
{
|
||||
return SaveGames.Push(node);
|
||||
}
|
||||
|
||||
if (node->bOldVersion)
|
||||
{ // Add node at bottom of list
|
||||
return SaveGames.Push(node);
|
||||
}
|
||||
else
|
||||
{ // Add node at top of list
|
||||
unsigned int i = 0;
|
||||
//if (SaveGames[0] == &NewSaveNode) i++; // To not insert above the "new savegame" dummy entry.
|
||||
for (; i < SaveGames.Size(); i++)
|
||||
{
|
||||
if (SaveGames[i]->bOldVersion || node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
SaveGames.Insert(i, node);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManagerBase::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave)
|
||||
{
|
||||
FSaveGameNode *node;
|
||||
|
||||
if (file.IsEmpty())
|
||||
return;
|
||||
|
||||
ReadSaveStrings();
|
||||
|
||||
// See if the file is already in our list
|
||||
for (unsigned i = 0; i<SaveGames.Size(); i++)
|
||||
{
|
||||
FSaveGameNode *node = SaveGames[i];
|
||||
#ifdef __unix__
|
||||
if (node->Filename.Compare(file) == 0)
|
||||
#else
|
||||
if (node->Filename.CompareNoCase(file) == 0)
|
||||
#endif
|
||||
{
|
||||
node->SaveTitle = title;
|
||||
node->bOldVersion = false;
|
||||
node->bMissingWads = false;
|
||||
if (okForQuicksave)
|
||||
{
|
||||
if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node;
|
||||
LastAccessed = LastSaved = i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
node = new FSaveGameNode;
|
||||
node->SaveTitle = title;
|
||||
node->Filename = file;
|
||||
node->bOldVersion = false;
|
||||
node->bMissingWads = false;
|
||||
int index = InsertSaveNode(node);
|
||||
|
||||
if (okForQuicksave)
|
||||
{
|
||||
if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node;
|
||||
LastAccessed = LastSaved = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
LastAccessed = ++LastSaved;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Loads the savegame
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManagerBase::LoadSavegame(int Selected)
|
||||
{
|
||||
PerformLoadGame(SaveGames[Selected]->Filename.GetChars(), true);
|
||||
if (quickSaveSlot == (FSaveGameNode*)1)
|
||||
{
|
||||
quickSaveSlot = SaveGames[Selected];
|
||||
}
|
||||
M_ClearMenus();
|
||||
LastAccessed = Selected;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
PARAM_INT(sel);
|
||||
self->LoadSavegame(sel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManagerBase::DoSave(int Selected, const char *savegamestring)
|
||||
{
|
||||
if (Selected != 0)
|
||||
{
|
||||
auto node = SaveGames[Selected];
|
||||
PerformSaveGame(node->Filename.GetChars(), savegamestring);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find an unused filename and save as that
|
||||
FString filename;
|
||||
int i;
|
||||
|
||||
for (i = 0;; ++i)
|
||||
{
|
||||
filename = BuildSaveName("save", i);
|
||||
if (!FileExists(filename))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
PerformSaveGame(filename, savegamestring);
|
||||
}
|
||||
M_ClearMenus();
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
PARAM_INT(sel);
|
||||
PARAM_STRING(name);
|
||||
self->DoSave(sel, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
unsigned FSavegameManagerBase::ExtractSaveData(int index)
|
||||
{
|
||||
FResourceFile *resf;
|
||||
FSaveGameNode *node;
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
if (SaveGames.Size() > 0 && SaveGames[0]->bNoDelete)
|
||||
{
|
||||
index = LastSaved + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = LastAccessed < 0? 0 : LastAccessed;
|
||||
}
|
||||
}
|
||||
|
||||
UnloadSaveData();
|
||||
|
||||
if ((unsigned)index < SaveGames.Size() &&
|
||||
(node = SaveGames[index]) &&
|
||||
!node->Filename.IsEmpty() &&
|
||||
!node->bOldVersion &&
|
||||
(resf = FResourceFile::OpenResourceFile(node->Filename.GetChars(), true)) != nullptr)
|
||||
{
|
||||
FResourceLump *info = resf->FindLump("info.json");
|
||||
if (info == nullptr)
|
||||
{
|
||||
// this should not happen because the file has already been verified.
|
||||
return index;
|
||||
}
|
||||
|
||||
void* data = info->Lock();
|
||||
FSerializer arc;
|
||||
if (!arc.OpenReader((const char*)data, info->LumpSize))
|
||||
{
|
||||
info->Unlock();
|
||||
return index;
|
||||
}
|
||||
info->Unlock();
|
||||
|
||||
SaveCommentString = ExtractSaveComment(arc);
|
||||
|
||||
FResourceLump *pic = resf->FindLump("savepic.png");
|
||||
if (pic != nullptr)
|
||||
{
|
||||
FileReader picreader;
|
||||
|
||||
picreader.OpenMemoryArray([=](TArray<uint8_t> &array)
|
||||
{
|
||||
auto cache = pic->Lock();
|
||||
array.Resize(pic->LumpSize);
|
||||
memcpy(&array[0], cache, pic->LumpSize);
|
||||
pic->Unlock();
|
||||
return true;
|
||||
});
|
||||
PNGHandle *png = M_VerifyPNG(picreader);
|
||||
if (png != nullptr)
|
||||
{
|
||||
SavePic = PNGTexture_CreateFromFile(png, node->Filename);
|
||||
delete png;
|
||||
if (SavePic && SavePic->GetDisplayWidth() == 1 && SavePic->GetDisplayHeight() == 1)
|
||||
{
|
||||
delete SavePic;
|
||||
SavePic = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete resf;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManagerBase::UnloadSaveData()
|
||||
{
|
||||
if (SavePic != nullptr)
|
||||
{
|
||||
delete SavePic;
|
||||
}
|
||||
|
||||
SaveCommentString = "";
|
||||
SavePic = nullptr;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, UnloadSaveData)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
self->UnloadSaveData();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManagerBase::ClearSaveStuff()
|
||||
{
|
||||
UnloadSaveData();
|
||||
if (quickSaveSlot == (FSaveGameNode*)1)
|
||||
{
|
||||
quickSaveSlot = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, ClearSaveStuff)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
self->ClearSaveStuff();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool FSavegameManagerBase::DrawSavePic(int x, int y, int w, int h)
|
||||
{
|
||||
if (SavePic == nullptr) return false;
|
||||
DrawTexture(twod, SavePic, x, y, DTA_DestWidth, w, DTA_DestHeight, h, DTA_Masked, false, TAG_DONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, DrawSavePic)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
PARAM_INT(x);
|
||||
PARAM_INT(y);
|
||||
PARAM_INT(w);
|
||||
PARAM_INT(h);
|
||||
ACTION_RETURN_BOOL(self->DrawSavePic(x, y, w, h));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManagerBase::SetFileInfo(int Selected)
|
||||
{
|
||||
if (!SaveGames[Selected]->Filename.IsEmpty())
|
||||
{
|
||||
SaveCommentString.Format("File on disk:\n%s", SaveGames[Selected]->Filename.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, SetFileInfo)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
PARAM_INT(i);
|
||||
self->SetFileInfo(i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
unsigned FSavegameManagerBase::SavegameCount()
|
||||
{
|
||||
return SaveGames.Size();
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
ACTION_RETURN_INT(self->SavegameCount());
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FSaveGameNode *FSavegameManagerBase::GetSavegame(int i)
|
||||
{
|
||||
return SaveGames[i];
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, GetSavegame)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
PARAM_INT(i);
|
||||
ACTION_RETURN_POINTER(self->GetSavegame(i));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManagerBase::InsertNewSaveNode()
|
||||
{
|
||||
NewSaveNode.SaveTitle = GStrings("NEWSAVE");
|
||||
NewSaveNode.bNoDelete = true;
|
||||
SaveGames.Insert(0, &NewSaveNode);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, InsertNewSaveNode)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
self->InsertNewSaveNode();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool FSavegameManagerBase::RemoveNewSaveNode()
|
||||
{
|
||||
if (SaveGames[0] == &NewSaveNode)
|
||||
{
|
||||
SaveGames.Delete(0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveNewSaveNode)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
ACTION_RETURN_INT(self->RemoveNewSaveNode());
|
||||
}
|
||||
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, ReadSaveStrings)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
self->ReadSaveStrings();
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, ExtractSaveData)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase);
|
||||
PARAM_INT(sel);
|
||||
ACTION_RETURN_INT(self->ExtractSaveData(sel));
|
||||
}
|
||||
|
||||
|
||||
DEFINE_FIELD(FSaveGameNode, SaveTitle);
|
||||
DEFINE_FIELD(FSaveGameNode, Filename);
|
||||
DEFINE_FIELD(FSaveGameNode, bOldVersion);
|
||||
DEFINE_FIELD(FSaveGameNode, bMissingWads);
|
||||
DEFINE_FIELD(FSaveGameNode, bNoDelete);
|
||||
|
||||
DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, WindowSize);
|
||||
DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, quickSaveSlot);
|
||||
DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, SaveCommentString);
|
||||
|
61
source/common/menu/savegamemanager.h
Normal file
61
source/common/menu/savegamemanager.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
#include "zstring.h"
|
||||
#include "tarray.h"
|
||||
|
||||
class FGameTexture;
|
||||
class FSerializer;
|
||||
|
||||
// The savegame manager contains too much code that is game specific. Parts are shareable but need more work first.
|
||||
struct FSaveGameNode
|
||||
{
|
||||
FString SaveTitle;
|
||||
FString Filename;
|
||||
bool bOldVersion = false;
|
||||
bool bMissingWads = false;
|
||||
bool bNoDelete = false;
|
||||
};
|
||||
|
||||
struct FSavegameManagerBase
|
||||
{
|
||||
protected:
|
||||
TArray<FSaveGameNode*> SaveGames;
|
||||
FSaveGameNode NewSaveNode;
|
||||
int LastSaved = -1;
|
||||
int LastAccessed = -1;
|
||||
FGameTexture *SavePic = nullptr;
|
||||
|
||||
public:
|
||||
int WindowSize = 0;
|
||||
FString SaveCommentString;
|
||||
FSaveGameNode *quickSaveSlot = nullptr;
|
||||
virtual ~FSavegameManagerBase();
|
||||
|
||||
protected:
|
||||
int InsertSaveNode(FSaveGameNode *node);
|
||||
virtual void PerformSaveGame(const char *fn, const char *sgdesc) = 0;
|
||||
virtual void PerformLoadGame(const char *fn, bool) = 0;
|
||||
virtual FString ExtractSaveComment(FSerializer &arc) = 0;
|
||||
virtual FString BuildSaveName(const char* prefix, int slot) = 0;
|
||||
public:
|
||||
void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave);
|
||||
void ClearSaveGames();
|
||||
|
||||
virtual void ReadSaveStrings() = 0;
|
||||
void UnloadSaveData();
|
||||
|
||||
int RemoveSaveSlot(int index);
|
||||
void LoadSavegame(int Selected);
|
||||
void DoSave(int Selected, const char *savegamestring);
|
||||
unsigned ExtractSaveData(int index);
|
||||
void ClearSaveStuff();
|
||||
bool DrawSavePic(int x, int y, int w, int h);
|
||||
void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor);
|
||||
void SetFileInfo(int Selected);
|
||||
unsigned SavegameCount();
|
||||
FSaveGameNode *GetSavegame(int i);
|
||||
void InsertNewSaveNode();
|
||||
bool RemoveNewSaveNode();
|
||||
|
||||
};
|
||||
|
|
@ -22,10 +22,8 @@ extern cycle_t drawtime, actortime, thinktime, gameupdatetime;
|
|||
extern bool r_NoInterpolate;
|
||||
|
||||
struct MapRecord;
|
||||
struct FSaveGameNode;
|
||||
extern MapRecord* g_nextmap;
|
||||
extern int g_nextskill;
|
||||
extern FSaveGameNode* g_savenode;
|
||||
|
||||
extern FMemArena dump; // this is for memory blocks than cannot be deallocated without some huge effort. Put them in here so that they do not register on shutdown.
|
||||
|
||||
|
|
|
@ -40,7 +40,8 @@ enum gameaction_t : int
|
|||
ga_savegame, // save the game
|
||||
ga_autosave, // autosave the game (for triggering a save from within the game.)
|
||||
ga_completed, // Level was exited.
|
||||
ga_nextlevel // Actually start the next level.
|
||||
ga_nextlevel, // Actually start the next level.
|
||||
ga_loadgamehidecon
|
||||
};
|
||||
extern gamestate_t gamestate;
|
||||
extern gameaction_t gameaction;
|
||||
|
|
|
@ -33,21 +33,6 @@ struct FSavegameInfo
|
|||
int currentsavever;
|
||||
};
|
||||
|
||||
struct FSaveGameNode
|
||||
{
|
||||
FString SaveTitle;
|
||||
FString Filename;
|
||||
bool bOldVersion = false;
|
||||
bool bMissingWads = false;
|
||||
bool bNoDelete = false;
|
||||
bool bIsExt = false;
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return Filename.IsNotEmpty() && !bOldVersion && !bMissingWads;
|
||||
}
|
||||
};
|
||||
|
||||
struct ReservedSpace
|
||||
{
|
||||
int top;
|
||||
|
@ -83,8 +68,8 @@ struct GameInterface
|
|||
virtual bool DrawSpecialScreen(const DVector2 &origin, int tilenum) { return false; }
|
||||
virtual void DrawCenteredTextScreen(const DVector2& origin, const char* text, int position, bool withbg = true);
|
||||
virtual double SmallFontScale() { return 1; }
|
||||
virtual bool SaveGame(FSaveGameNode*) { return true; }
|
||||
virtual bool LoadGame(FSaveGameNode*) { return true; }
|
||||
virtual bool SaveGame() { return true; }
|
||||
virtual bool LoadGame() { return true; }
|
||||
virtual void SerializeGameState(FSerializer& arc) {}
|
||||
virtual void DrawPlayerSprite(const DVector2& origin, bool onteam) {}
|
||||
virtual void QuitToTitle() {}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2001-2010 Randy Heit
|
||||
** Copyright 2010-2017 Christoph Oelckers
|
||||
** Copyright 2010-2020 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
|
@ -45,103 +45,7 @@
|
|||
#include "v_video.h"
|
||||
#include "findfile.h"
|
||||
#include "v_draw.h"
|
||||
|
||||
// Save name length limit for old binary formats.
|
||||
#define OLDSAVESTRINGSIZE 24
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Save data maintenance
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManager::ClearSaveGames()
|
||||
{
|
||||
for (unsigned i = 0; i<SaveGames.Size(); i++)
|
||||
{
|
||||
if (!SaveGames[i]->bNoDelete)
|
||||
delete SaveGames[i];
|
||||
}
|
||||
SaveGames.Clear();
|
||||
}
|
||||
|
||||
FSavegameManager::~FSavegameManager()
|
||||
{
|
||||
ClearSaveGames();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Save data maintenance
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
int FSavegameManager::RemoveSaveSlot(int index)
|
||||
{
|
||||
int listindex = SaveGames[0]->bNoDelete ? index - 1 : index;
|
||||
if (listindex < 0) return index;
|
||||
|
||||
remove(SaveGames[index]->Filename.GetChars());
|
||||
UnloadSaveData();
|
||||
|
||||
FSaveGameNode *file = SaveGames[index];
|
||||
|
||||
if (quickSaveSlot == SaveGames[index])
|
||||
{
|
||||
quickSaveSlot = nullptr;
|
||||
}
|
||||
if (!file->bNoDelete) delete file;
|
||||
|
||||
if (LastSaved == listindex) LastSaved = -1;
|
||||
else if (LastSaved > listindex) LastSaved--;
|
||||
if (LastAccessed == listindex) LastAccessed = -1;
|
||||
else if (LastAccessed > listindex) LastAccessed--;
|
||||
|
||||
SaveGames.Delete(index);
|
||||
if ((unsigned)index >= SaveGames.Size()) index--;
|
||||
ExtractSaveData(index);
|
||||
return index;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveSaveSlot)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
PARAM_INT(sel);
|
||||
ACTION_RETURN_INT(self->RemoveSaveSlot(sel));
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
int FSavegameManager::InsertSaveNode(FSaveGameNode *node)
|
||||
{
|
||||
if (SaveGames.Size() == 0)
|
||||
{
|
||||
return SaveGames.Push(node);
|
||||
}
|
||||
|
||||
if (node->bOldVersion)
|
||||
{ // Add node at bottom of list
|
||||
return SaveGames.Push(node);
|
||||
}
|
||||
else
|
||||
{ // Add node at top of list
|
||||
unsigned int i;
|
||||
for (i = 0; i < SaveGames.Size(); i++)
|
||||
{
|
||||
if (SaveGames[i]->bOldVersion || node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
SaveGames.Insert(i, node);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
#include "savegamehelp.h"
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
|
@ -153,7 +57,6 @@ int FSavegameManager::InsertSaveNode(FSaveGameNode *node)
|
|||
|
||||
void FSavegameManager::ReadSaveStrings()
|
||||
{
|
||||
#if 0
|
||||
if (SaveGames.Size() == 0)
|
||||
{
|
||||
void *filefirst;
|
||||
|
@ -162,153 +65,44 @@ void FSavegameManager::ReadSaveStrings()
|
|||
|
||||
LastSaved = LastAccessed = -1;
|
||||
quickSaveSlot = nullptr;
|
||||
filter = G_BuildSaveName("*." SAVEGAME_EXT, -1);
|
||||
filter = G_BuildSaveName("*");
|
||||
filefirst = I_FindFirst(filter.GetChars(), &c_file);
|
||||
if (filefirst != ((void *)(-1)))
|
||||
{
|
||||
do
|
||||
{
|
||||
// I_FindName only returns the file's name and not its full path
|
||||
FString filepath = G_BuildSaveName(I_FindName(&c_file), -1);
|
||||
FString filepath = G_BuildSaveName(I_FindName(&c_file));
|
||||
|
||||
std::unique_ptr<FResourceFile> savegame(FResourceFile::OpenResourceFile(filepath, true, true));
|
||||
FResourceFile *savegame = FResourceFile::OpenResourceFile(filepath, true, true);
|
||||
if (savegame != nullptr)
|
||||
{
|
||||
bool oldVer = false;
|
||||
bool missing = false;
|
||||
FResourceLump *info = savegame->FindLump("info.json");
|
||||
if (info == nullptr)
|
||||
{
|
||||
// savegame info not found. This is not a savegame so leave it alone.
|
||||
delete savegame;
|
||||
continue;
|
||||
}
|
||||
void *data = info->Lock();
|
||||
FSerializer arc;
|
||||
if (arc.OpenReader((const char *)data, info->LumpSize))
|
||||
auto fr = info->NewReader();
|
||||
FString title;
|
||||
int check = G_ValidateSavegame(fr, &title, true);
|
||||
fr.Close();
|
||||
delete savegame;
|
||||
if (check != 0)
|
||||
{
|
||||
int savever = 0;
|
||||
arc("Save Version", savever);
|
||||
FString engine = arc.GetString("Engine");
|
||||
FString iwad = arc.GetString("Game WAD");
|
||||
FString title = arc.GetString("Title");
|
||||
|
||||
|
||||
if (engine.Compare(GAMESIG) != 0 || savever > SAVEVER)
|
||||
{
|
||||
// different engine or newer version:
|
||||
// not our business. Leave it alone.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (savever < MINSAVEVER)
|
||||
{
|
||||
// old, incompatible savegame. List as not usable.
|
||||
oldVer = true;
|
||||
}
|
||||
else if (iwad.CompareNoCase(fileSystem.GetResourceFileName(fileSystem.GetIwadNum())) == 0)
|
||||
{
|
||||
missing = !G_CheckSaveGameWads(arc, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// different game. Skip this.
|
||||
continue;
|
||||
}
|
||||
|
||||
FSaveGameNode *node = new FSaveGameNode;
|
||||
node->Filename = filepath;
|
||||
node->bOldVersion = oldVer;
|
||||
node->bMissingWads = missing;
|
||||
node->bOldVersion = check == -1;
|
||||
node->bMissingWads = check == -2;
|
||||
node->SaveTitle = title;
|
||||
InsertSaveNode(node);
|
||||
}
|
||||
|
||||
}
|
||||
else // check for old formats.
|
||||
{
|
||||
FileReader file;
|
||||
if (file.OpenFile(filepath))
|
||||
{
|
||||
PNGHandle *png;
|
||||
char sig[16];
|
||||
char title[OLDSAVESTRINGSIZE + 1];
|
||||
bool oldVer = true;
|
||||
bool addIt = false;
|
||||
bool missing = false;
|
||||
|
||||
// ZDoom 1.23 betas 21-33 have the savesig first.
|
||||
// Earlier versions have the savesig second.
|
||||
// Later versions have the savegame encapsulated inside a PNG.
|
||||
//
|
||||
// Old savegame versions are always added to the menu so
|
||||
// the user can easily delete them if desired.
|
||||
|
||||
title[OLDSAVESTRINGSIZE] = 0;
|
||||
|
||||
if (nullptr != (png = M_VerifyPNG(file)))
|
||||
{
|
||||
char *ver = M_GetPNGText(png, "ZDoom Save Version");
|
||||
if (ver != nullptr)
|
||||
{
|
||||
// An old version
|
||||
if (!M_GetPNGText(png, "Title", title, OLDSAVESTRINGSIZE))
|
||||
{
|
||||
strncpy(title, I_FindName(&c_file), OLDSAVESTRINGSIZE);
|
||||
}
|
||||
addIt = true;
|
||||
delete[] ver;
|
||||
}
|
||||
delete png;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.Seek(0, FileReader::SeekSet);
|
||||
if (file.Read(sig, 16) == 16)
|
||||
{
|
||||
|
||||
if (strncmp(sig, "ZDOOMSAVE", 9) == 0)
|
||||
{
|
||||
if (file.Read(title, OLDSAVESTRINGSIZE) == OLDSAVESTRINGSIZE)
|
||||
{
|
||||
addIt = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(title, sig, 16);
|
||||
if (file.Read(title + 16, OLDSAVESTRINGSIZE - 16) == OLDSAVESTRINGSIZE - 16 &&
|
||||
file.Read(sig, 16) == 16 &&
|
||||
strncmp(sig, "ZDOOMSAVE", 9) == 0)
|
||||
{
|
||||
addIt = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addIt)
|
||||
{
|
||||
FSaveGameNode *node = new FSaveGameNode;
|
||||
node->Filename = filepath;
|
||||
node->bOldVersion = true;
|
||||
node->bMissingWads = false;
|
||||
node->SaveTitle = title;
|
||||
InsertSaveNode(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (I_FindNext(filefirst, &c_file) == 0);
|
||||
I_FindClose(filefirst);
|
||||
} while (I_FindNext (filefirst, &c_file) == 0);
|
||||
I_FindClose (filefirst);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, ReadSaveStrings)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
self->ReadSaveStrings();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -318,78 +112,19 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, ReadSaveStrings)
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManager::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave)
|
||||
void FSavegameManager::PerformLoadGame(const char *f, bool s)
|
||||
{
|
||||
FSaveGameNode *node;
|
||||
|
||||
if (file.IsEmpty())
|
||||
return;
|
||||
|
||||
ReadSaveStrings();
|
||||
|
||||
// See if the file is already in our list
|
||||
for (unsigned i = 0; i<SaveGames.Size(); i++)
|
||||
{
|
||||
FSaveGameNode *node = SaveGames[i];
|
||||
#ifdef __unix__
|
||||
if (node->Filename.Compare(file) == 0)
|
||||
#else
|
||||
if (node->Filename.CompareNoCase(file) == 0)
|
||||
#endif
|
||||
{
|
||||
node->SaveTitle = title;
|
||||
node->bOldVersion = false;
|
||||
node->bMissingWads = false;
|
||||
if (okForQuicksave)
|
||||
{
|
||||
if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node;
|
||||
LastAccessed = LastSaved = i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
node = new FSaveGameNode;
|
||||
node->SaveTitle = title;
|
||||
node->Filename = file;
|
||||
node->bOldVersion = false;
|
||||
node->bMissingWads = false;
|
||||
int index = InsertSaveNode(node);
|
||||
|
||||
if (okForQuicksave)
|
||||
{
|
||||
if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node;
|
||||
LastAccessed = LastSaved = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
LastAccessed = ++LastSaved;
|
||||
}
|
||||
G_LoadGame(f);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Loads the savegame
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManager::LoadSavegame(int Selected)
|
||||
void FSavegameManager::PerformSaveGame(const char *f, const char *s)
|
||||
{
|
||||
//G_LoadGame(SaveGames[Selected]->Filename.GetChars(), true);
|
||||
if (quickSaveSlot == (FSaveGameNode*)1)
|
||||
{
|
||||
quickSaveSlot = SaveGames[Selected];
|
||||
}
|
||||
M_ClearMenus();
|
||||
LastAccessed = Selected;
|
||||
G_SaveGame(f, s, false, false);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame)
|
||||
FString FSavegameManager::BuildSaveName(const char* fn, int slot)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
PARAM_INT(sel);
|
||||
self->LoadSavegame(sel);
|
||||
return 0;
|
||||
return G_BuildSaveName(FStringf("%s%04d", fn, slot));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
@ -398,302 +133,19 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame)
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManager::DoSave(int Selected, const char *savegamestring)
|
||||
FString FSavegameManager::ExtractSaveComment(FSerializer& arc)
|
||||
{
|
||||
#if 0
|
||||
if (Selected != 0)
|
||||
{
|
||||
auto node = SaveGames[Selected];
|
||||
G_SaveGame(node->Filename.GetChars(), savegamestring);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find an unused filename and save as that
|
||||
FString filename;
|
||||
int i;
|
||||
FString comment, fcomment, ncomment, mtime;
|
||||
|
||||
for (i = 0;; ++i)
|
||||
{
|
||||
filename = G_BuildSaveName("save", i);
|
||||
if (!FileExists(filename))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
G_SaveGame(filename, savegamestring);
|
||||
}
|
||||
#endif
|
||||
M_ClearMenus();
|
||||
arc("Creation Time", comment)
|
||||
("Map Label", fcomment)
|
||||
("Map Name", ncomment)
|
||||
("Map Time", mtime);
|
||||
|
||||
comment.AppendFormat("\n%s - %s\n%s", fcomment.GetChars(), ncomment.GetChars(), mtime.GetChars());
|
||||
return comment;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
PARAM_INT(sel);
|
||||
PARAM_STRING(name);
|
||||
self->DoSave(sel, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
unsigned FSavegameManager::ExtractSaveData(int index)
|
||||
{
|
||||
FResourceFile *resf;
|
||||
FSaveGameNode *node;
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
if (SaveGames.Size() > 0 && SaveGames[0]->bNoDelete)
|
||||
{
|
||||
index = LastSaved + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = LastAccessed < 0? 0 : LastAccessed;
|
||||
}
|
||||
}
|
||||
|
||||
UnloadSaveData();
|
||||
|
||||
if ((unsigned)index < SaveGames.Size() &&
|
||||
(node = SaveGames[index]) &&
|
||||
!node->Filename.IsEmpty() &&
|
||||
!node->bOldVersion &&
|
||||
(resf = FResourceFile::OpenResourceFile(node->Filename.GetChars(), true)) != nullptr)
|
||||
{
|
||||
FResourceLump *info = resf->FindLump("info.json");
|
||||
if (info == nullptr)
|
||||
{
|
||||
// this should not happen because the file has already been verified.
|
||||
return index;
|
||||
}
|
||||
void *data = info->Lock();
|
||||
FSerializer arc;
|
||||
if (arc.OpenReader((const char *)data, info->LumpSize))
|
||||
{
|
||||
FString comment;
|
||||
|
||||
FString time = arc.GetString("Creation Time");
|
||||
FString pcomment = arc.GetString("Comment");
|
||||
|
||||
comment = time;
|
||||
if (time.Len() > 0) comment += "\n";
|
||||
comment += pcomment;
|
||||
SaveCommentString = comment;
|
||||
|
||||
// Extract pic
|
||||
FResourceLump *pic = resf->FindLump("savepic.png");
|
||||
if (pic != nullptr)
|
||||
{
|
||||
FileReader picreader;
|
||||
|
||||
picreader.OpenMemoryArray([=](TArray<uint8_t> &array)
|
||||
{
|
||||
auto cache = pic->Lock();
|
||||
array.Resize(pic->LumpSize);
|
||||
memcpy(&array[0], cache, pic->LumpSize);
|
||||
return true;
|
||||
});
|
||||
PNGHandle *png = M_VerifyPNG(picreader);
|
||||
if (png != nullptr)
|
||||
{
|
||||
SavePic = PNGTexture_CreateFromFile(png, node->Filename);
|
||||
delete png;
|
||||
if (SavePic && SavePic->GetDisplayWidth() == 1 && SavePic->GetDisplayHeight() == 1)
|
||||
{
|
||||
delete SavePic;
|
||||
SavePic = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete resf;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, ExtractSaveData)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
PARAM_INT(sel);
|
||||
ACTION_RETURN_INT(self->ExtractSaveData(sel));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManager::UnloadSaveData()
|
||||
{
|
||||
if (SavePic != nullptr)
|
||||
{
|
||||
delete SavePic;
|
||||
}
|
||||
|
||||
SaveCommentString = "";
|
||||
SavePic = nullptr;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, UnloadSaveData)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
self->UnloadSaveData();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManager::ClearSaveStuff()
|
||||
{
|
||||
UnloadSaveData();
|
||||
if (quickSaveSlot == (FSaveGameNode*)1)
|
||||
{
|
||||
quickSaveSlot = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, ClearSaveStuff)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
self->ClearSaveStuff();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool FSavegameManager::DrawSavePic(int x, int y, int w, int h)
|
||||
{
|
||||
if (SavePic == nullptr) return false;
|
||||
DrawTexture(twod, SavePic, x, y, DTA_DestWidth, w, DTA_DestHeight, h, DTA_Masked, false, TAG_DONE);
|
||||
return true;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, DrawSavePic)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
PARAM_INT(x);
|
||||
PARAM_INT(y);
|
||||
PARAM_INT(w);
|
||||
PARAM_INT(h);
|
||||
ACTION_RETURN_BOOL(self->DrawSavePic(x, y, w, h));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManager::SetFileInfo(int Selected)
|
||||
{
|
||||
if (!SaveGames[Selected]->Filename.IsEmpty())
|
||||
{
|
||||
SaveCommentString.Format("File on disk:\n%s", SaveGames[Selected]->Filename.GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, SetFileInfo)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
PARAM_INT(i);
|
||||
self->SetFileInfo(i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
unsigned FSavegameManager::SavegameCount()
|
||||
{
|
||||
return SaveGames.Size();
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
ACTION_RETURN_INT(self->SavegameCount());
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
FSaveGameNode *FSavegameManager::GetSavegame(int i)
|
||||
{
|
||||
return SaveGames[i];
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, GetSavegame)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
PARAM_INT(i);
|
||||
ACTION_RETURN_POINTER(self->GetSavegame(i));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FSavegameManager::InsertNewSaveNode()
|
||||
{
|
||||
NewSaveNode.SaveTitle = GStrings["NEWSAVE"];
|
||||
NewSaveNode.bNoDelete = true;
|
||||
SaveGames.Insert(0, &NewSaveNode);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, InsertNewSaveNode)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
self->InsertNewSaveNode();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool FSavegameManager::RemoveNewSaveNode()
|
||||
{
|
||||
if (SaveGames[0] == &NewSaveNode)
|
||||
{
|
||||
SaveGames.Delete(0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveNewSaveNode)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager);
|
||||
ACTION_RETURN_INT(self->RemoveNewSaveNode());
|
||||
}
|
||||
|
||||
|
||||
FSavegameManager savegameManager;
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FSavegameManager, GetManager)
|
||||
|
@ -702,15 +154,3 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, GetManager)
|
|||
ACTION_RETURN_POINTER(&savegameManager);
|
||||
}
|
||||
|
||||
|
||||
|
||||
DEFINE_FIELD(FSaveGameNode, SaveTitle);
|
||||
DEFINE_FIELD(FSaveGameNode, Filename);
|
||||
DEFINE_FIELD(FSaveGameNode, bOldVersion);
|
||||
DEFINE_FIELD(FSaveGameNode, bMissingWads);
|
||||
DEFINE_FIELD(FSaveGameNode, bNoDelete);
|
||||
|
||||
DEFINE_FIELD(FSavegameManager, WindowSize);
|
||||
DEFINE_FIELD(FSavegameManager, quickSaveSlot);
|
||||
DEFINE_FIELD(FSavegameManager, SaveCommentString);
|
||||
|
||||
|
|
|
@ -61,6 +61,8 @@
|
|||
#include "razemenu.h"
|
||||
#include "mapinfo.h"
|
||||
#include "statistics.h"
|
||||
#include "i_net.h"
|
||||
#include "savegamehelp.h"
|
||||
|
||||
EXTERN_CVAR(Int, cl_gfxlocalization)
|
||||
EXTERN_CVAR(Bool, m_quickexit)
|
||||
|
@ -131,12 +133,12 @@ bool M_SetSpecialMenu(FName& menu, int param)
|
|||
case NAME_Quitmenu:
|
||||
// This is no separate class
|
||||
C_DoCommand("menu_quit");
|
||||
return true;
|
||||
return false;
|
||||
|
||||
case NAME_EndGameMenu:
|
||||
// This is no separate class
|
||||
C_DoCommand("menu_endgame");
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// End of special checks
|
||||
|
@ -251,54 +253,43 @@ CCMD(menu_endgame)
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (quicksave)
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD(quicksave)
|
||||
{ // F6
|
||||
#if 0
|
||||
if (!usergame || (players[consoleplayer].health <= 0 && !multiplayer))
|
||||
{
|
||||
S_Sound (CHAN_VOICE, CHANF_UI, "menu/invalid", snd_menuvolume, ATTN_NONE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gamestate != GS_LEVEL)
|
||||
return;
|
||||
|
||||
// If the quick save rotation is enabled, it handles the save slot.
|
||||
if (quicksaverotation)
|
||||
{
|
||||
G_DoQuickSave();
|
||||
return;
|
||||
}
|
||||
if (!gi->CanSave()) return;
|
||||
|
||||
if (savegameManager.quickSaveSlot == NULL || savegameManager.quickSaveSlot == (FSaveGameNode*)1)
|
||||
{
|
||||
S_Sound(CHAN_VOICE, CHANF_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
|
||||
M_StartControlPanel(false);
|
||||
M_StartControlPanel(true);
|
||||
M_SetMenu(NAME_Savegamemenu);
|
||||
return;
|
||||
}
|
||||
|
||||
auto slot = savegameManager.quickSaveSlot;
|
||||
|
||||
// [mxd]. Just save the game, no questions asked.
|
||||
if (!saveloadconfirmation)
|
||||
{
|
||||
G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars());
|
||||
G_SaveGame(savegameManager.quickSaveSlot->Filename, savegameManager.quickSaveSlot->SaveTitle, true, true);
|
||||
return;
|
||||
}
|
||||
|
||||
S_Sound(CHAN_VOICE, CHANF_UI, "menu/activate", snd_menuvolume, ATTN_NONE);
|
||||
|
||||
FString tempstring = GStrings("QSPROMPT");
|
||||
tempstring.Substitute("%s", savegameManager.quickSaveSlot->SaveTitle.GetChars());
|
||||
tempstring.Substitute("%s", slot->SaveTitle.GetChars());
|
||||
M_StartControlPanel(true);
|
||||
|
||||
DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []()
|
||||
{
|
||||
G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->SaveTitle.GetChars());
|
||||
S_Sound(CHAN_VOICE, CHANF_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
|
||||
M_ClearMenus();
|
||||
});
|
||||
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []()
|
||||
{
|
||||
G_SaveGame(savegameManager.quickSaveSlot->Filename, savegameManager.quickSaveSlot->SaveTitle, true, true);
|
||||
});
|
||||
|
||||
M_ActivateMenu(newmenu);
|
||||
#endif
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
@ -307,21 +298,20 @@ CCMD (quicksave)
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (quickload)
|
||||
CCMD(quickload)
|
||||
{ // F9
|
||||
#if 0
|
||||
if (netgame)
|
||||
{
|
||||
M_StartControlPanel(true);
|
||||
M_StartMessage (GStrings("QLOADNET"), 1);
|
||||
M_StartMessage(GStrings("QLOADNET"), 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (savegameManager.quickSaveSlot == NULL || savegameManager.quickSaveSlot == (FSaveGameNode*)1)
|
||||
if (savegameManager.quickSaveSlot == nullptr || savegameManager.quickSaveSlot == (FSaveGameNode*)1)
|
||||
{
|
||||
M_StartControlPanel(true);
|
||||
// signal that whatever gets loaded should be the new quicksave
|
||||
savegameManager.quickSaveSlot = (FSaveGameNode *)1;
|
||||
savegameManager.quickSaveSlot = (FSaveGameNode*)1;
|
||||
M_SetMenu(NAME_Loadgamemenu);
|
||||
return;
|
||||
}
|
||||
|
@ -329,7 +319,7 @@ CCMD (quickload)
|
|||
// [mxd]. Just load the game, no questions asked.
|
||||
if (!saveloadconfirmation)
|
||||
{
|
||||
G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars());
|
||||
G_LoadGame(savegameManager.quickSaveSlot->Filename);
|
||||
return;
|
||||
}
|
||||
FString tempstring = GStrings("QLPROMPT");
|
||||
|
@ -337,14 +327,11 @@ CCMD (quickload)
|
|||
|
||||
M_StartControlPanel(true);
|
||||
|
||||
DMenu *newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []()
|
||||
{
|
||||
G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars());
|
||||
S_Sound(CHAN_VOICE, CHANF_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE);
|
||||
M_ClearMenus();
|
||||
DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []()
|
||||
{
|
||||
G_LoadGame(savegameManager.quickSaveSlot->Filename);
|
||||
});
|
||||
M_ActivateMenu(newmenu);
|
||||
#endif
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "menu.h"
|
||||
#include "gamestruct.h"
|
||||
#include "c_cvars.h"
|
||||
#include "savegamemanager.h"
|
||||
|
||||
extern bool help_disabled;
|
||||
|
||||
|
@ -14,45 +15,13 @@ void M_StartupSkillMenu(FNewGameStartup *gs);
|
|||
void SetDefaultMenuColors();
|
||||
void BuildGameMenus();
|
||||
|
||||
// The savegame manager contains too much code that is game specific. Parts are shareable but need more work first.
|
||||
|
||||
struct FSavegameManager
|
||||
class FSavegameManager : public FSavegameManagerBase
|
||||
{
|
||||
private:
|
||||
TArray<FSaveGameNode*> SaveGames;
|
||||
FSaveGameNode NewSaveNode;
|
||||
int LastSaved = -1;
|
||||
int LastAccessed = -1;
|
||||
FGameTexture *SavePic = nullptr;
|
||||
|
||||
public:
|
||||
int WindowSize = 0;
|
||||
FString SaveCommentString;
|
||||
FSaveGameNode *quickSaveSlot = nullptr;
|
||||
~FSavegameManager();
|
||||
|
||||
private:
|
||||
int InsertSaveNode(FSaveGameNode *node);
|
||||
public:
|
||||
void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave);
|
||||
void ClearSaveGames();
|
||||
|
||||
void ReadSaveStrings();
|
||||
void UnloadSaveData();
|
||||
|
||||
int RemoveSaveSlot(int index);
|
||||
void LoadSavegame(int Selected);
|
||||
void DoSave(int Selected, const char *savegamestring);
|
||||
unsigned ExtractSaveData(int index);
|
||||
void ClearSaveStuff();
|
||||
bool DrawSavePic(int x, int y, int w, int h);
|
||||
void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor);
|
||||
void SetFileInfo(int Selected);
|
||||
unsigned SavegameCount();
|
||||
FSaveGameNode *GetSavegame(int i);
|
||||
void InsertNewSaveNode();
|
||||
bool RemoveNewSaveNode();
|
||||
|
||||
void PerformSaveGame(const char *fn, const char *sgdesc) override;
|
||||
void PerformLoadGame(const char *fn, bool) override;
|
||||
FString ExtractSaveComment(FSerializer &arc) override;
|
||||
FString BuildSaveName(const char* prefix, int slot) override;
|
||||
void ReadSaveStrings() override;
|
||||
};
|
||||
|
||||
extern FSavegameManager savegameManager;
|
||||
|
|
|
@ -61,6 +61,7 @@ static FResourceFile *savereader;
|
|||
void LoadEngineState();
|
||||
void SaveEngineState();
|
||||
void WriteSavePic(FileWriter* file, int width, int height);
|
||||
extern FString BackupSaveGame;
|
||||
|
||||
CVAR(String, cl_savedir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||
|
||||
|
@ -592,6 +593,48 @@ static int nextquicksave = -1;
|
|||
self = 1;
|
||||
}
|
||||
|
||||
void DoLoadGame(const char* name)
|
||||
{
|
||||
if (OpenSaveGameForRead(name))
|
||||
{
|
||||
if (gi->LoadGame())
|
||||
{
|
||||
gameaction = ga_level;
|
||||
}
|
||||
else
|
||||
{
|
||||
I_Error("%s: Failed to load savegame", name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
I_Error("%s: Failed to open savegame", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void G_LoadGame(const char *filename)
|
||||
{
|
||||
inputState.ClearAllInput();
|
||||
gi->FreeLevelData();
|
||||
DoLoadGame(filename);
|
||||
BackupSaveGame = filename;
|
||||
}
|
||||
|
||||
void G_SaveGame(const char *fn, const char *desc, bool ok4q, bool forceq)
|
||||
{
|
||||
if (OpenSaveGameForWrite(fn, desc))
|
||||
{
|
||||
if (gi->SaveGame() && FinishSavegameWrite())
|
||||
{
|
||||
savegameManager.NotifyNewSave(fn, desc, ok4q, forceq);
|
||||
Printf(PRINT_NOTIFY, "%s\n", GStrings("GAME SAVED"));
|
||||
BackupSaveGame = fn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void M_Autosave()
|
||||
{
|
||||
if (disableautosave) return;
|
||||
|
@ -611,12 +654,11 @@ void M_Autosave()
|
|||
num.Int = nextautosave;
|
||||
autosavenum.ForceSet(num, CVAR_Int);
|
||||
|
||||
FSaveGameNode sg;
|
||||
sg.Filename = G_BuildSaveName(FStringf("auto%04d", nextautosave));
|
||||
auto Filename = G_BuildSaveName(FStringf("auto%04d", nextautosave));
|
||||
readableTime = myasctime();
|
||||
sg.SaveTitle.Format("Autosave %s", readableTime);
|
||||
FStringf SaveTitle("Autosave %s", readableTime);
|
||||
nextautosave = (nextautosave + 1) % count;
|
||||
//savegameManager.SaveGame(&sg, false, false);
|
||||
G_SaveGame(Filename, SaveTitle, false, false);
|
||||
}
|
||||
|
||||
CCMD(autosave)
|
||||
|
@ -643,11 +685,11 @@ CCMD(rotatingquicksave)
|
|||
quicksavenum.ForceSet(num, CVAR_Int);
|
||||
|
||||
FSaveGameNode sg;
|
||||
sg.Filename = G_BuildSaveName(FStringf("quick%04d", nextquicksave));
|
||||
auto Filename = G_BuildSaveName(FStringf("quick%04d", nextquicksave));
|
||||
readableTime = myasctime();
|
||||
sg.SaveTitle.Format("Quicksave %s", readableTime);
|
||||
FStringf SaveTitle("Quicksave %s", readableTime);
|
||||
nextquicksave = (nextquicksave + 1) % count;
|
||||
//savegameManager.SaveGame(&sg, false, false);
|
||||
G_SaveGame(Filename, SaveTitle, false, false);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ class FileReader;
|
|||
FString G_BuildSaveName (const char *prefix);
|
||||
int G_ValidateSavegame(FileReader &fr, FString *savetitle, bool formenu);
|
||||
|
||||
void G_LoadGame(const char* filename);
|
||||
void G_SaveGame(const char* fn, const char* desc, bool ok4q, bool forceq);
|
||||
|
||||
void SaveEngineState();
|
||||
void LoadEngineState();
|
||||
void M_Autosave();
|
||||
|
|
|
@ -243,8 +243,8 @@ struct GameInterface : ::GameInterface
|
|||
void MenuClosed() override;
|
||||
bool StartGame(FNewGameStartup& gs) override;
|
||||
FSavegameInfo GetSaveSig() override;
|
||||
bool LoadGame(FSaveGameNode* sv) override;
|
||||
bool SaveGame(FSaveGameNode* sv) override;
|
||||
bool LoadGame() override;
|
||||
bool SaveGame() override;
|
||||
bool CanSave() override;
|
||||
ReservedSpace GetReservedScreenSpace(int viewsize) override { return { 0, 24 }; }
|
||||
void QuitToTitle() override;
|
||||
|
|
|
@ -34,14 +34,14 @@ void LoadTextureState();
|
|||
|
||||
static TArray<SavegameHelper*> sghelpers(TArray<SavegameHelper*>::NoInit);
|
||||
|
||||
bool GameInterface::SaveGame(FSaveGameNode* sv)
|
||||
bool GameInterface::SaveGame()
|
||||
{
|
||||
for (auto sgh : sghelpers) sgh->Save();
|
||||
SaveTextureState();
|
||||
return 1; // CHECKME
|
||||
}
|
||||
|
||||
bool GameInterface::LoadGame(FSaveGameNode* sv)
|
||||
bool GameInterface::LoadGame()
|
||||
{
|
||||
|
||||
for (auto sgh : sghelpers) sgh->Load();
|
||||
|
|
|
@ -2193,8 +2193,8 @@ struct GameInterface : ::GameInterface
|
|||
bool CanSave() override;
|
||||
bool StartGame(FNewGameStartup& gs) override;
|
||||
FSavegameInfo GetSaveSig() override;
|
||||
bool LoadGame(FSaveGameNode* sv) override;
|
||||
bool SaveGame(FSaveGameNode* sv) override;
|
||||
bool LoadGame() override;
|
||||
bool SaveGame() override;
|
||||
void SetAmbience(bool on) override { if (on) StartAmbientSound(); else StopAmbientSound(); }
|
||||
FString GetCoordString() override;
|
||||
ReservedSpace GetReservedScreenSpace(int viewsize) override;
|
||||
|
|
|
@ -204,7 +204,7 @@ int LoadSymCodeInfo(MFILE_READ fil, void **ptr)
|
|||
|
||||
|
||||
|
||||
bool GameInterface::SaveGame(FSaveGameNode *sv)
|
||||
bool GameInterface::SaveGame()
|
||||
{
|
||||
MFILE_WRITE fil;
|
||||
int i,j;
|
||||
|
@ -643,7 +643,7 @@ bool GameInterface::SaveGame(FSaveGameNode *sv)
|
|||
}
|
||||
|
||||
|
||||
bool GameInterface::LoadGame(FSaveGameNode* sv)
|
||||
bool GameInterface::LoadGame()
|
||||
{
|
||||
MFILE_READ fil;
|
||||
int i,j,saveisshot=0;
|
||||
|
|
|
@ -377,11 +377,9 @@ ImageScroller "CreditsMenu"
|
|||
|
||||
ListMenu "LoadGameMenu"
|
||||
{
|
||||
/*
|
||||
Caption "$MNU_LOADGAME"
|
||||
Position 0, 40
|
||||
Class "LoadMenu" // uses its own implementation
|
||||
*/
|
||||
CaptionItem "$MNU_LOADGAME"
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
|
@ -392,11 +390,9 @@ ListMenu "LoadGameMenu"
|
|||
|
||||
ListMenu "SaveGameMenu"
|
||||
{
|
||||
/*
|
||||
Caption "$MNU_SAVEGAME"
|
||||
Position 0, 40
|
||||
Class "SaveMenu" // uses its own implementation
|
||||
*/
|
||||
CaptionItem "$MNU_SAVEGAME"
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -389,6 +389,7 @@ struct Screen native
|
|||
native static vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...);
|
||||
native static vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...);
|
||||
native static void DrawLine(int x0, int y0, int x1, int y1, Color color, int alpha = 255);
|
||||
native static void DrawLineFrame(Color color, int x0, int y0, int w, int h, int thickness = 1);
|
||||
native static void DrawThickLine(int x0, int y0, int x1, int y1, double thickness, Color color, int alpha = 255);
|
||||
native static Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true);
|
||||
native static double GetAspectRatio();
|
||||
|
|
|
@ -6,3 +6,25 @@ enum ETranslationTable
|
|||
TRANSLATION_Remap,
|
||||
};
|
||||
|
||||
enum gameaction_t : int
|
||||
{
|
||||
ga_nothing,
|
||||
ga_level, // Switch to play mode without any initialization
|
||||
ga_intro,
|
||||
ga_intermission,
|
||||
|
||||
ga_startup, // go back to intro after uninitializing the game state
|
||||
ga_mainmenu, // go back to main menu after uninitializing the game state
|
||||
ga_mainmenunostopsound, // Same but doesn't stop playing sounds.
|
||||
ga_creditsmenu, // go to the credits menu after uninitializing the game state
|
||||
ga_newgame, // start a new game
|
||||
ga_recordgame, // start a new demo recording (later)
|
||||
ga_loadgame, // load a savegame and resume play.
|
||||
ga_loadgameplaydemo, // load a savegame and play a demo.
|
||||
ga_autoloadgame, // load last autosave and resume play.
|
||||
ga_savegame, // save the game
|
||||
ga_autosave, // autosave the game (for triggering a save from within the game.)
|
||||
ga_completed, // Level was exited.
|
||||
ga_nextlevel, // Actually start the next level.
|
||||
ga_loadgamehidecon
|
||||
};
|
||||
|
|
|
@ -91,14 +91,11 @@ class LoadSaveMenu : ListMenu
|
|||
int listboxRows;
|
||||
int listboxHeight;
|
||||
int listboxRight;
|
||||
int listboxBottom;
|
||||
|
||||
int commentLeft;
|
||||
int commentTop;
|
||||
int commentWidth;
|
||||
int commentHeight;
|
||||
int commentRight;
|
||||
int commentBottom;
|
||||
int commentRows;
|
||||
|
||||
bool mEntering;
|
||||
|
@ -118,33 +115,34 @@ class LoadSaveMenu : ListMenu
|
|||
override void Init(Menu parent, ListMenuDescriptor desc)
|
||||
{
|
||||
Super.Init(parent, desc);
|
||||
bool aspect43 = true;
|
||||
int Width43 = screen.GetHeight() * 4 / 3;
|
||||
int Left43 = (screen.GetWidth() - Width43) / 2;
|
||||
|
||||
manager = SavegameManager.GetManager();
|
||||
manager.ReadSaveStrings();
|
||||
double wScale = Width43 / 640.;
|
||||
|
||||
savepicLeft = 10;
|
||||
savepicTop = 54*CleanYfac;
|
||||
savepicWidth = 216*screen.GetWidth() / 640;
|
||||
savepicHeight = 135*screen.GetHeight() / 400;
|
||||
savepicLeft = Left43 + int(20 * wScale);
|
||||
savepicTop = mDesc.mYpos * screen.GetHeight() / 200 ;
|
||||
savepicWidth = int(240 * wScale);
|
||||
savepicHeight = int(180 * wScale);
|
||||
|
||||
FontScale = max(screen.GetHeight() / 480, 1);
|
||||
rowHeight = int(max((NewConsoleFont.GetHeight() + 1) * FontScale, 1));
|
||||
|
||||
listboxLeft = savepicLeft + savepicWidth + 14;
|
||||
listboxLeft = savepicLeft + savepicWidth + int(20*wScale);
|
||||
listboxTop = savepicTop;
|
||||
listboxWidth = screen.GetWidth() - listboxLeft - 10;
|
||||
int listboxHeight1 = screen.GetHeight() - listboxTop - 10;
|
||||
listboxWidth = Width43 + Left43 - listboxLeft - int(30 * wScale);
|
||||
int listboxHeight1 = screen.GetHeight() - listboxTop - int(20*wScale);
|
||||
listboxRows = (listboxHeight1 - 1) / rowHeight;
|
||||
listboxHeight = listboxRows * rowHeight + 1;
|
||||
listboxRight = listboxLeft + listboxWidth;
|
||||
listboxBottom = listboxTop + listboxHeight;
|
||||
|
||||
commentLeft = savepicLeft;
|
||||
commentTop = savepicTop + savepicHeight + 16;
|
||||
commentTop = savepicTop + savepicHeight + int(16 * wScale);
|
||||
commentWidth = savepicWidth;
|
||||
//commentHeight = (51+(screen.GetHeight()>200?10:0))*CleanYfac;
|
||||
commentHeight = listboxHeight - savepicHeight - 16;
|
||||
commentRight = commentLeft + commentWidth;
|
||||
commentBottom = commentTop + commentHeight;
|
||||
commentHeight = listboxHeight - savepicHeight - int(16 * wScale);
|
||||
commentRows = commentHeight / rowHeight;
|
||||
}
|
||||
|
||||
|
@ -169,7 +167,8 @@ class LoadSaveMenu : ListMenu
|
|||
|
||||
virtual void DrawFrame(int left, int top, int width, int height)
|
||||
{
|
||||
// Todo: Define this in subclasses
|
||||
let framecolor = Color(255, 80, 80, 80);
|
||||
Screen.DrawLineFrame(framecolor, left, top, width, height, screen.GetHeight() / 240);
|
||||
}
|
||||
|
||||
override void Drawer ()
|
||||
|
@ -182,31 +181,30 @@ class LoadSaveMenu : ListMenu
|
|||
bool didSeeSelected = false;
|
||||
|
||||
// Draw picture area
|
||||
/* (todo: move to subclass)
|
||||
if (gameaction == ga_loadgame || gameaction == ga_loadgamehidecon || gameaction == ga_savegame)
|
||||
{
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
DrawFrame (savepicLeft, savepicTop, savepicWidth, savepicHeight);
|
||||
DrawFrame(savepicLeft, savepicTop, savepicWidth, savepicHeight);
|
||||
if (!manager.DrawSavePic(savepicLeft, savepicTop, savepicWidth, savepicHeight))
|
||||
{
|
||||
screen.Clear (savepicLeft, savepicTop, savepicLeft+savepicWidth, savepicTop+savepicHeight, 0, 0);
|
||||
screen.Dim(0, 0.6, savepicLeft, savepicTop, savepicWidth, savepicHeight);
|
||||
|
||||
if (manager.SavegameCount() > 0)
|
||||
{
|
||||
if (Selected >= manager.SavegameCount()) Selected = 0;
|
||||
String text = (Selected == -1 || !manager.GetSavegame(Selected).bOldVersion)? Stringtable.Localize("$MNU_NOPICTURE") : Stringtable.Localize("$MNU_DIFFVERSION");
|
||||
int textlen = NewSmallFont.StringWidth(text) * CleanXfac;
|
||||
int textlen = NewSmallFont.StringWidth(text);
|
||||
|
||||
screen.DrawText (NewSmallFont, Font.CR_GOLD, savepicLeft+(savepicWidth-textlen)/2,
|
||||
savepicTop+(savepicHeight-rowHeight)/2, text, DTA_CleanNoMove, true);
|
||||
screen.DrawText (NewSmallFont, Font.CR_GOLD, (savepicLeft+(savepicWidth-textlen)/2) / FontScale,
|
||||
(savepicTop+(savepicHeight-rowHeight)/2) / FontScale, text, DTA_VirtualWidthF, screen.GetWidth() / FontScale, DTA_VirtualHeightF, screen.GetHeight() / FontScale);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw comment area
|
||||
DrawFrame (commentLeft, commentTop, commentWidth, commentHeight);
|
||||
screen.Clear (commentLeft, commentTop, commentRight, commentBottom, 0, 0);
|
||||
screen.Dim(0, 0.6, commentLeft, commentTop, commentWidth, commentHeight);
|
||||
|
||||
int numlinestoprint = min(commentRows, BrokenSaveComment? BrokenSaveComment.Count() : 0);
|
||||
for(int i = 0; i < numlinestoprint; i++)
|
||||
|
@ -218,7 +216,7 @@ class LoadSaveMenu : ListMenu
|
|||
|
||||
// Draw file area
|
||||
DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight);
|
||||
screen.Clear (listboxLeft, listboxTop, listboxRight, listboxBottom, 0, 0);
|
||||
screen.Dim(0, 0.6, listboxLeft, listboxTop, listboxWidth, listboxHeight);
|
||||
|
||||
if (manager.SavegameCount() == 0)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue