metaforce/Runtime/CGameState.cpp

317 lines
9.1 KiB
C++
Raw Normal View History

#include "CGameState.hpp"
2015-08-23 16:58:07 -07:00
#include "IOStreams.hpp"
2016-03-28 01:54:02 -07:00
#include "zeus/Math.hpp"
2016-09-24 18:58:20 -07:00
#include "GameGlobalObjects.hpp"
#include "CMemoryCardSys.hpp"
#include "CSimplePool.hpp"
#include "CSaveWorld.hpp"
2017-04-14 22:32:25 -07:00
#include "MP1/MP1.hpp"
2016-03-04 15:04:53 -08:00
namespace urde
{
union BitsToDouble
{
struct
{
#if BYTE_ORDER == __LITTLE_ENDIAN
u32 high;
u32 low;
#else
u32 low;
u32 high;
#endif
};
double doub;
};
2016-10-09 00:45:04 -07:00
CWorldLayerState::CWorldLayerState(CBitStreamReader& reader, const CSaveWorld& saveWorld)
{
u32 bitCount = reader.ReadEncoded(10);
x10_saveLayers.reserve(bitCount);
for (u32 i=0 ; i<bitCount ; ++i)
{
bool bit = reader.ReadEncoded(1);
if (bit)
x10_saveLayers.setBit(i);
else
x10_saveLayers.unsetBit(i);
}
}
2016-10-09 14:41:23 -07:00
void CWorldLayerState::PutTo(CBitStreamWriter& writer) const
{
u32 totalLayerCount = 0;
for (int i=0 ; i<x0_areaLayers.size() ; ++i)
totalLayerCount += GetAreaLayerCount(i) - 1;
writer.WriteEncoded(totalLayerCount, 10);
for (int i=0 ; i<x0_areaLayers.size() ; ++i)
{
u32 count = GetAreaLayerCount(i);
for (u32 l=1 ; l<count ; ++l)
writer.WriteEncoded(IsLayerActive(i, l), 1);
}
}
2016-10-09 00:45:04 -07:00
void CWorldLayerState::InitializeWorldLayers(const std::vector<CWorldLayers::Area>& layers)
{
if (x0_areaLayers.size())
return;
x0_areaLayers = layers;
if (x10_saveLayers.getBitCount() == 0)
return;
u32 a = 0;
u32 b = 0;
for (const CWorldLayers::Area& area : x0_areaLayers)
{
for (u32 l=1 ; l<area.m_layerCount ; ++l)
2016-10-09 00:45:04 -07:00
SetLayerActive(a, l, x10_saveLayers.getBit(b++));
++a;
}
x10_saveLayers.clear();
}
2017-08-12 22:26:14 -07:00
CWorldState::CWorldState(CAssetId id)
: x0_mlvlId(id), x4_areaId(0)
{
x8_relayTracker = std::make_shared<CRelayTracker>();
xc_mapWorldInfo = std::make_shared<CMapWorldInfo>();
2017-11-14 20:12:13 -08:00
x10_desiredAreaAssetId = {};
2016-10-09 00:45:04 -07:00
x14_layerState = std::make_shared<CWorldLayerState>();
}
2017-08-12 22:26:14 -07:00
CWorldState::CWorldState(CBitStreamReader& reader, CAssetId mlvlId, const CSaveWorld& saveWorld)
2016-09-24 18:58:20 -07:00
: x0_mlvlId(mlvlId)
{
x4_areaId = reader.ReadEncoded(32);
x10_desiredAreaAssetId = u32(reader.ReadEncoded(32));
2016-09-24 18:58:20 -07:00
x8_relayTracker = std::make_shared<CRelayTracker>(reader, saveWorld);
xc_mapWorldInfo = std::make_shared<CMapWorldInfo>(reader, saveWorld, mlvlId);
2016-10-09 00:45:04 -07:00
x14_layerState = std::make_shared<CWorldLayerState>(reader, saveWorld);
2016-09-24 18:58:20 -07:00
}
2016-10-09 14:41:23 -07:00
void CWorldState::PutTo(CBitStreamWriter& writer, const CSaveWorld& savw) const
{
writer.WriteEncoded(x4_areaId, 32);
2017-08-12 22:26:14 -07:00
writer.WriteEncoded(x10_desiredAreaAssetId.Value(), 32);
2016-10-09 14:41:23 -07:00
x8_relayTracker->PutTo(writer, savw);
2017-01-06 17:58:05 -08:00
xc_mapWorldInfo->PutTo(writer, savw, x0_mlvlId);
2016-10-09 14:41:23 -07:00
x14_layerState->PutTo(writer);
}
2016-12-20 13:51:50 -08:00
CGameState::GameFileStateInfo CGameState::LoadGameFileState(const u8* data)
{
CBitStreamReader stream(data, 4096);
GameFileStateInfo ret;
for (u32 i = 0; i < 128; i++)
stream.ReadEncoded(8);
ret.x14_timestamp = stream.ReadEncoded(32);
ret.x20_hardMode = stream.ReadEncoded(1);
stream.ReadEncoded(1);
2017-08-12 22:26:14 -07:00
CAssetId origMLVL = stream.ReadEncoded(32);
2017-02-05 19:21:58 -08:00
ret.x8_mlvlId = g_ResFactory->TranslateOriginalToNew(origMLVL);
2016-12-20 13:51:50 -08:00
BitsToDouble conv;
2016-12-20 13:51:50 -08:00
conv.low = stream.ReadEncoded(32);
conv.high = stream.ReadEncoded(32);
ret.x0_playTime = conv.doub;
CPlayerState playerState(stream);
ret.x10_energyTanks = playerState.GetItemCapacity(CPlayerState::EItemType::EnergyTanks);
u32 itemPercent;
2017-02-05 19:21:58 -08:00
if (origMLVL == 0x158EFE17)
2016-12-20 13:51:50 -08:00
itemPercent = 0;
else
itemPercent = playerState.CalculateItemCollectionRate() * 100 / playerState.GetPickupTotal();
2017-02-06 19:52:04 -08:00
2016-12-20 13:51:50 -08:00
ret.x18_itemPercent = itemPercent;
2017-07-30 04:00:30 -07:00
float scanPercent;
2016-12-20 13:51:50 -08:00
if (playerState.GetTotalLogScans() == 0)
2017-07-30 04:00:30 -07:00
scanPercent = 0.f;
2016-12-20 13:51:50 -08:00
else
2017-07-30 04:00:30 -07:00
scanPercent = 100.f * playerState.GetLogScans() / float(playerState.GetTotalLogScans());
ret.x1c_scanPercent = scanPercent;
2016-12-20 13:51:50 -08:00
return ret;
}
CGameState::CGameState()
{
2017-02-05 19:21:58 -08:00
x98_playerState = std::make_shared<CPlayerState>();
x9c_transManager = std::make_shared<CWorldTransManager>();
2018-04-04 23:58:11 -07:00
x228_25_initPowerupsAtFirstSpawn = true;
2017-02-05 19:21:58 -08:00
if (g_MemoryCardSys)
InitializeMemoryStates();
}
2016-12-29 22:37:01 -08:00
CGameState::CGameState(CBitStreamReader& stream, u32 saveIdx)
: x20c_saveFileIdx(saveIdx)
2016-06-30 12:33:38 -07:00
{
2017-02-05 19:21:58 -08:00
x9c_transManager = std::make_shared<CWorldTransManager>();
2018-04-04 23:58:11 -07:00
x228_25_initPowerupsAtFirstSpawn = true;
2016-06-30 12:33:38 -07:00
for (u32 i = 0; i < 128; i++)
2016-10-09 14:41:23 -07:00
x0_[i] = stream.ReadEncoded(8);
stream.ReadEncoded(32);
2016-10-09 14:41:23 -07:00
2016-12-16 15:05:29 -08:00
x228_24_hardMode = stream.ReadEncoded(1);
2018-04-04 23:58:11 -07:00
x228_25_initPowerupsAtFirstSpawn = stream.ReadEncoded(1);
x84_mlvlId = g_ResFactory->TranslateOriginalToNew(stream.ReadEncoded(32));
2017-04-14 22:32:25 -07:00
MP1::CMain::EnsureWorldPakReady(x84_mlvlId);
2016-10-09 14:41:23 -07:00
BitsToDouble conv;
2016-10-09 14:41:23 -07:00
conv.low = stream.ReadEncoded(32);
conv.high = stream.ReadEncoded(32);
xa0_playTime = conv.doub;
2016-06-30 12:33:38 -07:00
2016-09-24 18:58:20 -07:00
x98_playerState = std::make_shared<CPlayerState>(stream);
x17c_gameOptions = CGameOptions(stream);
x1f8_hintOptions = CHintOptions(stream);
const auto& memWorlds = g_MemoryCardSys->GetMemoryWorlds();
2016-09-24 18:58:20 -07:00
x88_worldStates.reserve(memWorlds.size());
for (const auto& memWorld : memWorlds)
2016-09-24 18:58:20 -07:00
{
TLockedToken<CSaveWorld> saveWorld =
g_SimplePool->GetObj(SObjectTag{FOURCC('SAVW'), memWorld.second.GetSaveWorldAssetId()});
x88_worldStates.emplace_back(stream, memWorld.first, *saveWorld);
2016-09-24 18:58:20 -07:00
}
2017-02-05 19:21:58 -08:00
InitializeMemoryWorlds();
WriteBackupBuf();
2016-06-30 12:33:38 -07:00
}
2015-08-19 19:52:07 -07:00
2016-12-29 22:37:01 -08:00
void CGameState::ReadPersistentOptions(CBitStreamReader& r)
{
xa8_systemOptions = CPersistentOptions(r);
}
2016-12-22 22:41:39 -08:00
void CGameState::ImportPersistentOptions(const CPersistentOptions& opts)
2016-12-20 13:51:50 -08:00
{
2016-12-31 22:46:52 -08:00
if (opts.xd0_24_fusionLinked)
xa8_systemOptions.xd0_24_fusionLinked = true;
if (opts.xd0_27_fusionBeat)
xa8_systemOptions.xd0_27_fusionBeat = true;
2016-12-20 13:51:50 -08:00
if (&opts != &xa8_systemOptions)
2018-04-04 23:58:11 -07:00
memcpy(xa8_systemOptions.x0_nesState, opts.x0_nesState, 98);
2017-07-30 22:19:05 -07:00
xa8_systemOptions.SetLogScanPercent(opts.GetLogScanPercent());
2016-12-20 13:51:50 -08:00
xa8_systemOptions.SetAllItemsCollected(opts.GetAllItemsCollected());
2016-12-31 22:46:52 -08:00
xa8_systemOptions.SetPlayerBeatNormalMode(opts.GetPlayerBeatNormalMode());
2016-12-20 13:51:50 -08:00
xa8_systemOptions.SetPlayerBeatHardMode(opts.GetPlayerBeatHardMode());
}
2016-10-09 14:41:23 -07:00
2016-12-22 22:41:39 -08:00
void CGameState::ExportPersistentOptions(CPersistentOptions& opts) const
{
2016-12-31 22:46:52 -08:00
if (xa8_systemOptions.xd0_24_fusionLinked)
opts.xd0_24_fusionLinked = true;
if (xa8_systemOptions.xd0_27_fusionBeat)
opts.xd0_27_fusionBeat = true;
2016-12-22 22:41:39 -08:00
if (&opts != &xa8_systemOptions)
2018-04-04 23:58:11 -07:00
memcpy(opts.x0_nesState, xa8_systemOptions.x0_nesState, 98);
2016-12-31 22:46:52 -08:00
opts.SetPlayerFusionSuitActive(xa8_systemOptions.GetPlayerFusionSuitActive());
2016-12-22 22:41:39 -08:00
}
void CGameState::WriteBackupBuf()
{
x218_backupBuf.resize(940);
CBitStreamWriter w(x218_backupBuf.data(), 940);
PutTo(w);
}
2016-10-09 14:41:23 -07:00
void CGameState::PutTo(CBitStreamWriter& writer) const
{
for (u32 i = 0; i < 128; i++)
writer.WriteEncoded(x0_[i], 8);
writer.WriteEncoded(CBasics::ToWiiTime(std::chrono::system_clock::now()) / CBasics::TICKS_PER_SECOND, 32);
2016-12-16 15:05:29 -08:00
writer.WriteEncoded(x228_24_hardMode, 1);
2018-04-04 23:58:11 -07:00
writer.WriteEncoded(x228_25_initPowerupsAtFirstSpawn, 1);
2017-08-12 22:26:14 -07:00
writer.WriteEncoded(g_ResFactory->TranslateNewToOriginal(x84_mlvlId).Value(), 32);
2016-10-09 14:41:23 -07:00
BitsToDouble conv;
2016-10-09 14:41:23 -07:00
conv.doub = xa0_playTime;
writer.WriteEncoded(conv.low, 32);
writer.WriteEncoded(conv.high, 32);
x98_playerState->PutTo(writer);
x17c_gameOptions.PutTo(writer);
x1f8_hintOptions.PutTo(writer);
const auto& memWorlds = g_MemoryCardSys->GetMemoryWorlds();
for (const auto& memWorld : memWorlds)
{
TLockedToken<CSaveWorld> saveWorld =
g_SimplePool->GetObj(SObjectTag{FOURCC('SAVW'), memWorld.second.GetSaveWorldAssetId()});
const CWorldState& wld = const_cast<CGameState&>(*this).StateForWorld(memWorld.first);
wld.PutTo(writer, *saveWorld);
}
}
2017-08-12 22:26:14 -07:00
void CGameState::SetCurrentWorldId(CAssetId id)
2015-08-19 19:52:07 -07:00
{
2016-10-09 14:41:23 -07:00
StateForWorld(id);
x84_mlvlId = id;
2017-04-14 22:32:25 -07:00
MP1::CMain::EnsureWorldPakReady(x84_mlvlId);
2015-08-19 19:52:07 -07:00
}
2016-03-28 01:54:02 -07:00
void CGameState::SetTotalPlayTime(float time)
{
xa0_playTime = zeus::clamp<double>(0.0, time, 359999.0);
}
2017-08-12 22:26:14 -07:00
CWorldState& CGameState::StateForWorld(CAssetId mlvlId)
{
auto it = x88_worldStates.begin();
for (; it != x88_worldStates.end() ; ++it)
{
if (it->GetWorldAssetId() == mlvlId)
break;
}
if (it == x88_worldStates.end())
{
x88_worldStates.emplace_back(mlvlId);
return x88_worldStates.back();
}
return *it;
}
float CGameState::GetHardModeDamageMultiplier() const
{
return g_tweakGame->GetHardModeDamageMultiplier();
}
float CGameState::GetHardModeWeaponMultiplier() const
{
return g_tweakGame->GetHardModeWeaponMultiplier();
}
2017-02-05 19:21:58 -08:00
void CGameState::InitializeMemoryWorlds()
{
const auto& memoryWorlds = g_MemoryCardSys->GetMemoryWorlds();
for (const auto& wld : memoryWorlds)
{
const auto& layerState = StateForWorld(wld.first).GetLayerState();
layerState->InitializeWorldLayers(wld.second.GetDefaultLayerStates());
}
}
void CGameState::InitializeMemoryStates()
{
x98_playerState->InitializeScanTimes();
x1f8_hintOptions.InitializeMemoryState();
InitializeMemoryWorlds();
WriteBackupBuf();
}
}