Editor: Add "reset to saved scenario" command

console-destruction
Sven Eberhardt 2016-09-07 01:53:27 -04:00
parent 856730aabd
commit b95d1387a4
15 changed files with 190 additions and 52 deletions

View File

@ -535,6 +535,7 @@ IDS_MNU_PLAYERNAMES=Spielernamen
IDS_MNU_QUIT=Beenden
IDS_MNU_RECENT=Zuletzt geöffnet
IDS_MNU_RECORD=Aufnahme
IDS_MNU_REINITSCEN=Zum Speicherstand zurücksetzen
IDS_MNU_SAVEGAME=Spiel speichern
IDS_MNU_SAVEGAMEAS=Spiel speichern unter...
IDS_MNU_SAVESCENARIO=Szenario speichern

View File

@ -535,6 +535,7 @@ IDS_MNU_PLAYERNAMES=Player names
IDS_MNU_QUIT=Quit
IDS_MNU_RECENT=Recent
IDS_MNU_RECORD=Record
IDS_MNU_REINITSCEN=Reset to saved scenario
IDS_MNU_SAVEGAME=Save game
IDS_MNU_SAVEGAMEAS=Save game as...
IDS_MNU_SAVESCENARIO=Save scenario

View File

@ -1892,3 +1892,56 @@ void C4ControlVoteEnd::CompileFunc(StdCompiler *pComp)
{
C4ControlVote::CompileFunc(pComp);
}
// *** C4ControlReInitScenario
C4ControlReInitScenario::C4ControlReInitScenario()
{
// Create a temp file with the scenario files to be loaded as a section
char *tmp_fn = const_cast<char *>(Config.AtTempPath("ReinitSectionSave.ocs"));
MakeTempFilename(tmp_fn);
C4Group grp;
grp.Open(tmp_fn, true);
StdBuf buf;
bool success = true;
const char *section_components[] = { C4CFN_ScenarioCore, C4CFN_ScenarioObjects, C4CFN_ScenarioObjectsScript, C4CFN_Map, C4CFN_MapFg, C4CFN_MapBg };
for (const char *section_component : section_components)
{
if (::Game.ScenarioFile.LoadEntry(section_component, &buf))
{
if (!grp.Add(section_component, buf, false, true)) success = false;
}
buf.Clear();
}
if (!grp.Save(false)) success = false;
if (!success) return;
// Move into buffer to be sent via queue
success = data.LoadFromFile(tmp_fn);
EraseFile(tmp_fn);
if (!success) return;
}
void C4ControlReInitScenario::CompileFunc(StdCompiler *comp)
{
comp->Value(data);
}
void C4ControlReInitScenario::Execute() const
{
// Valid?
if (!data.getSize()) return;
// Store section group to temp file
char *tmp_fn = const_cast<char *>(Config.AtTempPath("ReinitSection.ocs"));
MakeTempFilename(tmp_fn);
if (!data.SaveToFile(tmp_fn)) return;
// Group to section
const char *reinit_section_name = "EditorReloadSection";
if (!::Game.CreateSectionFromTempFile(reinit_section_name, tmp_fn))
{
EraseFile(tmp_fn);
return;
}
// Load that section!
::Game.LoadScenarioSection(reinit_section_name, C4S_REINIT_SCENARIO);
}

View File

@ -611,4 +611,14 @@ public:
DECLARE_C4CONTROL_VIRTUALS
};
struct C4ControlReInitScenario : public C4ControlPacket // sync
{
public:
C4ControlReInitScenario();
protected:
StdBuf data;
public:
DECLARE_C4CONTROL_VIRTUALS
};
#endif

View File

@ -120,7 +120,7 @@ bool C4GameSave::SaveScenarioSections()
{
// compose section filename
SCopy(C4CFN_ScenarioSections, fn);
SDelete(fn, 1, iWildcardPos); SInsert(fn, pSect->szName, iWildcardPos);
SDelete(fn, 1, iWildcardPos); SInsert(fn, pSect->name.getData(), iWildcardPos);
// do not save self, because that is implied in CurrentScenarioSection and the main landscape/object data
if (pSect == Game.pCurrentScenarioSection)
pSaveGroup->DeleteEntry(fn);
@ -129,7 +129,7 @@ bool C4GameSave::SaveScenarioSections()
// modified section: delete current
pSaveGroup->DeleteEntry(fn);
// replace by new
pSaveGroup->Add(pSect->szTempFilename, fn);
pSaveGroup->Add(pSect->temp_filename.getData(), fn);
}
}
// done, success

