#include "Library/Area/AreaObjUtil.h" #include "Library/Area/AreaObj.h" #include "Library/Area/AreaObjDirector.h" #include "Library/Area/AreaObjGroup.h" #include "Library/Area/AreaShape.h" #include "Library/Area/IUseAreaObj.h" #include "Library/Math/MathUtil.h" #include "Library/Placement/PlacementFunction.h" namespace al { AreaObj* tryFindAreaObj(const IUseAreaObj* areaUser, const char* name, const sead::Vector3f& position) { return areaUser->getAreaObjDirector()->getInVolumeAreaObj(name, position); } AreaObj* tryFindAreaObjWithFilter(const IUseAreaObj* areaUser, const char* name, const sead::Vector3f& position, AreaObjFilterBase* filter) { AreaObjGroup* areaObjGroup = tryFindAreaObjGroup(areaUser, name); if (!areaObjGroup) return nullptr; AreaObj* currentAreaObj = nullptr; s32 size = areaObjGroup->getSize(); for (s32 i = 0; i < size; i++) { AreaObj* areaObj = areaObjGroup->getAreaObj(i); if ((!currentAreaObj || currentAreaObj->getPriority() <= areaObj->getPriority()) && areaObj->isInVolume(position) && filter->isValidArea(areaObj)) { currentAreaObj = areaObj; } } return currentAreaObj; } bool tryFindAreaObjAll(const IUseAreaObj* areaUser, const char* name, const sead::Vector3f& position, AreaObjFindCallBack* callBack) { AreaObjGroup* areaObjGroup = tryFindAreaObjGroup(areaUser, name); if (!areaObjGroup) return false; bool foundAnyArea = false; s32 size = areaObjGroup->getSize(); for (s32 i = 0; i < size; i++) { AreaObj* areaObj = areaObjGroup->getAreaObj(i); if (areaObj->isInVolume(position)) { callBack->findArea(areaObj); foundAnyArea = true; } } return foundAnyArea; } AreaObjGroup* tryFindAreaObjGroup(const IUseAreaObj* areaUser, const char* name) { return areaUser->getAreaObjDirector()->getAreaObjGroup(name); } bool isInAreaObj(const AreaObjGroup* group, const sead::Vector3f& position) { return tryGetAreaObj(group, position) != nullptr; } AreaObj* tryGetAreaObj(const AreaObjGroup* group, const sead::Vector3f& position) { if (!group) return nullptr; return group->getInVolumeAreaObj(position); } bool isInAreaPos(const AreaObj* areaObj, const sead::Vector3f& position) { return areaObj->isInVolume(position); } bool isInAreaObj(const IUseAreaObj* areaUser, const char* name, const sead::Vector3f& position) { return tryFindAreaObj(areaUser, name, position) != nullptr; } bool isExistAreaObj(const IUseAreaObj* areaUser, const char* name) { return areaUser->getAreaObjDirector()->isExistAreaGroup(name); } bool isInDeathArea(const IUseAreaObj* areaUser, const sead::Vector3f& position) { return isInAreaObj(areaUser, "DeathArea", position); } bool isInWaterArea(const IUseAreaObj* areaUser, const sead::Vector3f& position) { return isInAreaObj(areaUser, "WaterArea", position); } bool isInPlayerControlOffArea(const IUseAreaObj* areaUser, const sead::Vector3f& position) { return isInAreaObj(areaUser, "PlayerControlOffArea", position); } s32 calcAreaObjNum(const IUseAreaObj* areaUser, const char* name) { AreaObjGroup* group = tryFindAreaObjGroup(areaUser, name); if (!group) return 0; return group->getSize(); } f32 calcWaterSinkDepth(const IUseAreaObj* areaUser, const sead::Vector3f& position) { AreaObj* areaObj = tryFindAreaObj(areaUser, "WaterArea", position); if (!areaObj) return -1.0f; sead::Vector3f hitPosition; sead::Vector3f normal; sead::Vector3f position2 = {position.x, position.y + 100000.0f, position.z}; if (!checkAreaObjCollisionByArrow(&hitPosition, &normal, areaObj, position, position2)) return -1.0f; return hitPosition.y - position.y; } bool tryGetAreaObjArg(s32* outArg, const AreaObj* areaObj, const char* key) { if (!areaObj->getPlacementInfo()) return false; return tryGetArg(outArg, *areaObj->getPlacementInfo(), key); } bool tryGetAreaObjArg(f32* outArg, const AreaObj* areaObj, const char* key) { if (!areaObj->getPlacementInfo()) return false; return tryGetArg(outArg, *areaObj->getPlacementInfo(), key); } bool tryGetAreaObjArg(bool* outArg, const AreaObj* areaObj, const char* key) { if (!areaObj->getPlacementInfo()) return false; return tryGetArg(outArg, *areaObj->getPlacementInfo(), key); } bool tryGetAreaObjStringArg(const char** outArg, const AreaObj* areaObj, const char* key) { if (!areaObj->getPlacementInfo()) return false; return tryGetStringArg(outArg, *areaObj->getPlacementInfo(), key); } const sead::Matrix34f& getAreaObjBaseMtx(const AreaObj* areaObj) { return areaObj->getAreaMtx(); } const sead::Vector3f& getAreaObjScale(const AreaObj* areaObj) { return areaObj->getAreaShape()->getScale(); } void getAreaObjDirFront(sead::Vector3f* outFrontDir, const AreaObj* areaObj) { getAreaObjBaseMtx(areaObj).getBase(*outFrontDir, 2); } void getAreaObjDirUp(sead::Vector3f* outUpDir, const AreaObj* areaObj) { getAreaObjBaseMtx(areaObj).getBase(*outUpDir, 1); } void getAreaObjDirSide(sead::Vector3f* outSideDir, const AreaObj* areaObj) { getAreaObjBaseMtx(areaObj).getBase(*outSideDir, 0); } bool calcNearestAreaObjEdgePos(sead::Vector3f* outNearestEdgePos, const AreaObj* areaObj, const sead::Vector3f& position) { return areaObj->getAreaShape()->calcNearestEdgePoint(outNearestEdgePos, position); } void calcNearestAreaObjEdgePosTopY(sead::Vector3f* outNearestEdgePosTopY, const AreaObj* areaObj, const sead::Vector3f& position) { sead::Vector3f scale = {0.0f, 0.0f, 0.0f}; tryGetScale(&scale, *areaObj->getPlacementInfo()); sead::Vector3f areaPos = getAreaObjBaseMtx(areaObj).getBase(3); sead::Vector3f sideDir; getAreaObjDirSide(&sideDir, areaObj); sead::Vector3f upDir; getAreaObjDirUp(&upDir, areaObj); sead::Vector3f diff; diff.x = position.x - areaPos.x; diff.y = position.y - areaPos.y; diff.z = position.z - areaPos.z; verticalizeVec(&diff, upDir, diff); limitVectorParallelVertical(&diff, sideDir, scale.x * 1000.0f, scale.z * 1000.0f); diff.setScaleAdd(scale.y * 1000.0f, upDir, diff); outNearestEdgePosTopY->set(diff + areaPos); } f32 calcNearestAreaObjEdgeRateTopY(const AreaObj* areaObj, const sead::Vector3f& position) { sead::Vector3f areaPos = getAreaObjBaseMtx(areaObj).getBase(3); sead::Vector3f upDir; getAreaObjDirUp(&upDir, areaObj); sead::Vector3f nearestEdgePosTopY; calcNearestAreaObjEdgePosTopY(&nearestEdgePosTopY, areaObj, position); f32 distToAreaPos = upDir.dot(nearestEdgePosTopY - areaPos); if (distToAreaPos < 0.0f || isNearZero(distToAreaPos)) return 1.0f; f32 distToPosition = sead::Mathf::clampMin(upDir.dot(nearestEdgePosTopY - position), 0.0f); return sead::Mathf::clamp(distToPosition / distToAreaPos, 0.0f, 1.0f); } void calcAreaObjCenterPos(sead::Vector3f* outCenterPosition, const AreaObj* areaObj) { sead::Vector3f pos = getAreaObjBaseMtx(areaObj).getBase(3); f32 scaleY = getAreaObjScale(areaObj).y; outCenterPosition->x = pos.x; outCenterPosition->y = pos.y + scaleY * 1000.0f / 2.0f; outCenterPosition->z = pos.z; } bool checkAreaObjCollisionByArrow(sead::Vector3f* outHitPosition, sead::Vector3f* outNormal, const AreaObj* areaObj, const sead::Vector3f& position1, const sead::Vector3f& position2) { return areaObj->getAreaShape()->checkArrowCollision(outHitPosition, outNormal, position1, position2); } bool calcFindAreaSurface(const IUseAreaObj* areaUser, const char* name, sead::Vector3f* outHitPosition, sead::Vector3f* outNormal, const sead::Vector3f& position1, const sead::Vector3f& position2) { if (tryFindAreaObj(areaUser, name, position1)) return false; sead::Vector3f positionHalfway = (position1 + position2) / 2.0f; AreaObj* areaObj = tryFindAreaObj(areaUser, name, positionHalfway); if (!areaObj) { areaObj = tryFindAreaObj(areaUser, name, position2); if (!areaObj) return false; } return checkAreaObjCollisionByArrow(outHitPosition, outNormal, areaObj, position1, position2); } bool calcFindAreaSurface(const IUseAreaObj* areaUser, const char* name, sead::Vector3f* outHitPosition, sead::Vector3f* outNormal, const sead::Vector3f& position, const sead::Vector3f& direction, f32 distance) { sead::Vector3f position1; sead::Vector3f position2; position1.setScaleAdd(distance, direction, position); position2.setScaleAdd(distance, -direction, position); if (tryFindAreaObj(areaUser, name, position1)) return false; AreaObj* areaObj = tryFindAreaObj(areaUser, name, position); if (!areaObj) { areaObj = tryFindAreaObj(areaUser, name, position2); if (!areaObj) return false; } return checkAreaObjCollisionByArrow(outHitPosition, outNormal, areaObj, position1, position2); } } // namespace al