Files
ogre-prototype/src/gamedata/CharacterModule.cpp

818 lines
25 KiB
C++

#include <iostream>
#include <Ogre.h>
#include "GameData.h"
#include "WaterModule.h"
#include "TerrainModule.h"
#include "Components.h"
#include "PhysicsModule.h"
#include "physics.h"
#include "CharacterAnimationModule.h"
#include "CharacterManagerModule.h"
#include "CharacterModule.h"
#include "goap.h"
namespace ECS
{
CharacterModule::CharacterModule(flecs::world &ecs)
{
struct TriggerPhysicsChange {};
ecs.module<CharacterModule>();
ecs.component<Character>();
ecs.component<Player>();
ecs.component<CharacterBase>();
ecs.component<CharacterGravity>();
ecs.component<CharacterLocation>();
ecs.component<CharacterBuoyancy>();
ecs.component<CharacterConf>();
ecs.component<CharacterDisablePhysics>();
ecs.component<CharacterUpdatePhysicsState>();
ecs.component<CharacterInActuator>();
ecs.component<Blackboard>();
ecs.component<ActionTarget>();
ecs.component<Plan>();
ecs.component<Male>();
ecs.component<Female>();
ecs.component<Planner>().add(flecs::Singleton);
ecs.import <CharacterAnimationModule>();
ecs.import <TerrainModule>();
ecs.import <WaterModule>();
ecs.system<EngineData, CharacterBase>("UpdateTimer")
.kind(flecs::OnUpdate)
.each([this](EngineData &eng, CharacterBase &ch) {
ch.mTimer += eng.delta;
});
ecs.system<Input, Camera>("HandleInput")
.kind(flecs::OnUpdate)
.each([this](Input &input, Camera &camera) {
flecs::entity player =
ECS::get<CharacterManagerModule>().getPlayer();
if (!player.is_valid())
return;
/* handle input */
// if (input.control == input.control_prev)
// return;
uint32_t pressed = input.control & ~input.control_prev;
uint32_t released = input.control_prev & ~input.control;
uint32_t active = input.control;
float zaxis = input.motion.z;
zaxis *= 0.9f;
if (!camera.mCameraPivot || !camera.mCameraGoal)
return;
if (pressed & 1)
std::cout << "W pressed\n";
if (released & 1)
std::cout << "W released\n";
if (active & 1)
zaxis -= 1.0f;
if (active & 4)
zaxis += 1.0f;
if (zaxis > -1.0f && zaxis < 1.0f)
zaxis = 0.0f;
else
zaxis = Ogre::Math::Sign(zaxis);
if (active & 32)
input.act = true;
else
input.act = false;
if (pressed & 32)
input.act_pressed = true;
else
input.act_pressed = false;
if (active & 64)
input.act2 = true;
else
input.act2 = false;
if (pressed & 64)
input.act2_pressed = true;
else
input.act2_pressed = false;
input.motion.z = zaxis;
float xaxis = input.motion.x;
xaxis *= 0.9f;
if (active & 2)
xaxis = -1.0f;
if (active & 8)
xaxis += 1.0f;
if (xaxis > -1.0f && xaxis < 1.0f)
xaxis = 0.0f;
else
xaxis = Ogre::Math::Sign(xaxis);
input.motion.x = xaxis;
if (active & 16)
input.fast = true;
else
input.fast = false;
input.control_prev = input.control;
if (input.mouse_moved) {
updateCameraGoal(camera, -0.18f * input.mouse.x,
-0.12f * input.mouse.y, 0);
input.mouse_moved = false;
input.mouse.x = 0;
input.mouse.y = 0;
}
if (input.wheel_moved) {
updateCameraGoal(camera, 0, 0,
-0.15f * input.wheel_y);
input.wheel_moved = false;
input.wheel_y = 0;
}
ECS::get().modified<ECS::Input>();
});
ecs.system<CharacterBase>()
.kind(flecs::OnUpdate)
.with<TerrainReady>()
.with<WaterReady>()
.with<InWater>()
.each([this](flecs::entity e, CharacterBase &ch) {
float full_subm = 2.0f;
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
float current_subm = -Ogre::Math::Clamp(
pos.y + Ogre::Math::Sin(ch.mTimer * 0.13f +
130.0f) *
0.07f,
-full_subm, 0.0f);
if (current_subm > 0.9f)
ch.is_submerged = true;
else if (current_subm < 0.8f)
ch.is_submerged = false;
});
#if 0
ecs.system<const EngineData, const CharacterBase, CharacterVelocity>(
"HandleGravityBouyanceWater")
.kind(flecs::OnUpdate)
.with<TerrainReady>()
.with<WaterReady>()
.with<InWater>()
.without<CharacterDisablePhysics>()
.without<CharacterUpdatePhysicsState>()
.each([this](flecs::entity e, const EngineData &eng,
const CharacterBase &ch, CharacterVelocity &gr) {
Ogre::Vector3 gravity(0, -9.8f, 0);
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
Ogre::Vector3 v(0, 0, 0);
if (e.has<CharacterGravity>())
v += gravity;
if (e.has<CharacterBuoyancy>()) {
float volume = 2.0f * 0.5f * 0.5f;
float density = 900.0f;
float full_subm = 2.0f;
float mass = 80.0f;
float multiplier = 0.25f;
float current_subm = -Ogre::Math::Clamp(
pos.y + Ogre::Math::Sin(ch.mTimer *
0.13f +
130.0f) *
0.07f,
-full_subm, 0.0f);
Ogre::Vector3 b = -gravity * density * volume *
multiplier * current_subm /
full_subm / mass;
v += b;
}
gr.gvelocity += v * eng.delta;
gr.gvelocity.y =
Ogre::Math::Clamp(gr.gvelocity.y, -2.5f, 1.5f);
gr.gvelocity *= (1.0 - eng.delta);
gr.velocity.y *= (1.0 - eng.delta);
});
#endif
#if 0
ecs.system<const EngineData, const CharacterBase, CharacterVelocity>(
"HandleGravityNoWater")
.kind(flecs::OnUpdate)
.with<TerrainReady>()
.with<WaterReady>()
.without<InWater>()
.with<CharacterGravity>()
.without<CharacterDisablePhysics>()
.each([this](flecs::entity e, const EngineData &eng,
const CharacterBase &ch, CharacterVelocity &gr) {
Ogre::Vector3 gravity(0, -9.8f, 0);
Ogre::Vector3 pos = ch.mBodyNode->getPosition();
gr.gvelocity += gravity * eng.delta;
if (pos.y < -1.2) {
gr.gvelocity.y = 0.0f;
}
gr.gvelocity *= (1.0 - eng.delta);
gr.velocity.y *= (1.0 - eng.delta);
});
#endif
#define TURN_SPEED 500.0f // character turning in degrees per second
ecs.system<const Input, const Camera, CharacterBase>("UpdateBody")
.kind(flecs::OnUpdate)
.with<Character>()
.with<Player>()
.without<CharacterInActuator>()
.each([](flecs::entity e, const Input &input,
const Camera &camera, CharacterBase &ch) {
ch.mGoalDirection = Ogre::Vector3::ZERO;
float delta = e.world().delta_time();
if (!input.motion.zeroLength()) {
// calculate actually goal direction in world based on player's key directions
ch.mGoalDirection +=
input.motion.z *
camera.mCameraNode->getOrientation()
.zAxis();
ch.mGoalDirection +=
input.motion.x *
camera.mCameraNode->getOrientation()
.xAxis();
ch.mGoalDirection.y = 0;
ch.mGoalDirection.normalise();
Ogre::Quaternion toGoal =
ch.mBodyNode->getOrientation()
.zAxis()
.getRotationTo(
ch.mGoalDirection);
// calculate how much the character has to turn to face goal direction
Ogre::Real yawToGoal =
toGoal.getYaw().valueDegrees();
// this is how much the character CAN turn this frame
Ogre::Real yawAtSpeed =
yawToGoal / Ogre::Math::Abs(yawToGoal) *
delta * TURN_SPEED;
// reduce "turnability" if we're in midair
// if (mBaseAnimID == ANIM_JUMP_LOOP) yawAtSpeed *= 0.2f;
if (yawToGoal < 0)
yawToGoal = std::min<Ogre::Real>(
0,
std::max<Ogre::Real>(
yawToGoal,
yawAtSpeed)); //yawToGoal = Math::Clamp<Real>(yawToGoal, yawAtSpeed, 0);
else if (yawToGoal > 0)
yawToGoal = std::max<Ogre::Real>(
0,
std::min<Ogre::Real>(
yawToGoal,
yawAtSpeed)); //yawToGoal = Math::Clamp<Real>(yawToGoal, 0, yawAtSpeed);
ch.mBodyNode->yaw(Ogre::Degree(yawToGoal));
}
});
#if 0
ecs.system<const EngineData, CharacterLocation, CharacterBase,
CharacterBody>("UpdateCharacterBase")
.kind(flecs::OnUpdate)
.with<Character>()
.with<CharacterBody>()
.with<CharacterBase>()
.each([](const EngineData &eng, CharacterLocation &loc,
CharacterBase &ch, CharacterBody &body) {
if (!ch.mBodyNode) {
} else {
loc.orientation =
ch.mBodyNode->_getDerivedOrientation();
loc.position =
ch.mBodyNode->_getDerivedPosition();
}
});
#endif
static int characterCount = 0;
ecs.observer<const EngineData, const CharacterLocation,
const CharacterConf, CharacterBase>(
"SetupCharacterBaseObs")
.event(flecs::OnAdd)
.each([&](flecs::entity e, const EngineData &eng,
const CharacterLocation &loc,
const CharacterConf &conf, CharacterBase &ch) {
ch.mBodyEnt = eng.mScnMgr->createEntity(conf.type);
ch.mBodyNode = eng.mScnMgr->getRootSceneNode()
->createChildSceneNode();
ch.mBodyNode->setOrientation(loc.orientation);
ch.mBodyNode->setPosition(loc.position);
ch.mBodyNode->attachObject(ch.mBodyEnt);
ch.mSkeleton = ch.mBodyEnt->getSkeleton();
OgreAssert(ch.mBodyEnt->getSkeleton()->hasBone("Root"),
"No root bone");
OgreAssert(ch.mSkeleton->hasBone("Root"),
"No root bone");
ch.mRootBone = ch.mSkeleton->getBone("Root");
OgreAssert(ch.mRootBone, "No root bone");
ch.mBoneMotion = Ogre::Vector3::ZERO;
ch.mBonePrevMotion = Ogre::Vector3::ZERO;
});
ecs.observer<AnimationControl>("SetupAnimationControlObs")
.event(flecs::OnAdd)
.each([](flecs::entity e, AnimationControl &anim) {
anim.configured = false;
});
ecs.observer<const CharacterLocation, const CharacterConf>(
"SetupCharacterObs")
.event(flecs::OnSet)
.with<Character>()
.without<CharacterBase>()
.without<AnimationControl>()
.write<CharacterBase>()
.write<AnimationControl>()
.each([&](flecs::entity e, const CharacterLocation &loc,
const CharacterConf &conf) {
std::cout << "OBSERVER!!!"
<< " " << e.id() << std::endl;
if (e.has<CharacterBase>() || e.has<AnimationControl>())
return;
e.world().defer_begin();
e.add<CharacterBase>();
e.add<AnimationControl>();
e.set<CharacterVelocity>(
{ { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } });
e.add<CharacterGravity>();
e.add<CharacterBuoyancy>();
e.world().defer_end();
});
#if 0
ecs.system<const EngineData, const CharacterLocation,
const CharacterConf, Body2Entity>("SetupCharacter")
.kind(flecs::OnUpdate)
.with<Character>()
.without<CharacterBase>()
.without<CharacterBody>()
.each([](flecs::entity e, const EngineData &eng,
const CharacterLocation &loc,
const CharacterConf &conf, Body2Entity &b2e) {
CharacterBase &ch = e.ensure<CharacterBase>();
CharacterBody &body = e.ensure<CharacterBody>();
AnimationControl &anim = e.ensure<AnimationControl>();
ch.mBodyEnt = eng.mScnMgr->createEntity(conf.type);
ch.mBodyNode = eng.mScnMgr->getRootSceneNode()
->createChildSceneNode();
ch.mBodyNode->setOrientation(loc.orientation);
ch.mBodyNode->setPosition(loc.position);
ch.mBodyNode->attachObject(ch.mBodyEnt);
ch.mSkeleton = ch.mBodyEnt->getSkeleton();
OgreAssert(ch.mBodyEnt->getSkeleton()->hasBone("Root"),
"No root bone");
OgreAssert(ch.mSkeleton->hasBone("Root"),
"No root bone");
ch.mRootBone = ch.mSkeleton->getBone("Root");
OgreAssert(ch.mRootBone, "No root bone");
// body.mController = nullptr;
ch.mBoneMotion = Ogre::Vector3::ZERO;
ch.mBonePrevMotion = Ogre::Vector3::ZERO;
e.set<CharacterVelocity>(
{ { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } });
body.checkGround = false;
body.checkGroundResult = false;
#if 0
body.mCollisionShape = nullptr;
body.mGhostObject = nullptr;
body.mController = nullptr;
body.mGhostObject = new btPairCachingGhostObject();
b2e.entities[body.mGhostObject] = e;
body.mCollisionShape = new btCompoundShape(false);
body.mGhostObject->setCollisionShape(
body.mCollisionShape);
{
btVector3 inertia(0, 0, 0);
// mCollisionShape = new btCompoundShape();
btScalar height = 1.0f;
btScalar radius = 0.3f;
btCapsuleShape *shape = new btCapsuleShape(
radius, 2 * height - 2 * radius);
btTransform transform;
transform.setIdentity();
transform.setOrigin(btVector3(0, 1, 0));
static_cast<btCompoundShape *>(
body.mCollisionShape)
->addChildShape(transform, shape);
btScalar masses[1] = { 0 };
btTransform principal;
static_cast<btCompoundShape *>(
body.mCollisionShape)
->calculatePrincipalAxisTransform(
masses, principal, inertia);
}
body.mGhostObject->setCollisionFlags(body.mGhostObject->getCollisionFlags() | btCollisionObject::CF_CHARACTER_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT
/*btCollisionObject::CF_KINEMATIC_OBJECT |
btCollisionObject::CF_NO_CONTACT_RESPONSE */);
body.mGhostObject->setActivationState(
DISABLE_DEACTIVATION);
eng.mWorld->attachCollisionObject(
body.mGhostObject, ch.mBodyEnt, 1, 0x7FFFFFFF);
OgreAssert(body.mGhostObject, "Need GhostObject");
OgreAssert(body.mCollisionShape, "No collision shape");
#endif
e.add<CharacterGravity>();
e.add<CharacterBuoyancy>();
anim.configured = false;
// OgreAssert(body.mGhostObject->hasContactResponse(),
// "need contact response");
});
#endif
#if 0
ecs.system<const EngineData, CharacterBase, CharacterBody>(
"UpdateCharacterPhysics")
.kind(flecs::OnUpdate)
.with<Character>()
.with<TerrainReady>()
.with<WaterReady>()
.each([](const EngineData &eng, CharacterBase &ch,
CharacterBody &body) {
#if 0
if (ch.mBodyNode && !body.mController &&
eng.startupDelay < 0.0f) {
body.mController =
new Ogre::Bullet::KinematicMotionSimple(
body.mGhostObject,
ch.mBodyNode);
body.mController->enableManualNarrowPhase(true);
eng.mWorld->getBtWorld()->addAction(
body.mController);
OgreAssert(body.mController, "Need controller");
}
#endif
});
#endif
#define CAM_HEIGHT 1.6f // height of camera above character's center of mass
ecs.system<const EngineData, Camera, const CharacterBase>(
"UpdateCamera")
.kind(flecs::OnUpdate)
.with<Player>()
.with<GroundCheckReady>()
.each([](const EngineData &eng, Camera &camera,
const CharacterBase &ch) {
float delta = eng.delta;
if (!camera.configured) {
// create a pivot at roughly the character's shoulder
camera.mCameraPivot =
eng.mScnMgr->getRootSceneNode()
->createChildSceneNode();
camera.mCameraGoal =
camera.mCameraPivot
->createChildSceneNode(
Ogre::Vector3(0, 2, 3));
camera.mCameraNode->setPosition(
camera.mCameraPivot->getPosition() +
camera.mCameraGoal->getPosition());
camera.mCameraPivot->setFixedYawAxis(true);
camera.mCameraGoal->setFixedYawAxis(true);
camera.mCameraNode->setFixedYawAxis(true);
// our model is quite small, so reduce the clipping planes
camera.mCamera->setNearClipDistance(0.1f);
camera.mCamera->setFarClipDistance(700);
camera.mPivotPitch = 0;
camera.configured = true;
} else {
// place the camera pivot roughly at the character's shoulder
camera.mCameraPivot->setPosition(
ch.mBodyNode->getPosition() +
Ogre::Vector3::UNIT_Y * CAM_HEIGHT);
// move the camera smoothly to the goal
Ogre::Vector3 goalOffset =
camera.mCameraGoal
->_getDerivedPosition() -
camera.mCameraNode->getPosition();
camera.mCameraNode->translate(goalOffset *
delta * 9.0f);
// always look at the pivot
camera.mCameraNode->lookAt(
camera.mCameraPivot
->_getDerivedPosition(),
Ogre::Node::TS_PARENT);
}
});
#if 0
class ClosestNotMeRayResultCallback
: public btCollisionWorld::ClosestRayResultCallback {
btCollisionObject *mMe;
public:
ClosestNotMeRayResultCallback(btCollisionObject *me,
const btVector3 &from,
const btVector3 &to)
: btCollisionWorld::ClosestRayResultCallback(from, to)
{
mMe = me;
}
virtual btScalar
addSingleResult(btCollisionWorld::LocalRayResult &rayResult,
bool normalInWorldSpace)
{
if (rayResult.m_collisionObject == mMe)
return 1.0f;
return ClosestRayResultCallback::addSingleResult(
rayResult, normalInWorldSpace);
}
};
#endif
ecs.system<const EngineData, CharacterBase>("CheckGround")
.kind(flecs::OnUpdate)
.with<Character>()
.with<Player>()
.without<GroundCheckReady>()
.each([](const EngineData &eng, CharacterBase &ch) {
#if 0
if (body.mGhostObject) {
btVector3 from =
body.mGhostObject->getWorldTransform()
.getOrigin() +
btVector3(0, 0.2f, 0);
btVector3 to = from + btVector3(0, -3000.0f, 0);
ClosestNotMeRayResultCallback resultCallback(
body.mGhostObject, from, to);
body.mGhostObject->rayTest(from, to,
resultCallback);
body.checkGroundResult =
resultCallback.hasHit();
if (resultCallback.hasHit())
ECS::get().add<GroundCheckReady>();
}
#endif
ECS::get().add<GroundCheckReady>();
});
#if 0
ecs.system<const WaterBody, const CharacterBase, CharacterBody>(
"CharacterWater1")
.kind(flecs::OnUpdate)
.with<Character>()
.without<InWater>()
.each([](flecs::entity e, const WaterBody &waterb,
const CharacterBase &ch, CharacterBody &body) {
#if 0
if (waterb.isInWater(body.mGhostObject) &&
ch.mBodyNode->_getDerivedPosition().y < -0.05f) {
e.add<InWater>();
std::cout << "Big Splash\n";
}
#endif
#if 0
if (waterb.mInWater.find(body.mGhostObject) ==
waterb.mInWater.end())
e.add<InWater>();
std::cout << waterb.mInWater.size() << " InWater\n";
#endif
});
#endif
#if 0
ecs.system<const WaterBody, const CharacterBase, CharacterBody>(
"CharacterWater2")
.kind(flecs::OnUpdate)
.with<Character>()
.with<InWater>()
.each([](flecs::entity e, const WaterBody &waterb,
const CharacterBase &ch, CharacterBody &body) {
float h = ch.mBodyNode->_getDerivedPosition().y;
#if 0
if (waterb.isInWater(body.mGhostObject) && h > 0.05f)
e.remove<InWater>();
else if (!waterb.isInWater(body.mGhostObject) &&
h > 0.05f)
e.remove<InWater>();
#endif
});
#endif
#if 0
ecs.system<const EngineData, CharacterBase, CharacterBody>(
"DisplayPlayerPos")
.kind(flecs::OnUpdate)
.with<Character>()
.with<Player>()
.each([](const EngineData &eng, CharacterBase &ch,
CharacterBody &body) {
std::cout << "player: " << ch.mBodyNode->getPosition()
<< "\n";
});
#endif
#if 0
#endif
}
void CharacterModule::updateCameraGoal(Camera &camera, Ogre::Real deltaYaw,
Ogre::Real deltaPitch,
Ogre::Real deltaZoom)
{
static float canonDist = 0;
camera.mCameraPivot->yaw(Ogre::Degree(deltaYaw), Ogre::Node::TS_PARENT);
if (!(camera.mPivotPitch + deltaPitch > 25 && deltaPitch > 0) &&
!(camera.mPivotPitch + deltaPitch < -60 && deltaPitch < 0)) {
camera.mCameraPivot->pitch(Ogre::Degree(deltaPitch),
Ogre::Node::TS_LOCAL);
camera.mPivotPitch += deltaPitch;
}
Ogre::Real dist = camera.mCameraGoal->_getDerivedPosition().distance(
camera.mCameraPivot->_getDerivedPosition());
Ogre::Real distChange = deltaZoom * dist;
// bound the zoom
if (!(dist + distChange < 1.5f && distChange < 0) &&
!(dist + distChange > 10 && distChange > 0)) {
camera.mCameraGoal->translate(0, 0, distChange,
Ogre::Node::TS_LOCAL);
canonDist += distChange;
}
JPH::BodyID id;
Ogre::Vector3 position;
Ogre::Vector3 d = (camera.mCameraPivot->_getDerivedPosition() -
camera.mCameraGoal->_getDerivedPosition())
.normalisedCopy();
if (JoltPhysicsWrapper::getSingleton().raycastQuery(
camera.mCameraPivot->_getDerivedPosition(),
camera.mCameraGoal->_getDerivedPosition() - d * 0.6,
position, id)) {
float l = camera.mCameraPivot->_getDerivedPosition()
.squaredDistance(
camera.mCameraGoal
->_getDerivedPosition());
float m = camera.mCameraPivot->_getDerivedPosition()
.squaredDistance(position);
if (m < l)
camera.mCameraGoal->_setDerivedPosition(position +
d * 0.6f);
} else {
Ogre::Real dist2 =
camera.mCameraGoal->_getDerivedPosition().distance(
camera.mCameraPivot->_getDerivedPosition());
if (deltaZoom < 0.0f || deltaZoom > 0.0f)
canonDist = dist2;
else {
if (canonDist < dist2)
canonDist = dist2;
if (dist2 < canonDist)
camera.mCameraGoal->translate(
0, 0, 0.08f, Ogre::Node::TS_LOCAL);
}
}
}
CharacterAIModule::CharacterAIModule(flecs::world &ecs)
{
ecs.module<CharacterAIModule>();
ecs.system<Blackboard>("UpdateCharacters")
.kind(flecs::OnUpdate)
.each([&](flecs::entity e, Blackboard &bb) {
bb.flags &=
~(Blackboard::LOW_HEALTH |
Blackboard::FULL_HEALTH |
Blackboard::LOW_STAMINA |
Blackboard::FULL_STAMINA |
Blackboard::LOW_LUST | Blackboard::HIGH_LUST |
Blackboard::FULL_LUST);
if (bb.health < 5)
bb.flags |= Blackboard::LOW_HEALTH;
else if (bb.health >= 100)
bb.flags |= Blackboard::FULL_HEALTH;
if (bb.stamina < 5)
bb.flags |= Blackboard::LOW_STAMINA;
if (bb.stamina >= 100)
bb.flags |= Blackboard::FULL_STAMINA;
if (bb.lust >= 100)
bb.flags |= Blackboard::FULL_LUST;
if (bb.lust > 10)
bb.flags |= Blackboard::HIGH_LUST;
if (bb.lust < 5)
bb.flags |= Blackboard::LOW_LUST;
if (bb.stamina < 0)
bb.stamina = 0;
else if (bb.stamina > 100)
bb.stamina = 100;
if (bb.lust < 0)
bb.lust = 0;
else if (bb.lust > 100)
bb.lust = 100;
});
ecs.system<Blackboard, Plan>("UpdateCharactersPlan2")
.kind(flecs::OnUpdate)
.each([&](flecs::entity e, Blackboard &bb, Plan &p) {
int i;
bool ok_plan = true;
for (i = p.position; i < p.length; i++) {
if (!p.actions[i]->can_run(bb, true)) {
ok_plan = false;
break;
}
int ret = p.actions[i]->execute(bb);
p.position = i;
if (ret == BaseAction::BUSY)
break;
else if (ret == BaseAction::ABORT) {
ok_plan = false;
break;
}
if (ret == BaseAction::OK && i == p.length - 1)
ok_plan = false;
// stop_this = true;
}
if (!ok_plan) {
std::cout << e.name() << ": invalidated plan"
<< " step: " << i << std::endl;
for (i = 0; i < p.length; i++)
p.actions[i]->stop(bb);
e.remove<Plan>();
}
});
ecs.system<Blackboard, Planner>("UpdateCharacters2")
.kind(flecs::OnUpdate)
.without<Plan>()
.each([&](flecs::entity e, Blackboard &bb, Planner &planner) {
int i;
std::vector<BaseAction *> actions;
actions.insert(actions.end(), planner.actions.begin(),
planner.actions.end());
e.world()
.query_builder<const ActionTarget>()
.build()
.each([&](flecs::entity me,
const ActionTarget &t) {
actions.insert(actions.end(),
t.actions.begin(),
t.actions.end());
#if 0
auto it = t.actions.begin();
while (it != t.actions.end()) {
if (me != bb.me)
actions.push_back(*it);
// std::cout << (*it)->get_name()
// << std::endl;
it++;
}
#endif
});
#if 0
for (i = 0; i < actions.size(); i++)
std::cout << "action: " << i << " "
<< actions[i]->get_name()
<< std::endl;
#endif
if (actions.size() == 0)
return;
int len = -1;
OgreAssert(
bb.stamina < 100 ||
bb.stamina >= 100 &&
!bb.get_flag(
Blackboard::LOW_STAMINA),
"bad thing");
for (i = 0; i < planner.goals.size(); i++) {
if (planner.goals[i]->distance_to(bb) > 1000000)
continue;
len = planner.planner.plan(
bb, *planner.goals[i], actions.data(),
actions.size(), planner.path.data(),
100);
std::cout << bb.me.name() << ": goal: " << len
<< " " << planner.goals[i]->get_name()
<< std::endl;
if (len > 0)
break;
}
// std::cout << "plan length: " << len << std::endl;
#if 0
if (len > 0)
stop_this = true;
if (len < 0)
stop_this = true;
#endif
if (len > 0) {
Plan &p = e.ensure<Plan>();
p.actions = planner.path;
p.position = 0;
p.length = len;
for (i = 0; i < len; i++)
std::cout
<< i << " "
<< planner.path[i]->get_name()
<< " "
<< planner.path[i]->get_cost(bb)
<< std::endl;
bool ok_plan = true;
for (i = 0; i < len; i++) {
if (!planner.path[i]->can_run(bb,
true)) {
ok_plan = false;
break;
}
int ret = planner.path[i]->execute(bb);
p.position = i;
std::cout << "exec: " << i << " "
<< planner.path[i]->get_name()
<< std::endl;
if (ret == BaseAction::BUSY)
break;
else if (ret == BaseAction::ABORT) {
ok_plan = false;
} else if (ret == BaseAction::OK)
std::cout
<< "exec: complete "
<< i << " "
<< planner.path[i]
->get_name()
<< std::endl;
}
e.modified<Plan>();
if (!ok_plan) {
std::cout << e.name()
<< ": invalidate plan"
<< " step: " << i
<< std::endl;
for (i = 0; i < len; i++)
planner.path[i]->stop(bb);
e.remove<Plan>();
}
}
});
}
}