View File

@ -773,6 +773,7 @@ void C4Playback::Strip()
case CID_Script:
case CID_EMMoveObj:
case CID_EMDrawTool:
case CID_ReInitScenario:
if (fCheckCheat) Log(DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(*pPkt, FormatString("Frame %d", i->Frame).getData())).getData());
break;
// Strip sync check
@ -806,6 +807,7 @@ void C4Playback::Strip()
case CID_Script:
case CID_EMMoveObj:
case CID_EMDrawTool:
case CID_ReInitScenario:
if (fCheckCheat) Log(DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(*i->pPkt, FormatString("Frame %d", i->Frame).getData())).getData());
break;
// Strip some stuff

View File

@ -373,6 +373,7 @@
<addaction name="actionFileSaveScenario"/>
<addaction name="actionFileSaveScenarioAs"/>
<addaction name="actionFileSaveGameAs"/>
<addaction name="actionFileReInitScenario"/>
<addaction name="separator"/>
<addaction name="actionFileClose"/>
<addaction name="actionFileQuit"/>
@ -1045,6 +1046,17 @@
<string comment="res">IDS_CNS_SHOWHELPTIP</string>
</property>
</action>
<action name="actionFileReInitScenario">
<property name="text">
<string comment="res">IDS_MNU_REINITSCEN</string>
</property>
<property name="toolTip">
<string comment="res">IDS_MNU_REINITSCEN</string>
</property>
<property name="shortcut">
<string>F12</string>
</property>
</action>
</widget>
<resources>
<include location="resource.qrc"/>
@ -1674,6 +1686,22 @@
</hint>
</hints>
</connection>
<connection>
<sender>actionFileReInitScenario</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>FileReInitScenario()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>477</x>
<y>312</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>PlayPressed(bool)</slot>
@ -1714,5 +1742,6 @@
<slot>SelectionDuplicate()</slot>
<slot>SelectionEjectContents()</slot>
<slot>HelpToggle(bool)</slot>
<slot>FileReInitScenario()</slot>
</slots>
</ui>

View File

@ -326,6 +326,11 @@ void C4ConsoleQtMainWindow::FileSaveGameAs() { ::Console.FileSaveAs(true); }
void C4ConsoleQtMainWindow::FileClose() { ::Console.FileClose(); }
void C4ConsoleQtMainWindow::FileQuit() { ::Console.FileQuit(); }
void C4ConsoleQtMainWindow::FileReInitScenario()
{
::Control.DoInput(CID_ReInitScenario, new C4ControlReInitScenario(), CDT_Decide);
}
// Player menu
void C4ConsoleQtMainWindow::PlayerJoin() { ::Console.PlayerJoin(); }
// Window menu
@ -491,7 +496,6 @@ void C4ConsoleQtMainWindow::SelectionEjectContents()
}
/* Common C4ConsoleGUI interface */
C4ConsoleGUIState::C4ConsoleGUIState(C4ConsoleGUI *console) : viewport_area(NULL),

View File

@ -120,6 +120,7 @@ public slots:
void FileSaveGameAs();
void FileClose();
void FileQuit();
void FileReInitScenario();
// Player menu
void PlayerJoin();
// Window menu

View File

