Skip to content

Commit

Permalink
Organized raised platform data based on new understanding.
Browse files Browse the repository at this point in the history
  • Loading branch information
afritz1 committed Jul 29, 2024
1 parent 01d241a commit 0f21f75
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 87 deletions.
93 changes: 61 additions & 32 deletions OpenTESArena/src/Assets/ExeData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "ExeData.h"
#include "ExeUnpacker.h"
#include "../Utilities/Platform.h"
#include "../World/MapType.h"

#include "components/debug/Debug.h"
#include "components/utilities/Bytes.h"
Expand Down Expand Up @@ -699,6 +700,65 @@ bool ExeData::Races::init(const char *data, const KeyValueFile &keyValueFile)
return true;
}

bool ExeData::RaisedPlatforms::init(const char *data, const KeyValueFile &keyValueFile)
{
const std::string sectionName = "RaisedPlatforms";
const KeyValueFile::Section *section = keyValueFile.getSectionByName(sectionName);
if (section == nullptr)
{
DebugLogWarning("Couldn't find \"" + sectionName + "\" section in .exe strings file.");
return false;
}

const int boxArraysOffset = ExeData::get(*section, "BoxArrays");
const int boxArraysCopyOffset = ExeData::get(*section, "BoxArraysCopy");
const int box3aOffset = ExeData::get(*section, "Box3A");
const int box3bOffset = ExeData::get(*section, "Box3B");
const int box4Offset = ExeData::get(*section, "Box4");

initInt16Array(this->boxArrays, data + boxArraysOffset);
initInt16Array(this->boxArraysCopy, data + boxArraysCopyOffset);
initInt16Array(this->box3a, data + box3aOffset);
initInt16Array(this->box3b, data + box3bOffset);
initInt8Array(this->box4, data + box4Offset);

this->heightsInterior.init(this->boxArrays.data(), 8);
this->heightsCity.init(this->boxArrays.data() + 8, 8);
this->heightsWild.init(this->boxArrays.data() + 16, 8);
this->thicknessesInterior.init(this->boxArrays.data() + 24, 16);
this->thicknessesCity.init(this->boxArrays.data() + 40, 16); // Box2B is for city and wilderness.
this->thicknessesWild = this->thicknessesCity;
this->texMappingInterior.init(this->box3a);
this->texMappingCity.init(this->box3b);
this->texMappingWild.init(reinterpret_cast<uint16_t*>(this->box4.data()), 8); // Treat Box4 as a Box3C.

return true;
}

int ExeData::RaisedPlatforms::getTextureMappingValueA(MapType mapType, int heightIndex) const
{
constexpr int maxTextureHeight = 64;

switch (mapType)
{
case MapType::Interior:
return this->texMappingInterior.get(heightIndex) % maxTextureHeight;
case MapType::City:
return this->texMappingCity.get(heightIndex) % maxTextureHeight;
case MapType::Wilderness:
return this->texMappingWild.get(heightIndex) % maxTextureHeight;
default:
DebugUnhandledReturnMsg(int, std::to_string(static_cast<int>(mapType)));
}
}

int ExeData::RaisedPlatforms::getTextureMappingValueB(int thicknessIndex, int textureMappingValueA) const
{
constexpr int maxTextureHeight = 64;
DebugAssertIndex(this->box4, thicknessIndex);
return maxTextureHeight - this->box4[thicknessIndex] - textureMappingValueA;
}

bool ExeData::Status::init(const char *data, const KeyValueFile &keyValueFile)
{
const std::string sectionName = "Status";
Expand Down Expand Up @@ -824,37 +884,6 @@ bool ExeData::UI::init(const char *data, const KeyValueFile &keyValueFile)
return true;
}

