diff --git a/include/MetroidPrime/CMemoryCard.hpp b/include/MetroidPrime/CMemoryCard.hpp index 71cb2a8b..1fcf91c7 100644 --- a/include/MetroidPrime/CMemoryCard.hpp +++ b/include/MetroidPrime/CMemoryCard.hpp @@ -5,12 +5,7 @@ #include "Kyoto/CObjectReference.hpp" #include "MetroidPrime/TGameTypes.hpp" - -class CWorldSaveGameInfo { - // TODO: move to it's own file -public: - enum EScanCategory { kSC_None, kSC_Data, kSC_Lore, kSC_Creature, kSC_Research, kSC_Artifact }; -}; +#include "MetroidPrime/Player/CWorldSaveGameInfo.hpp" class CMemoryCard { public: diff --git a/include/MetroidPrime/CWorld.hpp b/include/MetroidPrime/CWorld.hpp index fa2a6e75..02f64d34 100644 --- a/include/MetroidPrime/CWorld.hpp +++ b/include/MetroidPrime/CWorld.hpp @@ -6,8 +6,8 @@ #include "MetroidPrime/CGameArea.hpp" #include "MetroidPrime/TGameTypes.hpp" -#include "Kyoto/IObjectStore.hpp" #include "Kyoto/Audio/CSfxHandle.hpp" +#include "Kyoto/IObjectStore.hpp" #include "rstl/string.hpp" @@ -37,6 +37,20 @@ class CSoundGroupData; class IDvdRequest; class IFactory; +class CRelay { +public: + const TEditorId& GetRelayId() const { return x0_relay; } + const TEditorId& GetTargetId() const { return x4_target; } + ushort GetMessage() const { return x8_msg; } + bool GetActive() const { return xa_active; } + +private: + TEditorId x0_relay; + TEditorId x4_target; + ushort x8_msg; + bool xa_active; +}; + // TODO move? enum EEnvFxType { kEFX_None, @@ -66,8 +80,10 @@ public: bool IsAreaValid(TAreaId id) const { return GetArea(id)->IsLoaded(); } CAssetId GetWorldAssetId() const { return x8_mlvlId; } TAreaId GetAreaIdForSaveId(int saveId) const; + const rstl::vector< CRelay >& GetRelays() const { return x2c_relays; } - static void PropogateAreaChain(CGameArea::EOcclusionState occlusionState, CGameArea* area, CWorld* world); + static void PropogateAreaChain(CGameArea::EOcclusionState occlusionState, CGameArea* area, + CWorld* world); private: enum Phase { diff --git a/include/MetroidPrime/Player/CWorldSaveGameInfo.hpp b/include/MetroidPrime/Player/CWorldSaveGameInfo.hpp new file mode 100644 index 00000000..15164d36 --- /dev/null +++ b/include/MetroidPrime/Player/CWorldSaveGameInfo.hpp @@ -0,0 +1,22 @@ +#ifndef _CWORLDSAVEGAMEINFO +#define _CWORLDSAVEGAMEINFO + +#include "MetroidPrime/TGameTypes.hpp" + +#include "rstl/vector.hpp" + +class CWorldSaveGameInfo { +public: + enum EScanCategory { kSC_None, kSC_Data, kSC_Lore, kSC_Creature, kSC_Research, kSC_Artifact }; + + int GetRelayIndex(const TEditorId&) const; + + const rstl::vector& GetRelays() const { return x14_relays; } + +private: + uint x0_areaCount; + rstl::vector x4_cinematics; + rstl::vector x14_relays; +}; + +#endif // _CWORLDSAVEGAMEINFO diff --git a/include/MetroidPrime/TGameTypes.hpp b/include/MetroidPrime/TGameTypes.hpp index ed22b40d..4fff46a0 100644 --- a/include/MetroidPrime/TGameTypes.hpp +++ b/include/MetroidPrime/TGameTypes.hpp @@ -33,8 +33,8 @@ struct TEditorId { TEditorId(CInputStream& in); // TODO uint Value() const { return value & 0x3FFFFFF; } - uint Id() const { return value; } - uint AreaNum() const { return value; } + uint Id() const { return value & 0xffff; } + int AreaNum() const { return (value >> 16) & 0x3ff; } void PutTo(COutputStream&) const; diff --git a/include/rstl/reserved_vector.hpp b/include/rstl/reserved_vector.hpp index 19338482..ed733ce6 100644 --- a/include/rstl/reserved_vector.hpp +++ b/include/rstl/reserved_vector.hpp @@ -70,7 +70,17 @@ public: inline const T& back() const { return data()[x0_count - 1]; } inline T& operator[](int idx) { return data()[idx]; } inline const T& operator[](int idx) const { return data()[idx]; } - iterator erase(iterator it) {} + void erase(iterator it) { + if (it < begin()) { + return; + } + if (it < end()) { + for (iterator j = it; j < end() - 1; ++j) { + *j = *(j + 1); + } + --x0_count; + } + } }; } // namespace rstl diff --git a/src/MetroidPrime/CScriptMailbox.cpp b/src/MetroidPrime/CScriptMailbox.cpp index 9321753b..ba31dbc1 100644 --- a/src/MetroidPrime/CScriptMailbox.cpp +++ b/src/MetroidPrime/CScriptMailbox.cpp @@ -1,18 +1,84 @@ #include "MetroidPrime/CScriptMailbox.hpp" +#include "MetroidPrime/CStateManager.hpp" +#include "MetroidPrime/CWorld.hpp" +#include "MetroidPrime/Player/CWorldSaveGameInfo.hpp" + #include "Kyoto/Streams/CInputStream.hpp" +#include "Kyoto/Streams/COutputStream.hpp" CScriptMailbox::CScriptMailbox() { CMemory::OffsetFakeStatics(sizeof(*this)); } CScriptMailbox::CScriptMailbox(CInputStream& in, const CWorldSaveGameInfo& world) { + rstl::vector< bool > relayStates(world.GetRelays().size(), false); + for (int i = 0; i < relayStates.size(); ++i) { + relayStates[i] = in.ReadBits(1); + } + + for (int i = 0; i < relayStates.size(); ++i) { + if (relayStates[i]) { + TEditorId it = world.GetRelays()[i]; + x0_relays.push_back(it); + } + } + CMemory::OffsetFakeStatics(sizeof(*this)); } CScriptMailbox::~CScriptMailbox() { CMemory::OffsetFakeStatics(-sizeof(*this)); } -void CScriptMailbox::PutTo(COutputStream& out, CWorldSaveGameInfo& world) const {} +void CScriptMailbox::PutTo(COutputStream& out, CWorldSaveGameInfo& world) const { + rstl::vector< bool > relayStates(world.GetRelays().size(), false); -void CScriptMailbox::SendMsgs(const TAreaId& area, CStateManager& mgr) {} + for (rstl::reserved_vector< TEditorId, 512 >::const_iterator it = x0_relays.begin(); + it != x0_relays.end(); ++it) { + TEditorId id = *it; + relayStates[world.GetRelayIndex(id)] = true; + } + + for (int i = 0; i < relayStates.size(); ++i) { + out.WriteBits(relayStates[i] ? 1 : 0, 1); + } +} + +void CScriptMailbox::SendMsgs(const TAreaId& areaId, CStateManager& mgr) { + CWorld* world = mgr.World(); + + if (world->GetRelays().size() <= 0) { + return; + } + + bool hasActiveRelays = false; + for (rstl::vector< CRelay >::const_iterator it = world->GetRelays().begin(); + it != world->GetRelays().end(); ++it) { + + TEditorId targetId = it->GetTargetId(); + if (targetId.AreaNum() != areaId.Value()) + continue; + + TEditorId relayId = it->GetRelayId(); + if (HasMsg(relayId)) { + mgr.SendScriptMsg(kInvalidUniqueId, targetId, EScriptObjectMessage(it->GetMessage()), kSS_Any); + if (it->GetActive()) { + hasActiveRelays = true; + } + } + } + + if (!hasActiveRelays) + return; + + for (rstl::vector< CRelay >::const_iterator it = world->GetRelays().begin(); + it != world->GetRelays().end(); ++it) { + if (it->GetTargetId().AreaNum() != areaId.Value()) + continue; + + TEditorId relayId = it->GetRelayId(); + if (HasMsg(relayId) && it->GetActive()) { + RemoveMsg(relayId); + } + } +} void CScriptMailbox::AddMsg(TEditorId id) { rstl::reserved_vector< TEditorId, 512 >::iterator iter = x0_relays.begin(); @@ -25,7 +91,15 @@ void CScriptMailbox::AddMsg(TEditorId id) { x0_relays.push_back(id); } -void CScriptMailbox::RemoveMsg(TEditorId id) {} +void CScriptMailbox::RemoveMsg(TEditorId id) { + rstl::reserved_vector< TEditorId, 512 >::iterator iter = x0_relays.begin(); + for (; iter != x0_relays.end(); ++iter) { + if (*iter == id) { + x0_relays.erase(iter); + return; + } + } +} bool CScriptMailbox::HasMsg(TEditorId id) const { rstl::reserved_vector< TEditorId, 512 >::const_iterator iter = x0_relays.begin();