@ -2860,11 +2860,9 @@ bool C4Game::LoadScenarioComponents()
}
// load this section into temp store
C4ScenarioSection *pSection = new C4ScenarioSection(SctName);
if (!pSection->ScenarioLoad(ScenarioFile, fn))
if (!pSection->ScenarioLoad(fn, false))
{ LogFatal(FormatString(LoadResStr("IDS_ERR_SCENSECTION"), fn).getData()); return false; }
}
// Success
return true;
}
@ -3401,6 +3399,48 @@ void C4Game::OnKeyboardLayoutChanged()
PlayerControlUserAssignmentSets.ResolveRefs(&PlayerControlDefs);
}
bool C4Game::CreateSectionFromTempFile(const char *section_name, const char *temp_filename)
{
// Remove existing (temp) section of same name
C4ScenarioSection *existing_section = pScenarioSections, *prev = nullptr;
while (existing_section) if (SEqualNoCase(existing_section->name.getData(), section_name)) break; else existing_section = (prev = existing_section)->pNext;
bool deleted_current_section = false;
if (existing_section)
{
deleted_current_section = (existing_section == pCurrentScenarioSection);
if (deleted_current_section)
{
pCurrentScenarioSection = nullptr;
pScenarioObjectsScript = nullptr;
}
if (existing_section->pObjectScripts)
{
delete existing_section->pObjectScripts;
}
if (prev) prev->pNext = existing_section->pNext; else pScenarioSections = existing_section->pNext;
existing_section->pNext = nullptr;
delete existing_section;
}
// Create new (temp) section
C4ScenarioSection *new_section = new C4ScenarioSection(section_name);
if (!new_section->ScenarioLoad(temp_filename, true))
{
pScenarioSections = new_section->pNext;
new_section->pNext = nullptr;
delete new_section;
return false;
}
// Re-Link current section into newly created section
if (deleted_current_section)
{
pCurrentScenarioSection = new_section;
pScenarioObjectsScript = new_section->pObjectScripts;
}
// Link new Objects.c (or re-link because old Objects.c was removed)
ReLinkScriptEngine();
return !!new_section;
}
bool C4Game::LoadScenarioSection(const char *szSection, DWORD dwFlags)
{
// note on scenario section saving:
@ -3412,13 +3452,13 @@ bool C4Game::LoadScenarioSection(const char *szSection, DWORD dwFlags)
// if current section was the loaded section (maybe main, but need not for resumed savegames)
if (!pCurrentScenarioSection)
{
if (!*CurrentScenarioSection) SCopy(C4ScenSect_Main, CurrentScenarioSection, C4MaxName);
pCurrentScenarioSection = new C4ScenarioSection(CurrentScenarioSection);
pCurrentScenarioSection->pObjectScripts = Game.pScenarioObjectsScript;
if (!*CurrentScenarioSection) SCopy(C4ScenSect_Main, CurrentScenarioSection, C4MaxName);
}
// find section to load
C4ScenarioSection *pLoadSect = pScenarioSections;
while (pLoadSect) if (SEqualNoCase(pLoadSect->szName, szSection)) break; else pLoadSect = pLoadSect->pNext;
while (pLoadSect) if (SEqualNoCase(pLoadSect->name.getData(), szSection)) break; else pLoadSect = pLoadSect->pNext;
if (!pLoadSect)
{
DebugLogF("LoadScenarioSection: scenario section %s not found!", szSection);
@ -3430,7 +3470,7 @@ bool C4Game::LoadScenarioSection(const char *szSection, DWORD dwFlags)
// ensure that the section file does point to temp store
if (!pCurrentScenarioSection->EnsureTempStore(!(dwFlags & C4S_SAVE_LANDSCAPE), !(dwFlags & C4S_SAVE_OBJECTS)))
{
DebugLogF("LoadScenarioSection(%s): could not extract section files of current section %s", szSection, pCurrentScenarioSection->szName);
DebugLogF("LoadScenarioSection(%s): could not extract section files of current section %s", szSection, pCurrentScenarioSection->name.getData());
return false;
}
// open current group
@ -3529,7 +3569,7 @@ bool C4Game::LoadScenarioSection(const char *szSection, DWORD dwFlags)
SCopy(C4S.Landscape.SkyDef, szOldSky, C4MaxDefString);
// do not warn on ignored values in main section
// they are caused because not all parts of scenario core are compiled on section change
bool is_main_section = SEqualNoCase(pLoadSect->szName, C4ScenSect_Main);
bool is_main_section = SEqualNoCase(pLoadSect->name.getData(), C4ScenSect_Main);
// overload scenario values (fails if no scenario core is present; that's OK)
C4S.Load(*pGrp, true, is_main_section);
// determine whether a new sky has to be loaded
@ -3556,12 +3596,12 @@ bool C4Game::LoadScenarioSection(const char *szSection, DWORD dwFlags)
C4PropListNumbered::UnshelveNumberedPropLists();
// set new current section
pCurrentScenarioSection = pLoadSect;
SCopy(pCurrentScenarioSection->szName, CurrentScenarioSection);
SCopy(pCurrentScenarioSection->name.getData(), CurrentScenarioSection);
// Final init on game re-init (doing mostly player initialization)
if (dwFlags & C4S_REINIT_SCENARIO)
{
InitGameFinal(IM_ReInit);
// Extra InitializePlayers on the already-joined players to start intros, etc.
// Extra InitializePlayers callback on the already-joined players to start intros, etc.
// (unless the call is still pending - can happen if section is loaded during player join)
if (::Game.InitialPlayersJoined && ::Players.GetCount())
::Game.GRBroadcast(PSF_InitializePlayers);

View File

@ -218,6 +218,7 @@ public:
C4Value GRBroadcast(const char *szFunction, C4AulParSet *pPars = 0, bool fPassError=false, bool fRejectTest=false); // call function in scenario script and all goals/rules/environment objects
bool LoadScenarioSection(const char *szSection, DWORD dwFlags);
bool CreateSectionFromTempFile(const char *section_name, const char *temp_filename);
bool DrawTextSpecImage(C4Facet& fctTarget, const char *szSpec, class C4DrawTransform* pTransform, uint32_t dwClr=0xff);
float GetTextSpecImageAspect(const char* szSpec);

View File

@ -249,20 +249,20 @@ extern const char *C4ScenSect_Main;
class C4ScenarioSection
{
public:
C4ScenarioSection(char *szName); // ctor
C4ScenarioSection(const char *szName); // ctor
~C4ScenarioSection(); // dtor
public:
char *szName; // section name
char *szTempFilename; // filename of data file if in temp dir
char *szFilename; // filename of section in scenario file
StdCopyStrBuf name; // section name
StdCopyStrBuf temp_filename; // filename of data file if in temp dir
StdCopyStrBuf filename; // filename of section in scenario file
bool fModified; // if set, the file is temp and contains runtime landscape and/or object data
class C4ScenarioObjectsScriptHost *pObjectScripts; // points to loaded script file for section Objects.c
C4ScenarioSection *pNext; // next member of linked list
public:
bool ScenarioLoad(C4Group &rGrp, char *szFilename); // called when scenario is loaded: extract to temp store
bool ScenarioLoad(const char *szFilename, bool is_temp_file); // called when scenario is loaded: extract to temp store
C4Group *GetGroupfile(C4Group &rGrp); // get group at section file (returns temp group, scenario subgroup or scenario group itself)
bool EnsureTempStore(bool fExtractLandscape, bool fExtractObjects); // make sure that a temp file is created, and nothing is modified within the main scenario file
};

View File

@ -24,18 +24,11 @@
const char *C4ScenSect_Main = "main";
C4ScenarioSection::C4ScenarioSection(char *szName)
C4ScenarioSection::C4ScenarioSection(const char *szName)
{
// copy name
if (szName && !SEqualNoCase(szName, C4ScenSect_Main) && *szName)
{
this->szName = new char[strlen(szName)+1];
SCopy(szName, this->szName);
}
else
this->szName = const_cast<char *>(C4ScenSect_Main);
name.Copy(szName);
// zero fields
szTempFilename = szFilename = 0;
fModified = false;
pObjectScripts = NULL;
// link into main list
@ -54,28 +47,30 @@ C4ScenarioSection::~C4ScenarioSection()
delete pDel;
}
// del temp file
if (szTempFilename)
if (temp_filename.getData())
{
EraseItem(szTempFilename);
delete szTempFilename;
EraseItem(temp_filename.getData());
}
// del filename if assigned
if (szFilename) delete szFilename;
// del name if owned
if (szName != C4ScenSect_Main) delete szName;
}
bool C4ScenarioSection::ScenarioLoad(C4Group &rGrp, char *szFilename)
bool C4ScenarioSection::ScenarioLoad(const char *szFilename, bool is_temp_file)
{
// safety
if (this->szFilename || !szFilename) return false;
if (filename.getData() || !szFilename) return false;
// store name
this->szFilename = new char[strlen(szFilename)+1];
SCopy(szFilename, this->szFilename, _MAX_FNAME);
// extract if it's not an open folder
if (Game.ScenarioFile.IsPacked()) if (!EnsureTempStore(true, true)) return false;
filename.Copy(szFilename);
if (is_temp_file)
{
// temp: Remember temp filename to be deleted on destruction
temp_filename.Copy(szFilename);
}
else
{
// non-temp: extract if it's not an open folder
if (Game.ScenarioFile.IsPacked()) if (!EnsureTempStore(true, true)) return false;
}
// load section object script
if (!SEqualNoCase(szName, C4ScenSect_Main))
if (!SEqualNoCase(name.getData(), C4ScenSect_Main))
{
C4Group GrpSect, *pGrp;
if ((pGrp = GetGroupfile(GrpSect)) && pGrp->FindEntry(C4CFN_ScenarioObjectsScript))
@ -101,19 +96,19 @@ bool C4ScenarioSection::ScenarioLoad(C4Group &rGrp, char *szFilename)
C4Group *C4ScenarioSection::GetGroupfile(C4Group &rGrp)
{
// check temp filename
if (szTempFilename)
if (temp_filename.getData())
{
if (rGrp.Open(szTempFilename)) return &rGrp;
if (rGrp.Open(temp_filename.getData())) return &rGrp;
else return NULL;
}
// check filename within scenario
if (szFilename)
if (filename.getData())
{
if (rGrp.OpenAsChild(&Game.ScenarioFile, szFilename)) return &rGrp;
if (rGrp.OpenAsChild(&Game.ScenarioFile, filename.getData())) return &rGrp;
else return NULL;
}
// unmodified main section: return main group
if (SEqualNoCase(szName, C4ScenSect_Main)) return &Game.ScenarioFile;
if (SEqualNoCase(name.getData(), C4ScenSect_Main)) return &Game.ScenarioFile;
// failure
return NULL;
}
@ -121,12 +116,12 @@ C4Group *C4ScenarioSection::GetGroupfile(C4Group &rGrp)
bool C4ScenarioSection::EnsureTempStore(bool fExtractLandscape, bool fExtractObjects)
{
// if it's temp store already, don't do anything
if (szTempFilename) return true;
if (temp_filename.getData()) return true;
// make temp filename
char *szTmp = const_cast<char *>(Config.AtTempPath(szFilename ? GetFilename(szFilename) : szName));
char *szTmp = const_cast<char *>(Config.AtTempPath(filename.getData() ? GetFilename(filename.getData()) : name.getData()));
MakeTempFilename(szTmp);
// main section: extract section files from main scenario group (create group as open dir)
if (!szFilename)
if (!filename.getData())
{
if (!CreatePath(szTmp)) return false;
C4Group hGroup;
@ -143,12 +138,12 @@ bool C4ScenarioSection::EnsureTempStore(bool fExtractLandscape, bool fExtractObj
else
{
// subsection: simply extract section from main group
if (!Game.ScenarioFile.ExtractEntry(szFilename, szTmp)) return false;
if (!Game.ScenarioFile.ExtractEntry(filename.getData(), szTmp)) return false;
// delete undesired landscape/object files
if (!fExtractLandscape || !fExtractObjects)
{
C4Group hGroup;
if (hGroup.Open(szFilename))
if (hGroup.Open(filename.getData()))
{
if (!fExtractLandscape) hGroup.Delete(C4FLS_SectionLandscape);
if (!fExtractObjects) hGroup.Delete(C4FLS_SectionObjects);
@ -156,8 +151,7 @@ bool C4ScenarioSection::EnsureTempStore(bool fExtractLandscape, bool fExtractObj
}
}
// copy temp filename
szTempFilename = new char[strlen(szTmp)+1];
SCopy(szTmp, szTempFilename, _MAX_PATH);
temp_filename.Copy(szTmp);
// done, success
return true;
}

View File

@ -125,6 +125,7 @@ const C4PktHandlingData PktHandlingData[] =
{ CID_MenuCommand, PC_Control, "Menu Command", false, true, 0, PKT_UNPACK(C4ControlMenuCommand)},
{ CID_EMMoveObj, PC_Control, "EM Move Obj", false, true, 0, PKT_UNPACK(C4ControlEMMoveObject)},
{ CID_EMDrawTool, PC_Control, "EM Draw Tool", false, true, 0, PKT_UNPACK(C4ControlEMDrawTool) },
{ CID_ReInitScenario,PC_Control, "Reinit Scenario", false, true, 0, PKT_UNPACK(C4ControlReInitScenario) },
{ CID_DebugRec, PC_Control, "Debug Rec", false, true, 0, PKT_UNPACK(C4ControlDebugRec) },

View File

@ -165,6 +165,7 @@ enum C4PacketType
CID_EMMoveObj = CID_First | 0x30,
CID_EMDrawTool = CID_First | 0x31,
CID_ReInitScenario= CID_First | 0x32,
CID_DebugRec = CID_First | 0x40,
CID_MenuCommand = CID_First | 0x41,