mirror of
https://github.com/zeldaret/botw
synced 2026-08-10 11:13:50 -04:00
ksys/act: Implement most other base Ai functions
Remaining: two ASList functions we can't implement yet
This commit is contained in:
@@ -100,7 +100,7 @@ public:
|
||||
virtual void calc() {}
|
||||
virtual void getCurrentName(sead::BufferedSafeString* name, ActionBase* last) const;
|
||||
|
||||
virtual ActionBase* changeChild(const sead::SafeString& name) { return nullptr; }
|
||||
virtual ActionBase* changeChildLater(const sead::SafeString& name) { return nullptr; }
|
||||
virtual void getParams(ParamNameTypePairs* pairs, bool update_use_count) const;
|
||||
virtual s32 getNumChildren() const { return 0; }
|
||||
virtual bool initChildren(const AIDefSet& set, sead::Heap* heap) { return true; }
|
||||
|
||||
@@ -70,6 +70,25 @@ bool Ai::initChildren_(s32 num_children, const char** names, sead::Buffer<u16>&
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ai::gatherParamsFromChildren(sead::Heap* heap) {
|
||||
if (mFlags.isOff(Flag::DynamicParamChild) || mFlags.isOn(Flag::_20))
|
||||
return true;
|
||||
|
||||
ParamNameTypePairs pairs;
|
||||
for (auto* child : mChildren) {
|
||||
if (auto* ai = sead::DynamicCast<Ai>(child)) {
|
||||
if (ai->mFlags.isOn(Flag::DynamicParamChild) && ai->mFlags.isOff(Flag::_20) &&
|
||||
!ai->gatherParamsFromChildren(heap)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
child->getParams(&pairs, true);
|
||||
}
|
||||
|
||||
mFlags.set(Flag::_20);
|
||||
return mParams.load(*mActor, pairs, mChildren.size(), heap);
|
||||
}
|
||||
|
||||
void Ai::calc() {
|
||||
calc_();
|
||||
|
||||
@@ -77,7 +96,7 @@ void Ai::calc() {
|
||||
if (child)
|
||||
child->calc();
|
||||
|
||||
if (mPendingChildIdx != InvalidIdx && mChildIdx != mPendingChildIdx) {
|
||||
if (hasPendingChildChange()) {
|
||||
handlePendingChildChange_();
|
||||
auto* new_child = getCurrentChild();
|
||||
if (new_child)
|
||||
@@ -85,6 +104,86 @@ void Ai::calc() {
|
||||
}
|
||||
}
|
||||
|
||||
bool Ai::handlePendingChildChange() {
|
||||
if (!hasPendingChildChange())
|
||||
return false;
|
||||
handlePendingChildChange_();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ai::hasPendingChildChange() const {
|
||||
return mPendingChildIdx != InvalidIdx && mChildIdx != mPendingChildIdx;
|
||||
}
|
||||
|
||||
s32 Ai::getChildIdx(const sead::SafeString& name) const {
|
||||
const s32 idx = mChildren.binarySearch(
|
||||
name, +[](ActionBase* const& action, const sead::SafeString& key) {
|
||||
if (action == nullptr)
|
||||
return 0;
|
||||
return sead::SafeString(action->getName()).compare(key);
|
||||
});
|
||||
return idx == -1 ? InvalidIdx : idx;
|
||||
}
|
||||
|
||||
void Ai::changeChild(u32 idx, InlineParamPack* params) {
|
||||
const auto do_change = [&](InlineParamPack* pack) {
|
||||
auto* current_child = getCurrentChild();
|
||||
mNewChildIdx = idx;
|
||||
if (current_child)
|
||||
current_child->leave();
|
||||
|
||||
changeChildIdx(idx);
|
||||
if (mChildren[idx])
|
||||
mChildren[idx]->enter(pack, getName());
|
||||
|
||||
setRootAiFlag(RootAiFlag::_100);
|
||||
};
|
||||
|
||||
if (mFlags.isOff(Flag::DynamicParamChild) || params) {
|
||||
do_change(params);
|
||||
} else {
|
||||
InlineParamPack pack;
|
||||
copyParams(&pack, false);
|
||||
do_change(&pack);
|
||||
}
|
||||
}
|
||||
|
||||
void Ai::changeChild(const char* name, InlineParamPack* params) {
|
||||
const auto idx = getChildIdx(name);
|
||||
if (idx != InvalidIdx)
|
||||
changeChild(idx, params);
|
||||
}
|
||||
|
||||
bool Ai::reenter(ActionBase* other, const sead::SafeString& context) {
|
||||
auto* ai = sead::DynamicCast<Ai>(other);
|
||||
if (!ai)
|
||||
return false;
|
||||
|
||||
if (ai->getNumChildren() != getNumChildren())
|
||||
return false;
|
||||
|
||||
mPendingChildIdx = InvalidIdx;
|
||||
|
||||
const bool reenter_ret = reenter_(ai, false);
|
||||
|
||||
if (mFlags.isOn(Flag::_40)) {
|
||||
if (auto* child = getCurrentChild())
|
||||
child->leave();
|
||||
mFlags.reset(Flag::_40);
|
||||
}
|
||||
|
||||
mPrevChildIdx = ai->mPrevChildIdx;
|
||||
mChildIdx = ai->mChildIdx;
|
||||
if (!reenter_ret)
|
||||
return false;
|
||||
|
||||
auto* other_child = ai->getCurrentChild();
|
||||
auto* child = getCurrentChild();
|
||||
if (!other_child || !child)
|
||||
return true;
|
||||
return child->takeOver(other_child, getName());
|
||||
}
|
||||
|
||||
bool Ai::isFlag4Set() const {
|
||||
auto* child = getCurrentChild();
|
||||
if (child)
|
||||
@@ -99,13 +198,67 @@ ActionBase* Ai::getCurrentChild() const {
|
||||
return mChildren[mChildIdx];
|
||||
}
|
||||
|
||||
void Ai::updateChildIdx(u16 new_idx) {
|
||||
bool Ai::isCurrentChild(const sead::SafeString& name) const {
|
||||
const auto* child = getCurrentChild();
|
||||
if (!child)
|
||||
return false;
|
||||
return name == child->getName();
|
||||
}
|
||||
|
||||
bool Ai::isCurrentAction(const sead::SafeString& name) {
|
||||
auto* action = getCurrentAction();
|
||||
if (!action)
|
||||
return false;
|
||||
return name == action->getName();
|
||||
}
|
||||
|
||||
void Ai::changeChildIdx(u16 new_idx) {
|
||||
const auto prev_idx = mChildIdx;
|
||||
mChildIdx = new_idx;
|
||||
mPrevChildIdx = prev_idx;
|
||||
mPendingChildIdx = InvalidIdx;
|
||||
}
|
||||
|
||||
ActionBase* Ai::changeChildLater(const sead::SafeString& name) {
|
||||
const auto idx = getChildIdx(name);
|
||||
if (idx == InvalidIdx)
|
||||
return nullptr;
|
||||
|
||||
if (idx == mChildIdx)
|
||||
return getCurrentChild();
|
||||
|
||||
mPendingChildIdx = idx;
|
||||
return mChildren[idx];
|
||||
}
|
||||
|
||||
void Ai::getNames(sead::BufferedSafeString* out) const {
|
||||
if (mPrevChildIdx == InvalidIdx)
|
||||
return;
|
||||
|
||||
const auto* child = mChildren[mPrevChildIdx];
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
out->appendWithFormat("/%s", child->getName());
|
||||
if (auto* child_ai = sead::DynamicCast<const Ai>(child))
|
||||
child_ai->getNames(out);
|
||||
}
|
||||
|
||||
void Ai::getParams(ParamNameTypePairs* pairs, bool update_use_count) const {
|
||||
auto* ptr = this;
|
||||
do {
|
||||
ptr->ActionBase::getParams(pairs, update_use_count);
|
||||
if (ptr->mFlags.isOff(Flag::DynamicParamChild))
|
||||
return;
|
||||
if (!sead::IsDerivedFrom<Ai>(ptr))
|
||||
return;
|
||||
if (ptr->getNumChildren() <= 0)
|
||||
return;
|
||||
ptr = static_cast<const Ai*>(ptr->getChild(0));
|
||||
update_use_count = false;
|
||||
} while (ptr);
|
||||
}
|
||||
|
||||
Ais::Ais() = default;
|
||||
|
||||
Ais::~Ais() {
|
||||
|
||||
@@ -12,26 +12,38 @@ public:
|
||||
~Ai() override;
|
||||
|
||||
bool isFlag4Set() const override;
|
||||
bool reenter_(ActionBase* other, bool x) override;
|
||||
void calc() override;
|
||||
ActionBase* changeChild(const sead::SafeString& name) override;
|
||||
ActionBase* changeChildLater(const sead::SafeString& name) override;
|
||||
void getParams(ParamNameTypePairs* pairs, bool update_use_count) const override;
|
||||
s32 getNumChildren() const override { return mChildren.size(); }
|
||||
bool initChildren(const AIDefSet& set, sead::Heap* heap) override;
|
||||
ActionBase* getCurrentChild() const override;
|
||||
ActionType getType() const override { return ActionType::AI; }
|
||||
bool reenter(ActionBase* other, const sead::SafeString& context) override;
|
||||
void postLeave() override { updateChildIdx(InvalidIdx); }
|
||||
void postLeave() override { changeChildIdx(InvalidIdx); }
|
||||
ActionBase* getChild(s32 idx) const override { return mChildren[idx]; }
|
||||
virtual void getNames(sead::BufferedSafeString* out);
|
||||
virtual void getNames(sead::BufferedSafeString* out) const;
|
||||
|
||||
bool gatherParamsFromChildren(sead::Heap* heap);
|
||||
|
||||
void changeAS(const char* as_name, bool b, int x, int y);
|
||||
// TODO: figure out what this actually does and rename
|
||||
bool checkAS(int x, int y);
|
||||
|
||||
/// @returns whether there was a pending child change.
|
||||
bool handlePendingChildChange();
|
||||
bool hasPendingChildChange() const;
|
||||
s32 getChildIdx(const sead::SafeString& name) const;
|
||||
void changeChild(u32 idx, InlineParamPack* params = nullptr);
|
||||
void changeChild(const char* name, InlineParamPack* params = nullptr);
|
||||
|
||||
bool isCurrentChild(const sead::SafeString& name) const;
|
||||
bool isCurrentAction(const sead::SafeString& name);
|
||||
|
||||
protected:
|
||||
virtual void calc_() {}
|
||||
virtual void handlePendingChildChange_() { changeChildState(mPendingChildIdx); }
|
||||
void updateChildIdx(u16 new_idx);
|
||||
void changeChildState(u16 idx, InlineParamPack* params = nullptr);
|
||||
virtual void handlePendingChildChange_() { changeChild(mPendingChildIdx); }
|
||||
void changeChildIdx(u16 new_idx);
|
||||
|
||||
static constexpr u16 InvalidIdx = 0xffff;
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ KSYS_CHECK_SIZE_NX150(ParamNameType, 0x10);
|
||||
struct ParamNameTypePairs {
|
||||
void addPair(AIDefParamType type, const sead::SafeString& name, bool update_use_count);
|
||||
|
||||
sead::SafeArray<ParamNameType, 32> pairs;
|
||||
s32 count;
|
||||
sead::SafeArray<ParamNameType, 32> pairs{};
|
||||
s32 count = 0;
|
||||
};
|
||||
KSYS_CHECK_SIZE_NX150(ParamNameTypePairs, 0x208);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user