diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d0250f16..01ea58859 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ include_directories(${ATHENA_INCLUDE_DIR} ${LOGVISOR_INCLUDE_DIR} ${HECL_INCLUDE add_subdirectory(DataSpec) add_subdirectory(Editor) add_subdirectory(Runtime) +add_subdirectory(mpcksum) unset(GIT_EXECUTABLE CACHE) find_package(Git) diff --git a/Runtime/CPlayerState.cpp b/Runtime/CPlayerState.cpp index 18e30f1e2..324796153 100644 --- a/Runtime/CPlayerState.cpp +++ b/Runtime/CPlayerState.cpp @@ -1,5 +1,6 @@ #include "CPlayerState.hpp" #include "IOStreams.hpp" +#include "zeus/Math.hpp" namespace urde { @@ -9,60 +10,66 @@ namespace urde * a proper RE is still required! */ -const u32 CPlayerState::PowerUpMaxes[41] = +const u32 CPlayerState::PowerUpMaxValues[41] = { 1, 1, 1, 1, 250, 1, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; const char* PowerUpNames[41]= { - "Unknown", - "Unknown", - "Unknown", - "Unknown", + "Power Beam", + "Ice Beam", + "Wave Beam", + "Plasma Beam", "Missiles", - "Unknown", - "Unknown", + "Scan Visor", + "Morph Ball Bombs", "Power Bombs", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", + "Flamethrower", + "Thermal Visor", + "Charge Beam", + "Super Missile", + "GrappleBeam", + "X-Ray Visor", + "Ice Spreader", + "Space Jump Boots", + "Morph Ball", + "Combat Visor", + "Boost Ball", + "Spider Ball", + "Power Suit", + "Gravity Suit", + "Varia Suit", + "Phazon Suit", "Energy Tanks", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", - "Unknown", + "Unknown Item 1", + "Health Refill", + "Unknown Item 2", + "Wavebuster", + "Artifact of Truth", + "Artifact of Strength", + "Artifact of Elder", + "Artifact of Wild", + "Artifact of Lifegiver", + "Artifact of Warrior", + "Artifact of Chozo", + "Artifact of Nature", + "Artifact of Sun", + "Artifact of World", + "Artifact of Spirit", + "Artifact of Newborn", }; CPlayerState::CPlayerState(CBitStreamReader& in) : x188_staticIntf(5) { x0_24_ = true; + u32 bitCount = 0; + std::for_each(std::cbegin(CPlayerState::PowerUpMaxValues), std::cend(CPlayerState::PowerUpMaxValues), [&bitCount](const u32& max){ + bitCount += CBitStreamReader::GetBitCount(max); + }); + +#if 1 in.readUint32Big(); in.readBool(); in.readBool(); @@ -72,87 +79,351 @@ CPlayerState::CPlayerState(CBitStreamReader& in) in.readBytesToBuf(data, 0xAE); for (u32 k = 0; k < 3; k++) { - printf("Game %i\n", k+1); atInt8 save[0x3AC]; in.readBytesToBuf(save, 0x3AC); { - CBitStreamReader stream(save, 0x3AC); + CBitStreamReader stream(save, 0x1000); std::string filename = athena::utility::sprintf("Game%i.dat", k + 1); + std::string logFilename = athena::utility::sprintf("Game%i.txt", k + 1); + FILE * f = fopen(logFilename.c_str(), "w"); CBitStreamWriter w{filename}; - printf("Game State\n"); + fprintf(f, "Game State\n"); for (u32 i = 0; i < 0x80; i++) { u32 tmp = stream.ReadEncoded(8); - printf("%i\n", tmp); + if (!(i % 16)) + fprintf(f, "\n"); + fprintf(f, "%.2i ", tmp); w.WriteEncoded(tmp, 8); } + fprintf(f, "\n\n"); s32 tmp = stream.ReadEncoded(32); w.WriteEncoded(tmp, 0x20); - printf("%i\n", tmp); + fprintf(f, "%i\n", tmp); tmp = stream.ReadEncoded(1); w.WriteEncoded(tmp, 1); - printf("%i\n", tmp); + fprintf(f, "%i\n", tmp); tmp = stream.ReadEncoded(1); w.WriteEncoded(tmp, 1); - printf("%i\n", tmp); + fprintf(f, "%i\n", tmp); tmp = stream.ReadEncoded(32); w.WriteEncoded(tmp, 0x20); - printf("%f\n", *reinterpret_cast(&tmp)); + fprintf(f, "%f\n", *reinterpret_cast(&tmp)); tmp = stream.ReadEncoded(32); w.WriteEncoded(tmp, 0x20); - printf("%f\n", *reinterpret_cast(&tmp)); + fprintf(f, "%f\n", *reinterpret_cast(&tmp)); tmp = stream.ReadEncoded(32); - printf("%x\n", tmp); + fprintf(f, "%x\n", tmp); w.WriteEncoded(tmp, 0x20); - printf("PlayerState\n"); + fprintf(f, "PlayerState\n"); x4_ = stream.ReadEncoded(0x20); w.WriteEncoded(x4_, 0x20); - printf("%x\n", tmp); + fprintf(f, "%x\n", x4_); tmp = stream.ReadEncoded(0x20); - printf("Base health %f\n", *reinterpret_cast(&tmp)); - xc_baseHealth = *reinterpret_cast(&tmp); + fprintf(f, "Base health %f\n", *reinterpret_cast(&tmp)); + xc_currentHealth = *reinterpret_cast(&tmp); w.WriteEncoded(tmp, 0x20); - x8_ = stream.ReadEncoded(CBitStreamReader::GetBitCount(5)); - printf("%i\n", x8_); - w.WriteEncoded(x8_, CBitStreamReader::GetBitCount(5)); - x20_ = stream.ReadEncoded(CBitStreamReader::GetBitCount(4)); - printf("%i\n", x20_); - w.WriteEncoded(x20_, CBitStreamReader::GetBitCount(4)); + x8_currentBeam = stream.ReadEncoded(CBitStreamReader::GetBitCount(5)); + fprintf(f, "%i\n", x8_currentBeam); + w.WriteEncoded(x8_currentBeam, CBitStreamReader::GetBitCount(5)); + x20_currentSuit = EPlayerSuit(stream.ReadEncoded(CBitStreamReader::GetBitCount(4))); + fprintf(f, "%i\n", x20_currentSuit); + w.WriteEncoded(u32(x20_currentSuit), CBitStreamReader::GetBitCount(4)); x24_powerups.resize(41); - printf("Powerups\n"); + fprintf(f, "Powerups\n"); for (u32 i = 0; i < x24_powerups.size(); ++i) { - if (PowerUpMaxes[i] == 0) + if (PowerUpMaxValues[i] == 0) continue; - u32 a = stream.ReadEncoded(CBitStreamReader::GetBitCount(PowerUpMaxes[i])); - u32 b = stream.ReadEncoded(CBitStreamReader::GetBitCount(PowerUpMaxes[i])); - w.WriteEncoded(a, CBitStreamReader::GetBitCount(PowerUpMaxes[i])); - w.WriteEncoded(b, CBitStreamReader::GetBitCount(PowerUpMaxes[i])); + u32 a = stream.ReadEncoded(CBitStreamReader::GetBitCount(PowerUpMaxValues[i])); + u32 b = stream.ReadEncoded(CBitStreamReader::GetBitCount(PowerUpMaxValues[i])); + w.WriteEncoded(a, CBitStreamReader::GetBitCount(PowerUpMaxValues[i])); + w.WriteEncoded(b, CBitStreamReader::GetBitCount(PowerUpMaxValues[i])); x24_powerups[i] = CPowerUp(a, b); - printf("%2i(%15s): a=%i b=%i\n", i, PowerUpNames[i], a, b); + fprintf(f, "%2i(%21s): cur=%3i max=%3i\n", i, PowerUpNames[i], a, b); } - for (u32 i = 0; i < 0x304 * 8; i++) + for (u32 i = 0; i < 832; i++) { u32 tmp = stream.ReadEncoded(1); - printf("%i\n", tmp); + if (!(i % 32)) + fprintf(f, "\n"); + + fprintf(f, "%i ", tmp); w.WriteEncoded(tmp, 1); } + fprintf(f, "\n\n"); tmp = stream.ReadEncoded(CBitStreamReader::GetBitCount(0x100)); - printf("%i\n", tmp); w.WriteEncoded(tmp, CBitStreamReader::GetBitCount(0x100)); + fprintf(f, "%i\n", tmp); tmp = stream.ReadEncoded(CBitStreamReader::GetBitCount(0x100)); - printf("%i\n", tmp); w.WriteEncoded(tmp, CBitStreamReader::GetBitCount(0x100)); + fprintf(f, "%i\n", tmp); + fprintf(f, "Final Offset %.8llx\n", stream.position()); + fprintf(f, "Completion: %.2i%%\n", CalculateItemCollectionRate()); w.save(); } } +#endif +} + +float CPlayerState::GetBeamSwitchTime() const +{ + static const float switchTimes[4] { + 0.2, 0.1, 0.2, 0.2 + }; + + return switchTimes[u32(x8_currentBeam)]; +} + +u32 CPlayerState::CalculateItemCollectionRate() const +{ + u32 total = GetItemCapacity(EItemType::PowerBombs); + + if (total >= 4) + total -= 3; + total += GetItemCapacity(EItemType::WaveBeam); + total += GetItemCapacity(EItemType::IceBeam); + total += GetItemCapacity(EItemType::PlasmaBeam); + total += GetItemCapacity(EItemType::Missiles) / 5; + total += GetItemCapacity(EItemType::MorphBallBombs); + total += GetItemCapacity(EItemType::Flamethrower); + total += GetItemCapacity(EItemType::ThermalVisor); + total += GetItemCapacity(EItemType::ChargeBeam); + total += GetItemCapacity(EItemType::SuperMissile); + total += GetItemCapacity(EItemType::GrappleBeam); + total += GetItemCapacity(EItemType::XRayVisor); + total += GetItemCapacity(EItemType::IceSpreader); + total += GetItemCapacity(EItemType::SpaceJumpBoots); + total += GetItemCapacity(EItemType::MorphBall); + total += GetItemCapacity(EItemType::BoostBall); + total += GetItemCapacity(EItemType::SpiderBall); + total += GetItemCapacity(EItemType::GravitySuit); + total += GetItemCapacity(EItemType::VariaSuit); + total += GetItemCapacity(EItemType::EnergyTanks); + total += GetItemCapacity(EItemType::ArtifactOfTruth); + total += GetItemCapacity(EItemType::ArtifactOfStrength); + total += GetItemCapacity(EItemType::ArtifactOfElder); + total += GetItemCapacity(EItemType::ArtifactOfWild); + total += GetItemCapacity(EItemType::ArtifactOfLifegiver); + total += GetItemCapacity(EItemType::ArtifactOfWarrior); + total += GetItemCapacity(EItemType::ArtifactOfChozo); + total += GetItemCapacity(EItemType::ArtifactOfNature); + total += GetItemCapacity(EItemType::ArtifactOfSun); + total += GetItemCapacity(EItemType::ArtifactOfWorld); + total += GetItemCapacity(EItemType::ArtifactOfSpirit); + total += GetItemCapacity(EItemType::ArtifactOfNewborn); + return total + GetItemCapacity(EItemType::Wavebuster); +} + +CPlayerState::EPlayerSuit CPlayerState::GetCurrentSuit() const +{ + if (GetFusion()) + return EPlayerSuit::FusionPower; + + return x20_currentSuit; +} + +bool CPlayerState::CanVisorSeeFog(const CStateManager& stateMgr) const +{ + u32 activeVisor = u32(GetActiveVisor(stateMgr)); + if (activeVisor == 0 || activeVisor == 2) + return true; + return true; +} + +CPlayerState::EPlayerVisor CPlayerState::GetActiveVisor(const CStateManager& stateMgr) const +{ + /* TODO: We need CGameCamera, and gang in order to enable this */ +#if 0 + CFirstPersionCamera* cam = dynamic_cast(stateMgr.GetCameraManager()->GetCurrentCamera(stateMgr)); + if (!cam) + return EVisorType::Zero; +#endif + return x14_currentVisor; +} + +void CPlayerState::UpdateStaticInterference(CStateManager& stateMgr, const float& dt) +{ + x188_staticIntf.Update(stateMgr, dt); +} + +void CPlayerState::NewScanTime(u32 time) +{ +} + +bool CPlayerState::GetIsVisorTransitioning() const +{ + if (x14_currentVisor != x18_transitioningVisor || x1c_visorTransitionFactor < 0.2f) + return true; + + return false; +} + +float CPlayerState::GetVisorTransitionFactor() const +{ + return x1c_visorTransitionFactor; +} + +void CPlayerState::UpdateVisorTransition(float dt) +{ + if (!GetIsVisorTransitioning()) + return; + + if (x14_currentVisor == x18_transitioningVisor) + { + x1c_visorTransitionFactor += dt; + if (x1c_visorTransitionFactor > 0.2) + x1c_visorTransitionFactor = 0.2; + } + else + { + x1c_visorTransitionFactor -= dt; + if (x1c_visorTransitionFactor < 0.f) + { + x14_currentVisor = x18_transitioningVisor; + x1c_visorTransitionFactor = fabs(x1c_visorTransitionFactor); + if (x1c_visorTransitionFactor < 0.19f) + x1c_visorTransitionFactor = 0.19f; + } + } +} + +bool CPlayerState::StartVisorTransition(CPlayerState::EPlayerVisor visor) +{ + x18_transitioningVisor = visor; + return x14_currentVisor == x18_transitioningVisor; +} + +void CPlayerState::ResetVisor() +{ + x18_transitioningVisor = x14_currentVisor = EPlayerVisor::Combat; + x1c_visorTransitionFactor = 0.0f; +} + +bool CPlayerState::ItemEnabled(CPlayerState::EItemType type) +{ + if (HasPowerUp(type)) + return x24_powerups[u32(type)].x4_capacity != 0; + return false; +} + +bool CPlayerState::HasPowerUp(CPlayerState::EItemType type) +{ + if (type < EItemType::Max) + return x24_powerups[u32(type)].x4_capacity != 0; + return false; +} + +u32 CPlayerState::GetItemCapacity(CPlayerState::EItemType type) const +{ + if (type < EItemType::Max) + return x24_powerups[u32(type)].x4_capacity; + return 0; +} + +u32 CPlayerState::GetItemAmount(CPlayerState::EItemType type) const +{ + if (type != EItemType::ThermalVisor && type < EItemType::Max) + return x24_powerups[u32(type)].x0_amount; + return 0; +} + +void CPlayerState::DecrPickup(CPlayerState::EItemType type, s32 amount) +{ + if (type >= EItemType::Max) + return; + + if ((type == EItemType::Missiles || type >= EItemType::PowerBombs) && type < EItemType::ThermalVisor) + x24_powerups[u32(type)].x0_amount -= amount; +} + +void CPlayerState::IncrPickup(EItemType type, s32 amount) +{ + if (type >= EItemType::Max) + return; + + if (amount < 0) + return; + + switch(type) + { + case EItemType::Missiles: + case EItemType::PowerBombs: + case EItemType::ChargeBeam: + case EItemType::SpaceJumpBoots: + case EItemType::EnergyTanks: + case EItemType::ArtifactOfTruth: + case EItemType::ArtifactOfStrength: + case EItemType::ArtifactOfElder: + case EItemType::ArtifactOfWild: + case EItemType::ArtifactOfLifegiver: + case EItemType::ArtifactOfWarrior: + case EItemType::ArtifactOfChozo: + case EItemType::ArtifactOfNature: + case EItemType::ArtifactOfSun: + case EItemType::ArtifactOfWorld: + case EItemType::ArtifactOfSpirit: + case EItemType::ArtifactOfNewborn: + { + CPowerUp& pup = x24_powerups[u32(type)]; + pup.x0_amount = std::min(pup.x0_amount + amount, pup.x4_capacity); + if (type == EItemType::EnergyTanks) + IncrPickup(EItemType::HealthRefill, 9999); + break; + } + case EItemType::HealthRefill: + { + float health = CalculateHealth(amount); + xc_currentHealth = std::min(health, xc_currentHealth + amount); + } + default: + break; + } +} + +void CPlayerState::ResetAndIncrPickUp(CPlayerState::EItemType type, s32 amount) +{ + x24_powerups[u32(type)].x0_amount = 0; + IncrPickup(type, amount); +} + +float CPlayerState::CalculateHealth(u32 health) +{ + return (GetBaseHealthCapacity() + (health * GetEnergyTankCapacity())); +} + +void CPlayerState::InitializePowerUp(CPlayerState::EItemType type, u32 capacity) +{ + if (type >= EItemType::Max) + return; + + CPowerUp& pup = x24_powerups[(u32)type]; + pup.x0_amount = zeus::clamp(u32(0), pup.x4_capacity + capacity, PowerUpMaxValues[u32(type)]); + pup.x0_amount = std::min(pup.x0_amount, pup.x4_capacity); + if (type >= EItemType::PowerSuit && type <= EItemType::PhazonSuit) + { + if (HasPowerUp(EItemType::PhazonSuit)) + x20_currentSuit = EPlayerSuit::Phazon; + else if (HasPowerUp(EItemType::GravitySuit)) + x20_currentSuit = EPlayerSuit::Gravity; + else if (HasPowerUp(EItemType::VariaSuit)) + x20_currentSuit = EPlayerSuit::Varia; + else + x20_currentSuit = EPlayerSuit::Power; + } +} + +void CPlayerState::ReInitalizePowerUp(CPlayerState::EItemType type, u32 capacity) +{ + x24_powerups[u32(type)].x4_capacity = 0; + InitializePowerUp(type, capacity); } } diff --git a/Runtime/CPlayerState.hpp b/Runtime/CPlayerState.hpp index abe232cfc..3fceabc29 100644 --- a/Runtime/CPlayerState.hpp +++ b/Runtime/CPlayerState.hpp @@ -12,33 +12,138 @@ namespace urde class CPlayerState { - static const u32 PowerUpMaxes[41]; - class CPowerUp +public: + enum class EItemType : u32 { - int x0_a = 0; - int x4_b = 0; - public: + PowerBeam, + IceBeam, + WaveBeam, + PlasmaBeam, + Missiles, + ScanVisor, + MorphBallBombs, + PowerBombs, + Flamethrower, + ThermalVisor, + ChargeBeam, + SuperMissile, + GrappleBeam, + XRayVisor, + IceSpreader, + SpaceJumpBoots, + MorphBall, + CombatVisor, + BoostBall, + SpiderBall, + PowerSuit, + GravitySuit, + VariaSuit, + PhazonSuit, + EnergyTanks, + UnknownItem1, + HealthRefill, + UnknownItem2, + Wavebuster, + ArtifactOfTruth, + ArtifactOfStrength, + ArtifactOfElder, + ArtifactOfWild, + ArtifactOfLifegiver, + ArtifactOfWarrior, + ArtifactOfChozo, + ArtifactOfNature, + ArtifactOfSun, + ArtifactOfWorld, + ArtifactOfSpirit, + ArtifactOfNewborn, + + /* This must remain at the end of the list */ + Max + }; + + enum class EPlayerVisor : u32 + { + Combat, + XRay, + Scan, + Thermal, + + /* This must remain at the end of the list */ + Max + }; + + enum class EPlayerSuit : u32 + { + Power, + Gravity, + Varia, + Phazon, + FusionPower, + FusionGravity, + FusionVaria, + FusionPhazon + }; + +private: + + static const u32 PowerUpMaxValues[41]; + struct CPowerUp + { + int x0_amount = 0; + int x4_capacity = 0; CPowerUp() {} - CPowerUp(int a, int b) : x0_a(a), x4_b(b) {} + CPowerUp(int amount, int capacity) : x0_amount(amount), x4_capacity(capacity) {} }; union { - struct { bool x0_24_ : 1; bool x0_25_ : 1; bool x0_26_; }; + struct { bool x0_24_ : 1; bool x0_25_ : 1; bool x0_26_fusion; }; u32 dummy = 0; }; u32 x4_ = 0; - u32 x8_ = 0; - float xc_baseHealth = 99.f; + u32 x8_currentBeam = 0; + float xc_currentHealth = 99.f; float x10_ = 50.f; - u32 x14_ = 0; - u32 x18_ = x14_; - float x1c_ = 0.2f; - u32 x20_ = 0; + EPlayerVisor x14_currentVisor = EPlayerVisor::Combat; + EPlayerVisor x18_transitioningVisor = x14_currentVisor; + float x1c_visorTransitionFactor = 0.2f; + EPlayerSuit x20_currentSuit = EPlayerSuit::Power; rstl::reserved_vector x24_powerups; CStaticInterference x188_staticIntf; public: + + float GetBeamSwitchTime() const; + u32 CalculateItemCollectionRate() const; + + u32 GetBaseHealthCapacityInt32() { return 99; } + void SetFusion(bool val) { x0_26_fusion = val; } + bool GetFusion() const { return x0_26_fusion; } + EPlayerSuit GetCurrentSuit() const; + bool CanVisorSeeFog(const CStateManager& stateMgr) const; + EPlayerVisor GetActiveVisor(const CStateManager& stateMgr) const; + void UpdateStaticInterference(CStateManager& stateMgr, const float& dt); + void IncreaseScanTime(u32 time, float val); + void NewScanTime(u32 time); + bool GetIsVisorTransitioning() const; + float GetVisorTransitionFactor() const; + void UpdateVisorTransition(float dt); + bool StartVisorTransition(EPlayerVisor visor); + void ResetVisor(); + bool ItemEnabled(EItemType type); + void DisableItem(EItemType type); + void EnableItem(EItemType type); + bool HasPowerUp(EItemType type); + u32 GetItemCapacity(EItemType type) const; + u32 GetItemAmount(EItemType type) const; + void DecrPickup(EItemType type, s32 amount); + void IncrPickup(EItemType type, s32 amount); + void ResetAndIncrPickUp(EItemType type, s32 amount); + float GetEnergyTankCapacity() const { return 100.f; } + float GetBaseHealthCapacity() const { return 99.f; } + float CalculateHealth(u32 health); + void ReInitalizePowerUp(EItemType type, u32 capacity); + void InitializePowerUp(EItemType type, u32 capacity); CPlayerState() : x188_staticIntf(5) { x0_24_ = true; } CPlayerState(CBitStreamReader& stream); }; diff --git a/Runtime/GuiSys/CRasterFont.cpp b/Runtime/GuiSys/CRasterFont.cpp index bb772b305..c732dcff7 100644 --- a/Runtime/GuiSys/CRasterFont.cpp +++ b/Runtime/GuiSys/CRasterFont.cpp @@ -33,12 +33,7 @@ CRasterFont::CRasterFont(urde::CInputStream& in, urde::IObjectStore& store) u32 txtrId = in.readUint32Big(); x30_fontInfo = CFontInfo(tmp1, tmp2, tmp3, tmp4, name.c_str()); x80_texture = store.GetObj({'TXTR', txtrId}); - EColorType mode = EColorType(in.readUint32Big()); - /* TODO: Make an enum */ - if (mode == EColorType::Outline) - x2c_mode = EColorType::Outline; - else if (mode == EColorType::Main) - x2c_mode = EColorType::Main; + x2c_mode = EColorType(in.readUint32Big()); u32 glyphCount = in.readUint32Big(); xc_glyphs.reserve(glyphCount); @@ -75,13 +70,16 @@ CRasterFont::CRasterFont(urde::CInputStream& in, urde::IObjectStore& store) s32 howMuch = in.readUint32Big(); x1c_kerning[i] = CKernPair(first, second, howMuch); } + + if (magic == SBIG('FONT') && version <= 2) + x0_initialized = true; } void CRasterFont::SinglePassDrawString(const CDrawStringOptions& opts, int x, int y, int& xout, int& yout, CTextRenderBuffer* renderBuf, const wchar_t* str, s32 length) const { - if (!x0_) + if (!x0_initialized) return; const wchar_t* chr = str; @@ -133,7 +131,7 @@ void CRasterFont::DrawSpace(const CDrawStringOptions& opts, int x, int y, int& x void CRasterFont::DrawString(const CDrawStringOptions& opts, int x, int y, int& xout, int& yout, CTextRenderBuffer* renderBuf, const wchar_t* str, int len) const { - if (!x0_) + if (!x0_initialized) return; if (renderBuf) diff --git a/Runtime/GuiSys/CRasterFont.hpp b/Runtime/GuiSys/CRasterFont.hpp index b5a273222..24beacfe5 100644 --- a/Runtime/GuiSys/CRasterFont.hpp +++ b/Runtime/GuiSys/CRasterFont.hpp @@ -89,16 +89,14 @@ public: class CRasterFont { - bool x0_ = false; + bool x0_initialized = false; s32 x4_monoWidth = 16; s32 x8_monoHeight = 16; std::vector> xc_glyphs; std::vector x1c_kerning; - s32 x28_lineMargin = 0; EColorType x2c_mode = EColorType::Main; CFontInfo x30_fontInfo; TLockedToken x80_texture; - bool x88_ = false; s32 x8c_baseline; s32 x90_lineMargin = 0; diff --git a/Runtime/IOStreams.cpp b/Runtime/IOStreams.cpp index b77f30dbf..942129ecf 100644 --- a/Runtime/IOStreams.cpp +++ b/Runtime/IOStreams.cpp @@ -31,7 +31,9 @@ s32 CBitStreamReader::ReadEncoded(u32 bitCount) baseVal = (baseVal & (x1c_val >> (32 - x20_bitOffset))) << diff; x20_bitOffset = 0; - readUBytesToBuf(&x1c_val, 4); + u32 bit = diff & 7; + u32 count = (diff >> 3) + ((-bit | bit) >> 31); + readUBytesToBuf(&x1c_val, count); /* The game uses Big Endian, which doesn't work for us */ /* Little Endian sucks */ athena::utility::BigUint32(x1c_val); @@ -41,7 +43,7 @@ s32 CBitStreamReader::ReadEncoded(u32 bitCount) baseVal2 = (1 << diff) - 1; ret = baseVal | (baseVal2 & (x1c_val >> (32 - diff))) << x20_bitOffset; - x20_bitOffset = (4 << 3) - diff; + x20_bitOffset = (count << 3) - diff; x1c_val <<= diff; } @@ -70,7 +72,9 @@ void CBitStreamWriter::WriteEncoded(u32 val, u32 bitCount) x18_bitOffset = 0; u32 tmp = x14_val; athena::utility::BigUint32(tmp); - writeBytes(&tmp, 4); + u32 bit = (32 - x18_bitOffset) & 7; + u32 count = ((32 - x18_bitOffset) >> 3) + ((-bit | bit) >> 31); + writeBytes(&tmp, count); u32 rem = 32 - diff; baseVal = -1; diff --git a/mpcksum/CMakeLists.txt b/mpcksum/CMakeLists.txt new file mode 100644 index 000000000..652450238 --- /dev/null +++ b/mpcksum/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories(${CMAKE_CURRENT_SOURCE_DIR} ./../Runtime) + +add_executable(mpcksum + main.cpp) + +target_link_libraries(mpcksum + athena-core z lzo2) diff --git a/mpcksum/main.cpp b/mpcksum/main.cpp new file mode 100644 index 000000000..057bbf8d2 --- /dev/null +++ b/mpcksum/main.cpp @@ -0,0 +1,51 @@ +#include +#include "athena/MemoryReader.hpp" +#include "athena/FileWriter.hpp" +#include "athena/Checksums.hpp" + +#if __BYTE_ORDER__ == __BIG_ENDIAN +#define SBIG(q) q +#else +#define SBIG(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \ + | ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 ) +#endif + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + printf("mpcksum [output]\n"); + return 1; + } + + athena::io::MemoryCopyReader in(argv[1]); + std::unique_ptr out; + if (argc > 2) + out.reset(new athena::io::FileWriter(argv[2])); + else + out.reset(new athena::io::FileWriter(argv[1])); + + atUint32 magic; + in.readUBytesToBuf(&magic, 4); + if (magic != SBIG('GM8E') && magic != SBIG('GM8P') && magic != SBIG('GM8J')) + { + printf("Unsupported file, MP .gci file expected\n"); + return 1; + } + + if (in.length() != 8256) + { + printf("File too small expected 8,256 bytes got %llu", in.length()); + return 1; + } + + atUint8* data = in.data(); + + atUint32 newCkSum = athena::Checksums::crc32(data + 68, 8188, 0); + *(atUint32*)(data + 64) = SBIG(newCkSum); + out->writeBytes(data, 8256); + + delete data; + + return 0; +}