mirror of https://github.com/PrimeDecomp/prime.git
Add CStateMachine, mostly matched, constructor needs work
This commit is contained in:
parent
8fad208125
commit
06464964dd
|
@ -92,7 +92,7 @@ LIBS = [
|
||||||
"MetroidPrime/ScriptObjects/CScriptWaypoint",
|
"MetroidPrime/ScriptObjects/CScriptWaypoint",
|
||||||
"MetroidPrime/Enemies/CPatterned",
|
"MetroidPrime/Enemies/CPatterned",
|
||||||
"MetroidPrime/ScriptObjects/CScriptDoor",
|
"MetroidPrime/ScriptObjects/CScriptDoor",
|
||||||
"MetroidPrime/Enemies/CStateMachine",
|
["MetroidPrime/Enemies/CStateMachine", False],
|
||||||
"MetroidPrime/CMapArea",
|
"MetroidPrime/CMapArea",
|
||||||
["MetroidPrime/Cameras/CBallCamera", False],
|
["MetroidPrime/Cameras/CBallCamera", False],
|
||||||
"MetroidPrime/ScriptObjects/CScriptEffect",
|
"MetroidPrime/ScriptObjects/CScriptEffect",
|
||||||
|
|
|
@ -64,6 +64,11 @@ template <>
|
||||||
inline bool cinput_stream_helper(const TType< bool >& type, CInputStream& in) {
|
inline bool cinput_stream_helper(const TType< bool >& type, CInputStream& in) {
|
||||||
return in.ReadBool();
|
return in.ReadBool();
|
||||||
}
|
}
|
||||||
|
template <>
|
||||||
|
inline char cinput_stream_helper(const TType< char >& type, CInputStream& in) {
|
||||||
|
return in.ReadChar();
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline int cinput_stream_helper(const TType< int >& type, CInputStream& in) {
|
inline int cinput_stream_helper(const TType< int >& type, CInputStream& in) {
|
||||||
return in.ReadLong();
|
return in.ReadLong();
|
||||||
|
|
|
@ -16,8 +16,8 @@ class CAiFuncMap;
|
||||||
class CAi : public CPhysicsActor {
|
class CAi : public CPhysicsActor {
|
||||||
public:
|
public:
|
||||||
// static void CreateFuncLookup(CAiFuncMap* funcMap);
|
// static void CreateFuncLookup(CAiFuncMap* funcMap);
|
||||||
// static CAiStateFunc GetStateFunc(std::string_view func);
|
static CAiStateFunc GetStateFunc(const char* func);
|
||||||
// static CAiTriggerFunc GetTriggerFunc(std::string_view func);
|
static CAiTriggerFunc GetTriggerFunc(const char* func);
|
||||||
|
|
||||||
// const CStateMachine* GetStateMachine() const;
|
// const CStateMachine* GetStateMachine() const;
|
||||||
~CAi();
|
~CAi();
|
||||||
|
|
|
@ -9,6 +9,11 @@ enum EStateMsg {
|
||||||
kStateMsg_Deactivate = 2,
|
kStateMsg_Deactivate = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CAi;
|
||||||
|
class CStateManager;
|
||||||
|
typedef void (CAi::*CAiStateFunc)(CStateManager& mgr, EStateMsg msg, float arg);
|
||||||
|
typedef bool (CAi::*CAiTriggerFunc)(CStateManager& mgr, float arg);
|
||||||
|
|
||||||
class CAiFuncMap {
|
class CAiFuncMap {
|
||||||
public:
|
public:
|
||||||
CAiFuncMap();
|
CAiFuncMap();
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
#ifndef _CSTATEMACHINE
|
||||||
|
#define _CSTATEMACHINE
|
||||||
|
|
||||||
|
#include "rstl/string.hpp"
|
||||||
|
#include "rstl/vector.hpp"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
#include "MetroidPrime/Enemies/CAiFuncMap.hpp"
|
||||||
|
|
||||||
|
class CAi;
|
||||||
|
class CStateManager;
|
||||||
|
class CInputStream;
|
||||||
|
|
||||||
|
class CAiState;
|
||||||
|
class CAiTrigger {
|
||||||
|
public:
|
||||||
|
CAiTrigger()
|
||||||
|
: x0_func(nullptr), xc_arg(0.f), x10_andTrigger(nullptr), x14_state(nullptr), x18_lNot(false) {}
|
||||||
|
CAiTrigger* GetAnd() const { return x10_andTrigger; }
|
||||||
|
CAiState* GetState() const { return x14_state; }
|
||||||
|
|
||||||
|
bool CallFunc(CStateManager& mgr, CAi& ai) {
|
||||||
|
bool ret = true;
|
||||||
|
if (x0_func) {
|
||||||
|
ret = (ai.*x0_func)(mgr, xc_arg);
|
||||||
|
if (x18_lNot) {
|
||||||
|
ret = !ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Setup(CAiTriggerFunc func, bool lnot, float arg, CAiTrigger* andTrig) {
|
||||||
|
x0_func = func;
|
||||||
|
x18_lNot = lnot;
|
||||||
|
xc_arg = arg;
|
||||||
|
x10_andTrigger = andTrig;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Setup(CAiTriggerFunc func, bool lnot, float arg, CAiState* state) {
|
||||||
|
x0_func = func;
|
||||||
|
x18_lNot = lnot;
|
||||||
|
xc_arg = arg;
|
||||||
|
x14_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CAiTriggerFunc x0_func;
|
||||||
|
float xc_arg;
|
||||||
|
CAiTrigger* x10_andTrigger;
|
||||||
|
CAiState* x14_state;
|
||||||
|
bool x18_lNot;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CAiState {
|
||||||
|
public:
|
||||||
|
CAiState(CAiStateFunc func, const char* name) {
|
||||||
|
x0_func = func;
|
||||||
|
strncpy(xc_name, name, 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
CAiTrigger* GetTrig(int idx) { return &x30_firstTrigger[idx]; }
|
||||||
|
const char* GetName() const { return xc_name; }
|
||||||
|
void SetTriggers(CAiTrigger* triggers) { x30_firstTrigger = triggers; }
|
||||||
|
void SetNumTriggers(int numTriggers) { x2c_numTriggers = numTriggers; }
|
||||||
|
int GetNumTriggers() const { return x2c_numTriggers; }
|
||||||
|
|
||||||
|
void CallFunc(CStateManager& mgr, CAi& ai, EStateMsg msg, float arg) const {
|
||||||
|
if (x0_func) {
|
||||||
|
(ai.*x0_func)(mgr, msg, arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CAiStateFunc x0_func;
|
||||||
|
char xc_name[32];
|
||||||
|
uint x2c_numTriggers;
|
||||||
|
CAiTrigger* x30_firstTrigger;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CStateMachine {
|
||||||
|
public:
|
||||||
|
explicit CStateMachine(CInputStream& in);
|
||||||
|
|
||||||
|
int GetStateIndex(const rstl::string& state) const;
|
||||||
|
const rstl::vector< CAiState >& GetStateVector() const { return x0_states; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
rstl::vector< CAiState > x0_states;
|
||||||
|
rstl::vector< CAiTrigger > x10_triggers;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CStateMachineState {
|
||||||
|
public:
|
||||||
|
CStateMachineState();
|
||||||
|
|
||||||
|
void Update(CStateManager& mgr, CAi& ai, float delta);
|
||||||
|
void SetState(CStateManager& mgr, CAi& ai, int state);
|
||||||
|
void SetState(CStateManager& mgr, CAi&, const CStateMachine* machine, const rstl::string& state);
|
||||||
|
const rstl::vector< CAiState >& GetStateVector() const { return x0_machine->GetStateVector(); }
|
||||||
|
void Setup(const CStateMachine* machine);
|
||||||
|
const char* GetName() const;
|
||||||
|
void SetDelay(float delay) { x10_delay = delay; }
|
||||||
|
float GetTime() const { return x8_time; }
|
||||||
|
float GetRandom() const { return xc_random; }
|
||||||
|
float GetDelay() const { return x10_delay; }
|
||||||
|
void SetCodeTrigger() { x18_24_codeTrigger = true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CStateMachine* x0_machine;
|
||||||
|
CAiState* x4_state;
|
||||||
|
float x8_time;
|
||||||
|
float xc_random;
|
||||||
|
float x10_delay;
|
||||||
|
float x14_;
|
||||||
|
bool x18_24_codeTrigger : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _CSTATEMACHINE
|
|
@ -97,6 +97,7 @@ public:
|
||||||
|
|
||||||
~basic_string() { internal_dereference(); }
|
~basic_string() { internal_dereference(); }
|
||||||
|
|
||||||
|
size_t size() const { return x8_size; }
|
||||||
void assign(const basic_string&);
|
void assign(const basic_string&);
|
||||||
basic_string& operator=(const basic_string&);
|
basic_string& operator=(const basic_string&);
|
||||||
basic_string operator+(const basic_string&);
|
basic_string operator+(const basic_string&);
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
#include "MetroidPrime/Enemies/CStateMachine.hpp"
|
||||||
|
|
||||||
|
#include "MetroidPrime/Enemies/CAi.hpp"
|
||||||
|
|
||||||
|
#include "Kyoto/Streams/CInputStream.hpp"
|
||||||
|
|
||||||
|
void CStateMachineState::Update(CStateManager& mgr, CAi& ai, float delta) {
|
||||||
|
if (x4_state) {
|
||||||
|
x8_time += delta;
|
||||||
|
x4_state->CallFunc(mgr, ai, kStateMsg_Update, delta);
|
||||||
|
for (int i = 0; i < x4_state->GetNumTriggers(); ++i) {
|
||||||
|
CAiTrigger* trig = x4_state->GetTrig(i);
|
||||||
|
CAiState* state = nullptr;
|
||||||
|
bool andPassed = true;
|
||||||
|
while (andPassed && trig) {
|
||||||
|
andPassed = false;
|
||||||
|
if (trig->CallFunc(mgr, ai)) {
|
||||||
|
andPassed = true;
|
||||||
|
state = trig->GetState();
|
||||||
|
trig = trig->GetAnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (andPassed && state != nullptr) {
|
||||||
|
x4_state->CallFunc(mgr, ai, kStateMsg_Deactivate, 0.f);
|
||||||
|
x4_state = state;
|
||||||
|
x8_time = 0.f;
|
||||||
|
x18_24_codeTrigger = false;
|
||||||
|
xc_random = mgr.Random()->Float();
|
||||||
|
x4_state->CallFunc(mgr, ai, kStateMsg_Activate, 0.f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStateMachineState::SetState(CStateManager& mgr, CAi& ai, int idx) {
|
||||||
|
const CAiState* state = &x0_machine->GetStateVector()[idx];
|
||||||
|
if (x4_state == state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (x4_state) {
|
||||||
|
x4_state->CallFunc(mgr, ai, kStateMsg_Deactivate, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
x4_state = const_cast< CAiState* >(state);
|
||||||
|
x8_time = 0.f;
|
||||||
|
xc_random = mgr.Random()->Float();
|
||||||
|
x18_24_codeTrigger = false;
|
||||||
|
x4_state->CallFunc(mgr, ai, kStateMsg_Activate, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStateMachineState::SetState(CStateManager& mgr, CAi& ai, const CStateMachine* machine,
|
||||||
|
const rstl::string& state) {
|
||||||
|
if (!machine)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!x0_machine)
|
||||||
|
Setup(machine);
|
||||||
|
|
||||||
|
s32 idx = machine->GetStateIndex(state);
|
||||||
|
SetState(mgr, ai, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
CStateMachineState::CStateMachineState()
|
||||||
|
: x0_machine(nullptr)
|
||||||
|
, x4_state(nullptr)
|
||||||
|
, x8_time(0.f)
|
||||||
|
, xc_random(0.f)
|
||||||
|
, x10_delay(0.f)
|
||||||
|
, x18_24_codeTrigger(false) {}
|
||||||
|
|
||||||
|
void CStateMachineState::Setup(const CStateMachine* machine) {
|
||||||
|
x0_machine = machine;
|
||||||
|
x4_state = nullptr;
|
||||||
|
x8_time = 0.f;
|
||||||
|
xc_random = 0.f;
|
||||||
|
x10_delay = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* CStateMachineState::GetName() const {
|
||||||
|
if (x4_state != nullptr) {
|
||||||
|
return x4_state->GetName();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CStateMachine::CStateMachine(CInputStream& in) {
|
||||||
|
CAiTrigger* lastTrig = nullptr;
|
||||||
|
int stateCount = in.ReadLong();
|
||||||
|
|
||||||
|
x0_states.reserve(stateCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < stateCount; ++i) {
|
||||||
|
char name[32];
|
||||||
|
int nameLen = 0;
|
||||||
|
for (; nameLen < 31; ++nameLen) {
|
||||||
|
name[nameLen] = in.Get< char >();
|
||||||
|
if (name[nameLen] == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name[nameLen] = '\0';
|
||||||
|
CAiStateFunc func = CAi::GetStateFunc(name);
|
||||||
|
x0_states.push_back(CAiState(func, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
x10_triggers.reserve(in.Get< int >());
|
||||||
|
|
||||||
|
for (int i = 0; i < stateCount; ++i) {
|
||||||
|
x0_states[i].SetNumTriggers(in.Get< int >());
|
||||||
|
|
||||||
|
if (x0_states[i].GetNumTriggers() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAiTrigger* firstTrig = x10_triggers.data() + x10_triggers.size();
|
||||||
|
x0_states[i].SetTriggers(firstTrig);
|
||||||
|
|
||||||
|
for (int j = 0; j < x0_states[i].GetNumTriggers(); ++j) {
|
||||||
|
const int triggerCount = in.Get< int >();
|
||||||
|
const int lastTriggerIdx = triggerCount - 1;
|
||||||
|
|
||||||
|
for (int k = 0; k < triggerCount; ++k) {
|
||||||
|
char name[32];
|
||||||
|
int nameLen = 0;
|
||||||
|
for (; nameLen < 31; ++nameLen) {
|
||||||
|
name[nameLen] = in.Get< char >();
|
||||||
|
|
||||||
|
if (name[nameLen] == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool isNot = name[0] == '!';
|
||||||
|
const CAiTriggerFunc func = CAi::GetTriggerFunc(isNot ? name + 1 : name);
|
||||||
|
const float arg = in.Get< float >();
|
||||||
|
CAiTrigger* newTrig;
|
||||||
|
if (k < lastTriggerIdx) {
|
||||||
|
x10_triggers.push_back(CAiTrigger());
|
||||||
|
newTrig = &x10_triggers.back();
|
||||||
|
} else {
|
||||||
|
newTrig = &firstTrig[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == 0) {
|
||||||
|
newTrig->Setup(func, isNot, arg, &x0_states[in.Get< int >()]);
|
||||||
|
} else {
|
||||||
|
newTrig->Setup(func, isNot, arg, lastTrig);
|
||||||
|
}
|
||||||
|
lastTrig = newTrig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int CStateMachine::GetStateIndex(const rstl::string& state) const {
|
||||||
|
for (int i = 0; i < x0_states.size(); ++i) {
|
||||||
|
if (strncmp(x0_states[i].GetName(), state.data(), 31) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue