2016-04-24 02:46:13 +00:00
|
|
|
#include "CWorld.hpp"
|
2016-07-23 21:41:18 +00:00
|
|
|
#include "CGameArea.hpp"
|
|
|
|
#include "GameGlobalObjects.hpp"
|
|
|
|
#include "CSimplePool.hpp"
|
2016-07-24 04:46:32 +00:00
|
|
|
#include "CStateManager.hpp"
|
|
|
|
#include "CInGameTweakManagerBase.hpp"
|
2016-08-01 04:35:42 +00:00
|
|
|
#include "Audio/CAudioGroupSet.hpp"
|
2016-04-24 02:46:13 +00:00
|
|
|
|
|
|
|
namespace urde
|
|
|
|
{
|
|
|
|
|
2016-07-24 22:51:15 +00:00
|
|
|
CWorld::CSoundGroupData::CSoundGroupData(int grpId, ResId agsc)
|
|
|
|
: x0_groupId(grpId), x4_agscId(agsc)
|
|
|
|
{
|
|
|
|
x1c_groupData = g_SimplePool->GetObj(SObjectTag{FOURCC('AGSC'), agsc});
|
|
|
|
}
|
|
|
|
|
2016-07-23 21:41:18 +00:00
|
|
|
CDummyWorld::CDummyWorld(ResId mlvlId, bool loadMap)
|
|
|
|
: x4_loadMap(loadMap)
|
|
|
|
{
|
|
|
|
SObjectTag tag{FOURCC('MLVL'), mlvlId};
|
|
|
|
g_ResFactory->LoadResourceAsync(tag, x34_loadBuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
ResId CDummyWorld::IGetWorldAssetId() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return xc_mlvlId;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ResId CDummyWorld::IGetStringTableAssetId() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x10_strgId;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ResId CDummyWorld::IGetSaveWorldAssetId() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x14_savwId;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const CMapWorld* CDummyWorld::IGetMapWorld() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x2c_mapWorld.GetObj();
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CMapWorld* CDummyWorld::IMapWorld()
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x2c_mapWorld.GetObj();
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
const IGameArea* CDummyWorld::IGetAreaAlways(TAreaId id) const
|
2016-07-23 21:41:18 +00:00
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return &x18_areas.at(id);
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
TAreaId CDummyWorld::IGetCurrentAreaId() const
|
2016-07-23 21:41:18 +00:00
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x3c_curAreaId;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
TAreaId CDummyWorld::IGetAreaId(ResId id) const
|
2016-07-23 21:41:18 +00:00
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
int ret = 0;
|
|
|
|
if (id == -1)
|
|
|
|
return kInvalidAreaId;
|
|
|
|
for (const CDummyGameArea& area : x18_areas)
|
|
|
|
{
|
|
|
|
if (area.xc_mrea == id)
|
|
|
|
return ret;
|
|
|
|
++ret;
|
|
|
|
}
|
|
|
|
return kInvalidAreaId;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
std::vector<CWorld::CRelay> CWorld::CRelay::ReadMemoryRelays(athena::io::MemoryReader& r)
|
2016-07-23 21:41:18 +00:00
|
|
|
{
|
|
|
|
std::vector<CWorld::CRelay> ret;
|
|
|
|
u32 count = r.readUint32Big();
|
|
|
|
ret.reserve(count);
|
|
|
|
for (u32 i=0 ; i<count ; ++i)
|
|
|
|
ret.emplace_back(r);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
CWorldLayers CWorldLayers::ReadWorldLayers(athena::io::MemoryReader& r)
|
2016-07-23 21:41:18 +00:00
|
|
|
{
|
|
|
|
CWorldLayers ret;
|
|
|
|
|
|
|
|
u32 areaCount = r.readUint32Big();
|
|
|
|
ret.m_areas.reserve(areaCount);
|
|
|
|
for (u32 i=0 ; i<areaCount ; ++i)
|
|
|
|
{
|
|
|
|
ret.m_areas.emplace_back();
|
|
|
|
ret.m_areas.back().m_layerCount = r.readUint32Big();
|
|
|
|
ret.m_areas.back().m_layerBits = r.readUint64Big();
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 nameCount = r.readUint32Big();
|
|
|
|
ret.m_names.reserve(areaCount);
|
|
|
|
for (u32 i=0 ; i<nameCount ; ++i)
|
|
|
|
ret.m_names.push_back(r.readString());
|
|
|
|
|
|
|
|
areaCount = r.readUint32Big();
|
|
|
|
for (u32 i=0 ; i<areaCount ; ++i)
|
|
|
|
ret.m_areas[i].m_startNameIdx = r.readUint32Big();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CDummyWorld::ICheckWorldComplete()
|
|
|
|
{
|
|
|
|
switch (x8_phase)
|
|
|
|
{
|
|
|
|
case Phase::Loading:
|
|
|
|
{
|
|
|
|
if (!x34_loadBuf)
|
|
|
|
return false;
|
|
|
|
athena::io::MemoryReader r(x34_loadBuf.get(), UINT32_MAX, false);
|
|
|
|
r.readUint32Big();
|
|
|
|
int version = r.readUint32Big();
|
|
|
|
x10_strgId = r.readUint32Big();
|
|
|
|
|
|
|
|
if (version >= 15)
|
|
|
|
x14_savwId = r.readUint32Big();
|
|
|
|
if (version >= 12)
|
|
|
|
r.readUint32Big();
|
|
|
|
if (version >= 17)
|
2016-07-24 04:46:32 +00:00
|
|
|
CWorld::CRelay::ReadMemoryRelays(r);
|
2016-07-23 21:41:18 +00:00
|
|
|
|
|
|
|
u32 areaCount = r.readUint32Big();
|
|
|
|
r.readUint32Big();
|
|
|
|
|
|
|
|
x18_areas.reserve(areaCount);
|
|
|
|
for (u32 i=0 ; i<areaCount ; ++i)
|
|
|
|
x18_areas.emplace_back(r, i, version);
|
|
|
|
|
|
|
|
x28_mapWorldId = r.readUint32Big();
|
|
|
|
if (x4_loadMap)
|
|
|
|
x2c_mapWorld = g_SimplePool->GetObj(SObjectTag{FOURCC('MAPW'), x28_mapWorldId});
|
|
|
|
|
|
|
|
if (version > 10)
|
|
|
|
{
|
|
|
|
u32 audioGroupCount = r.readUint32Big();
|
|
|
|
for (u32 i=0 ; i<audioGroupCount ; ++i)
|
|
|
|
{
|
|
|
|
r.readUint32Big();
|
|
|
|
r.readUint32Big();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (version > 12)
|
|
|
|
r.readString();
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
CWorldLayers::ReadWorldLayers(r);
|
2016-07-23 21:41:18 +00:00
|
|
|
|
|
|
|
if (x4_loadMap)
|
|
|
|
x8_phase = Phase::LoadingMap;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
x8_phase = Phase::Done;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case Phase::LoadingMap:
|
|
|
|
{
|
|
|
|
if (!x2c_mapWorld.IsLoaded() || !x2c_mapWorld.GetObj())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
x2c_mapWorld->SetWhichMapAreasLoaded(*this, 0, 9999);
|
|
|
|
x8_phase = Phase::LoadingMapAreas;
|
|
|
|
}
|
|
|
|
case Phase::LoadingMapAreas:
|
|
|
|
{
|
|
|
|
if (x2c_mapWorld->IsMapAreasStreaming())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
x8_phase = Phase::Done;
|
|
|
|
}
|
|
|
|
case Phase::Done:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string CDummyWorld::IGetDefaultAudioTrack() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return {};
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int CDummyWorld::IGetAreaCount() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x18_areas.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
CWorld::CWorld(IObjectStore& objStore, IFactory& resFactory, ResId mlvlId)
|
|
|
|
: x60_objectStore(objStore), x64_resFactory(resFactory)
|
|
|
|
{
|
|
|
|
SObjectTag tag{FOURCC('MLVL'), mlvlId};
|
|
|
|
resFactory.LoadResourceAsync(tag, x40_loadBuf);
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ResId CWorld::IGetWorldAssetId() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x8_mlvlId;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ResId CWorld::IGetStringTableAssetId() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return xc_strgId;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ResId CWorld::IGetSaveWorldAssetId() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x10_savwId;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const CMapWorld* CWorld::IGetMapWorld() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return GetMapWorld();
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CMapWorld* CWorld::IMapWorld()
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return (CMapWorld*)GetMapWorld();
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
const IGameArea* CWorld::IGetAreaAlways(TAreaId id) const
|
2016-07-23 21:41:18 +00:00
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x18_areas.at(id).get();
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
TAreaId CWorld::IGetCurrentAreaId() const
|
2016-07-23 21:41:18 +00:00
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x68_curAreaId;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
TAreaId CWorld::IGetAreaId(ResId id) const
|
2016-07-23 21:41:18 +00:00
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
int ret = 0;
|
|
|
|
if (id == -1)
|
|
|
|
return kInvalidAreaId;
|
|
|
|
for (const std::unique_ptr<CGameArea>& area : x18_areas)
|
|
|
|
{
|
|
|
|
if (area->x84_mrea == id)
|
|
|
|
return ret;
|
|
|
|
++ret;
|
|
|
|
}
|
|
|
|
return kInvalidAreaId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorld::MoveToChain(CGameArea* area, EChain chain)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-07-24 22:51:15 +00:00
|
|
|
void CWorld::LoadSoundGroup(int groupId, ResId agscId, CSoundGroupData& data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorld::LoadSoundGroups()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
bool CWorld::CheckWorldComplete(CStateManager* mgr, TAreaId id, ResId mreaId)
|
|
|
|
{
|
|
|
|
if (mreaId != -1)
|
|
|
|
{
|
|
|
|
x68_curAreaId = 0;
|
|
|
|
TAreaId aid = 0;
|
|
|
|
for (const std::unique_ptr<CGameArea>& area : x18_areas)
|
|
|
|
{
|
|
|
|
if (area->x84_mrea == mreaId)
|
|
|
|
{
|
|
|
|
x68_curAreaId = aid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++aid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
x68_curAreaId = id;
|
|
|
|
|
|
|
|
switch (x4_phase)
|
|
|
|
{
|
|
|
|
case Phase::Loading:
|
|
|
|
{
|
|
|
|
if (!x40_loadBuf)
|
|
|
|
return false;
|
|
|
|
athena::io::MemoryReader r(x40_loadBuf.get(), UINT32_MAX, false);
|
|
|
|
r.readUint32Big();
|
|
|
|
int version = r.readUint32Big();
|
|
|
|
xc_strgId = r.readUint32Big();
|
|
|
|
|
|
|
|
if (version >= 15)
|
|
|
|
x10_savwId = r.readUint32Big();
|
|
|
|
if (version >= 12)
|
|
|
|
{
|
|
|
|
ResId skyboxId = r.readUint32Big();
|
|
|
|
if (skyboxId != -1 && mgr)
|
2016-07-24 22:51:15 +00:00
|
|
|
x94_skybox = g_SimplePool->GetObj(SObjectTag{FOURCC('CMDL'), skyboxId});
|
2016-07-24 04:46:32 +00:00
|
|
|
}
|
|
|
|
if (version >= 17)
|
|
|
|
x2c_relays = CWorld::CRelay::ReadMemoryRelays(r);
|
|
|
|
|
|
|
|
u32 areaCount = r.readUint32Big();
|
|
|
|
r.readUint32Big();
|
|
|
|
|
|
|
|
x18_areas.reserve(areaCount);
|
|
|
|
for (u32 i=0 ; i<areaCount ; ++i)
|
|
|
|
x18_areas.push_back(std::make_unique<CGameArea>(r, i, version));
|
|
|
|
|
|
|
|
if (x48_chainCount < 5)
|
|
|
|
{
|
|
|
|
for (int i=x48_chainCount ; i<5 ; ++i)
|
|
|
|
x4c_chainHeads[i] = nullptr;
|
|
|
|
x48_chainCount = 5;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (std::unique_ptr<CGameArea>& area : x18_areas)
|
|
|
|
MoveToChain(area.get(), EChain::One);
|
|
|
|
|
|
|
|
x24_mapwId = r.readUint32Big();
|
|
|
|
x28_mapWorld = g_SimplePool->GetObj(SObjectTag{FOURCC('MAPW'), x24_mapwId});
|
|
|
|
|
|
|
|
if (mgr)
|
|
|
|
{
|
|
|
|
std::vector<TEditorId> ids;
|
|
|
|
mgr->LoadScriptObjects(kInvalidAreaId, r, ids);
|
|
|
|
mgr->InitScriptObjects(ids);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (version > 10)
|
|
|
|
{
|
|
|
|
u32 audioGroupCount = r.readUint32Big();
|
|
|
|
x74_soundGroupData.reserve(audioGroupCount);
|
|
|
|
for (u32 i=0 ; i<audioGroupCount ; ++i)
|
|
|
|
{
|
|
|
|
int grpId = r.readUint32Big();
|
|
|
|
ResId agscId = r.readUint32Big();
|
|
|
|
x74_soundGroupData.emplace_back(grpId, agscId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (version > 12)
|
|
|
|
{
|
|
|
|
x84_defAudioTrack = r.readString();
|
|
|
|
std::string trackKey = hecl::Format("WorldDefault: %8.8x", u32(x8_mlvlId));
|
|
|
|
if (g_TweakManager->HasTweakValue(trackKey))
|
|
|
|
x84_defAudioTrack = g_TweakManager->GetTweakValue(trackKey)->x30_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
CWorldLayers::ReadWorldLayers(r);
|
|
|
|
|
|
|
|
x4_phase = Phase::LoadingMap;
|
|
|
|
}
|
|
|
|
case Phase::LoadingMap:
|
|
|
|
{
|
2016-07-24 22:51:15 +00:00
|
|
|
if (!x28_mapWorld.IsLoaded() || !x28_mapWorld.GetObj())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (x68_curAreaId == kInvalidAreaId)
|
|
|
|
x28_mapWorld->SetWhichMapAreasLoaded(*this, 0, 9999);
|
|
|
|
else
|
|
|
|
x28_mapWorld->SetWhichMapAreasLoaded(*this, x68_curAreaId, 3);
|
|
|
|
|
2016-07-24 04:46:32 +00:00
|
|
|
x4_phase = Phase::LoadingMapAreas;
|
|
|
|
}
|
|
|
|
case Phase::LoadingMapAreas:
|
|
|
|
{
|
2016-07-24 22:51:15 +00:00
|
|
|
if (x28_mapWorld->IsMapAreasStreaming())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
x4_phase = Phase::LoadingSkyBox;
|
|
|
|
}
|
|
|
|
case Phase::LoadingSkyBox:
|
|
|
|
{
|
|
|
|
x70_26_ = true;
|
|
|
|
x70_27_ = false;
|
|
|
|
|
|
|
|
if (!x94_skybox.IsLoaded())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
CModel* skybox = x94_skybox.GetObj();
|
|
|
|
if (!skybox)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
skybox->Touch(0);
|
|
|
|
if (!skybox->IsLoaded(0))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
xa4_skyboxB = x94_skybox;
|
|
|
|
|
|
|
|
for (CSoundGroupData& group : x74_soundGroupData)
|
|
|
|
group.x1c_groupData.Lock();
|
|
|
|
|
|
|
|
x4_phase = Phase::LoadingSoundGroups;
|
|
|
|
}
|
|
|
|
case Phase::LoadingSoundGroups:
|
|
|
|
{
|
|
|
|
bool allLoaded = true;
|
|
|
|
for (CSoundGroupData& group : x74_soundGroupData)
|
|
|
|
{
|
|
|
|
bool loaded = group.x1c_groupData.IsLoaded();
|
|
|
|
allLoaded &= loaded;
|
|
|
|
if (loaded)
|
|
|
|
{
|
|
|
|
CAudioGroupSet* groupData = group.x1c_groupData.GetObj();
|
|
|
|
if (groupData)
|
|
|
|
LoadSoundGroup(group.x0_groupId, group.x4_agscId, group);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!allLoaded)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
LoadSoundGroups();
|
2016-07-24 04:46:32 +00:00
|
|
|
x4_phase = Phase::Done;
|
|
|
|
}
|
|
|
|
case Phase::Done:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-07-24 22:51:15 +00:00
|
|
|
return false;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CWorld::ICheckWorldComplete()
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return CheckWorldComplete(nullptr, kInvalidAreaId, -1);
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string CWorld::IGetDefaultAudioTrack() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x84_defAudioTrack;
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int CWorld::IGetAreaCount() const
|
|
|
|
{
|
2016-07-24 04:46:32 +00:00
|
|
|
return x18_areas.size();
|
2016-07-23 21:41:18 +00:00
|
|
|
}
|
|
|
|
|
2016-04-24 02:46:13 +00:00
|
|
|
bool CWorld::DoesAreaExist(TAreaId area) const
|
|
|
|
{
|
|
|
|
return (area >= 0 && area < x18_areas.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|