Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
WarSceneAI.cpp
Go to the documentation of this file.
1
2
3#include "Headers/WarScene.h"
5
18
19namespace Divide {
20
21namespace {
22 bool g_navMeshStarted = false;
23}
24
25void WarScene::printMessage(const U8 eventId, const string& unitName) const {
26 string eventName;
27 switch (eventId) {
28 case 0:
29 eventName = "Captured flag";
30 break;
31 case 1:
32 eventName = "Recovered flag";
33 break;
34 default:
35 eventName = "Unknown!";
36 break;
37 }
38
39 U32 elapsedTimeMinutes = Time::MicrosecondsToSeconds<U32>(_elapsedGameTime) / 60 % 60;
40 U32 elapsedTimeSeconds = Time::MicrosecondsToSeconds<U32>(_elapsedGameTime) % 60;
41
42 Console::d_printfn(Util::StringFormat("[GAME TIME: {}:{}][{}]: {}", elapsedTimeMinutes, elapsedTimeSeconds, eventName.c_str(), unitName.c_str()).c_str());
43}
44
45void WarScene::checkGameCompletion() {
46 bool restartGame = false;
47 bool timeReason = false;
51 if (_scoreLimit == 3) {
52 _scoreLimit = 5;
54 restartGame = true;
55 } else if (_scoreLimit == 5) {
56 _scoreLimit = 20;
58 restartGame = true;
59 }
60 else if (_scoreLimit == 20) {
61 if (_runCount == 1) {
62 _scoreLimit = 3;
64 _runCount = 2;
65 restartGame = true;
66 } else if (_runCount == 2) {
67 _context.app().RequestShutdown(false);
68 }
69 }
70 }
71
72 const U32 elapsedTimeMinutes = Time::MicrosecondsToSeconds<U32>(_elapsedGameTime) / 60 % 60;
73 if (elapsedTimeMinutes >= _timeLimitMinutes) {
74 timeReason = true;
75 if (_timeLimitMinutes == 5) {
77 _scoreLimit = 5;
78 } else if (_timeLimitMinutes == 8) {
80 _scoreLimit = 20;
81 } else if (_timeLimitMinutes == 30) {
82 if (_runCount == 1) {
84 _scoreLimit = 3;
85 _runCount = 2;
86 }
87 else if (_runCount == 2) {
88 _context.app().RequestShutdown(false);
89 }
90 }
91 restartGame = true;
92 }
93
94 if (restartGame) {
96 Console::d_printfn(Util::StringFormat("\n\nRESTARTING GAME!. Reason: {} \n\n", timeReason ? "TIME" : "SCORE").c_str());
99 if (timeReason) {
100 _resetUnits = true;
101 for (U8 i = 0; i < 2; ++i) {
103 flagtComp->popTransforms();
104 _flag[i]->setParent(_sceneGraph->getRoot());
105 flagtComp->setPosition(vec3<F32>(25.0f, 0.1f, i == 0 ? -206.0f : 206.0f));
106 }
109 }
110 }
111}
112
113void WarScene::registerPoint(const U16 teamID, const string& unitName) {
114 if (!_resetUnits)
115 {
116 _resetUnits = true;
117
118 for (U8 i = 0; i < 2; ++i) {
119 if ( _flag[i] != nullptr )
120 {
122 WAIT_FOR_CONDITION(!flagtComp->popTransforms());
123 _flag[i]->setParent(_sceneGraph->getRoot());
124 flagtComp->setPosition(vec3<F32>(25.0f, 0.1f, i == 0 ? -206.0f : 206.0f));
125 }
126 }
130
131 U32 elapsedTimeMinutes = Time::MicrosecondsToSeconds<U32>(_elapsedGameTime) / 60 % 60;
132 U32 elapsedTimeSeconds = Time::MicrosecondsToSeconds<U32>(_elapsedGameTime) % 60;
133 Console::d_printfn(Util::StringFormat("[GAME TIME: {}:{}][TEAM {} REGISTER POINT]: {}", elapsedTimeMinutes, elapsedTimeSeconds, teamID == 0 ? "A" : "B", unitName.c_str()).c_str());
135 }
136}
137
138bool WarScene::initializeAI(bool /*continueOnErrors*/) {
139 //------------------------Artificial Intelligence------------------------//
140 // Create 2 AI teams
141 for (U8 i = 0; i < 2; ++i)
142 {
143 _faction[i] = _aiManager->registerTeam(i);
144 }
145 // Make the teams fight each other
146 _faction[0]->addEnemyTeam(_faction[1]->teamID());
147 _faction[1]->addEnemyTeam(_faction[0]->teamID());
148
149 //if (addUnits())
150 {
151 //_sceneGraph->findNode("Soldier1")->setActive(false);
152 //_sceneGraph->findNode("Soldier2")->setActive(false);
153 //_sceneGraph->findNode("Soldier3")->setActive(false);
154 return true;
155 }
156
157 //return false;
158}
159
160bool WarScene::removeUnits()
161{
162 WAIT_FOR_CONDITION(!_aiManager->updating());
163 for (U8 i = 0; i < 2; ++i)
164 {
165 for (SceneGraphNode* npc : _armyNPCs[i])
166 {
167 _aiManager->unregisterEntity(npc->get<UnitComponent>()->getUnit<NPC>()->getAIEntity());
168 _sceneGraph->removeNode(npc);
169 }
170 _armyNPCs[i].clear();
171 }
172
173 return true;
174}
175
176bool WarScene::addUnits() {
177 using namespace AI;
178
179 // Go near the enemy flag.
180 // The enemy flag will never be at the home base, because that is a scoring condition
181 WarSceneAction approachEnemyFlag(ActionType::APPROACH_ENEMY_FLAG, "ApproachEnemyFlag");
182 approachEnemyFlag.setPrecondition(GOAPFact(Fact::NEAR_ENEMY_FLAG), GOAPValue(false));
183 approachEnemyFlag.setEffect(GOAPFact(Fact::NEAR_ENEMY_FLAG), GOAPValue(true));
184 approachEnemyFlag.setEffect(GOAPFact(Fact::AT_HOME_BASE), GOAPValue(false));
185
186 WarSceneAction protectFlagInBase(ActionType::APPROACH_ENEMY_FLAG, "ProtectFlagInBase");
187 protectFlagInBase.setPrecondition(GOAPFact(Fact::NEAR_ENEMY_FLAG), GOAPValue(false));
188 protectFlagInBase.setPrecondition(GOAPFact(Fact::AT_HOME_BASE), GOAPValue(true));
189 protectFlagInBase.setEffect(GOAPFact(Fact::NEAR_ENEMY_FLAG), GOAPValue(true));
190
191 // Grab the enemy flag only if we do not already have it and if we are near it
192 // The enemy flag will never be at the home base, because that is a scoring condition
193 WarSceneAction captureEnemyFlag(ActionType::CAPTURE_ENEMY_FLAG, "CaptureEnemyFlag");
194 captureEnemyFlag.setPrecondition(GOAPFact(Fact::NEAR_ENEMY_FLAG), GOAPValue(true));
195 captureEnemyFlag.setPrecondition(GOAPFact(Fact::HAS_ENEMY_FLAG), GOAPValue(false));
196 captureEnemyFlag.setPrecondition(GOAPFact(Fact::AT_HOME_BASE), GOAPValue(false));
197 captureEnemyFlag.setEffect(GOAPFact(Fact::HAS_ENEMY_FLAG), GOAPValue(true));
198
199 // Kill the enemy flag carrier to recover our own flag and return it to base
200 WarSceneAction recoverFlag(ActionType::RECOVER_FLAG, "RecoverFlag");
201 recoverFlag.setPrecondition(GOAPFact(Fact::ENEMY_HAS_FLAG), GOAPValue(true));
202 recoverFlag.setPrecondition(GOAPFact(Fact::ENEMY_DEAD), GOAPValue(true));
203 recoverFlag.setEffect(GOAPFact(Fact::ENEMY_HAS_FLAG), GOAPValue(false));
204
205 // A general purpose "go home" action
206 WarSceneAction returnToBase(ActionType::RETURN_TO_BASE, "ReturnToBase");
207 returnToBase.setPrecondition(GOAPFact(Fact::AT_HOME_BASE), GOAPValue(false));
208 returnToBase.setEffect(GOAPFact(Fact::AT_HOME_BASE), GOAPValue(true));
209
210 // We can only score if we and both flags are in the same base location
211 WarSceneAction scoreEnemyFlag(ActionType::SCORE_FLAG, "ScoreEnemyFlag");
212 scoreEnemyFlag.setPrecondition(GOAPFact(Fact::AT_HOME_BASE), GOAPValue(true));
213 scoreEnemyFlag.setPrecondition(GOAPFact(Fact::HAS_ENEMY_FLAG), GOAPValue(true));
214 scoreEnemyFlag.setPrecondition(GOAPFact(Fact::ENEMY_HAS_FLAG), GOAPValue(false));
215 scoreEnemyFlag.setEffect(GOAPFact(Fact::HAS_ENEMY_FLAG), GOAPValue(false));
216
217 // Do nothing, but do nothing at home
218 WarSceneAction idleAction(ActionType::IDLE, "Idle");
219 idleAction.setPrecondition(GOAPFact(Fact::AT_HOME_BASE), GOAPValue(true));
220 idleAction.setEffect(GOAPFact(Fact::IDLING), GOAPFact(true));
221
222 // Kill stuff in lack of a better occupation
223 WarSceneAction attackAction(ActionType::ATTACK_ENEMY, "Attack");
224 attackAction.setPrecondition(GOAPFact(Fact::ENEMY_DEAD), GOAPValue(false));
225 attackAction.setEffect(GOAPFact(Fact::ENEMY_DEAD), GOAPValue(true));
226
227 GOAPGoal recoverOwnFlag("Recover flag", to_base(WarSceneOrder::WarOrder::RECOVER_FLAG));
228 recoverOwnFlag.setVariable(GOAPFact(Fact::ENEMY_HAS_FLAG), GOAPValue(false));
229
230 GOAPGoal captureFlag("Capture enemy flag", to_base(WarSceneOrder::WarOrder::CAPTURE_ENEMY_FLAG));
231 captureFlag.setVariable(GOAPFact(Fact::HAS_ENEMY_FLAG), GOAPValue(true));
232 captureFlag.setVariable(GOAPFact(Fact::AT_HOME_BASE), GOAPValue(true));
233
234 GOAPGoal scoreFlag("Score", to_base(WarSceneOrder::WarOrder::SCORE_ENEMY_FLAG));
235 scoreFlag.setVariable(GOAPFact(Fact::HAS_ENEMY_FLAG), GOAPValue(false));
236
237 GOAPGoal idle("Idle", to_base(WarSceneOrder::WarOrder::IDLE));
238 idle.setVariable(GOAPFact(Fact::IDLING), GOAPValue(true));
239
240 GOAPGoal killEnemy("Kill", to_base(WarSceneOrder::WarOrder::KILL_ENEMY));
241 killEnemy.setVariable(GOAPFact(Fact::ENEMY_DEAD), GOAPValue(true));
242
243 GOAPGoal protectFlagCarrier("Protect Flag Carrier", to_base(WarSceneOrder::WarOrder::PROTECT_FLAG_CARRIER));
244 protectFlagCarrier.setVariable(GOAPFact(Fact::NEAR_ENEMY_FLAG), GOAPValue(true));
245
246 std::array<GOAPPackage, to_base(WarSceneAIProcessor::AIType::COUNT)> goapPackages;
247 for (GOAPPackage& goapPackage : goapPackages) {
248 goapPackage._worldState.setVariable(GOAPFact(Fact::AT_HOME_BASE), GOAPValue(true));
249 goapPackage._worldState.setVariable(GOAPFact(Fact::ENEMY_DEAD), GOAPValue(false));
250 goapPackage._worldState.setVariable(GOAPFact(Fact::ENEMY_HAS_FLAG), GOAPValue(false));
251 goapPackage._worldState.setVariable(GOAPFact(Fact::HAS_ENEMY_FLAG), GOAPValue(false));
252 goapPackage._worldState.setVariable(GOAPFact(Fact::IDLING), GOAPValue(true));
253 goapPackage._worldState.setVariable(GOAPFact(Fact::NEAR_ENEMY_FLAG), GOAPValue(false));
254
255 goapPackage._actionSet.push_back(idleAction);
256 goapPackage._actionSet.push_back(attackAction);
257 goapPackage._actionSet.push_back(recoverFlag);
258 goapPackage._actionSet.push_back(protectFlagInBase);
259 goapPackage._goalList.push_back(idle);
260 goapPackage._goalList.push_back(killEnemy);
261 goapPackage._goalList.push_back(recoverOwnFlag);
262 }
263
264 GOAPPackage& lightPackage = goapPackages[to_base(WarSceneAIProcessor::AIType::LIGHT)];
265 GOAPPackage& heavyPackage = goapPackages[to_base(WarSceneAIProcessor::AIType::HEAVY)];
266
267 heavyPackage._actionSet.push_back(approachEnemyFlag);
268 heavyPackage._actionSet.push_back(captureEnemyFlag);
269 heavyPackage._actionSet.push_back(returnToBase);
270 heavyPackage._actionSet.push_back(scoreEnemyFlag);
271 lightPackage._actionSet.push_back(approachEnemyFlag);
272
273 heavyPackage._goalList.push_back(captureFlag);
274 heavyPackage._goalList.push_back(scoreFlag);
275 heavyPackage._goalList.push_back(protectFlagCarrier);
276 lightPackage._goalList.push_back(protectFlagCarrier);
277
278#if 1
279 SceneGraphNode* lightNode(_sceneGraph->findNode("Soldier1"));
280 SceneGraphNode* animalNode(_sceneGraph->findNode("Soldier2"));
281 SceneGraphNode* heavyNode(_sceneGraph->findNode("Soldier3"));
282
283 const SceneNodeHandle lightNodeMesh = lightNode->handle();
284 const SceneNodeHandle animalNodeMesh = animalNode->handle();
285 const SceneNodeHandle heavyNodeMesh = heavyNode->handle();
286
287 AIEntity* aiSoldier = nullptr;
288
289 vec3<F32> currentScale;
290 string currentName;
291
292 constexpr U32 normalMask = to_base(ComponentType::NAVIGATION) |
300
301 SceneGraphNode* root = _sceneGraph->getRoot();
302 for (I32 k = 0; k < 2; ++k)
303 {
304 for (I32 i = 0; i < 15; ++i)
305 {
306 F32 speed = Metric::Base(-1.0f);
307 F32 acc = Metric::Base(-1.0f);
308
309 F32 zFactor = 0.0f;
310 I32 damage = 5;
312
313 SceneGraphNodeDescriptor npcNodeDescriptor;
314 npcNodeDescriptor._serialize = false;
315 if (IS_IN_RANGE_INCLUSIVE(i, 0, 4))
316 {
317 npcNodeDescriptor._nodeHandle = lightNodeMesh;
318 currentScale = lightNode->get<TransformComponent>()->getWorldScale();
319 Util::StringFormat( currentName, "Soldier_1_{}_{}", k, i );
320 speed = Metric::Base(Random(6.5f, 9.5f));
321 acc = Metric::Base(Random(4.5f, 8.0f));
323 }
324 else if (IS_IN_RANGE_INCLUSIVE(i, 5, 9))
325 {
326 npcNodeDescriptor._nodeHandle = animalNodeMesh;
327 currentScale = animalNode->get<TransformComponent>()->getWorldScale();
328 Util::StringFormat( currentName, "Soldier_2_{}_{}", k, i % 5 );
329 speed = Metric::Base(Random(8.5f, 11.5f));
330 acc = Metric::Base(Random(6.0f, 9.0f));
331 zFactor = 1.0f;
333 damage = 10;
334 }
335 else
336 {
337 npcNodeDescriptor._nodeHandle = heavyNodeMesh;
338 currentScale = heavyNode->get<TransformComponent>()->getWorldScale();
339 Util::StringFormat( currentName, "Soldier_3_{}_{}", k, i % 10 );
340 speed = Metric::Base(Random(4.5f, 7.5f));
341 acc = Metric::Base(Random(4.0f, 6.5f));
342 zFactor = 2.0f;
344 damage = 15;
345 }
346
348 npcNodeDescriptor._componentMask = normalMask | to_base(ComponentType::SELECTION);
349 npcNodeDescriptor._name = currentName;
350
351 SceneGraphNode* currentNode = root->addChildNode(npcNodeDescriptor);
352
353 currentNode->get<RigidBodyComponent>()->physicsCollisionGroup(PhysicsGroup::GROUP_KINEMATIC);
354
355 TransformComponent* tComp = currentNode->get<TransformComponent>();
356 tComp->setScale(currentScale);
357
358 if (k == 0)
359 {
360 zFactor *= -25;
361 zFactor -= 200;
362 tComp->translateX(Metric::Base(-25.0f));
363 }
364 else
365 {
366 zFactor *= 25;
367 zFactor += 200;
368 tComp->rotateY(Angle::DEGREES<F32>(180.0f));
369 tComp->translateX(Metric::Base(100.0f));
370 tComp->translateX(Metric::Base(25.0f));
371 }
372
373 tComp->setPosition(vec3<F32>(Metric::Base(-125.0f + 25 * (i % 5)),
374 Metric::Base(-0.01f),
375 Metric::Base(zFactor)));
376
377 std::shared_ptr<NPC> soldier = std::make_shared<NPC>( tComp->getWorldPosition(), currentNode->name() );
378 soldier->setAttribute(to_base(AI::UnitAttributes::HEALTH_POINTS), 100);
379 soldier->setAttribute(to_base(AI::UnitAttributes::DAMAGE), damage);
380 soldier->setAttribute(to_base(AI::UnitAttributes::ALIVE_FLAG), 1);
381 soldier->setMovementSpeed(speed);
382 soldier->setAcceleration(acc);
383
384 aiSoldier = soldier->getAIEntity();
385 if (!aiSoldier->addSensor( AI::SensorType::VISUAL_SENSOR ))
386 {
388 }
389
390 AI::WarSceneAIProcessor* brain = new AI::WarSceneAIProcessor( type, *_aiManager );
391 // GOAP
392 brain->registerGOAPPackage( goapPackages[to_U32( type )] );
393 if (!aiSoldier->setAndSurrenderAIProcessor( brain ))
394 {
396 }
397
398 currentNode->get<UnitComponent>()->setUnit(soldier);
399 _armyNPCs[k].push_back(currentNode);
400 _aiManager->registerEntity(k, aiSoldier);
401
402 }
403 }
404
405 //----------------------- AI controlled units ---------------------//
406 return !(_armyNPCs[0].empty() || _armyNPCs[1].empty());
407#else
408 return true;
409#endif
410}
411
412AI::AIEntity* WarScene::findAI(SceneGraphNode* node) {
413 const I64 targetGUID = node->getGUID();
414
415 for (U8 i = 0; i < 2; ++i) {
416 for (SceneGraphNode* npc : _armyNPCs[i]) {
417 if (npc->getGUID() == targetGUID) {
418 return npc->get<UnitComponent>()->getUnit<NPC>()->getAIEntity();
419 }
420 }
421 }
422
423 return nullptr;
424}
425
426bool WarScene::resetUnits() {
427 _aiManager->pauseUpdate(true);
428 bool state = false;
429 if (removeUnits()) {
430 state = addUnits();
431 }
432 _aiManager->pauseUpdate(false);
433 return state;
434}
435
436bool WarScene::deinitializeAI(bool /*continueOnErrors*/) {
437 _aiManager->pauseUpdate(true);
438 if (removeUnits())
439 {
440 for (U8 i = 0; i < 2; ++i)
441 {
442 if (_aiManager->unregisterTeam(i))
443 {
444 _faction[i] = nullptr;
445 }
446 else
447 {
449 }
450 }
451 return true;
452 }
453
454 return false;
455}
456
457void WarScene::startSimulation(I64 /*btnGUID*/)
458{
459 if (g_navMeshStarted || _armyNPCs[0].empty()) {
460 return;
461 }
462
463 g_navMeshStarted = true;
464
465 _aiManager->pauseUpdate(true);
466 _infoBox->setTitle("NavMesh state");
468 bool previousMesh = false;
469 bool loadedFromFile = true;
470 const U64 currentTime = Time::App::ElapsedMicroseconds();
471 const U64 diffTime = currentTime - _lastNavMeshBuildTime;
472
473 AI::AIEntity* aiEntity = _armyNPCs[0][0]->get<UnitComponent>()->getUnit<NPC>()->getAIEntity();
474
475 if (_lastNavMeshBuildTime == 0UL || diffTime > Time::SecondsToMicroseconds(10))
476 {
478
479 AI::Navigation::NavigationMesh* navMesh = _aiManager->getNavMesh(radius);
480 if (navMesh)
481 {
482 previousMesh = true;
483 _aiManager->destroyNavMesh( radius );
484 }
485
486 navMesh = _aiManager->addNavMesh(_context, *_parent.parent().recast(), *this, radius);
487 navMesh->setFileName(resourceName());
488
489 if (!navMesh->load(_sceneGraph->getRoot()))
490 {
491 loadedFromFile = false;
492 navMesh->build(_sceneGraph->getRoot(),
494 {
495 _aiManager->toggleNavMeshDebugDraw(true);
496 g_navMeshStarted = false;
497 });
498 }
499 else
500 {
502 {
503 navMesh->debugDraw(true);
504 }
505 }
506
507 if (previousMesh) {
508 if (loadedFromFile) {
510 "Re-loaded the navigation mesh from file!");
511 }
512 else {
514 "Re-building the navigation mesh in a background thread!");
515 }
516 }
517 else {
518 if (loadedFromFile) {
519 _infoBox->setMessage("Navigation mesh loaded from file!");
520 }
521 else {
523 "Navigation mesh building in a background thread!");
524 }
525 }
526 //_infoBox->show();
527 _lastNavMeshBuildTime = currentTime;
528 for (U8 i = 0; i < 2; ++i) {
529 _faction[i]->clearOrders();
530 _faction[i]->addOrder(std::make_shared<AI::WarSceneOrder>(
532 _faction[i]->addOrder(std::make_shared<AI::WarSceneOrder>(
534 _faction[i]->addOrder(std::make_shared<AI::WarSceneOrder>(
536 _faction[i]->addOrder(std::make_shared<AI::WarSceneOrder>(
538 _faction[i]->addOrder(std::make_shared<AI::WarSceneOrder>(
540 _faction[i]->addOrder(std::make_shared<AI::WarSceneOrder>(
542 }
543 } else {
544 string info(
545 "Can't reload the navigation mesh this soon.\n Please wait \\[ ");
546 info.append(
547 Util::to_string(Time::MicrosecondsToSeconds<I32>(diffTime)));
548 info.append(" ] seconds more!");
549
550 _infoBox->setMessage(info);
552 _infoBox->show();
553 }
554
555 _aiManager->pauseUpdate(false);
556}
557
558} // namespace Divide
#define WAIT_FOR_CONDITION(...)
#define DIVIDE_UNEXPECTED_CALL()
Based on OgreCrowd.
Definition: AIEntity.h:60
bool setAndSurrenderAIProcessor(AIProcessor *processor)
Definition: AIEntity.cpp:139
bool addSensor(SensorType type)
Definition: AIEntity.cpp:117
PresetAgentRadius getAgentRadiusCategory() const noexcept
The radius category of this character.
Definition: AIEntity.h:105
void addOrder(const OrderPtr &order)
Definition: AITeam.h:110
void clearOrders()
Definition: AITeam.h:105
bool addEnemyTeam(U32 enemyTeamID)
Definition: AITeam.cpp:192
bool build(SceneGraphNode *sgn, CreationCallback creationCompleteCallback, bool threaded=true)
Definition: NavMesh.cpp:174
void debugDraw(const bool state) noexcept
Definition: NavMesh.h:143
void setFileName(const Str< 256 > &fileName)
Definition: NavMesh.h:128
bool load(const SceneGraphNode *sgn)
Load a saved NavigationMesh from a file.
Definition: NavMesh.cpp:701
void registerGOAPPackage(const GOAPPackage &package)
static U8 getScore(const U16 teamID)
static void resetScore(const U8 teamID)
static void registerFlags(SceneGraphNode *flag1, SceneGraphNode *flag2)
static void incrementScore(const U16 teamID)
FORCE_INLINE I64 getGUID() const noexcept
Definition: GUIDWrapper.h:51
void setMessage(const string &message)
void show() noexcept
Definition: GUIMessageBox.h:66
void setTitle(const string &titleText)
void setMessageType(MessageType type)
void translateX(F32 positionX)
Translate the object on the X axis by the specified amount.
NPC base class. Every character in the game is an NPC by default except the Player.
Definition: NPC.h:46
AI::AIEntity * getAIEntity() const noexcept
Definition: NPC.cpp:20
FORCE_INLINE SceneNodeHandle handle() const noexcept
void setParent(SceneGraphNode *parent, bool defer=false)
Changing a node's parent means removing this node from the current parent's child list and appending ...
SceneGraphNode * addChildNode(const SceneGraphNodeDescriptor &descriptor)
Add child node increments the node's ref counter if the node was already added to the scene graph.
FORCE_INLINE T * get() const
Returns a pointer to a specific component. Returns null if the SGN does not have the component reques...
void setPosition(const vec3< F32 > &position) override
Component <-> Transform interface.
void rotateY(Angle::DEGREES< F32 > angle) override
Rotate on the Y axis (Axis-Angle used) by the specified angle (either degrees or radians)
void setScale(const vec3< F32 > &amount) override
Set the local X,Y and Z scale factors.
vec3< F32 > getWorldPosition() const
Return the position.
std::shared_ptr< T > getUnit() const noexcept
Definition: UnitComponent.h:49
void setPrecondition(const I32 key, const bool value)
Definition: Action.h:59
void setEffect(const I32 key, const bool value)
Definition: Action.h:66
bool GOAPValue
Definition: GOAPInterface.h:46
constexpr bool IS_DEBUG_BUILD
Definition: config.h:55
constexpr T Base(T a)
Base value.
Definition: MathHelper.inl:503
U64 ElapsedMicroseconds() noexcept
constexpr T SecondsToMicroseconds(U a) noexcept
Definition: MathHelper.inl:767
Str StringFormat(const char *fmt, Args &&...args)
string to_string(GET_PASS_TYPE< T > value)
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
constexpr U32 to_U32(const T value)
AI::AITeam * _faction[2]
Teams are factions for AIEntites so they can manage friend/foe situations.
Definition: WarScene.h:100
U64 _lastNavMeshBuildTime
Definition: WarScene.h:92
U64 _elapsedGameTime
Definition: WarScene.h:88
bool IS_IN_RANGE_INCLUSIVE(const T x, const U min, const U max) noexcept
bool removeUnits()
Definition: WarSceneAI.cpp:160
int32_t I32
uint8_t U8
bool addUnits()
Definition: WarSceneAI.cpp:176
vector< SceneGraphNode * > _armyNPCs[2]
NPC's are the actual game entities.
Definition: WarScene.h:94
T Random()
Definition: MathHelper.inl:95
U32 _scoreLimit
Definition: WarScene.h:86
uint16_t U16
U32 _runCount
Definition: WarScene.h:87
SceneGraphNode * _flag[2]
Definition: WarScene.h:96
bool _resetUnits
Definition: WarScene.h:90
U32 _timeLimitMinutes
Definition: WarScene.h:85
GUIMessageBox * _infoBox
Definition: WarScene.h:81
void checkGameCompletion()
Definition: WarSceneAI.cpp:45
int64_t I64
uint32_t U32
uint64_t U64
constexpr auto to_base(const Type value) -> Type
vector< WarSceneAction > _actionSet
static NO_INLINE void d_printfn(const char *format, T &&... args)
void setVariable(const int var_id, const bool value)
Definition: WorldState.cpp:15