bool ExeData::WallHeightTables::init(const char *data, const KeyValueFile &keyValueFile)
{
const std::string sectionName = "WallHeightTables";
const KeyValueFile::Section *section = keyValueFile.getSectionByName(sectionName);
if (section == nullptr)
{
DebugLogWarning("Couldn't find \"" + sectionName + "\" section in .exe strings file.");
return false;
}

const int box1aOffset = ExeData::get(*section, "Box1A");
const int box1bOffset = ExeData::get(*section, "Box1B");
const int box1cOffset = ExeData::get(*section, "Box1C");
const int box2aOffset = ExeData::get(*section, "Box2A");
const int box2bOffset = ExeData::get(*section, "Box2B");
const int box3aOffset = ExeData::get(*section, "Box3A");
const int box3bOffset = ExeData::get(*section, "Box3B");
const int box4Offset = ExeData::get(*section, "Box4");

initInt16Array(this->box1a, data + box1aOffset);
initInt16Array(this->box1b, data + box1bOffset);
initInt16Array(this->box1c, data + box1cOffset);
initInt16Array(this->box2a, data + box2aOffset);
initInt16Array(this->box2b, data + box2bOffset);
initInt16Array(this->box3a, data + box3aOffset);
initInt16Array(this->box3b, data + box3bOffset);
initInt16Array(this->box4, data + box4Offset);

return true;
}

bool ExeData::Weather::init(const char *data, const KeyValueFile &keyValueFile)
{
const std::string sectionName = "Weather";
Expand Down Expand Up @@ -1036,7 +1065,7 @@ bool ExeData::init(bool floppyVersion)
success &= this->status.init(dataPtr, keyValueFile);
success &= this->travel.init(dataPtr, keyValueFile);
success &= this->ui.init(dataPtr, keyValueFile);
success &= this->wallHeightTables.init(dataPtr, keyValueFile);
success &= this->raisedPlatforms.init(dataPtr, keyValueFile);
success &= this->weather.init(dataPtr, keyValueFile);
success &= this->wild.init(dataPtr, keyValueFile);

Expand Down
70 changes: 43 additions & 27 deletions OpenTESArena/src/Assets/ExeData.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "ExeTypes.h"

#include "components/utilities/BufferView.h"
#include "components/utilities/KeyValueFile.h"

// This class stores data from the Arena executable. In other words, it represents a
Expand All @@ -18,6 +19,8 @@

class KeyValueFile;

enum class MapType;

class ExeData
{
public:
Expand Down Expand Up @@ -397,6 +400,45 @@ class ExeData
bool init(const char *data, const KeyValueFile &keyValueFile);
};

struct RaisedPlatforms
{
// Heights, sizes, and texture mapping for interior and exterior raised platforms.

// If ceiling2 is given, the box value is scaled with (x * ceiling2) / 256. Otherwise,
// if it is wilderness, the scale value is 192.

// In the voxel data, the most significant byte of raised platforms contains the thickness
// and height indices, organized as 0x0tttthhh.

// 'a': interiors/dungeons
// 'b': cities
// 'c': wilderness

// Raised platform Y heights (Box1A/Box1B/Box1C) and thicknesses (Box2A/Box2B).
std::array<uint16_t, 56> boxArrays;

// Unscaled copy of previous array to restore global variables with in the original game.
std::array<uint16_t, 56> boxArraysCopy;

// Raised platform texture mapping values. Box4 is incorrectly accessed in the original game as if it were a Box3C.
std::array<uint16_t, 8> box3a, box3b;

// Number of texels tall a 64x64 texture is rendered as, also used with calculation for starting row in texture.
std::array<uint8_t, 16> box4;

BufferView<uint16_t> heightsInterior, heightsCity, heightsWild;
BufferView<uint16_t> thicknessesInterior, thicknessesCity, thicknessesWild;
BufferView<uint16_t> texMappingInterior, texMappingCity, texMappingWild;

bool init(const char *data, const KeyValueFile &keyValueFile);

// Unknown
int getTextureMappingValueA(MapType mapType, int heightIndex) const;

// Determines the starting row in a texture?
int getTextureMappingValueB(int thicknessIndex, int textureMappingValueA) const;
};

struct Status
{
// Status pop-up text (with %s/%d tokens).
Expand Down Expand Up @@ -493,32 +535,6 @@ class ExeData
bool init(const char *data, const KeyValueFile &keyValueFile);
};

struct WallHeightTables
{
// Values for interior and exterior wall heights and texture mapping.

// If ceiling2 is given, the box value is scaled with (x * ceiling2) / 256. Otherwise,
// if it is wilderness, the scale value is 192.

// In the voxel data, the most significant byte of raised platforms contains the thickness
// and height indices, organized as 0x0tttthhh.

// Box1: raised platform heights
// Box2: raised platform thicknesses
// Box3 and Box4: texture coordinates? Possible bug that Box4 is used instead of Box3c.
// 'a': interiors/dungeons
// 'b': cities
// 'c': wilderness

std::array<uint16_t, 8> box1a, box1b, box1c;
std::array<uint16_t, 16> box2a, box2b;
// Ignore "source" array, a copy of previous 56 words.
std::array<uint16_t, 8> box3a, box3b;
std::array<uint16_t, 16> box4;

bool init(const char *data, const KeyValueFile &keyValueFile);
};

struct Weather
{
std::array<uint8_t, 3> thunderstormFlashColors;
Expand Down Expand Up @@ -576,7 +592,7 @@ class ExeData
Status status;
Travel travel;
UI ui;
WallHeightTables wallHeightTables;
RaisedPlatforms raisedPlatforms;
Weather weather;
Wilderness wild;

Expand Down
15 changes: 7 additions & 8 deletions OpenTESArena/src/World/MapGeneration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,28 +538,27 @@ namespace MapGeneration
}
}();

