diff --git a/esm/esmmain.d b/esm/esmmain.d index 0ca83d808..2340ea59e 100644 --- a/esm/esmmain.d +++ b/esm/esmmain.d @@ -25,6 +25,8 @@ module esm.esmmain; public import esm.records; +import ogre.ogre; + /* This file is the main module for loading from ESM, ESP and ESS files. It stores all the data in the appropriate data structures for later referal. TODO: Put this in a class or whatever? Nah, we @@ -115,11 +117,21 @@ void loadTESFiles(char[][] files) hyperlinks.sort(); } -// Load a TES savegame file (.ess). Currently VERY limited, only reads -// the header. -void importSavegame(char[] file) +// Contains the small bits of information that we currently extract +// from savegames. +struct PlayerSaveInfo +{ + char[] cellName; + char[] playerName; + Placement pos; +} + +// Load a TES savegame file (.ess). Currently VERY limited, reads the +// player's cell name and position +PlayerSaveInfo importSavegame(char[] file) { - writefln("Loading savegame %s", file); + PlayerSaveInfo pi; + esFile.open(file, esmRegion); scope(exit) esFile.close(); @@ -128,14 +140,28 @@ void importSavegame(char[] file) with(esFile.saveData) { - writefln("Floats:"); - foreach(i, f; unknown) - writefln(" %s: %s", i, f); - - writefln("Cell name: ", stripz(cell)); + pi.cellName = stripz(cell); + pi.playerName = stripz(player); + } - writefln("Strange value: ", unk2); - writefln("Player name: ", stripz(player)); + with(esFile) + { + while(hasMoreRecs()) + { + if(isNextHRec("REFR")) + { + while(hasMoreSubs()) + { + getSubName(); + if(retSubName() == "DATA") + readHExact(&pi.pos, pi.pos.sizeof); + else + skipHSub(); + } + } + else + skipHRecord(); + } } - writefln(); + return pi; } diff --git a/esm/filereader.d b/esm/filereader.d index 6d1c71ec6..4d1dfb2d9 100644 --- a/esm/filereader.d +++ b/esm/filereader.d @@ -174,7 +174,7 @@ struct TES3File // name. struct _saveData { - float[6] unknown; // 24 bytes + float[6] unknown; char[64] cell; // Cell name float unk2; // Unknown value char[32] player; // Player name @@ -534,13 +534,26 @@ struct TES3File // Size of current sub record uint getSubSize() { return leftSub; } - // Skip the rest of this record + // Skip the rest of this record. Assumes the name and header have + // already been read void skipRecord() { file.seekCur(leftRec); leftRec = 0; } + // Skip an entire record + void skipHRecord() + { + if(!leftFile) return; + + uint flags; + + getRecName(); + getRecHeader(flags); + skipRecord(); + } + // Skip current sub record and return size uint skipHSub() { diff --git a/esm/loadnpc.d b/esm/loadnpc.d index c18251d0a..59d2ff7b6 100644 --- a/esm/loadnpc.d +++ b/esm/loadnpc.d @@ -160,7 +160,7 @@ struct NPC readHExact(&AI, AI.sizeof); hasAI = true; } - else hasAI = false; + else hasAI = false; skipRecord(); diff --git a/openmw.d b/openmw.d index 33a492eb8..095e8cdd8 100644 --- a/openmw.d +++ b/openmw.d @@ -38,6 +38,7 @@ import bullet.bullet; import scene.celldata; import scene.soundlist; import scene.gamesettings; +import scene.player; import core.resource; import core.memory; @@ -90,6 +91,8 @@ void main(char[][] args) bool debugOut = false; bool extTest = false; bool doGen = false; + bool nextSave = false; + bool loadSave = false; // Some examples to try: // @@ -107,6 +110,9 @@ void main(char[][] args) // Cells to load char[][] cells; + // Savegame to load + char[] savefile; + foreach(char[] a; args[1..$]) if(a == "-n") render = false; else if(a == "-ex") extTest = true; @@ -115,6 +121,7 @@ void main(char[][] args) else if(a == "-rk") resetKeys = true; else if(a == "-oc") showOgreFlag = true; else if(a == "-ns") config.noSound = true; + else if(a == "-save") nextSave = true; else if(a == "-debug") { // Enable Monster debug output @@ -123,6 +130,11 @@ void main(char[][] args) // Tell OGRE to do the same later on debugOut = true; } + else if(nextSave) + { + savefile = a; + nextSave = false; + } else cells ~= a; if(cells.length > 1) @@ -142,6 +154,7 @@ void main(char[][] args) writefln(" -oc Show the Ogre config dialogue"); writefln(" -ns Completely disable sound"); writefln(" -debug Print debug information"); + writefln(" -save Load cell/pos from savegame"); writefln(" -h Show this help"); writefln(""); writefln("Specifying more than one cell implies -n"); @@ -156,11 +169,28 @@ void main(char[][] args) initializeMemoryRegions(); initMonsterScripts(); - /* - importSavegame("data/quiksave.ess"); - importSavegame("data/Perm1hal0000.ess"); - return; - */ + // This is getting increasingly hackish, but this entire engine + // design is now quickly outgrowing its usefulness, and a rewrite is + // coming soon anyway. + PlayerSaveInfo pi; + if(savefile != "") + { + if(cells.length) + { + writefln("Please don't specify both a savegame file (%s) and cell names (%s)", savefile, cells); + return; + } + + loadSave = true; + writefln("Loading savegame %s", savefile); + pi = importSavegame(savefile); + writefln(" Player name: %s", pi.playerName); + writefln(" Cell name: %s", pi.cellName); + writefln(" Pos: %s", pi.pos.position); + writefln(" Rot: %s", pi.pos.rotation); + + cells = [pi.cellName]; + } config.initialize(resetKeys); scope(exit) config.writeConfig(); @@ -181,7 +211,7 @@ void main(char[][] args) if(config.defaultCell.length) cells ~= config.defaultCell; - if(cells.length == 1) + if(cells.length == 1 && !loadSave) config.defaultCell = cells[0]; if(cells.length == 0) @@ -218,6 +248,10 @@ Perhaps this cell does not exist in your Morrowind language version? Try specifying another cell name on the command line, or edit openmw.ini."); return; } + + // If we're loading from save, override the player position + if(loadSave) + *playerData.position = pi.pos; } // Simple safety hack