2019-12-22 20:04:07 +00:00
|
|
|
#include "Runtime/World/CScriptMazeNode.hpp"
|
|
|
|
|
2020-09-19 17:30:44 +00:00
|
|
|
#include "Runtime/CStateManager.hpp"
|
2020-09-20 07:25:56 +00:00
|
|
|
#include "Runtime/Character/CModelData.hpp"
|
2020-09-19 17:30:44 +00:00
|
|
|
#include "Runtime/GameGlobalObjects.hpp"
|
2019-12-22 20:04:07 +00:00
|
|
|
#include "Runtime/World/CActorParameters.hpp"
|
|
|
|
|
2019-09-21 13:07:13 +00:00
|
|
|
#include "TCastTo.hpp" // Generated file, do not modify include path
|
2016-08-14 21:38:05 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
namespace urde {
|
2016-08-14 21:38:05 +00:00
|
|
|
|
2020-09-20 20:36:24 +00:00
|
|
|
std::array<s32, 300> sMazeSeeds;
|
2017-05-22 11:24:24 +00:00
|
|
|
|
2020-09-22 00:42:54 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
std::array<zeus::CVector3f, skMazeRows * skMazeCols> sDebugCellPos;
|
|
|
|
#endif
|
|
|
|
|
2017-11-13 06:19:18 +00:00
|
|
|
CScriptMazeNode::CScriptMazeNode(TUniqueId uid, std::string_view name, const CEntityInfo& info,
|
2020-09-21 22:38:11 +00:00
|
|
|
const zeus::CTransform& xf, bool active, s32 col, s32 row, s32 side,
|
2020-09-19 17:30:44 +00:00
|
|
|
const zeus::CVector3f& actorPos, const zeus::CVector3f& triggerPos,
|
|
|
|
const zeus::CVector3f& effectPos)
|
2017-01-04 04:08:30 +00:00
|
|
|
: CActor(uid, active, name, info, xf, CModelData::CModelDataNull(), CMaterialList(), CActorParameters::None(),
|
|
|
|
kInvalidUniqueId)
|
2020-09-21 22:38:11 +00:00
|
|
|
, xe8_col(col)
|
|
|
|
, xec_row(row)
|
|
|
|
, xf0_side(static_cast<ESide>(side))
|
2020-09-19 17:30:44 +00:00
|
|
|
, x100_actorPos(actorPos)
|
|
|
|
, x110_triggerPos(triggerPos)
|
|
|
|
, x120_effectPos(effectPos) {}
|
2016-08-14 21:38:05 +00:00
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CScriptMazeNode::Accept(IVisitor& visitor) { visitor.Visit(this); }
|
2017-05-22 11:24:24 +00:00
|
|
|
|
2020-09-19 18:52:43 +00:00
|
|
|
void CScriptMazeNode::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
|
|
|
|
if (GetActive()) {
|
|
|
|
if (msg == EScriptObjectMessage::Action) {
|
2020-09-20 05:47:12 +00:00
|
|
|
if (auto* maze = mgr.GetCurrentMaze()) {
|
|
|
|
bool shouldGenObjs = false;
|
|
|
|
auto& cell = maze->GetCell(xe8_col, xec_row);
|
2020-09-21 22:38:11 +00:00
|
|
|
if (xf0_side == ESide::Top && cell.x0_24_openTop) {
|
|
|
|
if (cell.x0_28_gateTop) {
|
2020-09-20 05:47:12 +00:00
|
|
|
shouldGenObjs = true;
|
2020-09-21 22:38:11 +00:00
|
|
|
x13c_25_hasGate = true;
|
2020-09-20 05:47:12 +00:00
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
} else if (xf0_side == ESide::Right && cell.x0_25_openRight) {
|
|
|
|
if (cell.x0_29_gateRight) {
|
2020-09-20 05:47:12 +00:00
|
|
|
shouldGenObjs = true;
|
2020-09-21 22:38:11 +00:00
|
|
|
x13c_25_hasGate = true;
|
2020-09-20 05:47:12 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
shouldGenObjs = true;
|
|
|
|
}
|
|
|
|
if (shouldGenObjs) {
|
|
|
|
GenerateObjects(mgr);
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (xf0_side == ESide::Right && cell.x1_24_puddle) {
|
|
|
|
x13c_24_hasPuddle = true;
|
2020-09-20 05:47:12 +00:00
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (x13c_25_hasGate) {
|
2020-09-20 05:47:12 +00:00
|
|
|
const auto origin = GetTranslation();
|
|
|
|
for (const auto& conn : GetConnectionList()) {
|
|
|
|
if (conn.x0_state != EScriptObjectState::Modify || conn.x4_msg != EScriptObjectMessage::Activate) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool wasGeneratingObject = mgr.GetIsGeneratingObject();
|
|
|
|
mgr.SetIsGeneratingObject(true);
|
|
|
|
const auto genObj = mgr.GenerateObject(conn.x8_objId);
|
|
|
|
mgr.SetIsGeneratingObject(wasGeneratingObject);
|
|
|
|
|
2020-09-21 22:38:11 +00:00
|
|
|
xf4_gateEffectId = genObj.second;
|
2020-09-20 05:47:12 +00:00
|
|
|
if (TCastToPtr<CActor> actor = mgr.ObjectById(genObj.second)) {
|
|
|
|
actor->SetTranslation(origin + x120_effectPos);
|
|
|
|
mgr.SendScriptMsg(actor, GetUniqueId(), EScriptObjectMessage::Activate);
|
|
|
|
}
|
2020-09-20 07:25:56 +00:00
|
|
|
break;
|
2020-09-20 05:47:12 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (x13c_24_hasPuddle) {
|
2020-09-20 05:47:12 +00:00
|
|
|
size_t count = 0;
|
|
|
|
for (const auto& conn : GetConnectionList()) {
|
|
|
|
if ((conn.x0_state == EScriptObjectState::Closed || conn.x0_state == EScriptObjectState::DeactivateState) &&
|
|
|
|
conn.x4_msg == EScriptObjectMessage::Activate) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
x12c_puddleObjectIds.reserve(count);
|
2020-09-20 05:47:12 +00:00
|
|
|
for (const auto& conn : GetConnectionList()) {
|
|
|
|
if ((conn.x0_state == EScriptObjectState::Closed || conn.x0_state == EScriptObjectState::DeactivateState) &&
|
|
|
|
conn.x4_msg == EScriptObjectMessage::Activate) {
|
|
|
|
bool wasGeneratingObject = mgr.GetIsGeneratingObject();
|
|
|
|
mgr.SetIsGeneratingObject(true);
|
|
|
|
const auto genObj = mgr.GenerateObject(conn.x8_objId);
|
|
|
|
mgr.SetIsGeneratingObject(wasGeneratingObject);
|
|
|
|
|
2020-09-21 22:38:11 +00:00
|
|
|
x12c_puddleObjectIds.push_back(genObj.second);
|
2020-09-20 05:47:12 +00:00
|
|
|
if (TCastToPtr<CActor> actor = mgr.ObjectById(genObj.second)) {
|
|
|
|
actor->SetTransform(GetTransform());
|
|
|
|
if (conn.x0_state == EScriptObjectState::Closed) {
|
|
|
|
mgr.SendScriptMsg(actor, GetUniqueId(), EScriptObjectMessage::Activate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-19 18:52:43 +00:00
|
|
|
} else if (msg == EScriptObjectMessage::SetToZero) {
|
2020-09-20 05:47:12 +00:00
|
|
|
auto* maze = mgr.GetCurrentMaze();
|
2020-09-21 22:38:11 +00:00
|
|
|
if (x13c_24_hasPuddle && maze != nullptr &&
|
|
|
|
std::any_of(x12c_puddleObjectIds.cbegin(), x12c_puddleObjectIds.cend(), [=](auto v) { return v == uid; })) {
|
|
|
|
for (const auto& id : x12c_puddleObjectIds) {
|
2020-09-20 05:47:12 +00:00
|
|
|
if (auto* ent = mgr.ObjectById(id)) {
|
|
|
|
if (ent->GetActive()) {
|
|
|
|
mgr.SendScriptMsg(ent, GetUniqueId(), EScriptObjectMessage::Activate);
|
|
|
|
} else {
|
|
|
|
mgr.FreeScriptObject(ent->GetUniqueId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-21 07:09:54 +00:00
|
|
|
for (const auto ent : mgr.GetAllObjectList()) {
|
2020-09-20 05:47:12 +00:00
|
|
|
if (TCastToPtr<CScriptMazeNode> node = ent) {
|
2020-09-21 22:38:11 +00:00
|
|
|
if (node->xe8_col == xe8_col - 1 && node->xec_row == xec_row && node->xf0_side == ESide::Right) {
|
|
|
|
auto& cell = maze->GetCell(xe8_col - 1, xec_row);
|
|
|
|
if (!cell.x0_25_openRight) {
|
|
|
|
cell.x0_25_openRight = true;
|
2020-09-20 05:47:12 +00:00
|
|
|
node->Reset(mgr);
|
2020-09-21 22:38:11 +00:00
|
|
|
node->x13c_25_hasGate = false;
|
2020-09-20 05:47:12 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (node->xe8_col == xe8_col && node->xec_row == xec_row && node->xf0_side == ESide::Right) {
|
2020-09-20 05:47:12 +00:00
|
|
|
auto& cell = maze->GetCell(xe8_col, xec_row);
|
2020-09-21 22:38:11 +00:00
|
|
|
if (!cell.x0_25_openRight) {
|
|
|
|
cell.x0_25_openRight = true;
|
2020-09-20 05:47:12 +00:00
|
|
|
node->Reset(mgr);
|
2020-09-21 22:38:11 +00:00
|
|
|
node->x13c_25_hasGate = false;
|
2020-09-20 05:47:12 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (node->xe8_col == xe8_col && node->xec_row == xec_row && node->xf0_side == ESide::Top) {
|
2020-09-20 05:47:12 +00:00
|
|
|
auto& cell = maze->GetCell(xe8_col, xec_row);
|
2020-09-21 22:38:11 +00:00
|
|
|
if (!cell.x0_24_openTop) {
|
|
|
|
cell.x0_24_openTop = true;
|
2020-09-20 05:47:12 +00:00
|
|
|
node->Reset(mgr);
|
2020-09-21 22:38:11 +00:00
|
|
|
node->x13c_25_hasGate = false;
|
2020-09-20 05:47:12 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (node->xe8_col == xe8_col && node->xec_row == xec_row + 1 && node->xf0_side == ESide::Top) {
|
2020-09-20 05:47:12 +00:00
|
|
|
auto& cell = maze->GetCell(xe8_col, xec_row + 1);
|
2020-09-21 22:38:11 +00:00
|
|
|
if (!cell.x0_24_openTop) {
|
|
|
|
cell.x0_24_openTop = true;
|
2020-09-20 05:47:12 +00:00
|
|
|
node->Reset(mgr);
|
2020-09-21 22:38:11 +00:00
|
|
|
node->x13c_25_hasGate = false;
|
2020-09-20 05:47:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-19 18:52:43 +00:00
|
|
|
} else if (msg == EScriptObjectMessage::Deactivate) {
|
2020-09-20 05:47:12 +00:00
|
|
|
Reset(mgr);
|
2020-09-19 18:52:43 +00:00
|
|
|
} else if (msg == EScriptObjectMessage::InitializedInArea) {
|
|
|
|
if (mgr.GetCurrentMaze() == nullptr) {
|
2020-09-22 00:42:54 +00:00
|
|
|
auto maze = std::make_unique<CMazeState>(skEnterCol, skEnterRow, skTargetCol, skTargetRow);
|
2020-09-19 18:52:43 +00:00
|
|
|
maze->Reset(sMazeSeeds[mgr.GetActiveRandom()->Next() % sMazeSeeds.size()]);
|
|
|
|
maze->Initialize();
|
2020-09-21 22:38:11 +00:00
|
|
|
maze->GenerateObstacles();
|
2020-09-19 18:52:43 +00:00
|
|
|
mgr.SetCurrentMaze(std::move(maze));
|
|
|
|
}
|
2020-09-22 00:42:54 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
if (xf0_side == ESide::Right) {
|
|
|
|
sDebugCellPos[xe8_col + xec_row * skMazeCols] = GetTranslation();
|
|
|
|
} else if (xe8_col == skMazeCols - 1) {
|
|
|
|
// Last column does not have right nodes, but we can infer the position
|
|
|
|
sDebugCellPos[xe8_col + xec_row * skMazeCols] = GetTranslation() - zeus::CVector3f{1.1875f, -0.1215f, 1.2187f};
|
|
|
|
}
|
|
|
|
#endif
|
2020-09-19 18:52:43 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-22 00:56:44 +00:00
|
|
|
// URDE change: used to be in the above if branch
|
|
|
|
if (msg == EScriptObjectMessage::Deleted) {
|
|
|
|
mgr.ClearCurrentMaze();
|
|
|
|
Reset(mgr);
|
|
|
|
}
|
2020-09-19 18:52:43 +00:00
|
|
|
CActor::AcceptScriptMsg(msg, uid, mgr);
|
|
|
|
}
|
|
|
|
|
2020-09-20 05:47:12 +00:00
|
|
|
void CScriptMazeNode::Think(float dt, CStateManager& mgr) {
|
2020-09-21 22:38:11 +00:00
|
|
|
if (!GetActive() || !x13c_25_hasGate) {
|
2020-09-20 05:47:12 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
xf8_msgTimer -= dt;
|
|
|
|
if (xf8_msgTimer <= 0.f) {
|
|
|
|
xf8_msgTimer = 1.f;
|
2020-09-21 22:38:11 +00:00
|
|
|
if (x13c_26_gateActive) {
|
|
|
|
x13c_26_gateActive = false;
|
2020-09-20 05:47:12 +00:00
|
|
|
SendScriptMsgs(mgr, EScriptObjectMessage::Deactivate);
|
|
|
|
} else {
|
2020-09-21 22:38:11 +00:00
|
|
|
x13c_26_gateActive = true;
|
2020-09-20 05:47:12 +00:00
|
|
|
SendScriptMsgs(mgr, EScriptObjectMessage::Activate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-08 05:30:43 +00:00
|
|
|
void CScriptMazeNode::LoadMazeSeeds() {
|
|
|
|
const SObjectTag* tag = g_ResFactory->GetResourceIdByName("DUMB_MazeSeeds");
|
2020-04-12 19:23:26 +00:00
|
|
|
const u32 resSize = g_ResFactory->ResourceSize(*tag);
|
|
|
|
const std::unique_ptr<u8[]> buf = g_ResFactory->LoadResourceSync(*tag);
|
2018-12-08 05:30:43 +00:00
|
|
|
CMemoryInStream in(buf.get(), resSize);
|
2020-04-12 19:23:26 +00:00
|
|
|
for (auto& seed : sMazeSeeds) {
|
2020-09-19 17:30:44 +00:00
|
|
|
seed = in.readInt32Big();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CScriptMazeNode::GenerateObjects(CStateManager& mgr) {
|
|
|
|
for (const auto& conn : GetConnectionList()) {
|
|
|
|
if (conn.x0_state != EScriptObjectState::MaxReached || conn.x4_msg != EScriptObjectMessage::Activate) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const auto* ent = mgr.GetObjectById(mgr.GetIdForScript(conn.x8_objId));
|
|
|
|
TCastToConstPtr<CScriptEffect> scriptEffect{ent};
|
|
|
|
TCastToConstPtr<CScriptActor> scriptActor{ent};
|
|
|
|
TCastToConstPtr<CScriptTrigger> scriptTrigger{ent};
|
2020-09-21 22:38:11 +00:00
|
|
|
if ((scriptEffect || scriptActor || scriptTrigger) && (!scriptEffect || !x13c_25_hasGate)) {
|
2020-09-19 17:30:44 +00:00
|
|
|
bool wasGeneratingObject = mgr.GetIsGeneratingObject();
|
|
|
|
mgr.SetIsGeneratingObject(true);
|
|
|
|
const auto genObj = mgr.GenerateObject(conn.x8_objId);
|
|
|
|
mgr.SetIsGeneratingObject(wasGeneratingObject);
|
2020-09-19 17:44:32 +00:00
|
|
|
if (auto* actor = static_cast<CActor*>(mgr.ObjectById(genObj.second))) {
|
2020-09-19 17:30:44 +00:00
|
|
|
mgr.SendScriptMsg(actor, GetUniqueId(), EScriptObjectMessage::Activate);
|
|
|
|
if (scriptEffect) {
|
|
|
|
actor->SetTranslation(GetTranslation() + x120_effectPos);
|
|
|
|
x11c_effectId = genObj.second;
|
|
|
|
}
|
|
|
|
if (scriptActor) {
|
|
|
|
actor->SetTranslation(GetTranslation() + x100_actorPos);
|
|
|
|
xfc_actorId = genObj.second;
|
|
|
|
}
|
|
|
|
if (scriptTrigger) {
|
|
|
|
actor->SetTranslation(GetTranslation() + x110_triggerPos);
|
|
|
|
x10c_triggerId = genObj.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-12 19:23:26 +00:00
|
|
|
}
|
2016-08-14 21:38:05 +00:00
|
|
|
}
|
2020-09-19 17:44:32 +00:00
|
|
|
|
|
|
|
void CScriptMazeNode::Reset(CStateManager& mgr) {
|
|
|
|
mgr.FreeScriptObject(x11c_effectId);
|
|
|
|
mgr.FreeScriptObject(xfc_actorId);
|
|
|
|
mgr.FreeScriptObject(x10c_triggerId);
|
2020-09-21 22:38:11 +00:00
|
|
|
mgr.FreeScriptObject(xf4_gateEffectId);
|
|
|
|
xf4_gateEffectId = kInvalidUniqueId;
|
2020-09-19 17:44:32 +00:00
|
|
|
xfc_actorId = kInvalidUniqueId;
|
|
|
|
x10c_triggerId = kInvalidUniqueId;
|
|
|
|
x11c_effectId = kInvalidUniqueId;
|
|
|
|
}
|
2020-09-19 18:52:43 +00:00
|
|
|
|
2020-09-20 05:47:12 +00:00
|
|
|
void CScriptMazeNode::SendScriptMsgs(CStateManager& mgr, EScriptObjectMessage msg) {
|
|
|
|
mgr.SendScriptMsg(x11c_effectId, GetUniqueId(), msg);
|
|
|
|
mgr.SendScriptMsg(xfc_actorId, GetUniqueId(), msg);
|
|
|
|
mgr.SendScriptMsg(x10c_triggerId, GetUniqueId(), msg);
|
2020-09-21 22:38:11 +00:00
|
|
|
mgr.SendScriptMsg(xf4_gateEffectId, GetUniqueId(), msg);
|
2020-09-20 05:47:12 +00:00
|
|
|
}
|
|
|
|
|
2020-09-21 22:38:11 +00:00
|
|
|
void CMazeState::Reset(s32 seed) {
|
2020-09-19 18:52:43 +00:00
|
|
|
x0_rand.SetSeed(seed);
|
|
|
|
x94_24_initialized = false;
|
2020-09-20 20:36:24 +00:00
|
|
|
x4_cells.fill({});
|
2020-09-19 19:52:15 +00:00
|
|
|
|
2020-09-21 22:38:11 +00:00
|
|
|
std::array<ESide, 4> sides{};
|
2020-09-20 20:36:24 +00:00
|
|
|
s32 cellIdx = 0;
|
2020-09-21 22:38:11 +00:00
|
|
|
for (u32 i = skMazeCols * skMazeRows - 1; i != 0;) {
|
2020-09-20 20:36:24 +00:00
|
|
|
u32 acc = 0;
|
2020-09-21 22:38:11 +00:00
|
|
|
if (cellIdx - skMazeCols > 0 && !GetCell(cellIdx - skMazeCols).IsOpen()) {
|
|
|
|
sides[acc++] = ESide::Top;
|
2020-09-19 19:52:15 +00:00
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (cellIdx < x4_cells.size() - 2 && (cellIdx + 1) % skMazeCols != 0 && !GetCell(cellIdx + 1).IsOpen()) {
|
|
|
|
sides[acc++] = ESide::Right;
|
2020-09-19 19:52:15 +00:00
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (cellIdx + skMazeCols < x4_cells.size() && !GetCell(cellIdx + skMazeCols).IsOpen()) {
|
|
|
|
sides[acc++] = ESide::Bottom;
|
2020-09-19 19:52:15 +00:00
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (cellIdx > 0 && cellIdx % skMazeCols != 0 && !GetCell(cellIdx - 1).IsOpen()) {
|
|
|
|
sides[acc++] = ESide::Left;
|
2020-09-19 19:52:15 +00:00
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
|
2020-09-20 20:36:24 +00:00
|
|
|
if (acc == 0) {
|
2020-09-21 22:38:11 +00:00
|
|
|
do {
|
2020-09-20 20:36:24 +00:00
|
|
|
cellIdx++;
|
|
|
|
if (cellIdx > x4_cells.size() - 1) {
|
|
|
|
cellIdx = 0;
|
2020-09-19 19:52:15 +00:00
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
} while (!GetCell(cellIdx).IsOpen());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
i--;
|
|
|
|
ESide side = sides[x0_rand.Next() % acc];
|
|
|
|
if (side == ESide::Bottom) {
|
|
|
|
GetCell(cellIdx).x0_26_openBottom = true;
|
|
|
|
GetCell(cellIdx + skMazeCols).x0_24_openTop = true;
|
|
|
|
cellIdx += skMazeCols;
|
|
|
|
} else if (side == ESide::Top) {
|
|
|
|
GetCell(cellIdx).x0_24_openTop = true;
|
|
|
|
GetCell(cellIdx - skMazeCols).x0_26_openBottom = true;
|
|
|
|
cellIdx -= skMazeCols;
|
|
|
|
} else if (side == ESide::Right) {
|
|
|
|
GetCell(cellIdx).x0_25_openRight = true;
|
|
|
|
GetCell(cellIdx + 1).x0_27_openLeft = true;
|
|
|
|
cellIdx++;
|
|
|
|
} else if (side == ESide::Left) {
|
|
|
|
GetCell(cellIdx).x0_27_openLeft = true;
|
|
|
|
GetCell(cellIdx - 1).x0_25_openRight = true;
|
|
|
|
cellIdx--;
|
2020-09-19 19:52:15 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-19 18:52:43 +00:00
|
|
|
}
|
|
|
|
|
2020-09-21 22:38:11 +00:00
|
|
|
void CMazeState::Initialize() {
|
|
|
|
std::array<s32, skMazeRows * skMazeCols> path{};
|
2020-09-22 00:42:54 +00:00
|
|
|
path[0] = x84_enterCol + x88_enterRow * skMazeCols;
|
2020-09-21 22:38:11 +00:00
|
|
|
GetCell(path[0]).x1_26_checked = true;
|
|
|
|
s32 pathLength = 1;
|
2020-09-22 00:42:54 +00:00
|
|
|
while (path[0] != x8c_targetCol + x90_targetRow * skMazeCols) {
|
2020-09-21 22:38:11 +00:00
|
|
|
if (GetCell(path[0]).x0_24_openTop) {
|
|
|
|
if (!GetCell(path[0] - skMazeCols).x1_26_checked) {
|
|
|
|
path[pathLength] = path[0] - skMazeCols;
|
|
|
|
pathLength++;
|
2020-09-19 18:52:43 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (GetCell(path[0]).x0_25_openRight) {
|
|
|
|
if (!GetCell(path[0] + 1).x1_26_checked) {
|
|
|
|
path[pathLength] = path[0] + 1;
|
|
|
|
pathLength++;
|
2020-09-19 18:52:43 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (GetCell(path[0]).x0_26_openBottom) {
|
|
|
|
if (!GetCell(path[0] + skMazeCols).x1_26_checked) {
|
|
|
|
path[pathLength] = path[0] + skMazeCols;
|
|
|
|
pathLength++;
|
2020-09-19 18:52:43 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (GetCell(path[0]).x0_27_openLeft) {
|
|
|
|
if (!GetCell(path[0] - 1).x1_26_checked) {
|
|
|
|
path[pathLength] = path[0] - 1;
|
|
|
|
pathLength++;
|
2020-09-19 18:52:43 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
if (path[0] == path[pathLength - 1]) {
|
|
|
|
pathLength--;
|
2020-09-19 18:52:43 +00:00
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
path[0] = path[pathLength - 1];
|
|
|
|
GetCell(path[0]).x1_26_checked = true;
|
2020-09-19 18:52:43 +00:00
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
s32* idx = &path[pathLength];
|
|
|
|
while (pathLength != 0) {
|
|
|
|
pathLength--;
|
|
|
|
idx--;
|
|
|
|
auto& cell = GetCell(*idx);
|
|
|
|
if (cell.x1_26_checked) {
|
|
|
|
cell.x1_25_onPath = true;
|
2020-09-22 00:42:54 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
if (pathLength > 0) {
|
|
|
|
m_path.push_back(*idx);
|
|
|
|
}
|
|
|
|
#endif
|
2020-09-19 18:52:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
x94_24_initialized = true;
|
|
|
|
}
|
2020-09-19 19:52:15 +00:00
|
|
|
|
2020-09-21 22:38:11 +00:00
|
|
|
void CMazeState::GenerateObstacles() {
|
2020-09-19 20:32:23 +00:00
|
|
|
if (!x94_24_initialized) {
|
|
|
|
Initialize();
|
|
|
|
}
|
2020-09-20 05:47:12 +00:00
|
|
|
|
2020-09-20 07:25:56 +00:00
|
|
|
auto GetRandom = [this](s32 offset) constexpr {
|
|
|
|
s32 tmp = x0_rand.Next();
|
|
|
|
return tmp + ((tmp / 5) * -5) + offset;
|
|
|
|
};
|
2020-09-21 22:38:11 +00:00
|
|
|
s32 gate1Idx = GetRandom(9);
|
|
|
|
s32 gate2Idx = GetRandom(21);
|
|
|
|
s32 gate3Idx = GetRandom(33);
|
|
|
|
s32 puddle1Idx = GetRandom(13);
|
|
|
|
s32 puddle2Idx = GetRandom(29);
|
2020-09-19 20:32:23 +00:00
|
|
|
|
2020-09-21 22:38:11 +00:00
|
|
|
ESide side = ESide::Invalid;
|
2020-09-20 05:47:12 +00:00
|
|
|
s32 idx = 0;
|
2020-09-19 20:32:23 +00:00
|
|
|
|
2020-09-22 00:42:54 +00:00
|
|
|
s32 prevCol = x84_enterCol;
|
|
|
|
s32 prevRow = x88_enterRow;
|
|
|
|
s32 col = x84_enterCol;
|
|
|
|
s32 row = x88_enterRow;
|
2020-09-19 20:32:23 +00:00
|
|
|
|
2020-09-22 00:42:54 +00:00
|
|
|
while (col != x8c_targetCol || row != x90_targetRow) {
|
2020-09-21 22:38:11 +00:00
|
|
|
if (idx == gate1Idx || idx == gate2Idx || idx == gate3Idx) {
|
|
|
|
if (side == ESide::Bottom) {
|
|
|
|
GetCell(col, row).x0_28_gateTop = true;
|
|
|
|
GetCell(prevCol, prevRow).x0_30_gateBottom = true;
|
|
|
|
} else if (side == ESide::Top) {
|
|
|
|
GetCell(col, row).x0_30_gateBottom = true;
|
|
|
|
GetCell(prevCol, prevRow).x0_28_gateTop = true;
|
|
|
|
} else if (side == ESide::Right) {
|
|
|
|
GetCell(col, row).x0_31_gateLeft = true;
|
|
|
|
GetCell(prevCol, prevRow).x0_29_gateRight = true;
|
|
|
|
} else if (side == ESide::Left) {
|
|
|
|
GetCell(col, row).x0_29_gateRight = true;
|
|
|
|
GetCell(prevCol, prevRow).x0_31_gateLeft = true;
|
2020-09-19 20:32:23 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-19 19:52:15 +00:00
|
|
|
|
2020-09-21 22:38:11 +00:00
|
|
|
s32 nextCol = col;
|
2020-09-20 20:36:24 +00:00
|
|
|
s32 nextRow = -1;
|
2020-09-21 22:38:11 +00:00
|
|
|
if (row < 1 || side == ESide::Bottom || !GetCell(col, row).x0_24_openTop || !GetCell(col, row - 1).x1_25_onPath) {
|
|
|
|
if (row < skMazeRows - 1 && side != ESide::Top && GetCell(col, row).x0_26_openBottom &&
|
|
|
|
GetCell(col, row + 1).x1_25_onPath) {
|
|
|
|
side = ESide::Bottom;
|
2020-09-20 05:47:12 +00:00
|
|
|
nextRow = row + 1;
|
2020-09-19 20:32:23 +00:00
|
|
|
} else {
|
2020-09-20 05:47:12 +00:00
|
|
|
nextRow = row;
|
2020-09-21 22:38:11 +00:00
|
|
|
if (col < 1 || side == ESide::Right || !GetCell(col, row).x0_27_openLeft ||
|
|
|
|
!GetCell(col - 1, row).x1_25_onPath) {
|
|
|
|
if (col > skMazeRows || side == ESide::Left || !GetCell(col, row).x0_25_openRight ||
|
|
|
|
!GetCell(col + 1, row).x1_25_onPath) {
|
2020-09-19 20:32:23 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
side = ESide::Right;
|
2020-09-20 05:47:12 +00:00
|
|
|
nextCol = col + 1;
|
2020-09-19 20:32:23 +00:00
|
|
|
} else {
|
2020-09-21 22:38:11 +00:00
|
|
|
side = ESide::Left;
|
2020-09-20 05:47:12 +00:00
|
|
|
nextCol = col - 1;
|
2020-09-19 20:32:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2020-09-21 22:38:11 +00:00
|
|
|
side = ESide::Top;
|
2020-09-20 05:47:12 +00:00
|
|
|
nextRow = row - 1;
|
2020-09-19 20:32:23 +00:00
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
|
|
|
|
if (idx == puddle1Idx || idx == puddle2Idx) {
|
|
|
|
if (col == 0 || row == 0 || col == skMazeCols - 1 || row == skMazeRows - 1) {
|
|
|
|
if (idx == puddle1Idx) {
|
|
|
|
puddle1Idx++;
|
2020-09-19 20:32:23 +00:00
|
|
|
} else {
|
2020-09-21 22:38:11 +00:00
|
|
|
puddle2Idx++;
|
2020-09-19 20:32:23 +00:00
|
|
|
}
|
|
|
|
} else {
|
2020-09-20 05:47:12 +00:00
|
|
|
auto& cell = GetCell(col, row);
|
2020-09-21 22:38:11 +00:00
|
|
|
cell.x1_24_puddle = true;
|
|
|
|
if (side == ESide::Bottom) {
|
|
|
|
GetCell(nextCol, nextRow).x0_24_openTop = false;
|
|
|
|
cell.x0_26_openBottom = false;
|
|
|
|
} else if (side == ESide::Top) {
|
|
|
|
GetCell(nextCol, nextRow).x0_26_openBottom = false;
|
|
|
|
cell.x0_24_openTop = false;
|
|
|
|
} else if (side == ESide::Right) {
|
|
|
|
GetCell(nextCol, nextRow).x0_27_openLeft = false;
|
|
|
|
cell.x0_25_openRight = false;
|
|
|
|
} else if (side == ESide::Left) {
|
|
|
|
GetCell(nextCol, nextRow).x0_25_openRight = false;
|
|
|
|
cell.x0_27_openLeft = false;
|
2020-09-19 20:32:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-21 22:38:11 +00:00
|
|
|
|
2020-09-20 05:47:12 +00:00
|
|
|
idx++;
|
|
|
|
prevCol = col;
|
|
|
|
prevRow = row;
|
|
|
|
col = nextCol;
|
|
|
|
row = nextRow;
|
|
|
|
};
|
2020-09-19 19:52:15 +00:00
|
|
|
}
|
2020-09-22 00:42:54 +00:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
void CMazeState::DebugRender() {
|
|
|
|
m_renderer.Reset();
|
|
|
|
m_renderer.AddVertex(sDebugCellPos[skEnterCol + skEnterRow * skMazeCols], zeus::skBlue, 2.f);
|
|
|
|
for (s32 i = m_path.size() - 1; i >= 0; --i) {
|
|
|
|
s32 idx = m_path[i];
|
|
|
|
zeus::CVector3f pos;
|
|
|
|
if (idx == skMazeCols - 1) {
|
|
|
|
// 8,0 has no node, infer from 8,1
|
|
|
|
pos = sDebugCellPos[idx + skMazeCols] + zeus::CVector3f{4.f, 0.f, 0.f};
|
|
|
|
} else {
|
|
|
|
pos = sDebugCellPos[idx];
|
|
|
|
}
|
|
|
|
m_renderer.AddVertex(pos, zeus::skBlue, 2.f);
|
|
|
|
}
|
|
|
|
m_renderer.Render();
|
|
|
|
}
|
|
|
|
#endif
|
2018-12-08 05:30:43 +00:00
|
|
|
} // namespace urde
|