const auto &wallHeightTables = exeData.wallHeightTables;
const auto &raisedPlatforms = exeData.raisedPlatforms;
const int heightIndex = mostSigByte & 0x07;
const int thicknessIndex = (mostSigByte & 0x78) >> 3;

int baseOffset, baseSize;
if (mapType == MapType::Interior)
{
baseOffset = wallHeightTables.box1a.at(heightIndex);
baseOffset = raisedPlatforms.heightsInterior.get(heightIndex);

const int boxSize = wallHeightTables.box2a.at(thicknessIndex);
const int boxSize = raisedPlatforms.thicknessesInterior.get(thicknessIndex);
const auto &boxScale = inf.getCeiling().boxScale;
baseSize = boxScale.has_value() ?
((boxSize * (*boxScale)) / 256) : boxSize;
baseSize = boxScale.has_value() ? ((boxSize * (*boxScale)) / 256) : boxSize;
}
else if (mapType == MapType::City)
{
baseOffset = wallHeightTables.box1b.at(heightIndex);
baseSize = wallHeightTables.box2b.at(thicknessIndex);
baseOffset = raisedPlatforms.heightsCity.get(heightIndex);
baseSize = raisedPlatforms.thicknessesCity.get(thicknessIndex);
}
else if (mapType == MapType::Wilderness)
{
baseOffset = wallHeightTables.box1c.at(heightIndex);
baseOffset = raisedPlatforms.heightsWild.get(heightIndex);

constexpr int boxSize = 32;
const auto &boxScale = inf.getCeiling().boxScale;
Expand Down
17 changes: 7 additions & 10 deletions data/text/aExeStrings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,13 @@ DoorUnlockedWithKey=0x40382
SingularNames=0x3E290
PluralNames=0x3E245

[RaisedPlatforms]
BoxArrays=0x48206
BoxArraysCopy=0x48276
Box3A=0x482E6
Box3B=0x482F6
Box4=0x48306

[Status]
PopUp=0x411D7
Date=0x404F4
Expand Down Expand Up @@ -238,16 +245,6 @@ Race4HelmetPaletteValues=0x37D1A
CurrentWorldPosition=0x43D5F
InspectedEntityName=0x43B30

[WallHeightTables]
Box1A=0x48206
Box1B=0x48216
Box1C=0x48226
Box2A=0x48236
Box2B=0x48256
Box3A=0x482E6
Box3B=0x482F6
Box4=0x48306

[Weather]
ThunderstormFlashColors=0x3F8D2

Expand Down
17 changes: 7 additions & 10 deletions data/text/acdExeStrings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,13 @@ DoorUnlockedWithKey=0x406BC
SingularNames=0x3E594
PluralNames=0x3E549

[RaisedPlatforms]
BoxArrays=0x48594
BoxArraysCopy=0x48604
Box3A=0x48654
Box3B=0x48664
Box4=0x48674

[Status]
PopUp=0x4157B
Date=0x40838
Expand Down Expand Up @@ -238,16 +245,6 @@ Race4HelmetPaletteValues=0x37F1A
CurrentWorldPosition=0x44103
InspectedEntityName=0x43ED4

[WallHeightTables]
Box1A=0x48594
Box1B=0x485A4
Box1C=0x485B4
Box2A=0x485C4
Box2B=0x485E4
Box3A=0x48654
Box3B=0x48664
Box4=0x48674

[Weather]
ThunderstormFlashColors=0x3FC0C

Expand Down

0 comments on commit 0f21f75

Please sign in to comment.