1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "ai_bot_npc.h"
20 #include "ai_grp_npc.h"
21 #include "ai_mgr_npc.h"
22 #include "ai_grp_fauna.h"
24 #include "ai_bot_fauna.h"
27 #include "path_behaviors.h"
29 #include "ai_player.h"
30 #include "ai_generic_fight.h"
31 #include "ai_profile_npc.h"
32 #include "group_profile.h"
34 extern bool simulateBug(int bugId
);
36 #include "dyn_grp_inline.h"
39 using namespace RYAI_MAP_CRUNCH
;
40 using namespace NLMISC
;
41 using namespace NLNET
;
42 using namespace AITYPES
;
44 // Global configuration variables
45 extern CVariable
<int> DefaultWanderMinTimer
;
46 extern CVariable
<int> DefaultWanderMaxTimer
;
47 extern CVariable
<sint32
> FameForGuardAttack
;
48 extern CVariable
<sint32
> FameForGuardHelp
;
50 // Stuff used for management of log messages
51 bool ai_profile_npc_VerboseLog
= false;
53 void ai_profile_npc_LOG(std::string
const& type
, std::string
const& profile
, std::string
const& step
, std::string
const& object
)
55 static size_t maxType
= 0;
56 static size_t maxProfile
= 0;
57 static size_t maxStep
= 0;
58 static size_t maxObject
= 0;
59 if (ai_profile_npc_VerboseLog
)
61 maxType
= std::max(maxType
, type
.length());
62 maxProfile
= std::max(maxProfile
, profile
.length());
63 maxStep
= std::max(maxStep
, step
.length());
64 maxObject
= std::max(maxObject
, object
.length());
65 std::string log
= "profile";
66 log
+= " " + type
+ std::string(maxType
- type
.length(), ' ');
67 log
+= " " + profile
+ std::string(maxProfile
- profile
.length(), ' ');
68 log
+= " " + step
+ std::string(maxStep
- step
.length(), ' ');
69 log
+= " " + object
+ std::string(maxObject
- object
.length(), ' ');
70 nlinfo("%s", log
.c_str());
73 #define PROFILE_LOG(type,profile,step,object) ai_profile_npc_LOG(type,profile,step,object)
75 #define LOG if (!ai_profile_npc_VerboseLog) {} else nlinfo
77 NLMISC_COMMAND(verboseAIProfiles
,"Turn on or off or check the state of verbose ai profile info logging","")
83 StrToBool (ai_profile_npc_VerboseLog
, args
[0]);
85 nlinfo("VerboseLogging is %s",ai_profile_npc_VerboseLog
?"ON":"OFF");
89 /****************************************************************************/
91 /****************************************************************************/
93 //////////////////////////////////////////////////////////////////////////////
94 // CBotProfileFightNpc //
95 //////////////////////////////////////////////////////////////////////////////
97 class CBotProfileFightNpc
98 : public CBotProfileFight
101 CBotProfileFightNpc(CProfileOwner
* owner
, CAIEntityPhysical
* ennemy
);
102 virtual ~CBotProfileFightNpc();
104 virtual std::string
getOneLineInfoString() const { return "fight npc bot profile"; }
108 void eventBeginFight();
109 void eventTargetKilled();
112 //////////////////////////////////////////////////////////////////////////////
113 // CBotProfileHealNpc //
114 //////////////////////////////////////////////////////////////////////////////
116 class CBotProfileHealNpc
117 : public CBotProfileHeal
118 , public IAIEntityPhysicalHealer
121 CBotProfileHealNpc(CAIEntityPhysical
* target
, CProfileOwner
* owner
);
122 virtual ~CBotProfileHealNpc();
124 virtual std::string
getOneLineInfoString() const { return "heal npc bot profile"; }
128 virtual void healerAdded(CAIEntityPhysical
* entity
);
129 virtual void healerRemoved(CAIEntityPhysical
* entity
);
131 // void eventBeginFight();
132 // void eventTargetKilled();
134 CAIEntityPhysical
* _Target
;
137 //////////////////////////////////////////////////////////////////////////////
138 // CBotProfileReturnAfterFightNpc //
139 //////////////////////////////////////////////////////////////////////////////
141 class CBotProfileReturnAfterFightNpc
142 : public CBotProfileReturnAfterFight
145 CBotProfileReturnAfterFightNpc(CSpawnBotNpc
* owner
);
146 ~CBotProfileReturnAfterFightNpc();
147 virtual void beginProfile();
148 virtual void endProfile();
149 virtual void updateProfile(uint ticksSinceLastUpdate
);
150 virtual std::string
getOneLineInfoString() const;
152 // virtual NLMISC::CSmartPtr<CMovementMagnet> const& getMovementMagnet() const { return _MovementMagnet; }
156 NLMISC::CSmartPtr
<CBotProfileFollowPos
> _MoveProfile
;
159 //////////////////////////////////////////////////////////////////////////////
160 // CGrpProfileTribu //
161 //////////////////////////////////////////////////////////////////////////////
163 class CGrpProfileTribu
: public CGrpProfileNormal
166 CGrpProfileTribu(CProfileOwner
*owner
);
167 virtual ~CGrpProfileTribu();
169 virtual void beginProfile();
170 virtual void endProfile();
171 virtual void updateProfile(uint ticksSinceLastUpdate
);
173 virtual std::string
getOneLineInfoString() const;
175 virtual TProfiles
getAIProfileType() const { return ACTIVITY_TRIBU
; }
178 CAIVector _CenterPos
;
181 //////////////////////////////////////////////////////////////////////////////
182 // CGrpProfileStandOnVertices //
183 //////////////////////////////////////////////////////////////////////////////
185 class CGrpProfileStandAtStartPoint
186 : public CMoveProfile
189 CGrpProfileStandAtStartPoint(CProfileOwner
* owner
);
190 virtual ~CGrpProfileStandAtStartPoint();
192 class CBotPositionner
: public CRefCount
195 CBotPositionner(RYAI_MAP_CRUNCH::TAStarFlag flags
);
196 CBotPositionner(TVerticalPos verticalPos
, CAIPos position
, RYAI_MAP_CRUNCH::TAStarFlag flag
);
197 virtual ~CBotPositionner();
198 void setBotAtDest(bool atDest
= true);
199 bool isBotAtDest() const;
203 TVerticalPos _VerticalPos
;
208 CPathCont
* getPathCont(CBot
const* bot
);
210 virtual void beginProfile();
211 void resumeProfile();
212 virtual void endProfile();
213 virtual void updateProfile(uint ticksSinceLastUpdate
);
215 void addBot(CBot
* bot
);
216 void removeBot(CBot
* bot
);
218 void setCurrentValidPos();
220 virtual TProfiles
getAIProfileType() const { return MOVE_STAND_ON_VERTICES
; }
221 virtual std::string
getOneLineInfoString() const;
224 typedef std::map
<CBot
const*, CSmartPtr
<CBotPositionner
> > TNpcBotPositionnerMap
;
226 TNpcBotPositionnerMap _NpcList
;
230 /****************************************************************************/
231 /* Local profile factories */
232 /****************************************************************************/
234 //- Simple profile factories (based on generic factory) ----------------------
236 // CGrpProfileFightFactory
237 typedef CAIGenericProfileFactory
<CGrpProfileFight
> CGrpProfileFightFactory
;
239 // CGrpProfileTribuFactory
240 typedef CAIGenericProfileFactory
<CGrpProfileTribu
> CGrpProfileTribuFactory
;
242 // CGrpProfileIdleFactory
243 typedef CAIGenericProfileFactory
<CGrpProfileIdle
> CGrpProfileIdleFactory
;
245 // CGrpProfileStandAtStartPointFactory
246 typedef CAIGenericProfileFactory
<CGrpProfileStandAtStartPoint
> CGrpProfileStandAtStartPointFactory
;
248 //- Singleton profiles (stateless ones) --------------------------------------
249 extern CGrpProfileFightFactory GrpProfileFightFactory
;
251 /****************************************************************************/
252 /* Implementations */
253 /****************************************************************************/
255 //////////////////////////////////////////////////////////////////////////////
257 //////////////////////////////////////////////////////////////////////////////
259 void CSpawnGroupNpc::botHaveDied(CBotNpc
* bot
)
261 // check bot profile type and update group profile bot list.
262 if (fightProfile().getAIProfile())
264 CSlaveProfile
* const profile
= NLMISC::type_cast
<CSlaveProfile
*>(fightProfile().getAIProfile());
266 profile
->removeBot(bot
);
268 if (movingProfile().getAIProfile())
270 CSlaveProfile
* const profile
= NLMISC::type_cast
<CSlaveProfile
*>(movingProfile().getAIProfile());
272 profile
->removeBot(bot
);
276 CSpawnBotNpc
* const spawn
= bot
->getSpawn();
278 spawn
->setAIProfile(BotProfileStandAtPosFactory
.createAIProfile(spawn
));
282 void CSpawnGroupNpc::botHaveDespawn(CBotNpc
* bot
)
284 CSpawnGroupNpc::botHaveDied(bot
);
287 void CSpawnGroupNpc::botHaveSpawn(CBotNpc
* bot
)
289 if (movingProfile().getAIProfile())
291 NLMISC::safe_cast
<CSlaveProfile
*>(movingProfile().getAIProfile())->addBot(bot
);
293 if (fightProfile().getAIProfile())
295 NLMISC::safe_cast
<CSlaveProfile
*>(fightProfile().getAIProfile())->addBot(bot
);
299 //////////////////////////////////////////////////////////////////////////////
300 // CBotProfileFightNpc //
301 //////////////////////////////////////////////////////////////////////////////
303 CBotProfileFightNpc::CBotProfileFightNpc(CProfileOwner
* owner
, CAIEntityPhysical
* ennemy
)
304 : CBotProfileFight(owner
, ennemy
)
306 PROFILE_LOG("bot", "fight_npc", "ctor", "");
309 CBotProfileFightNpc::~CBotProfileFightNpc()
311 PROFILE_LOG("bot", "fight_npc", "dtor", "");
314 void CBotProfileFightNpc::noMoreTarget()
316 _Bot
->setAIProfile(BotProfileStandAtPosFactory
.createAIProfile(_Bot
.ptr()));
319 void CBotProfileFightNpc::eventBeginFight()
322 CSpawnBotNpc
* spawnable
= NLMISC::safe_cast
<CSpawnBotNpc
*>(_Bot
.ptr());
323 CGroupNpc
* grpNpc
= static_cast<CGroupNpc
*>(spawnable
->getPersistent().getOwner());
324 grpNpc
->processStateEvent(grpNpc
->getEventContainer().EventBotBeginFight
);
327 void CBotProfileFightNpc::eventTargetKilled()
330 CSpawnBotNpc
* spawnable
= NLMISC::safe_cast
<CSpawnBotNpc
*>(_Bot
.ptr());
331 CGroupNpc
* grpNpc
= static_cast<CGroupNpc
*>(spawnable
->getPersistent().getOwner());
332 grpNpc
->processStateEvent(grpNpc
->getEventContainer().EventBotTargetKilled
);
336 //////////////////////////////////////////////////////////////////////////////
337 // CBotProfileHealNpc //
338 //////////////////////////////////////////////////////////////////////////////
340 CBotProfileHealNpc::CBotProfileHealNpc(CAIEntityPhysical
* target
, CProfileOwner
* owner
)
341 : CBotProfileHeal(target
->dataSetRow(), owner
)
344 PROFILE_LOG("bot", "heal_npc", "ctor", "");
346 _Target
->addHealer(this);
349 CBotProfileHealNpc::~CBotProfileHealNpc()
351 PROFILE_LOG("bot", "heal_npc", "dtor", "");
353 _Target
->delHealer(this);
356 void CBotProfileHealNpc::healerAdded(CAIEntityPhysical
* entity
)
360 void CBotProfileHealNpc::healerRemoved(CAIEntityPhysical
* entity
)
362 if (_Target
== entity
)
366 void CBotProfileHealNpc::noMoreTarget()
368 _Bot
->setAIProfile(BotProfileStandAtPosFactory
.createAIProfile(_Bot
.ptr()));
371 //////////////////////////////////////////////////////////////////////////////
372 // CBotProfileReturnAfterFightNpc //
373 //////////////////////////////////////////////////////////////////////////////
375 CBotProfileReturnAfterFightNpc::CBotProfileReturnAfterFightNpc(CSpawnBotNpc
* owner
)
376 : CBotProfileReturnAfterFight(owner
)
377 , _PathCont(owner
->getPersistent().getOwner()->getAStarFlag())
379 PROFILE_LOG("bot_npc", "return_after_fight", "ctor", "");
380 // CSpawnBotNpc* bot = NLMISC::safe_cast<CSpawnBotNpc*>(owner);
381 // RYAI_MAP_CRUNCH::TAStarFlag denyFlags = bot->getAStarFlag();
382 _PathCont
.setDestination(owner
->getReturnPos());
383 _MoveProfile
= NLMISC::CSmartPtr
<CBotProfileFollowPos
>(new CBotProfileFollowPos(&_PathCont
, owner
));
386 CBotProfileReturnAfterFightNpc::~CBotProfileReturnAfterFightNpc()
388 PROFILE_LOG("bot_npc", "return_after_fight", "dtor", "");
391 void CBotProfileReturnAfterFightNpc::beginProfile()
393 PROFILE_LOG("bot_npc", "return_after_fight", "begin", "");
394 CBotProfileReturnAfterFight::beginProfile();
395 _Bot
->ignoreReturnAggro(true);
396 _MoveProfile
->beginProfile();
399 void CBotProfileReturnAfterFightNpc::endProfile()
401 PROFILE_LOG("bot_npc", "return_after_fight", "end", "");
402 _MoveProfile
->endProfile();
403 _Bot
->ignoreReturnAggro(false);
404 CBotProfileReturnAfterFight::endProfile();
407 void CBotProfileReturnAfterFightNpc::updateProfile(uint ticksSinceLastUpdate
)
409 H_AUTO(CBotProfileReturnAfterFightFaunaUpdate
);
410 CBotProfileReturnAfterFight::updateProfile(ticksSinceLastUpdate
);
411 _MoveProfile
->updateProfile(ticksSinceLastUpdate
);
414 std::string
CBotProfileReturnAfterFightNpc::getOneLineInfoString() const
416 std::string info
= "return_after_fight npc bot profile";
418 info
+= _MoveProfile
?_MoveProfile
->getOneLineInfoString():std::string("<no move profile>");
423 //////////////////////////////////////////////////////////////////////////////
424 // CGrpProfileFight //
425 //////////////////////////////////////////////////////////////////////////////
427 CGrpProfileFight::CGrpProfileFight(CProfileOwner
*owner
)
428 : CFightProfile(owner
)
432 PROFILE_LOG("group", "fight", "ctor", "");
435 CGrpProfileFight::~CGrpProfileFight()
437 PROFILE_LOG("group", "fight", "dtor", "");
438 for (CCont
<CBot
>::iterator it
=_Grp
->bots().begin(), itEnd
=_Grp
->bots().end();it
!=itEnd
;++it
)
445 void CGrpProfileFight::beginProfile()
447 PROFILE_LOG("group", "fight", "begin", "");
448 if (_Grp
->getPersistent().getGrpDynBase() != /*(CDynGrpBase*)*/NULL
449 && !_Grp
->getPersistent().getGrpDynBase()->getFamilyBehavior().isNULL())
451 // this is a dynamic bots groups, activate assist between groups
452 _CheckAround
.set(CHECK_AROUND_PERIOD
);
456 for (CCont
<CBot
>::iterator it
=_Grp
->getPersistent().bots().begin(), itEnd
=_Grp
->getPersistent().bots().end();it
!=itEnd
;++it
)
460 _WasRunning
= _Grp
->checkProfileParameter("running");
462 _Grp
->addProfileParameter("running", "", 0.f
);
465 void CGrpProfileFight::endProfile()
467 PROFILE_LOG("group", "fight", "end", "");
469 _Grp
->removeProfileParameter("running");
472 void CGrpProfileFight::addBot(CBot
* bot
)
474 vector
<CBot
*>::iterator it
= find(_NpcList
.begin(), _NpcList
.end(), bot
);
475 if (it
==_NpcList
.end())
476 _NpcList
.push_back(bot
);
479 void CGrpProfileFight::removeBot(CBot
* bot
)
481 vector
<CBot
*>::iterator it
= find(_NpcList
.begin(), _NpcList
.end(), bot
);
482 if (it
!=_NpcList
.end())
486 void CGrpProfileFight::setFight(CSpawnBot
* bot
, CAIEntityPhysical
* ennemy
)
488 bot
->setAIProfile(new CBotProfileFightNpc(bot
, ennemy
));
491 void CGrpProfileFight::setHeal(CSpawnBot
* bot
, CAIEntityPhysical
* target
)
493 bot
->setAIProfile(new CBotProfileHealNpc(target
, bot
));
496 void CGrpProfileFight::setNoFight(CSpawnBot
* bot
)
498 if (!bot
->getTarget().isNULL())
499 bot
->setTarget(NULL
);
500 if ( bot
->getAIProfileType()==BOT_FLEE
501 || bot
->getAIProfileType()==BOT_FIGHT
502 || bot
->getAIProfileType()==BOT_HEAL
503 || bot
->getAIProfileType()==BOT_RETURN_AFTER_FIGHT
)
505 bot
->setAIProfile(new CBotProfileStandAtPos(bot
));
509 void CGrpProfileFight::setFlee(CSpawnBot
* bot
, CAIVector
& fleeVect
)
511 bot
->setMoveDecalage(fleeVect
);
512 if (bot
->getAIProfileType()!=BOT_FLEE
)
514 bot
->setAIProfile(new CBotProfileFlee(bot
));
518 void CGrpProfileFight::setReturnAfterFight(CSpawnBot
* bot
)
520 if (bot
->getAIProfileType()!=BOT_RETURN_AFTER_FIGHT
)
522 bot
->setAIProfile(new CBotProfileReturnAfterFightNpc(NLMISC::safe_cast
<CSpawnBotNpc
*>(bot
)));
526 bool CGrpProfileFight::stillHaveEnnemy() const
531 void CGrpProfileFight::updateProfile(uint ticksSinceLastUpdate
)
533 H_AUTO(GrpFightProfileUpdate
);
534 CFollowPathContext
fpcGrpFightProfileUpdate("GrpFightProfileUpdate");
536 // check if some bots died or are despawned.
538 for(uint i
= 0; i
< _NpcList
.size();)
540 CSpawnBot
*spawnBot
=_NpcList
[i
]->getSpawnObj();
542 || !spawnBot
->isAlive())
544 _NpcList
.erase(_NpcList
.begin()+i
);
549 reorganize(_NpcList
.begin(), _NpcList
.end());
551 // check groups around
552 if (_CheckAround
.test())
554 _CheckAround
.set(CHECK_AROUND_PERIOD
);
556 FOREACH(itBot
, vector
<CBot
*>, _NpcList
)
561 CSpawnBot
* bot
= pBot
->getSpawnObj();
563 bot
->propagateAggro();
569 std::string
CGrpProfileFight::getOneLineInfoString() const
571 return "fight profile";
574 std::vector
<CBot
*>& CGrpProfileFight::npcList()
579 //////////////////////////////////////////////////////////////////////////////
580 // CGrpProfileNormal //
581 //////////////////////////////////////////////////////////////////////////////
583 void CGrpProfileNormal::beginProfile()
585 PROFILE_LOG("group", "normal", "begin", "");
586 _GroupFighting
=false;
589 void CGrpProfileNormal::endProfile()
591 PROFILE_LOG("group", "normal", "end", "");
592 setGroupFighting(false);
595 void CGrpProfileNormal::updateProfile(uint ticksSinceLastUpdate
)
597 H_AUTO(GrpNormalProfileUpdate
);
598 CFollowPathContext
fpcGrpNormalProfileUpdate("GrpNormalProfileUpdate");
602 if (!_Grp
->fightProfile().getAIProfile())
603 _Grp
->fightProfile().setAIProfile(new CGrpProfileFight(_Grp
));
605 _Grp
->fightProfile().mayUpdateProfile(ticksSinceLastUpdate
);
607 CFightProfile
* profile
= NLMISC::safe_cast
<CFightProfile
*>(_Grp
->fightProfile().getAIProfile());
608 if (!profile
->stillHaveEnnemy ())
610 // :TODO: Verify if it's needed to erase bots aggro too/instead
611 // _Grp->clearAggroList(); // this erase all agro.
613 setGroupFighting(false);
614 _Grp
->fightProfile().setAIProfile(NULL
);
616 CSlaveProfile
* moveProfile
= NLMISC::type_cast
<CSlaveProfile
*>(_Grp
->movingProfile().getAIProfile());
618 moveProfile
->resumeProfile();
623 if (_Grp
->haveAggroOrReturnPlace())
625 if(_Grp
->isGroupAlive())
627 // set the fighting comportment.
628 if (!_Grp
->fightProfile().getAIProfile())
629 // _Grp->fightProfile().setAIProfile(new CGrpProfileFight(_Grp));
630 _Grp
->fightProfile().setAIProfile(_Grp
.ptr(), &GrpProfileFightFactory
, false);
632 setGroupFighting(true);
637 _Grp
->movingProfile().mayUpdateProfile(ticksSinceLastUpdate
);
642 std::string
CGrpProfileNormal::getOneLineInfoString() const
644 std::string info
= "normal profile";
645 info
+= " group_fighting=" + NLMISC::toString(_GroupFighting
);
649 //////////////////////////////////////////////////////////////////////////////
650 // CGrpProfileBandit //
651 //////////////////////////////////////////////////////////////////////////////
653 CGrpProfileBandit::CGrpProfileBandit(CProfileOwner
*owner
)
654 : CGrpProfileNormal(owner
)
656 PROFILE_LOG("group", "bandit", "ctor", "");
659 CGrpProfileBandit::~CGrpProfileBandit()
661 PROFILE_LOG("group", "bandit", "dtor", "");
664 void CGrpProfileBandit::beginProfile()
666 PROFILE_LOG("group", "bandit", "begin", "");
667 CGrpProfileNormal::beginProfile();
670 CGroupNpc
&persGrp
=_Grp
->getPersistent();
672 if (persGrp
.isRingGrp())
674 _AggroRange
= persGrp
.getAggroDist();
678 // look for aggro range parameter or set a default value
679 float aggroRangeFloat
= 0.f
;
681 if (!_Grp
->getProfileParameter("aggro range", aggroRangeFloat
))
682 _AggroRange
=static_cast<uint32
>( CGrpProfileBanditFactory::getDefaultBanditAggroRange() );
684 _AggroRange
= static_cast<uint32
>(aggroRangeFloat
);
686 bool resendInfo
= false;
689 if (!persGrp
.getPlayerAttackable ())
691 persGrp
.setPlayerAttackable (true);
694 if (!persGrp
.getBotAttackable ())
696 persGrp
.setBotAttackable (true);
700 _Grp
->sendInfoToEGS ();
706 void CGrpProfileBandit::endProfile()
708 PROFILE_LOG("group", "bandit", "end", "");
709 CGrpProfileNormal::endProfile();
712 void CGrpProfileBandit::updateProfile(uint ticksSinceLastUpdate
)
714 H_AUTO(GrpBanditProfileUpdate
);
715 CFollowPathContext
fpcGrpBanditProfileUpdate("GrpBanditProfileUpdate");
717 CAIVision
<CPersistentOfPhysical
> BanditVision
;
722 if (!_Grp
->calcCenterPos(centerPos
)) // true if there's some bots in the group.
724 _Grp
->setCenterPos(centerPos
);
726 uint32 playerRadius
=_AggroRange
;
727 uint32 botRadius
=_AggroRange
;
728 uint32 groupPlayerRadius
=playerRadius
*2;
729 uint32 groupBotRadius
=botRadius
*2;
731 uint32 minRadius
=playerRadius
>botRadius
?botRadius
:playerRadius
;
733 CFightProfile
* fightProfile
=static_cast<CFightProfile
*>(_Grp
->fightProfile().getAIProfile());
737 CAIVision
<CPersistentOfPhysical
> localBanditVision
;
739 for (vector
<CBot
*>::iterator it
=fightProfile
->npcList().begin(), itEnd
=fightProfile
->npcList().end();it
!=itEnd
;++it
)
742 CSpawnBot
*spawnBot
=bot
->getSpawnObj();
747 double distToCenter
=centerPos
.quickDistTo(spawnBot
->pos());
748 if (distToCenter
>minRadius
) // (minRadius*2) - minRadius
750 const CAIVector
spawnBotPos(spawnBot
->pos());
751 // bot vision update.
752 localBanditVision
.updateBotsAndPlayers(spawnBot
->getAIInstance(), spawnBotPos
, playerRadius
, botRadius
);
754 // bandits don't like guards nor escorted people
756 const std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> > &bots
= localBanditVision
.bots();
757 std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >::const_iterator
first(bots
.begin()), last(bots
.end());
758 for (; first
!= last
; ++first
)
760 CAIEntityPhysical
*ep
= (*first
)->getSpawnObj();
762 && ep
->getRyzomType()==RYZOMID::npc
765 CSpawnBotNpc
*botNpc
= NLMISC::safe_cast
<CSpawnBotNpc
*>(ep
);
767 if ( botNpc
->spawnGrp().activityProfile().getAIProfileType() == ACTIVITY_GUARD
768 || botNpc
->spawnGrp().activityProfile().getAIProfileType() == ACTIVITY_GUARD_ESCORTED
769 || botNpc
->spawnGrp().activityProfile().getAIProfileType() == ACTIVITY_ESCORTED
)
771 spawnBot
->setAggroMinimumFor(ep
->dataSetRow(), 0.8f
, false);
777 // bandits don't like players.
779 const std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> > &players
= localBanditVision
.players();
780 std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >::const_iterator
first(players
.begin()), last(players
.end());
781 for (; first
!= last
; ++first
)
783 CPersistentOfPhysical
*player
= (*first
);
784 CAIEntityPhysical
*ep
= player
->getSpawnObj();
787 && ep
->currentHitPoints()>0.f
)
789 const CRootCell
*const rootCell
=ep
->wpos().getRootCell();
791 && rootCell
->getFlag()!=0 ) // Safe Zone ?
794 spawnBot
->setAggroMinimumFor(ep
->dataSetRow(), 0.5f
, false);
801 // group vision update.
802 BanditVision
.updateBotsAndPlayers(_Grp
->getPersistent().getAIInstance(), centerPos
, playerRadius
, botRadius
);
805 CGrpProfileNormal::updateProfile(ticksSinceLastUpdate
);
807 // check if we are in war and if some bot are waiting for a bus.
810 // check if some bots are not fighting.
811 for (CCont
<CBot
>::iterator it
=_Grp
->getPersistent().bots().begin(), itEnd
=_Grp
->getPersistent().bots().end();it
!=itEnd
;++it
)
814 CSpawnBot
*spawnBot
=bot
->getSpawnObj();
816 && spawnBot
->isAlive()
817 && spawnBot
->getAIProfileType()==BOT_STAND_AT_POS
)
819 // :KLUDGE: We verify here that we have a moving profile, to prevent some crashes
820 // :TODO: Remove that check and make sure a group always have a moving profile (even if none is defined in primitives)
821 if (_Grp
->movingProfile().getAIProfile())
823 CMoveProfile
*moveProf
=NLMISC::safe_cast
<CMoveProfile
*>(_Grp
->movingProfile().getAIProfile());
824 moveProf
->resumeBot(bot
);
830 // bandits don't like guards nor escorted people
832 const std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> > &bots
= BanditVision
.bots();
833 std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >::const_iterator
first(bots
.begin()), last(bots
.end());
834 for (; first
!= last
; ++first
)
836 CAIEntityPhysical
*const ep
= (*first
)->getSpawnObj();
838 || ep
->getRyzomType()!=RYZOMID::npc
842 const CSpawnBot
*const bot
= NLMISC::safe_cast
<const CSpawnBot
*>(ep
);
844 const TProfiles profileType
=bot
->spawnGrp().activityProfile().getAIProfileType();
845 if ( profileType
!= ACTIVITY_GUARD
846 && profileType
!= ACTIVITY_GUARD_ESCORTED
847 && profileType
!= ACTIVITY_ESCORTED
)
850 _Grp
->setAggroMinimumFor(ep
->dataSetRow(), 0.8f
, false);
854 // bandits don't like players.
856 const std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> > &players
= BanditVision
.players();
858 std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >::const_iterator
first(players
.begin()), last(players
.end());
859 for (; first
!= last
; ++first
)
861 CPersistentOfPhysical
*const player
= (*first
);
862 CAIEntityPhysical
*const ep
= player
->getSpawnObj();
866 && ep
->currentHitPoints()>0.f
) // not in safe zone.
868 const CRootCell
*const rootCell
=ep
->wpos().getRootCell();
870 && rootCell
->getFlag()!=0 ) // Safe Zone ?
873 _Grp
->setAggroMinimumFor(ep
->dataSetRow(), 0.5f
, false);
879 std::string
CGrpProfileBandit::getOneLineInfoString() const
881 std::string info
= "bandit profile";
882 info
+= " aggro_range=" + NLMISC::toString(_AggroRange
);
886 //////////////////////////////////////////////////////////////////////////////
887 // CGrpProfileGuard //
888 //////////////////////////////////////////////////////////////////////////////
890 CGrpProfileGuard::CGrpProfileGuard(CProfileOwner
*owner
)
891 : CGrpProfileNormal(owner
)
893 PROFILE_LOG("group", "guard", "ctor", "");
896 CGrpProfileGuard::~CGrpProfileGuard()
898 PROFILE_LOG("group", "guard", "dtor", "");
901 void CGrpProfileGuard::beginProfile()
903 PROFILE_LOG("group", "guard", "begin", "");
904 CGrpProfileNormal::beginProfile();
905 CGroupNpc
&persGrp
=_Grp
->getPersistent();
907 if (persGrp
.isRingGrp())
909 _AggroRange
= persGrp
.getAggroDist();
917 void CGrpProfileGuard::endProfile()
919 PROFILE_LOG("group", "guard", "end", "");
920 CGrpProfileNormal::endProfile();
923 void CGrpProfileGuard::updateProfile(uint ticksSinceLastUpdate
)
925 H_AUTO(GrpGuardProfileUpdate
);
926 CFollowPathContext
fpcGrpGuardProfileUpdate("GrpGuardProfileUpdate");
928 CAIVision
<CPersistentOfPhysical
> GuardVision
;
932 if (_Grp
->getPersistent().getProfileParameter("aggro_range", f
)) // look for persistent aggro range
933 aggroSize
= (uint32
)f
;
935 aggroSize
= _Grp
->getPersistent()._AggroRange
;
940 TTicks startVisionTime
= CTime::getPerformanceTime();
943 H_AUTO(GrpGuardProfileVision
);
945 if (_Grp
->calcCenterPos(centerPos
)) // true if there's some bots in the group.
947 _Grp
->setCenterPos(centerPos
);
949 _CenterPos
=_Grp
->getCenterPos();
950 GuardVision
.updateBotsAndPlayers(_Grp
->getPersistent().getAIInstance(), _CenterPos
, aggroSize
, aggroSize
);
954 TTicks endVisionTime
= CTime::getPerformanceTime();
956 static uint32 s_maxBotsVisible
= 0;
957 static double s_maxBotsVisionTime
= 0.0;
959 uint32 numBotsVisible
= (uint32
)GuardVision
.bots().size();
960 double deltaVisionTime
= CTime::ticksToSecond(endVisionTime
-startVisionTime
);
961 bool bTellUs
= false;
962 if( s_maxBotsVisible
< numBotsVisible
)
964 s_maxBotsVisible
= numBotsVisible
;
968 if( s_maxBotsVisionTime
< deltaVisionTime
)
970 s_maxBotsVisionTime
= deltaVisionTime
;
976 nldebug( "==> max bots visible is now %u", s_maxBotsVisible
);
977 nldebug( "vision time: %.2f", (float)(deltaVisionTime
* 1000.0) );
980 uint32 factionIndex
=CStaticFames::INVALID_FACTION_INDEX
;
981 sint32 fameForGuardAttack
= FameForGuardAttack
;
983 H_AUTO(GrpGuardProfileFaction
);
984 CAliasCont
<CBot
> &bots
= _Grp
->getPersistent().bots();
985 if (!bots
.size() != 0 && bots
.begin() != bots
.end())
987 CBot
* bot
= *(bots
.begin());
990 factionIndex
=bot
->getSheet()->FactionIndex();
991 if (bot
->getSheet()->FameForGuardAttack() != AISHEETS::ICreature::InvalidFameForGuardAttack
)
992 fameForGuardAttack
= bot
->getSheet()->FameForGuardAttack();
994 /* if (factionIndex == CStaticFames::INVALID_FACTION_INDEX)
996 nlwarning("Bot sheet '%s' have invalid faction index (guard profile)", bot->getSheet()->SheetId().toString().c_str());
1005 if (_Grp
->getProfileParameter("faction", s
) && !s
.empty())
1007 factionIndex
= CStaticFames::getInstance().getFactionIndex(s
);
1010 if (_Grp
->getPersistent().getProfileParameter("fame_for_guard_attack", f
))
1012 fameForGuardAttack
= (sint32
)f
;
1014 else if (_Grp
->getProfileParameter("fame_for_guard_attack", f
))
1016 fameForGuardAttack
= (sint32
)f
;
1021 CGrpProfileNormal::updateProfile(ticksSinceLastUpdate
);
1023 // check if we are in war and if some bot are waiting for a bus.
1026 H_AUTO(GrpGuardProfileFighting
);
1027 const CAIVector
centerPos(_Grp
->getCenterPos());
1029 // check if some bots are not fighting.
1030 for (CCont
<CBot
>::iterator it
=_Grp
->getPersistent().bots().begin(), itEnd
=_Grp
->getPersistent().bots().end();it
!=itEnd
;++it
)
1032 const CBot
*const bot
=*it
;
1033 CSpawnBot
*const spawnBot
=bot
->getSpawnObj();
1035 && spawnBot
->isAlive())
1037 switch(spawnBot
->getAIProfileType())
1039 case BOT_STAND_AT_POS
:
1041 CMoveProfile
*const moveProf
=NLMISC::type_cast
<CMoveProfile
*>(_Grp
->movingProfile().getAIProfile());
1043 moveProf
->resumeBot(bot
);
1048 // This system is now managed by CBotAggroOwner itself
1050 const CAIEntityPhysical*const target=spawnBot->getTarget();
1053 // if target is out of range, then forget the aggro.
1054 if (centerPos.quickDistTo(target->pos())>50)
1056 spawnBot->forgetAggroFor(target->dataSetRow());
1057 _Grp->forgetAggroFor(target->dataSetRow());
1070 // guards don't like bandits.
1072 H_AUTO(GrpGuardProfileBandits
);
1073 const std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> > &bots
= GuardVision
.bots();
1074 std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >::const_iterator
first(bots
.begin()), last(bots
.end());
1075 for (; first
!= last
; ++first
)
1077 const CAIEntityPhysical
*const ep
= (*first
)->getSpawnObj();
1080 switch (ep
->getRyzomType())
1084 const CSpawnBotNpc
*const botNpc
= NLMISC::safe_cast
<const CSpawnBotNpc
*>(ep
);
1086 if (botNpc
->spawnGrp().activityProfile().getAIProfileType() == ACTIVITY_BANDIT
)
1088 if (_CenterPos
.quickDistTo(botNpc
->pos())<aggroSize
)
1090 _Grp
->setAggroMinimumFor(ep
->dataSetRow(), 0.5f
, false);
1095 case RYZOMID::creature
:
1097 const CSpawnBotFauna
*const botFauna
= NLMISC::safe_cast
<const CSpawnBotFauna
*>(ep
);
1099 if (botFauna
->getPersistent().faunaType()==FaunaTypePredator
)
1101 if (_CenterPos
.quickDistTo(botFauna
->pos())<aggroSize
)
1103 _Grp
->setAggroMinimumFor(ep
->dataSetRow(), 0.5f
, false);
1115 // guards don't like bots that attack players.
1117 H_AUTO(GrpGuardProfileAttack
);
1118 const std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> > &players
= GuardVision
.players();
1119 LOG("%u players in group vision with aggrosize %d", players
.size(), aggroSize
);
1121 const CAIVector
¢erPos
=_Grp
->getCenterPos();
1123 std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >::const_iterator
first(players
.begin()), last(players
.end());
1124 for (; first
!= last
; ++first
)
1126 const CPersistentOfPhysical
*const player
= (*first
);
1127 CAIEntityPhysical
*const ep
= player
->getSpawnObj();
1130 || ep
->currentHitPoints()<=0.f
1131 || ep
->wpos().toAIVector().quickDistTo(centerPos
)>aggroSize
)
1134 // check Fame before choosing what to do ..
1135 sint32
const fame
= ep
->getFameIndexed(factionIndex
);
1137 // if player is kos attack him (only if bot is attackable by player)
1138 if ((_Grp
->getPersistent().getPlayerAttackable() || (factionIndex
!=CStaticFames::INVALID_FACTION_INDEX
&& _Grp
->getPersistent().isFactionAttackable(CStaticFames::getInstance().getFactionName(factionIndex
), fame
))) && ((factionIndex
!=CStaticFames::INVALID_FACTION_INDEX
&& fame
<fameForGuardAttack
) || OUTPOSTHELPERS::isAttackingFaction(factionIndex
, ep
)))
1140 // the guard attack the player !
1141 _Grp
->setAggroMinimumFor(ep
->dataSetRow(), 1.f
, false);
1145 // check if player is attacked and assist him).
1146 CAIEntityPhysical
const* phys
= ep
->firstTargeter();
1149 switch(phys
->getRyzomType())
1151 case RYZOMID::player
:
1155 const CSpawnBotNpc
*const botNpc
=dynamic_cast<const CSpawnBotNpc
*>(phys
);
1157 && botNpc
->getPersistent().getGroup().getSpawnObj()->activityProfile().getAIProfileType() == ACTIVITY_GUARD
)
1162 // guard don't attack npc of the same faction, rather, they attack the player !
1163 if (factionIndex
!= CStaticFames::INVALID_FACTION_INDEX
&& botNpc
->getPersistent().getSheet()->FactionIndex() == factionIndex
)
1165 // the guard attack the player !
1166 _Grp
->setAggroMinimumFor(ep
->dataSetRow(), 1.f
, false);
1171 // guard defend only player with a not too bad fame
1172 if (fame
>= FameForGuardHelp
&& !OUTPOSTHELPERS::isAttackingFaction(factionIndex
, ep
))
1173 _Grp
->setAggroMinimumFor(phys
->dataSetRow(), 1.f
, false);
1176 phys
= phys
->nextTargeter();
1182 std::string
CGrpProfileGuard::getOneLineInfoString() const
1184 return "guard profile";
1187 //////////////////////////////////////////////////////////////////////////////
1188 // CGrpProfileTribu //
1189 //////////////////////////////////////////////////////////////////////////////
1191 CGrpProfileTribu::CGrpProfileTribu(CProfileOwner
*owner
)
1192 : CGrpProfileNormal(owner
)
1194 PROFILE_LOG("group", "tribe", "ctor", "");
1197 CGrpProfileTribu::~CGrpProfileTribu()
1199 PROFILE_LOG("group", "tribe", "dtor", "");
1202 void CGrpProfileTribu::beginProfile()
1204 PROFILE_LOG("group", "tribe", "begin", "");
1205 CGrpProfileNormal::beginProfile();
1208 void CGrpProfileTribu::endProfile()
1210 PROFILE_LOG("group", "tribe", "end", "");
1211 CGrpProfileNormal::endProfile();
1214 void CGrpProfileTribu::updateProfile(uint ticksSinceLastUpdate
)
1216 H_AUTO(GrpTribuProfileUpdate
);
1217 CFollowPathContext
fpcGrpTribuProfileUpdate("GrpTribuProfileUpdate");
1219 CAIVision
<CPersistentOfPhysical
> TribuVision
;
1220 const uint32 aggroSize
=40;
1224 CAIVector centerPos
;
1225 if (!_Grp
->calcCenterPos(centerPos
)) // true if there's some bots in the group.
1228 _Grp
->setCenterPos(centerPos
);
1229 if (!_GroupFighting
)
1230 _CenterPos
=_Grp
->getCenterPos();
1231 TribuVision
.updateBotsAndPlayers(_Grp
->getPersistent().getAIInstance(), _CenterPos
, aggroSize
, aggroSize
);
1234 uint32 factionIndex
=CStaticFames::INVALID_FACTION_INDEX
;
1236 CBotNpc
* bot
= static_cast<CBotNpc
*>(*_Grp
->getPersistent().bots().begin());
1237 factionIndex
= bot
->getSheet()->FactionIndex();
1240 CGrpProfileNormal::updateProfile(ticksSinceLastUpdate
);
1242 // check if we are in war and if some bot are waiting for a bus.
1245 CAIVector
centerPos(_Grp
->getCenterPos());
1247 // check if some bots are not fighting.
1248 for (CCont
<CBot
>::iterator it
=_Grp
->getPersistent().bots().begin(), itEnd
=_Grp
->getPersistent().bots().end();it
!=itEnd
;++it
)
1250 const CBot
*const bot
=*it
;
1251 CSpawnBot
*const spawnBot
=bot
->getSpawnObj();
1253 || !spawnBot
->isAlive())
1256 switch(spawnBot
->getAIProfileType())
1258 case BOT_STAND_AT_POS
:
1260 CMoveProfile
*moveProf
=NLMISC::safe_cast
<CMoveProfile
*>(_Grp
->movingProfile().getAIProfile());
1261 moveProf
->resumeBot(bot
);
1266 // This system is managed by CBotAggroOwner now
1268 const CAIEntityPhysical *const target=spawnBot->getTarget();
1272 // if target is out of range, then forget the aggro.
1273 if (centerPos.quickDistTo(target->pos())<=50)
1276 spawnBot->forgetAggroFor(target->dataSetRow());
1277 _Grp->forgetAggroFor(target->dataSetRow());
1287 // Tribus don't like players with bad fame.
1289 const std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> > &players
= TribuVision
.players();
1291 LOG("%u players in group vision", players
.size());
1293 std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >::const_iterator
first(players
.begin()), last(players
.end());
1294 for (; first
!= last
; ++first
)
1296 CPersistentOfPhysical
*const player
= (*first
);
1297 CAIEntityPhysical
*const ep
= player
->getSpawnObj();
1300 || ep
->currentHitPoints()<=0.f
)
1303 const CRootCell
*const rootCell
=ep
->wpos().getRootCell();
1305 && rootCell
->getFlag()!=0 ) // Safe Zone ?
1308 // check Fame before choosing what to do ..
1309 sint32
const fame
= ep
->getFameIndexed(factionIndex
);
1311 // check if player is attacked.
1312 if (fame
<-10000 || OUTPOSTHELPERS::isAttackingFaction(factionIndex
, ep
))
1314 _Grp
->setAggroMinimumFor(ep
->dataSetRow(), 1.f
, false);
1320 std::string
CGrpProfileTribu::getOneLineInfoString() const
1322 return "tribu profile";
1325 //////////////////////////////////////////////////////////////////////////////
1326 // CGrpProfileFollowRoute //
1327 //////////////////////////////////////////////////////////////////////////////
1329 CGrpProfileGoToPoint::CGrpProfileGoToPoint(CProfileOwner
*owner
, RYAI_MAP_CRUNCH::CWorldPosition
const& startPos
, RYAI_MAP_CRUNCH::CWorldPosition
const& endPos
, bool dontSendEvent
)
1330 : CMoveProfile(owner
)
1331 , _StartPos(startPos
)
1333 , _PathCont(NLMISC::safe_cast
<CSpawnGroup
*>(owner
)->getPersistent().getAStarFlag())
1334 , _DontSendEvent(dontSendEvent
)
1336 PROFILE_LOG("group", "go_to_point", "ctor", "");
1337 _GlobalOrient
.setX(1);
1338 _GlobalOrient
.setY(0);
1339 _FollowForward
=true;
1340 _ValidPosInit
=false;
1344 void CGrpProfileGoToPoint::setDirection(bool forward
)
1346 if ( _FollowForward
==forward
1351 _FollowForward
=forward
;
1354 void CGrpProfileGoToPoint::beginProfile()
1356 PROFILE_LOG("group", "go_to_point", "begin", "");
1357 _ProfileTerminated
= false;
1358 CMoveProfile::beginProfile();
1360 setCurrentDestination(_EndPos
); // *
1363 void CGrpProfileGoToPoint::stateChangeProfile()
1365 setCurrentDestination(_EndPos
); // *
1367 // set a stand at pos profile on every bots
1368 FOREACH(it
, CAliasCont
<CBot
>, _Grp
->bots())
1370 CSpawnBot
*sb
= (*it
)->getSpawnObj();
1372 sb
->setAIProfile(new CBotProfileStandAtPos(sb
));
1378 void CGrpProfileGoToPoint::endProfile()
1380 PROFILE_LOG("group", "go_to_point", "end", "");
1383 void CGrpProfileGoToPoint::resumeProfile()
1385 PROFILE_LOG("group", "go_to_point", "resume", "");
1386 FOREACH(it
, TBotFollowerMap
, _NpcList
)
1388 const CBot
*const bot
=it
->first
;
1389 CSpawnBot
*const sbot
=bot
->getSpawnObj();
1393 switch (sbot
->getAIProfileType())
1395 case BOT_FOLLOW_POS
:
1397 default: // push the correct comportment.
1398 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
1403 setCurrentDestination(_EndPos
);
1406 void CGrpProfileGoToPoint::addBot(CBot
* bot
)
1408 _NpcList
[bot
] = CBotFollower();
1410 CSpawnBot
*sbot
=bot
->getSpawnObj();
1412 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
1414 _MustCalcRatios
= true;
1417 void CGrpProfileGoToPoint::removeBot(CBot
* bot
)
1419 TBotFollowerMap::iterator it
=_NpcList
.find(bot
);
1421 if (it
==_NpcList
.end())
1424 CSpawnBotNpc
*const spawnBot
=NLMISC::safe_cast
<CBotNpc
*>(bot
)->getSpawn();
1426 spawnBot
->setAIProfile(BotProfileStandAtPosFactory
.createAIProfile(spawnBot
));
1428 _NpcList
.erase (it
);
1429 _MustCalcRatios
= true;
1432 void CGrpProfileGoToPoint::setCurrentDestination(RYAI_MAP_CRUNCH::CWorldPosition
const& dest
)
1434 _PathCont
.setDestination(dest
);
1436 FOREACH(it
, TBotFollowerMap
, _NpcList
)
1437 it
->second
.setBotAtDest(false);
1440 void CGrpProfileGoToPoint::calcRatios()
1442 _MustCalcRatios
= false;
1444 // loop to compute max speeds
1445 _MaxRunSpeed
= FLT_MAX
;
1446 _MaxWalkSpeed
= FLT_MAX
;
1447 FOREACH(it
, TBotFollowerMap
, _NpcList
)
1449 CBot
*bot
= it
->first
; //static_cast<CBotNpc*>(_Grp->bots()[botFollower.getIndex()]);
1450 CSpawnBot
*sbot
= bot
->getSpawnObj();
1452 || !sbot
->isAlive())
1455 _MaxRunSpeed
= std::min(sbot
->runSpeed(), _MaxRunSpeed
);
1456 _MaxWalkSpeed
= std::min(sbot
->walkSpeed(), _MaxWalkSpeed
);
1460 if (_Shape
!=SHAPE_RECTANGLE
)
1463 const uint32 nbbots
=(uint32
)_NpcList
.size();
1465 _NbRange
= (uint32
) sqrt(_Ratio
*nbbots
);
1468 _NbLines
= nbbots
/_NbRange
;
1469 _NbBotInNormalShape
= _NbLines
*_NbRange
;
1470 _Rest
= nbbots
-_NbBotInNormalShape
;
1472 _Cx
=(double(_NbRange
)-1.0)*0.5;
1473 _Cy
=(double(_NbLines
)-1.0)*0.5;
1474 _Cy
=(_Cy
*_NbBotInNormalShape
+double(_NbLines
)*_Rest
)/double(nbbots
);
1477 void CGrpProfileGoToPoint::updateProfile(uint ticksSinceLastUpdate
)
1479 H_AUTO(CGrpGoToPointProfileUpdate
);
1480 CFollowPathContext
fpcCGrpGoToPointProfileUpdate("CGrpGoToPointProfileUpdate");
1482 CMoveProfile::updateProfile(ticksSinceLastUpdate
);
1484 CSpawnGroupNpc
*NpcGrp
=NLMISC::safe_cast
<CSpawnGroupNpc
*>(_Grp
.ptr());
1485 CGroupNpc
&persGrp
=NpcGrp
->getPersistent();
1487 CAIVector groupPosition
= NpcGrp
->getCenterPos();
1488 CAIVector perpGlobalOrient
;
1489 NpcGrp
->calcCenterPos(groupPosition
);
1492 uint32 nbNewAtDest
=0;
1502 if (_Shape
==SHAPE_RECTANGLE
)
1504 perpGlobalOrient
.setX(-_GlobalOrient
.y());
1505 perpGlobalOrient
.setY(_GlobalOrient
.x());
1508 //////////////////////////////////////////////////////////////////////////
1509 // Calcs the correct gravity grid position (must be done only when bot are removed or add to the group.
1510 if (_MustCalcRatios
)
1514 FOREACH(it
, TBotFollowerMap
, _NpcList
)
1516 CBotFollower
&botFollower
=it
->second
;
1517 if (botFollower
.isBotAtDest())
1523 CBot
*bot
=it
->first
;
1524 CSpawnBot
*sbot
=bot
->getSpawnObj();
1526 || !sbot
->isAlive())
1529 // verify if the bot has a correct profile and if he reached the destination position.
1530 switch (sbot
->getAIProfileType())
1532 case BOT_FOLLOW_POS
:
1534 if (_ProfileTerminated
)
1536 // remove the profile
1537 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
1541 CBotProfileFollowPos
* prof
= NLMISC::safe_cast
<CBotProfileFollowPos
*>(sbot
->getAIProfile());
1543 // flag the sub profile to stop the npc
1544 prof
->setStop(_StopNpc
);
1547 if (prof
->_Status
==CFollowPath::FOLLOW_ARRIVED
)
1549 botFollower
.setBotAtDest();
1556 prof
->setMaxSpeeds(_MaxWalkSpeed
, _MaxRunSpeed
);
1562 default: // push the correct comportment.
1564 if (!_ProfileTerminated
)
1566 sbot
->setAIProfile(new CBotProfileFollowPos(&_PathCont
, sbot
));
1567 CBotProfileFollowPos
* prof
= NLMISC::safe_cast
<CBotProfileFollowPos
*>(sbot
->getAIProfile());
1569 prof
->setMaxSpeeds(_MaxWalkSpeed
, _MaxRunSpeed
);
1575 if (_Shape
==SHAPE_RECTANGLE
)
1577 NLMISC::CVector2d dir
=sbot
->theta().asVector2d();
1582 CAIVector idealPos
=groupPosition
;
1583 if (botIndex
>=_NbBotInNormalShape
)
1585 idealPos
+= perpGlobalOrient
* (_XSize
*(_Cx
-double(xIndex
)-(_NbRange
-_Rest
)*0.5));
1589 idealPos
+= perpGlobalOrient
* (_XSize
*(_Cx
-double(xIndex
)));
1592 idealPos
+=_GlobalOrient
*(_YSize
*(_Cy
-(double)yIndex
));
1593 idealPos
-=CAIVector(sbot
->pos());
1597 if (xIndex
>=_NbRange
)
1602 sbot
->setMoveDecalage(idealPos
);
1606 if (_Shape
==SHAPE_RECTANGLE
)
1608 _GlobalOrient
.setX(dx
/botIndex
);
1609 _GlobalOrient
.setY(dy
/botIndex
);
1612 // first to arrived ?
1613 if (nbAtDest
>0 && !_ProfileTerminated
)
1615 if (!_DontSendEvent
)
1617 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedFirst
);
1618 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedAll
);
1620 _ProfileTerminated
= true;
1624 CGrpProfileGoToPoint::~CGrpProfileGoToPoint()
1626 for (CCont
<CBot
>::iterator it
=_Grp
->bots().begin(), itEnd
=_Grp
->bots().end();it
!=itEnd
;++it
)
1630 CGrpProfileGoToPoint::CBotFollower::CBotFollower()
1635 CGrpProfileGoToPoint::CBotFollower::~CBotFollower()
1639 void CGrpProfileGoToPoint::CBotFollower::setBotAtDest(bool atDest
)
1641 _BotAtDest
= atDest
;
1644 const bool& CGrpProfileGoToPoint::CBotFollower::isBotAtDest() const
1649 bool CGrpProfileGoToPoint::getDirection()
1651 return _FollowForward
;
1655 CPathCont
* CGrpProfileGoToPoint::getPathCont(CBot
const* bot
)
1660 std::string
CGrpProfileGoToPoint::getOneLineInfoString() const
1662 std::string info
= "go_to_point profile";
1663 info
+= " stop_npc=" + NLMISC::toString(_StopNpc
);
1667 bool CGrpProfileGoToPoint::profileTerminated() const
1669 return _ProfileTerminated
;
1672 void CGrpProfileGoToPoint::stopNpc(bool stop
)
1677 //////////////////////////////////////////////////////////////////////////////
1678 // CGrpProfileGoToPoint //
1679 //////////////////////////////////////////////////////////////////////////////
1681 //RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileGoToPoint, "goto_point");
1683 //////////////////////////////////////////////////////////////////////////////
1684 // CGrpProfileFollowRoute //
1685 //////////////////////////////////////////////////////////////////////////////
1687 CGrpProfileFollowRoute::CGrpProfileFollowRoute(CProfileOwner
*owner
)
1688 : CMoveProfile(owner
)
1689 , _PathCont(NLMISC::safe_cast
<CSpawnGroup
*>(owner
)->getPersistent().getAStarFlag())
1690 , _DontSendEvent(false)
1692 PROFILE_LOG("group", "follow_route", "ctor", "");
1693 _GlobalOrient
.setX(1);
1694 _GlobalOrient
.setY(0);
1695 _FollowForward
= true;
1698 CGroupNpc
&grp
=*safe_cast
<CGroupNpc
*>(&_Grp
->getPersistent());
1701 const CAIState
*const state
= grp
.getCAIState();
1702 if (state
->isPositional())
1704 const CAIStatePositional
*const statePositionnal
=static_cast<const CAIStatePositional
*>(state
);
1705 _Geometry
=&statePositionnal
->shape().getGeometry();
1706 _GeometryComeFromState
= true;
1707 _VerticalPos
=statePositionnal
->shape().getVerticalPos();
1711 _GeometryComeFromState
= false;
1713 _VerticalPos
= TVerticalPos();
1716 nlassert(true==false); // Cannot use this constructor outside machine state context.
1721 CGrpProfileFollowRoute::CGrpProfileFollowRoute(CProfileOwner
*owner
,const std::vector
<CShape::TPosition
> &geometry
,const TVerticalPos
&verticalPos
, bool dontSendEvent
)
1722 : CMoveProfile(owner
)
1723 , _PathCont(NLMISC::safe_cast
<CSpawnGroup
*>(owner
)->getPersistent().getAStarFlag())
1724 , _GeometryComeFromState(false)
1725 , _Geometry(&geometry
)
1726 , _VerticalPos(verticalPos
)
1727 , _DontSendEvent(dontSendEvent
)
1729 PROFILE_LOG("group", "follow_route", "ctor2", "");
1730 _GlobalOrient
.setX(1);
1731 _GlobalOrient
.setY(0);
1732 _FollowForward
=true;
1733 _ValidPosInit
=false;
1738 void CGrpProfileFollowRoute::setDirection(bool forward
)
1740 if ( _FollowForward
==forward
1745 _FollowForward
=forward
;
1747 nlassert(_Geometry
);
1749 setCurrentValidPos(_VerticalPos
);
1752 void CGrpProfileFollowRoute::beginProfile()
1754 PROFILE_LOG("group", "follow_route", "begin", "");
1755 _ProfileTerminated
= false;
1756 CMoveProfile::beginProfile();
1758 if (_GeometryComeFromState
)
1759 assignGeometryFromState();
1762 void CGrpProfileFollowRoute::assignGeometryFromState()
1764 _ProfileTerminated
= false;
1766 // default value initialization.
1768 _Shape
= SHAPE_NOTHING
;
1773 if (_Grp
->getProfileParameter("shape", shape
)
1774 && shape
=="rectangle")
1776 _Shape
= SHAPE_RECTANGLE
;
1779 _Grp
->getProfileParameter("ratio", _Ratio
);
1780 _Grp
->getProfileParameter("xsize", _XSize
);
1781 _Grp
->getProfileParameter("ysize", _YSize
);
1785 CGroup
&persGrp
=NLMISC::safe_cast
<CSpawnGroup
*>(_Grp
.ptr())->getPersistent();
1786 // R2_PRIMITIVE_LAXITY
1787 if (IsRingShard
.get())
1789 nlassertex(_Geometry
, ("CGrpProfileFollowRoute : NULL geometry data for group '%s'", persGrp
.getFullName().c_str()));
1790 if (_Geometry
->empty())
1792 nlwarning("CGrpProfileFollowRoute : missing geometry data for group '%s'", persGrp
.getFullName().c_str());
1797 nlassertex(_Geometry
&& _Geometry
->size()>0, ("CGrpProfileFollowRoute : missing geometry data for group '%s'", persGrp
.getFullName().c_str()));
1801 CSpawnGroupNpc
*grp
= static_cast<CSpawnGroupNpc
*>(static_cast<CSpawnGroup
*>(_Grp
));
1802 CGroupNpc
&pgrp
= grp
->getPersistent();
1803 const CAIState
*const state
= pgrp
.getActiveState();
1806 || !state
->isPositional())
1809 const CAIStatePositional
*const sp
= static_cast<const CAIStatePositional
*const>(state
);
1810 if (!sp
->shape().hasPoints() && (_GeometryComeFromState
))
1812 nlwarning("Error, no position in state '%s'%s",
1813 sp
->getAliasFullName().c_str(),
1814 sp
->getAliasString().c_str());
1818 _Geometry
= &(sp
->shape().getGeometry());
1819 _GeometryComeFromState
= true;
1820 _MustCalcRatios
= true;
1823 setCurrentValidPos (_VerticalPos
); // static_cast<CSpawnGroupNpc*>(_Grp.ptr())->getPersistent().getGeometryVerticalPos(), geometry);
1826 void CGrpProfileFollowRoute::stateChangeProfile()
1828 assignGeometryFromState();
1830 // set a stand at pos profile on every bots
1831 FOREACH(it
, CAliasCont
<CBot
>, _Grp
->bots())
1833 CSpawnBot
*sb
= (*it
)->getSpawnObj();
1835 sb
->setAIProfile(new CBotProfileStandAtPos(sb
));
1837 // Reset stop flag to false
1843 void CGrpProfileFollowRoute::endProfile()
1845 PROFILE_LOG("group", "follow_route", "end", "");
1848 void CGrpProfileFollowRoute::resumeProfile()
1850 PROFILE_LOG("group", "follow_route", "resume", "");
1851 FOREACH(it
, TBotFollowerMap
, _NpcList
)
1853 const CBot
*const bot
=it
->first
;
1854 CSpawnBot
*const sbot
=bot
->getSpawnObj();
1858 switch (sbot
->getAIProfileType())
1860 case BOT_FOLLOW_POS
:
1862 default: // push the correct comportment.
1863 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
1868 // setCurrentValidPos (NLMISC::safe_cast<CAIStatePositional *>(NLMISC::safe_cast<CSpawnGroupNpc*>(_Grp)->getPersistent().getCAIState()));
1870 nlassert(_Geometry
);
1872 setCurrentValidPos (_VerticalPos
);
1875 void CGrpProfileFollowRoute::addBot (CBot
*bot
)
1877 _NpcList
[bot
]=CBotFollower();
1879 CSpawnBot
*sbot
=bot
->getSpawnObj();
1881 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
1883 _MustCalcRatios
= true;
1886 void CGrpProfileFollowRoute::removeBot (CBot
*bot
)
1888 TBotFollowerMap::iterator it
=_NpcList
.find(bot
);
1890 if (it
==_NpcList
.end())
1893 CSpawnBotNpc
*const spawnBot
=NLMISC::safe_cast
<CBotNpc
*>(bot
)->getSpawn();
1895 spawnBot
->setAIProfile(BotProfileStandAtPosFactory
.createAIProfile(spawnBot
));
1897 _NpcList
.erase (it
);
1898 _MustCalcRatios
= true;
1901 void CGrpProfileFollowRoute::setCurrentValidPos (TVerticalPos verticalPos
)
1903 if (_Geometry
->size()>0)
1906 nlassert(_Geometry
!=NULL
);
1908 size_t index
= getDirection()?_GeomIndex
:(_Geometry
->size()-_GeomIndex
-1);
1910 nlassert(index
< _Geometry
->size());
1912 _PathCont
.setDestination (verticalPos
, (*_Geometry
)[index
]);
1915 FOREACH(it
, TBotFollowerMap
, _NpcList
)
1916 it
->second
.setBotAtDest(false);
1919 void CGrpProfileFollowRoute::calcRatios ()
1921 _MustCalcRatios
= false;
1923 // loop to compute max speeds
1924 _MaxRunSpeed
= FLT_MAX
;
1925 _MaxWalkSpeed
= FLT_MAX
;
1926 FOREACH(it
, TBotFollowerMap
, _NpcList
)
1928 CBot
*bot
= it
->first
; //static_cast<CBotNpc*>(_Grp->bots()[botFollower.getIndex()]);
1929 CSpawnBot
*sbot
= bot
->getSpawnObj();
1931 || !sbot
->isAlive())
1934 _MaxRunSpeed
= std::min(sbot
->runSpeed(), _MaxRunSpeed
);
1935 _MaxWalkSpeed
= std::min(sbot
->walkSpeed(), _MaxWalkSpeed
);
1939 if (_Shape
!=SHAPE_RECTANGLE
)
1942 const uint32 nbbots
=(uint32
)_NpcList
.size();
1944 _NbRange
= (uint32
) sqrt(_Ratio
*nbbots
);
1947 _NbLines
= nbbots
/_NbRange
;
1948 _NbBotInNormalShape
= _NbLines
*_NbRange
;
1949 _Rest
= nbbots
-_NbBotInNormalShape
;
1951 _Cx
=(double(_NbRange
)-1.0)*0.5;
1952 _Cy
=(double(_NbLines
)-1.0)*0.5;
1953 _Cy
=(_Cy
*_NbBotInNormalShape
+double(_NbLines
)*_Rest
)/double(nbbots
);
1956 void CGrpProfileFollowRoute::updateProfile(uint ticksSinceLastUpdate
)
1958 H_AUTO(GrpFollowRouteProfileUpdate
);
1959 CFollowPathContext
fpcGrpFollowRouteProfileUpdate("GrpFollowRouteProfileUpdate");
1961 CMoveProfile::updateProfile(ticksSinceLastUpdate
);
1963 CSpawnGroupNpc
*NpcGrp
=NLMISC::safe_cast
<CSpawnGroupNpc
*>(_Grp
.ptr());
1964 CGroupNpc
&persGrp
=NpcGrp
->getPersistent();
1966 CAIVector groupPosition
= NpcGrp
->getCenterPos();
1967 CAIVector perpGlobalOrient
;
1968 NpcGrp
->calcCenterPos(groupPosition
);
1971 uint32 nbNewAtDest
=0;
1980 // R2_PRIMITIVE_LAXITY
1981 if (IsRingShard
.get())
1983 if (!_ProfileTerminated
&& _Geometry
->empty())
1984 _ProfileTerminated
= true;
1987 if (_Shape
==SHAPE_RECTANGLE
)
1989 perpGlobalOrient
.setX(-_GlobalOrient
.y());
1990 perpGlobalOrient
.setY(_GlobalOrient
.x());
1993 //////////////////////////////////////////////////////////////////////////
1994 // Calcs the correct gravity grid position (must be done only when bot are removed or add to the group.
1995 if (_MustCalcRatios
)
1999 FOREACH(it
, TBotFollowerMap
, _NpcList
)
2001 CBotFollower
&botFollower
=it
->second
;
2002 if (botFollower
.isBotAtDest())
2008 CBot
*bot
=it
->first
;
2009 CSpawnBot
*sbot
=bot
->getSpawnObj();
2011 || !sbot
->isAlive())
2014 // verify if the bot has a correct profile and if he reached the destination position.
2015 switch (sbot
->getAIProfileType())
2017 case BOT_FOLLOW_POS
:
2019 if (_ProfileTerminated
)
2021 // remove the profile
2022 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
2026 CBotProfileFollowPos
* prof
= NLMISC::safe_cast
<CBotProfileFollowPos
*>(sbot
->getAIProfile());
2028 // flag the sub profile to stop the npc
2029 prof
->setStop(_StopNpc
);
2032 if (prof
->_Status
==CFollowPath::FOLLOW_ARRIVED
)
2034 botFollower
.setBotAtDest();
2038 /* Following statement was missing */
2048 prof
->setMaxSpeeds(_MaxWalkSpeed
, _MaxRunSpeed
);
2054 default: // push the correct comportment.
2056 if (!_ProfileTerminated
)
2058 sbot
->setAIProfile(new CBotProfileFollowPos(&_PathCont
, sbot
));
2059 CBotProfileFollowPos
* prof
= NLMISC::safe_cast
<CBotProfileFollowPos
*>(sbot
->getAIProfile());
2061 prof
->setMaxSpeeds(_MaxWalkSpeed
, _MaxRunSpeed
);
2067 if (_Shape
==SHAPE_RECTANGLE
)
2069 NLMISC::CVector2d dir
=sbot
->theta().asVector2d();
2074 CAIVector idealPos
=groupPosition
;
2075 if (botIndex
>=_NbBotInNormalShape
)
2077 idealPos
+= perpGlobalOrient
* (_XSize
*(_Cx
-double(xIndex
)-(_NbRange
-_Rest
)*0.5));
2081 idealPos
+= perpGlobalOrient
* (_XSize
*(_Cx
-double(xIndex
)));
2084 idealPos
+=_GlobalOrient
*(_YSize
*(_Cy
-(double)yIndex
));
2085 idealPos
-=CAIVector(sbot
->pos());
2089 if (xIndex
>=_NbRange
)
2094 sbot
->setMoveDecalage(idealPos
);
2098 if (_Shape
==SHAPE_RECTANGLE
)
2100 _GlobalOrient
.setX(dx
/botIndex
);
2101 _GlobalOrient
.setY(dy
/botIndex
);
2104 // first to arrived ?
2105 if (nbAtDest
>0 && !_ProfileTerminated
)
2107 // oh la la (la, let 's go dancing)..
2110 nlassert(_Geometry
);
2113 if (_GeomIndex
>=_Geometry
->size()) // we reach the end.
2117 if (!_DontSendEvent
)
2119 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedFirst
);
2120 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedAll
);
2122 _ProfileTerminated
= true;
2126 setCurrentValidPos(_VerticalPos
);
2131 //////////////////////////////////////////////////////////////////////////////
2132 // CGrpProfileStandOnVertices //
2133 //////////////////////////////////////////////////////////////////////////////
2135 CPathCont
* CGrpProfileStandOnVertices::getPathCont(CBot
const* bot
)
2137 TNpcBotPositionnerMap::const_iterator it
=_NpcList
.find(bot
);
2138 if (it
==_NpcList
.end())
2140 return &it
->second
->_PathCont
;
2143 void CGrpProfileStandOnVertices::beginProfile()
2145 PROFILE_LOG("group", "stand_on_vertices", "begin", "");
2146 CMoveProfile::beginProfile();
2147 CSpawnGroupNpc
*NpcGrp
=NLMISC::safe_cast
<CSpawnGroupNpc
*>(_Grp
.ptr());
2149 CAIStatePositional
*grpState
=NLMISC::safe_cast
<CAIStatePositional
*>(NpcGrp
->getPersistent().getCAIState());
2152 || grpState
->shape().numPoints() == 0
2153 || !grpState
->isPositional())
2156 nlwarning("CGrpProfileStandOnVertices::beginProfile : grpState without valid points %s for group %s", grpState
->getAliasFullName().c_str(), NpcGrp
->getPersistent().getFullName().c_str());
2158 nlwarning("CGrpProfileStandOnVertices::beginProfile : invalid no grpState for group %s", NpcGrp
->getPersistent().getFullName().c_str());
2160 setCurrentValidPos (grpState
);
2164 void CGrpProfileStandOnVertices::setCurrentValidPos(CAIStatePositional
*grpState
)
2166 for (TNpcBotPositionnerMap::iterator it
=_NpcList
.begin(), itEnd
=_NpcList
.end();it
!=itEnd
;++it
)
2168 CBotPositionner
*botPos
=(*it
).second
;
2169 botPos
->setBotAtDest(false);
2170 botPos
->_PathCont
.setDestination(grpState
->shape().getVerticalPos(), *grpState
->shape().point(botPos
->_GeomIndex
));
2174 void CGrpProfileStandOnVertices::resumeProfile()
2176 PROFILE_LOG("group", "stand_on_vertices", "resume", "");
2177 for (TNpcBotPositionnerMap::iterator it
=_NpcList
.begin(), itEnd
=_NpcList
.end();it
!=itEnd
;++it
)
2179 const CBot
*const bot
=(*it
).first
;
2180 CSpawnBot
*sbot
=bot
->getSpawnObj();
2184 switch (sbot
->getAIProfileType())
2186 case BOT_FOLLOW_POS
:
2188 default: // push the correct behaviour
2190 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
2197 CSpawnGroupNpc
*NpcGrp
=NLMISC::safe_cast
<CSpawnGroupNpc
*>(_Grp
.ptr());
2198 CAIStatePositional
*grpState
=NLMISC::safe_cast
<CAIStatePositional
*>(NpcGrp
->getPersistent().getCAIState());
2199 nlassert( grpState
->shape().numPoints()>0
2201 && grpState
->isPositional());
2202 setCurrentValidPos (grpState
);
2206 void CGrpProfileStandOnVertices::addBot (CBot
*bot
)
2208 CGroupNpc
& grp
=NLMISC::safe_cast
<CBotNpc
*>(bot
)->grp();
2210 nlassert(grp
.getSpawnObj());
2213 CAIStatePositional
*grpState
=NLMISC::safe_cast
<CAIStatePositional
*>(grp
.getCAIState());
2215 CSpawnBot
*const sbot
=bot
->getSpawnObj();
2217 if ( grpState
->shape().numPoints() < 1 )
2219 nlwarning("CGrpProfileStandOnVertices : group state '%s'%s: no vertice !", grpState
->getAliasFullName().c_str(), grpState
->getAliasString().c_str());
2224 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
2226 _NpcList
[bot
]=new CBotPositionner (bot
->getChildIndex()%grpState
->shape().numPoints(), bot
->getGroup().getAStarFlag());
2229 void CGrpProfileStandOnVertices::removeBot (CBot
*bot
)
2231 TNpcBotPositionnerMap::iterator it
=_NpcList
.find(bot
);
2232 if (it
!=_NpcList
.end())
2234 CSpawnBotNpc
*spawnBot
=NLMISC::safe_cast
<CBotNpc
*>(bot
)->getSpawn();
2236 spawnBot
->setAIProfile(new CBotProfileStandAtPos(spawnBot
));
2238 _NpcList
.erase (it
);
2243 void CGrpProfileStandOnVertices::updateProfile(uint ticksSinceLastUpdate
)
2245 H_AUTO(GrpStandProfileUpdate
);
2246 CFollowPathContext
fpcGrpStandProfileUpdate("GrpStandProfileUpdate");
2248 CMoveProfile::updateProfile(ticksSinceLastUpdate
);
2250 CGroupNpc
&persGrp
=NLMISC::safe_cast
<CSpawnGroupNpc
*>(_Grp
.ptr())->getPersistent();
2251 CAIStatePositional
*grpState
=static_cast<CAIStatePositional
*>(persGrp
.getCAIState());
2254 uint32 nbNewAtDest
=0;
2256 for (TNpcBotPositionnerMap::iterator it
=_NpcList
.begin(), itEnd
=_NpcList
.end();it
!=itEnd
;++it
)
2258 CBotPositionner
*botPos
=(*it
).second
;
2259 if (!botPos
->isBotAtDest())
2261 const CBot
*const bot
=(*it
).first
;
2262 CSpawnBot
*sbot
=bot
->getSpawnObj();
2266 switch (sbot
->getAIProfileType())
2268 case BOT_FOLLOW_POS
:
2270 CBotProfileFollowPos
* prof
= NLMISC::safe_cast
<CBotProfileFollowPos
*>(sbot
->getAIProfile());
2272 if (prof
->_Status
==CFollowPath::FOLLOW_ARRIVED
)
2274 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
2275 botPos
->setBotAtDest();
2279 /* Following statement was missing */
2288 default: // push the correct comportment.
2290 sbot
->setAIProfile(new CBotProfileFollowPos(&botPos
->_PathCont
, sbot
));
2302 // first to arrived ?
2303 if ( nbNewAtDest
==nbAtDest
2306 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedFirst
);
2310 if ( nbAtDest
==_NpcList
.size()
2313 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedAll
);
2318 //////////////////////////////////////////////////////////////////////////////
2319 // CGrpProfileFollowPlayer //
2320 //////////////////////////////////////////////////////////////////////////////
2321 CGrpProfileFollowPlayer::CGrpProfileFollowPlayer(CProfileOwner
* owner
, TDataSetRow
const& playerRow
, uint32 dispersionRadius
)
2322 : CMoveProfile(owner
)
2323 , _PlayerRow(playerRow
)
2324 , _DispersionRadius(dispersionRadius
)
2325 , _PathPos(CAngle(0))
2326 , _PathCont(NLMISC::safe_cast
<CSpawnBotNpc
*>(owner
)->getAStarFlag())
2328 PROFILE_LOG("group", "follow player", "ctor", "");
2329 _Status
= CFollowPath::FOLLOWING
;
2332 bool CGrpProfileFollowPlayer::destinationReach() const
2334 return _Status
== CFollowPath::FOLLOW_ARRIVED
2335 || _Status
==CFollowPath::FOLLOW_NO_PATH
;
2338 void CGrpProfileFollowPlayer::beginProfile()
2340 _Status
= CFollowPath::FOLLOWING
;
2343 // TODO: this doesn't work very well at all...
2344 void CGrpProfileFollowPlayer::updateProfile(uint ticksSinceLastUpdate
)
2346 H_AUTO(CGrpProfileFollowPlayerUpdate
);
2347 CFollowPathContext
fpcGrpFollowPlayerUpdate("CGrpProfileFollowPlayerUpdate");
2349 // check all bot to see if there need to move
2350 CSpawnGroupNpc
* grp
= static_cast<CSpawnGroupNpc
*>(static_cast<CSpawnGroup
*>(_Grp
));
2351 CGroupNpc
&pgrp
= grp
->getPersistent();
2353 CBotPlayer
* plrPtr
= dynamic_cast<CBotPlayer
*>(CAIS::instance().getEntityPhysical(_PlayerRow
));
2356 nlwarning("CGrpProfileFollowPlayer: No valid player position to follow");
2360 _PathCont
.setDestination(plrPtr
->wpos());
2361 _PathPos
._Angle
= plrPtr
->theta();
2363 for (uint i
= 0; i
< pgrp
.bots().size(); ++i
)
2365 CBotNpc
* bot
= static_cast<CBotNpc
*>(pgrp
.bots()[i
]);
2369 // check current bot state
2370 CSpawnBotNpc
*sbot
= bot
->getSpawn();
2374 // Need to wait for a correct position before moving?
2375 CAIVector
const& dest
= _PathCont
.getDestination();
2376 if (dest
.x()==0 || dest
.y()==0)
2379 static const std::string
runParameter("running");
2381 if (sbot
->getPersistent().getOwner()->getSpawnObj()->checkProfileParameter(runParameter
))
2382 dist
= sbot
->runSpeed()*ticksSinceLastUpdate
;
2384 dist
= sbot
->walkSpeed()*ticksSinceLastUpdate
;
2387 CFollowPath::TFollowStatus
const status
= CFollowPath::getInstance()->followPath(
2395 if (status
==CFollowPath::FOLLOW_NO_PATH
)
2397 nlwarning("Problem with following player");
2406 //////////////////////////////////////////////////////////////////////////////
2407 // CGrpProfileIdle //
2408 //////////////////////////////////////////////////////////////////////////////
2410 CGrpProfileIdle::CGrpProfileIdle(CProfileOwner
* owner
)
2411 : CMoveProfile(owner
)
2413 PROFILE_LOG("group", "idle", "ctor", "");
2416 CGrpProfileIdle::~CGrpProfileIdle()
2418 PROFILE_LOG("group", "idle", "dtor", "");
2419 FOREACH(it
, CCont
<CBot
>, _Grp
->bots())
2426 CGrpProfileIdle::CBotPositionner::CBotPositionner()
2430 CGrpProfileIdle::CBotPositionner::~CBotPositionner()
2434 void CGrpProfileIdle::beginProfile()
2436 PROFILE_LOG("group", "idle", "begin", "");
2437 CMoveProfile::beginProfile();
2440 CPathCont
* CGrpProfileIdle::getPathCont(CBot
const* bot
)
2445 void CGrpProfileIdle::resumeProfile()
2447 PROFILE_LOG("group", "idle", "resume", "");
2448 typedef std::map
<CBot
*,CBotPositionner
> TCont
;
2449 FOREACH(it
, TCont
, _NpcList
)
2451 CBot
* bot
= (*it
).first
;
2452 CSpawnBot
* sbot
= bot
->getSpawnObj();
2455 switch (sbot
->getAIProfileType())
2457 case BOT_STAND_AT_POS
:
2459 default: // push the correct comportment.
2460 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
2467 void CGrpProfileIdle::addBot(CBot
* bot
)
2470 CGroupNpc
& grp
=NLMISC::safe_cast
<CBotNpc
*>(bot
)->grp();
2471 nlassert(grp
.getSpawnObj());
2473 _NpcList
[bot
]=CBotPositionner ();
2474 CSpawnBot
*sbot
=bot
->getSpawnObj();
2476 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
2479 void CGrpProfileIdle::removeBot(CBot
* bot
)
2481 std::map
<CBot
*, CBotPositionner
>::iterator it
=_NpcList
.find(bot
);
2482 if (it
!=_NpcList
.end())
2484 _NpcList
.erase (it
);
2489 void CGrpProfileIdle::endProfile()
2491 PROFILE_LOG("group", "idle", "end", "");
2494 void CGrpProfileIdle::updateProfile(uint ticksSinceLastUpdate
)
2496 CMoveProfile::updateProfile(ticksSinceLastUpdate
);
2499 std::string
CGrpProfileIdle::getOneLineInfoString() const
2501 return "idle profile";
2504 //////////////////////////////////////////////////////////////////////////////
2505 // CGrpProfileWander //
2506 //////////////////////////////////////////////////////////////////////////////
2508 CGrpProfileWander::CGrpProfileWander(CProfileOwner
* owner
, CNpcZone
const* npcZone
)
2509 : CMoveProfile(owner
)
2513 PROFILE_LOG("group", "wander", "ctor", "");
2514 _BotStandProfileType
= BOT_STAND_AT_POS
;
2515 _BotStandProfileFactory
= &BotProfileStandAtPosFactory
;
2516 _RandomPos
=&npcZone
->getPlaceRandomPos();
2519 CGrpProfileWander::CGrpProfileWander(CProfileOwner
* owner
)
2520 : CMoveProfile(owner
)
2523 PROFILE_LOG("group", "wander", "ctor2", "");
2524 affectZoneFromStateMachine();
2526 // R2_PRIMITIVE_LAXITY
2527 if (!IsRingShard
.get())
2529 nlassert(!_RandomPos
.isNULL());
2533 // default to stand apt pos profile
2534 _BotStandProfileType
= BOT_STAND_AT_POS
;
2535 _BotStandProfileFactory
= &BotProfileStandAtPosFactory
;
2538 CGrpProfileWander::~CGrpProfileWander()
2540 PROFILE_LOG("group", "wander", "dtor", "");
2543 void CGrpProfileWander::stateChangeProfile()
2545 affectZoneFromStateMachine();
2546 resetDestinationReachedData();
2549 void CGrpProfileWander::affectZoneFromStateMachine()
2551 CSpawnGroupNpc
* grp
= static_cast<CSpawnGroupNpc
*>(static_cast<CSpawnGroup
*>(_Grp
));
2552 CGroupNpc
& pgrp
= grp
->getPersistent();
2553 CAIState
const* const state
= pgrp
.getActiveState();
2556 || !state
->isPositional())
2559 CAIStatePositional
const* const sp
= static_cast<CAIStatePositional
const* const>(state
);
2560 if (!sp
->shape().hasPoints())
2562 if (sp
->getAliasNode())
2563 nlwarning("Error, no position in state %s", sp
->getAliasNode()->fullName().c_str());
2565 nlwarning("Error, no position in state %s", sp
->getName().c_str());
2567 if (sp
->shape().hasPatat())
2568 _RandomPos
=&(sp
->shape());
2571 void CGrpProfileWander::resetDestinationReachedData()
2573 _DestinationReachedFirst
= false;
2574 _DestinationReachedAll
= false;
2575 std::fill(_NpcDestinationReached
.begin(), _NpcDestinationReached
.end(), false);
2578 void CGrpProfileWander::setBotStandProfile(TProfiles botStandProfileType
, IAIProfileFactory
*botStandProfileFactory
)
2580 _BotStandProfileType
= botStandProfileType
;
2581 _BotStandProfileFactory
= botStandProfileFactory
;
2584 void CGrpProfileWander::beginProfile()
2586 PROFILE_LOG("group", "wander", "begin", "");
2587 CMoveProfile::beginProfile();
2589 CSpawnGroupNpc
*grp
= static_cast<CSpawnGroupNpc
*>(static_cast<CSpawnGroup
*>(_Grp
));
2591 if (grp
->checkProfileParameter("forage"))
2593 _BotStandProfileType
= BOT_FORAGE
;
2594 _BotStandProfileFactory
= &BotProfileForageFactory
;
2596 else if (grp
->checkProfileParameter("social"))
2601 _NpcDestinationReached
.resize( grp
->getPersistent().bots().size());
2602 resetDestinationReachedData();
2606 void CGrpProfileWander::addBot(CBot
* bot
)
2608 CSpawnBot
*const spawnBot
=bot
->getSpawnObj();
2612 if (_BotStandProfileType
== BOT_FORAGE
)
2614 // special case, only set the forage activity and let the bot live there life
2615 spawnBot
->setAIProfile(_BotStandProfileFactory
->createAIProfile(spawnBot
));
2619 CBotProfileStandAtPos
* const profile
= new CBotProfileStandAtPos(spawnBot
);
2621 nlassert(profile
!=NULL
);
2623 spawnBot
->setAIProfile(profile
);
2625 void CGrpProfileWander::removeBot(CBot
* bot
)
2628 CPathCont
* CGrpProfileWander::getPathCont(CBot
const* bot
)
2633 void CGrpProfileWander::endProfile()
2635 PROFILE_LOG("group", "wander", "end", "");
2638 void CGrpProfileWander::updateProfile(uint ticksSinceLastUpdate
)
2640 H_AUTO(GrpWanderProfileUpdate
);
2641 CFollowPathContext
fpcGrpWanderProfileUpdate("GrpWanderProfileUpdate");
2643 if (_BotStandProfileType
== BOT_FORAGE
)
2645 // special case, only set the forage activity and let the bot live there life
2649 // check all bot to see if there need to move
2650 CSpawnGroupNpc
* grp
= static_cast<CSpawnGroupNpc
*>(static_cast<CSpawnGroup
*>(_Grp
));
2651 CGroupNpc
&pgrp
= grp
->getPersistent();
2652 bool aNpcHasReachDestination
= false;
2653 for (uint i
=0; i
<pgrp
.bots().size(); ++i
)
2655 CBotNpc
* bot
= static_cast<CBotNpc
*>(pgrp
.bots()[i
]);
2659 // check current bot state
2660 CSpawnBotNpc
*sbot
= bot
->getSpawn();
2664 IAIProfile
*profile
= sbot
->getAIProfile();
2668 // init a profile on the bot
2669 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
2673 if (profile
->getAIProfileType() == BOT_MOVE_TO
)
2675 // check if we are arrived
2676 CBotProfileMoveTo
* mt
= static_cast<CBotProfileMoveTo
*>(profile
);
2677 if (mt
->destinationReach())
2679 if (!_DestinationReachedAll
)
2682 uint32 npcSize
= (uint32
)pgrp
.bots().size();
2683 uint32 reachedSize
= (uint32
)_NpcDestinationReached
.size();
2684 if (reachedSize
!= npcSize
)
2686 _NpcDestinationReached
.resize(npcSize
);
2687 // invalid the vector a new bot has arrived
2688 if (npcSize
>reachedSize
){ std::fill(_NpcDestinationReached
.begin(), _NpcDestinationReached
.end(), false); }
2691 if ( !_NpcDestinationReached
[i
])
2693 _NpcDestinationReached
[i
] = true;
2694 aNpcHasReachDestination
= true;
2699 // look arround for interesting target
2700 CAIVision
<CPersistentOfPhysical
> vision
;
2701 vision
.updateBotsAndPlayers(_Grp
->getPersistent().getAIInstance(), CAIVector(sbot
->pos()), 10, 10);
2703 CPersistentOfPhysical
*target
= NULL
;
2705 if (!vision
.players().empty())
2707 // there are some player near, look at one if it is not behin us
2708 uint index
= CAIS::rand16((uint32
)vision
.players().size());
2709 CAngle
angle(CAngle::pi());
2711 while (index
< vision
.players().size() && !target
)
2713 CPersistentOfPhysical
*pop
= vision
.players()[index
++];
2715 angle
= sbot
->pos().angleTo(pop
->getSpawnObj()->pos());
2717 if (angle
< CAngle::pi()/2 && angle
> CAngle::pi()/-2)
2724 if (!target
&& !vision
.bots().empty())
2726 // there are some bots near, look at one if it is not behin us
2727 uint index
= CAIS::rand16((uint32
)vision
.bots().size());
2728 CAngle
angle(CAngle::pi());
2730 while (index
< vision
.bots().size() && !target
)
2732 CPersistentOfPhysical
*pop
= vision
.bots()[index
++];
2734 angle
= sbot
->pos().angleTo(pop
->getSpawnObj()->pos());
2736 if (angle
< CAngle::pi()/2 && angle
> CAngle::pi()/-2)
2743 // set the visual target
2744 if (target
&& target
->isSpawned())
2745 sbot
->setVisualTarget(target
->getSpawnObj());
2747 sbot
->setVisualTarget(NULL
);
2749 // now, set the idle activity with a random timer
2751 sbot
->setAIProfile(_BotStandProfileFactory
->createAIProfile(sbot
));
2752 CBotProfileWanderBase
*wbs
= safe_cast
<CBotProfileWanderBase
*>(sbot
->getAIProfile());
2757 static string
waitMinStr("wait min");
2758 static string
waitMaxStr("wait max");
2759 if (grp
->getProfileParameter(waitMinStr
, waitMin
))
2761 if (!grp
->getProfileParameter(waitMaxStr
, waitMax
))
2764 waitMax
= waitMax
> waitMin
? waitMax
: waitMin
;
2768 waitMin
= float(DefaultWanderMinTimer
);
2769 waitMax
= float(DefaultWanderMaxTimer
);
2771 wbs
->setTimer(uint32(waitMin
+CAIS::rand32(uint32(waitMax
-waitMin
))));
2777 if (profile
->getAIProfileType()==_BotStandProfileType
)
2779 const CBotProfileWanderBase
*const wbs
= static_cast<CBotProfileStandAtPos
*>(sbot
->getAIProfile());
2783 if (!wbs
->testTimer())
2788 nlassert(_RandomPos
!= NULL
&& _RandomPos
->getRandomPosCount() != 0);
2790 // R2_PRIMITIVE_LAXITY
2791 // for a Ring shard stop here and only do a warning to avoid asserting later
2792 // primitives generated by players may be incorrect and should not crash the service
2793 if (IsRingShard
.get())
2795 if ( _RandomPos
== NULL
2796 || _RandomPos
->getRandomPosCount() == 0)
2798 string stateName
= "NULL state!";
2799 CAIState
const* const state
= pgrp
.getActiveState();
2801 stateName
= state
->getAliasFullName();
2802 nlwarning("No valid wander position for state '%s'", stateName
.c_str());
2807 // time out, move to another point in the geometry
2808 RYAI_MAP_CRUNCH::CWorldPosition wp
;
2810 if (_Social
&& CAIS::rand32(3) == 0)
2812 // this time, we try to reach an npc in the neighbour
2813 //TODO : implemente this behavior
2817 // standard random move
2818 _RandomPos
->getRandomPos(wp
);
2820 CBotProfileMoveTo
* mts
= new CBotProfileMoveTo(_RandomPos
->getVerticalPos(), wp
, sbot
);
2821 sbot
->setAIProfile(mts
);
2825 if (aNpcHasReachDestination
&& !_DestinationReachedAll
)
2828 if (!_DestinationReachedFirst
)
2830 _DestinationReachedFirst
= true;
2831 pgrp
.processStateEvent(pgrp
.mgr().EventDestinationReachedFirst
);
2834 uint32 first
=0, last
=(uint32
)_NpcDestinationReached
.size();
2835 for ( ; first
!= last
&& _NpcDestinationReached
[first
]; ++first
) {}
2839 _DestinationReachedAll
= true;
2840 pgrp
.processStateEvent(pgrp
.mgr().EventDestinationReachedAll
);
2845 std::string
CGrpProfileWander::getOneLineInfoString() const
2847 return "wander group profile";
2850 //////////////////////////////////////////////////////////////////////////////
2851 // CGrpProfileWanderNoPrim //
2852 //////////////////////////////////////////////////////////////////////////////
2854 CGrpProfileWanderNoPrim::CGrpProfileWanderNoPrim(CProfileOwner
* owner
, NLMISC::CSmartPtr
<CNpcZonePlaceNoPrim
> const& npcZone
)
2855 : CMoveProfile(owner
)
2859 PROFILE_LOG("group", "wander", "ctor", "");
2860 _BotStandProfileType
= BOT_STAND_AT_POS
;
2861 _BotStandProfileFactory
= &BotProfileStandAtPosFactory
;
2862 // _RandomPos = &npcZone->getPlaceRandomPos();
2865 CGrpProfileWanderNoPrim::CGrpProfileWanderNoPrim(CProfileOwner* owner)
2866 : CMoveProfile(owner)
2869 PROFILE_LOG("group", "wander", "ctor2", "");
2870 affectZoneFromStateMachine();
2872 nlassert(!_RandomPos.isNULL());
2875 // default to stand apt pos profile
2876 _BotStandProfileType = BOT_STAND_AT_POS;
2877 _BotStandProfileFactory = &BotProfileStandAtPosFactory;
2880 void CGrpProfileWanderNoPrim::stateChangeProfile()
2882 // affectZoneFromStateMachine();
2883 // resetDestinationReachedData();
2886 void CGrpProfileWanderNoPrim::affectZoneFromStateMachine()
2888 CSpawnGroupNpc* grp = static_cast<CSpawnGroupNpc*>(static_cast<CSpawnGroup *>(_Grp));
2889 CGroupNpc& pgrp = grp->getPersistent();
2890 CAIState const* const state = pgrp.getActiveState();
2893 || !state->isPositional())
2896 CAIStatePositional const* const sp = static_cast<CAIStatePositional const* const>(state);
2897 if (!sp->shape().hasPoints())
2899 if (sp->getAliasNode())
2900 nlwarning("Error, no position in state %s", sp->getAliasNode()->fullName().c_str());
2902 nlwarning("Error, no position in state %s", sp->getName().c_str());
2904 if (sp->shape().hasPatat())
2905 _RandomPos=&(sp->shape());
2909 CGrpProfileWanderNoPrim::~CGrpProfileWanderNoPrim()
2911 PROFILE_LOG("group", "wander", "dtor", "");
2914 void CGrpProfileWanderNoPrim::setBotStandProfile(TProfiles botStandProfileType
, IAIProfileFactory
*botStandProfileFactory
)
2916 _BotStandProfileType
= botStandProfileType
;
2917 _BotStandProfileFactory
= botStandProfileFactory
;
2920 void CGrpProfileWanderNoPrim::beginProfile()
2922 PROFILE_LOG("group", "wander", "begin", "");
2923 CMoveProfile::beginProfile();
2925 CSpawnGroupNpc
*grp
= static_cast<CSpawnGroupNpc
*>(static_cast<CSpawnGroup
*>(_Grp
));
2927 if (grp
->checkProfileParameter("forage"))
2929 _BotStandProfileType
= BOT_FORAGE
;
2930 _BotStandProfileFactory
= &BotProfileForageFactory
;
2932 else if (grp
->checkProfileParameter("social"))
2938 void CGrpProfileWanderNoPrim::addBot(CBot
* bot
)
2940 CSpawnBot
*const spawnBot
=bot
->getSpawnObj();
2944 if (_BotStandProfileType
== BOT_FORAGE
)
2946 // special case, only set the forage activity and let the bot live there life
2947 spawnBot
->setAIProfile(_BotStandProfileFactory
->createAIProfile(spawnBot
));
2951 CBotProfileStandAtPos
* const profile
= new CBotProfileStandAtPos(spawnBot
);
2953 nlassert(profile
!=NULL
);
2955 spawnBot
->setAIProfile(profile
);
2957 void CGrpProfileWanderNoPrim::removeBot(CBot
* bot
)
2960 CPathCont
* CGrpProfileWanderNoPrim::getPathCont(CBot
const* bot
)
2965 void CGrpProfileWanderNoPrim::endProfile()
2967 PROFILE_LOG("group", "wander", "end", "");
2970 void CGrpProfileWanderNoPrim::updateProfile(uint ticksSinceLastUpdate
)
2972 H_AUTO(GrpWanderProfileUpdate
);
2973 CFollowPathContext
fpcGrpWanderProfileUpdate("GrpWanderProfileUpdate");
2975 if (_BotStandProfileType
== BOT_FORAGE
)
2977 // special case, only set the forage activity and let the bot live there life
2981 // check all bot to see if there need to move
2982 CSpawnGroupNpc
* grp
= static_cast<CSpawnGroupNpc
*>(static_cast<CSpawnGroup
*>(_Grp
));
2983 CGroupNpc
&pgrp
= grp
->getPersistent();
2985 for (uint i
=0; i
<pgrp
.bots().size(); ++i
)
2987 CBotNpc
* bot
= static_cast<CBotNpc
*>(pgrp
.bots()[i
]);
2991 // check current bot state
2992 CSpawnBotNpc
*sbot
= bot
->getSpawn();
2996 IAIProfile
*profile
= sbot
->getAIProfile();
3000 // init a profile on the bot
3001 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
3005 if (profile
->getAIProfileType() == BOT_MOVE_TO
)
3007 // check if we are arrived
3008 CBotProfileMoveTo
* mt
= static_cast<CBotProfileMoveTo
*>(profile
);
3009 if (mt
->destinationReach())
3011 // look arround for interesting target
3012 CAIVision
<CPersistentOfPhysical
> vision
;
3013 vision
.updateBotsAndPlayers(_Grp
->getPersistent().getAIInstance(), CAIVector(sbot
->pos()), 10, 10);
3015 CPersistentOfPhysical
*target
= NULL
;
3017 if (!vision
.players().empty())
3019 // there are some player near, look at one if it is not behin us
3020 uint index
= CAIS::rand16((uint32
)vision
.players().size());
3021 CAngle
angle(CAngle::pi());
3023 while (index
< vision
.players().size() && !target
)
3025 CPersistentOfPhysical
*pop
= vision
.players()[index
++];
3027 angle
= sbot
->pos().angleTo(pop
->getSpawnObj()->pos());
3029 if (angle
< CAngle::pi()/2 && angle
> CAngle::pi()/-2)
3036 if (!target
&& !vision
.bots().empty())
3038 // there are some bots near, look at one if it is not behin us
3039 uint index
= CAIS::rand16((uint32
)vision
.bots().size());
3040 CAngle
angle(CAngle::pi());
3042 while (index
< vision
.bots().size() && !target
)
3044 CPersistentOfPhysical
*pop
= vision
.bots()[index
++];
3046 angle
= sbot
->pos().angleTo(pop
->getSpawnObj()->pos());
3048 if (angle
< CAngle::pi()/2 && angle
> CAngle::pi()/-2)
3055 // set the visual target
3056 if (target
&& target
->isSpawned())
3057 sbot
->setVisualTarget(target
->getSpawnObj());
3059 sbot
->setVisualTarget(NULL
);
3061 // now, set the idle activity with a random timer
3063 sbot
->setAIProfile(_BotStandProfileFactory
->createAIProfile(sbot
));
3064 CBotProfileWanderBase
*wbs
= safe_cast
<CBotProfileWanderBase
*>(sbot
->getAIProfile());
3069 static string
waitMinStr("wait min");
3070 static string
waitMaxStr("wait max");
3071 if (grp
->getProfileParameter(waitMinStr
, waitMin
))
3073 if (!grp
->getProfileParameter(waitMaxStr
, waitMax
))
3076 waitMax
= waitMax
> waitMin
? waitMax
: waitMin
;
3080 waitMin
= float(DefaultWanderMinTimer
);
3081 waitMax
= float(DefaultWanderMaxTimer
);
3083 wbs
->setTimer(uint32(waitMin
+CAIS::rand32(uint32(waitMax
-waitMin
))));
3085 pgrp
.processStateEvent(pgrp
.mgr().EventDestinationReachedFirst
);
3086 pgrp
.processStateEvent(pgrp
.mgr().EventDestinationReachedAll
);
3091 if (profile
->getAIProfileType()==_BotStandProfileType
)
3093 const CBotProfileWanderBase
*const wbs
= static_cast<CBotProfileStandAtPos
*>(sbot
->getAIProfile());
3097 if (!wbs
->testTimer())
3102 nlassert(_NpcZone
->getRandomPosCount());
3104 // time out, move to another point in the geometry
3105 RYAI_MAP_CRUNCH::CWorldPosition wp
;
3107 if (_Social
&& CAIS::rand32(3) == 0)
3109 // this time, we try to reach an npc in the neighbour
3110 //TODO : implemente this behavior
3114 // standard random move
3115 _NpcZone
->getRandomPos(wp
);
3117 CBotProfileMoveTo
* mts
= new CBotProfileMoveTo(_NpcZone
->getVerticalPos(), wp
, sbot
);
3118 sbot
->setAIProfile(mts
);
3122 std::string
CGrpProfileWanderNoPrim::getOneLineInfoString() const
3124 return "wander group profile (without primitive)";
3127 //////////////////////////////////////////////////////////////////////////////
3128 // CGrpProfileStandOnVertices //
3129 //////////////////////////////////////////////////////////////////////////////
3131 CGrpProfileStandAtStartPoint::CGrpProfileStandAtStartPoint(CProfileOwner
* owner
)
3132 : CMoveProfile(owner
)
3134 PROFILE_LOG("group", "stand_at_start_point", "ctor", "");
3137 CGrpProfileStandAtStartPoint::~CGrpProfileStandAtStartPoint()
3139 PROFILE_LOG("group", "stand_at_start_point", "dtor", "");
3140 for (CCont
<CBot
>::iterator it
=_Grp
->bots().begin(), itEnd
=_Grp
->bots().end();it
!=itEnd
;++it
)
3147 CGrpProfileStandAtStartPoint::CBotPositionner::CBotPositionner(RYAI_MAP_CRUNCH::TAStarFlag flags
)
3152 CGrpProfileStandAtStartPoint::CBotPositionner::CBotPositionner(TVerticalPos verticalPos
, CAIPos position
, RYAI_MAP_CRUNCH::TAStarFlag flag
)
3154 , _Position(position
)
3155 , _VerticalPos(verticalPos
)
3158 _PathCont
.setDestination(verticalPos
, position
);
3161 CGrpProfileStandAtStartPoint::CBotPositionner::~CBotPositionner()
3166 void CGrpProfileStandAtStartPoint::CBotPositionner::setBotAtDest(bool atDest
)
3168 _BotAtDest
= atDest
;
3172 bool CGrpProfileStandAtStartPoint::CBotPositionner::isBotAtDest() const
3177 CPathCont
* CGrpProfileStandAtStartPoint::getPathCont(CBot
const* bot
)
3179 TNpcBotPositionnerMap::const_iterator it
= _NpcList
.find(bot
);
3180 if (it
==_NpcList
.end())
3182 return &it
->second
->_PathCont
;
3185 void CGrpProfileStandAtStartPoint::beginProfile()
3187 PROFILE_LOG("group", "stand_at_start_point", "begin", "");
3188 CMoveProfile::beginProfile();
3190 setCurrentValidPos();
3194 void CGrpProfileStandAtStartPoint::resumeProfile()
3196 PROFILE_LOG("group", "stand_at_start_point", "resume", "");
3197 for (TNpcBotPositionnerMap::iterator it
=_NpcList
.begin(), itEnd
=_NpcList
.end();it
!=itEnd
;++it
)
3199 const CBot
*const bot
=(*it
).first
;
3200 CSpawnBot
*sbot
=bot
->getSpawnObj();
3204 switch (sbot
->getAIProfileType())
3206 case BOT_FOLLOW_POS
:
3208 default: // push the correct comportment.
3209 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
3215 setCurrentValidPos();
3219 void CGrpProfileStandAtStartPoint::addBot(CBot
* bot
)
3221 CBotNpc
* botNpc
= NLMISC::safe_cast
<CBotNpc
*>(bot
);
3223 CGroupNpc
& grp
= botNpc
->grp();
3225 nlassert(grp
.getSpawnObj());
3227 CAIStatePositional
*grpState
=NLMISC::safe_cast
<CAIStatePositional
*>(grp
.getCAIState());
3228 _NpcList
[bot
]=new CBotPositionner (botNpc
->getStartVerticalPos(), botNpc
->getStartPos(), botNpc
->getGroup().getAStarFlag());
3230 CSpawnBot
*const sbot
=bot
->getSpawnObj();
3232 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
3235 void CGrpProfileStandAtStartPoint::removeBot(CBot
* bot
)
3237 TNpcBotPositionnerMap::iterator it
=_NpcList
.find(bot
);
3239 if (it
==_NpcList
.end())
3242 CSpawnBotNpc
* const spawnBot
= NLMISC::safe_cast
<CBotNpc
*>(bot
)->getSpawn();
3244 spawnBot
->setAIProfile(new CBotProfileStandAtPos(spawnBot
));
3245 _NpcList
.erase (it
);
3248 void CGrpProfileStandAtStartPoint::setCurrentValidPos()
3250 FOREACH(it
, TNpcBotPositionnerMap
, _NpcList
)
3252 CBotPositionner
*botPos
=(*it
).second
;
3253 botPos
->setBotAtDest(false);
3254 botPos
->_PathCont
.setDestination(botPos
->_VerticalPos
, botPos
->_Position
);
3259 void CGrpProfileStandAtStartPoint::endProfile()
3261 PROFILE_LOG("group", "stand_at_start_point", "end", "");
3264 void CGrpProfileStandAtStartPoint::updateProfile(uint ticksSinceLastUpdate
)
3266 H_AUTO(GrpStandStartPointProfileUpdate
);
3267 CFollowPathContext
fpcGrpStandStartPointProfileUpdate("GrpStandStartPointProfileUpdate");
3269 CMoveProfile::updateProfile(ticksSinceLastUpdate
);
3271 CGroupNpc
&persGrp
=NLMISC::safe_cast
<CSpawnGroupNpc
*>(_Grp
.ptr())->getPersistent();
3272 CAIStatePositional
*grpState
=static_cast<CAIStatePositional
*>(persGrp
.getCAIState());
3275 uint32 nbNewAtDest
=0;
3277 for (TNpcBotPositionnerMap::iterator it
=_NpcList
.begin(), itEnd
=_NpcList
.end();it
!=itEnd
;++it
)
3279 CBotPositionner
*const botPos
=(*it
).second
;
3280 if (botPos
->isBotAtDest())
3286 const CBot
*const bot
=(*it
).first
;
3287 CSpawnBot
*sbot
=bot
->getSpawnObj();
3289 || !sbot
->isAlive())
3292 switch (sbot
->getAIProfileType())
3294 case BOT_FOLLOW_POS
:
3296 CBotProfileFollowPos
* prof
= NLMISC::safe_cast
<CBotProfileFollowPos
*>(sbot
->getAIProfile());
3298 if (prof
->_Status
==CFollowPath::FOLLOW_ARRIVED
)
3300 sbot
->setTheta(botPos
->_Position
.theta());
3301 sbot
->setAIProfile(new CBotProfileStandAtPos(sbot
));
3302 botPos
->setBotAtDest();
3306 /* Following statement was missing */
3316 default: // push the correct comportment.
3318 sbot
->setAIProfile(new CBotProfileFollowPos(&botPos
->_PathCont
, sbot
));
3325 // first to arrived ?
3326 if ( nbNewAtDest
==nbAtDest
3329 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedFirst
);
3333 if ( nbAtDest
==_NpcList
.size()
3336 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedAll
);
3341 std::string
CGrpProfileStandAtStartPoint::getOneLineInfoString() const
3343 std::string info
= "stand_at_start_point group profile";
3344 info
+= " finished=" + NLMISC::toString(_Finished
);
3348 //////////////////////////////////////////////////////////////////////////////
3349 // CGrpProfileEscorted //
3350 //////////////////////////////////////////////////////////////////////////////
3352 CGrpProfileEscorted::CGrpProfileEscorted(CProfileOwner
*owner
)
3353 : CGrpProfileNormal(owner
)
3355 PROFILE_LOG("group", "escorted", "ctor", "");
3358 CGrpProfileEscorted::~CGrpProfileEscorted()
3360 PROFILE_LOG("group", "escorted", "dtor", "");
3363 void CGrpProfileEscorted::beginProfile()
3365 PROFILE_LOG("group", "escorted", "begin", "");
3366 CGrpProfileNormal::beginProfile();
3367 _EscortTeamInRange
= false;
3370 void CGrpProfileEscorted::endProfile()
3372 PROFILE_LOG("group", "escorted", "end", "");
3373 if (_Grp
->movingProfile().getAIProfileType() == AITYPES::MOVE_FOLLOW_ROUTE
)
3375 CGrpProfileFollowRoute
* prof
= NLMISC::safe_cast
<CGrpProfileFollowRoute
*>(_Grp
->movingProfile().getAIProfile());
3377 prof
->stopNpc(false);
3381 void CGrpProfileEscorted::stateChangeProfile()
3383 CGrpProfileNormal::beginProfile();
3386 void CGrpProfileEscorted::updateProfile(uint ticksSinceLastUpdate
)
3388 H_AUTO(GrpEscortedProfileUpdate
);
3389 CFollowPathContext
fpcGrpEscortedProfileUpdate("GrpEscortedProfileUpdate");
3391 const uint32 ESCORT_RANGE_DELTA
= 3;
3392 CGroupNpc
&GrpRef
= _Grp
->getPersistent();
3393 const uint16 teamId
= GrpRef
.getEscortTeamId();
3395 if (teamId
== CTEAM::InvalidTeamId
)
3397 // no escort team assigned, can't move!
3398 _EscortTeamInRange
= false;
3402 // we need to have some member of the escort team in range to allow movement
3403 // look arround for an escort member
3404 CAIVector centerPos
;
3405 bool escortAway
= true;
3406 bool escortBack
= false;
3407 float escortRange
=GrpRef
.getEscortRange();
3408 double distAway
= escortRange
+ESCORT_RANGE_DELTA
;
3409 double distBack
= escortRange
-ESCORT_RANGE_DELTA
;
3410 // square the dist to speedup test
3411 distAway
*= distAway
;
3412 distBack
*= distBack
;
3413 if (_Grp
->calcCenterPos(centerPos
)) // true if there's some bots in the group.
3415 CAIVision
<CPersistentOfPhysical
> vision
;
3417 // group vision update.
3418 vision
.updateBotsAndPlayers(_Grp
->getPersistent().getAIInstance(), centerPos
, uint(escortRange
+ESCORT_RANGE_DELTA
), 0);
3420 if (vision
.players().empty())
3422 // no player, no need to check, the escort is away !
3427 // loop on each player until we know if escort is away or back
3428 vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >::const_iterator
first(vision
.players().begin()), last(vision
.players().end());
3429 for (;first
!= last
&& (escortAway
|| !escortBack
); ++first
)
3431 CBotPlayer
*player
= safe_cast
<CBotPlayer
*>((*first
).ptr()); // (CPersistentOfPhysical*)
3432 if (player
->isAlive())
3434 if (CMirrors::getTeamId(player
->getSpawnObj()->dataSetRow()) == teamId
)
3436 // on of our escort girl ;)
3437 // check the distance
3438 double sqrDist
= (centerPos
- player
->getSpawnObj()->pos()).sqrnorm();
3439 if (sqrDist
< distBack
)
3442 // the escort is back
3444 if (sqrDist
< distAway
)
3447 // the escort is not away
3455 if (_EscortTeamInRange
)
3459 // switch to 'wait for escort' mode and send event 'escort away'
3460 _EscortTeamInRange
= false;
3461 GrpRef
.processStateEvent(GrpRef
.mgr().getStateMachine()->EventEscortAway
);
3468 // switch to 'escort in range' mode and send event 'escort back'
3469 _EscortTeamInRange
= true;
3470 GrpRef
.processStateEvent(GrpRef
.mgr().getStateMachine()->EventEscortBack
);
3476 if (!_Grp
->fightProfile().getAIProfile())
3477 _Grp
->fightProfile().setAIProfile(_Grp
.ptr(), &GrpProfileFightFactory
, false);
3479 _Grp
->fightProfile().mayUpdateProfile(ticksSinceLastUpdate
);
3481 CFightProfile
* profile
= NLMISC::safe_cast
<CFightProfile
*>(_Grp
->fightProfile().getAIProfile());
3482 if (!profile
->stillHaveEnnemy())
3484 // :TODO: Verify if it's needed to erase bots aggro too/instead
3485 // _Grp->clearAggroList(); // this erase all aggro.
3486 setGroupFighting (false);
3488 _Grp
->fightProfile().setAIProfile(NULL
);
3489 (NLMISC::safe_cast
<CMoveProfile
*>(_Grp
->movingProfile().getAIProfile()))->resumeProfile ();
3494 if (!_Grp
->checkProfileParameter("defenceless"))
3496 if (_Grp
->haveAggroOrReturnPlace())
3498 if(_Grp
->isGroupAlive())
3500 // set the fighting comportment.
3501 if (!_Grp
->fightProfile().getAIProfile())
3502 _Grp
->fightProfile().setAIProfile(_Grp
.ptr(), &GrpProfileFightFactory
, false);
3504 setGroupFighting(true);
3510 if (_Grp
->movingProfile().getAIProfileType() == AITYPES::MOVE_FOLLOW_ROUTE
&& !_GroupFighting
)
3512 CGrpProfileFollowRoute
* prof
= NLMISC::safe_cast
<CGrpProfileFollowRoute
*>(_Grp
->movingProfile().getAIProfile());
3516 prof
->stopNpc(!_EscortTeamInRange
);
3517 _Grp
->movingProfile().mayUpdateProfile(ticksSinceLastUpdate
);
3522 std::string
CGrpProfileEscorted::getOneLineInfoString() const
3524 std::string info
= "escorted profile";
3525 info
+= " escort_team_in_range=" + NLMISC::toString(_EscortTeamInRange
);
3526 uint16 teamId
= _Grp
->getPersistent().getEscortTeamId();
3527 info
+= " team_id=" + (teamId
==CTEAM::InvalidTeamId
)?"InvalidTeamId":NLMISC::toString(teamId
);
3531 //////////////////////////////////////////////////////////////////////////////
3532 // CGrpProfileGuardEscorted //
3533 //////////////////////////////////////////////////////////////////////////////
3535 CGrpProfileGuardEscorted::CGrpProfileGuardEscorted(CProfileOwner
*owner
)
3536 : CGrpProfileNormal(owner
)
3538 PROFILE_LOG("group", "guard_escorted", "ctor", "");
3539 _GuardProfile
= new CGrpProfileGuard(owner
);
3540 _EscortedProfile
= new CGrpProfileEscorted(owner
);
3543 CGrpProfileGuardEscorted::~CGrpProfileGuardEscorted()
3545 PROFILE_LOG("group", "guard_escorted", "dtor", "");
3548 void CGrpProfileGuardEscorted::beginProfile()
3550 PROFILE_LOG("group", "guard_escorted", "begin", "");
3551 CGrpProfileNormal::beginProfile();
3553 _GuardProfile
->beginProfile();
3554 _EscortedProfile
->beginProfile();
3557 void CGrpProfileGuardEscorted::endProfile()
3559 PROFILE_LOG("group", "guard_escorted", "end", "");
3560 _EscortedProfile
->endProfile();
3561 _GuardProfile
->endProfile();
3564 void CGrpProfileGuardEscorted::stateChangeProfile()
3566 CGrpProfileNormal::beginProfile();
3567 _EscortedProfile
->stateChangeProfile();
3568 _GuardProfile
->stateChangeProfile();
3571 void CGrpProfileGuardEscorted::updateProfile(uint ticksSinceLastUpdate
)
3573 H_AUTO(GrpEscortedGuardProfileUpdate
);
3574 CFollowPathContext
fpcGrpEscortedGuardProfileUpdate("GrpEscortedGuardProfileUpdate");
3576 _GuardProfile
->updateProfile(ticksSinceLastUpdate
);
3577 if (!_EscortedProfile
->isGroupFighting())
3578 _EscortedProfile
->updateProfile(ticksSinceLastUpdate
);
3581 std::string
CGrpProfileGuardEscorted::getOneLineInfoString() const
3583 std::string info
= "guard_escorted profile";
3585 info
+= _GuardProfile
?_GuardProfile
->getOneLineInfoString():std::string("<no guard profile>");
3587 info
+= _EscortedProfile
?_EscortedProfile
->getOneLineInfoString():std::string("<no escorted profile>");
3592 //////////////////////////////////////////////////////////////////////////////
3593 // CGrpProfileSquad //
3594 //////////////////////////////////////////////////////////////////////////////
3596 CGrpProfileSquad::CGrpProfileSquad(CProfileOwner
* const owner
)
3597 : CGrpProfileFaction(owner
)
3599 PROFILE_LOG("group", "squad", "ctor", "");
3602 CGrpProfileSquad::~CGrpProfileSquad()
3604 PROFILE_LOG("group", "squad", "dtor", "");
3607 void CGrpProfileSquad::beginProfile()
3609 PROFILE_LOG("group", "squad", "begin", "");
3610 CGrpProfileFaction::beginProfile();
3611 CGroupNpc
& thisGrpNpc
= _Grp
->getPersistent();
3613 // Set aggro parameters
3614 thisGrpNpc
._AggroRange
= 25;
3615 thisGrpNpc
._UpdateNbTicks
= 10;
3618 string
CGrpProfileSquad::getOneLineInfoString() const
3620 return "squad profile";
3623 void CGrpProfileSquad::aggroEntity(CAIEntityPhysical
const* entity
)
3625 // COutpost* outpost = getDefendedOutpost();
3626 // if (!outpost || outpost->getShape()->atPlace(CAIVector(entity->pos())))
3627 _Grp
->setAggroMinimumFor(entity
->dataSetRow(), 0.5f
, false);
3630 NLMISC::CSmartPtr
<CAIPlace
const> CGrpProfileSquad::buildFirstHitPlace(TDataSetRow
const& aggroBot
)
3632 COutpost
* outpost
= getDefendedOutpost();
3634 return &*(outpost
->getShape());
3639 void CGrpProfileSquad::aggroEntity(CAIEntityPhysical const* entity)
3641 COutpost* outpost = getDefendedOutpost();
3644 // Check that the (player) entity is in the outpost zone (according to the rules of the EGS with timers)
3645 CMirrorPropValueRO<TYPE_IN_OUTPOST_ZONE_ALIAS> entityInOutpostAlias(TheDataset, entity->dataSetRow(), DSPropertyIN_OUTPOST_ZONE_ALIAS);
3646 if (entityInOutpostAlias != outpost->getAlias())
3649 _Grp->setBotAggroMinimum(entity->dataSetRow(), -0.5f);
3652 //////////////////////////////////////////////////////////////////////////////
3653 // CGrpProfileFaction //
3654 //////////////////////////////////////////////////////////////////////////////
3656 CGrpProfileFaction::CGrpProfileFaction(CProfileOwner
* const owner
)
3657 : CGrpProfileNormal(owner
)
3659 PROFILE_LOG("group", "faction", "ctor", "");
3663 CGrpProfileFaction::~CGrpProfileFaction()
3665 PROFILE_LOG("group", "faction", "dtor", "");
3668 void CGrpProfileFaction::beginProfile()
3670 PROFILE_LOG("group", "faction", "begin", "");
3673 void CGrpProfileFaction::endProfile()
3675 PROFILE_LOG("group", "faction", "end", "");
3678 AITYPES::CPropertySet
CGrpProfileFaction::_FameFactions
;
3680 void CGrpProfileFaction::initFameFactions()
3682 static bool inited
= false;
3686 std::map
<std::string
, NLMISC::TStringId
> factionTranslator
;
3687 std::vector
<NLMISC::TStringId
> const& factionNames
= CStaticFames::getInstance().getFactionNames();
3688 std::vector
<NLMISC::TStringId
>::const_iterator it
, end
=factionNames
.end();
3689 for (it
=factionNames
.begin(); it
!=end
; ++it
)
3691 std::string fameFaction
= CStringMapper::unmap(*it
);
3692 std::string scriptFaction
= fameFactionToScriptFaction(fameFaction
);
3693 factionTranslator
.insert(std::make_pair(scriptFaction
, *it
));
3694 _FameFactions
.addProperty(scriptFaction
);
3696 _FameFactions
.addProperty(CPropertyId("Player"));
3697 #ifdef NL_DEBUG_FACTION_NAME_CONVERTER
3698 nldebug("Testing script faction name converters");
3699 std::string names
[][2] = {
3700 { "matis", "FamousMatis" },
3701 { "fyros", "FamousFyros" },
3702 { "tryker", "FamousTryker" },
3703 { "zorai", "FamousZorai" },
3704 { "kami", "FamousKami" },
3705 { "black_kami", "FamousBlackKami" },
3706 { "karavan", "FamousKaravan" },
3707 { "white_karavan", "FamousWhiteKaravan" },
3708 { "tribe_ancient_dryads", "FamousTribeAncientDryads" },
3709 { "tribe_antikamis", "FamousTribeAntikamis" },
3710 { "tribe_barkers", "FamousTribeBarkers" },
3711 { "tribe_beachcombers", "FamousTribeBeachcombers" },
3712 { "tribe_black_circle", "FamousTribeBlackCircle" },
3713 { "tribe_cholorogoos", "FamousTribeCholorogoos" },
3714 { "tribe_cockroaches", "FamousTribeCockroaches" },
3715 { "tribe_company_of_the_eternal_tree", "FamousTribeCompanyOfTheEternalTree" },
3716 { "tribe_corsair", "FamousTribeCorsair" },
3717 { "tribe_cute", "FamousTribeCute" },
3718 { "tribe_darkening_sap", "FamousTribeDarkeningSap" },
3719 { "tribe_dune_riders", "FamousTribeDuneRiders" },
3720 { "tribe_ecowarriors", "FamousTribeEcowarriors" },
3721 { "tribe_firebrands", "FamousTribeFirebrands" },
3722 { "tribe_first_deserter", "FamousTribeFirstDeserter" },
3723 { "tribe_frahar", "FamousTribeFrahar" },
3724 { "tribe_frahar_hunters", "FamousTribeFraharHunters" },
3725 { "tribe_gibbay", "FamousTribeGibbay" },
3726 { "tribe_goo_heads", "FamousTribeGooHeads" },
3727 { "tribe_green_seed", "FamousTribeGreenSeed" },
3728 { "tribe_hamazans_of_the_dead_seed", "FamousTribeHamazansOfTheDeadSeed" },
3729 { "tribe_icon_workshipers", "FamousTribeIconWorkshipers" },
3730 { "tribe_keepers", "FamousTribeKeepers" },
3731 { "tribe_kitin_gatheres", "FamousTribeKitinGatheres" },
3732 { "tribe_lagoon_brothers", "FamousTribeLagoonBrothers" },
3733 { "tribe_lawless", "FamousTribeLawless" },
3734 { "tribe_leviers", "FamousTribeLeviers" },
3735 { "tribe_master_of_the_goo", "FamousTribeMasterOfTheGoo" },
3736 { "tribe_matisian_border_guards", "FamousTribeMatisianBorderGuards" },
3737 { "tribe_night_turners", "FamousTribeNightTurners" },
3738 { "tribe_oasis_diggers", "FamousTribeOasisDiggers" },
3739 { "tribe_pyromancers", "FamousTribePyromancers" },
3740 { "tribe_recoverers", "FamousTribeRecoverers" },
3741 { "tribe_renegades", "FamousTribeRenegades" },
3742 { "tribe_restorers", "FamousTribeRestorers" },
3743 { "tribe_root_tappers", "FamousTribeRootTappers" },
3744 { "tribe_sacred_sap", "FamousTribeSacredSap" },
3745 { "tribe_sap_gleaners", "FamousTribeSapGleaners" },
3746 { "tribe_sap_slaves", "FamousTribeSapSlaves" },
3747 { "tribe_scorchers", "FamousTribeScorchers" },
3748 { "tribe_shadow_runners", "FamousTribeShadowRunners" },
3749 { "tribe_siblings_of_the_weeds", "FamousTribeSiblingsOfTheWeeds" },
3750 { "tribe_silt_sculptors", "FamousTribeSiltSculptors" },
3751 { "tribe_slavers", "FamousTribeSlavers" },
3752 { "tribe_smuglers", "FamousTribeSmuglers" },
3753 { "tribe_the_arid_matis", "FamousTribeTheAridMatis" },
3754 { "tribe_the_kuilde", "FamousTribeTheKuilde" },
3755 { "tribe_the_slash_and_burn", "FamousTribeTheSlashAndBurn" },
3756 { "tribe_tutors", "FamousTribeTutors" },
3757 { "tribe_water_breakers", "FamousTribeWaterBreakers" },
3758 { "tribe_woven_bridles", "FamousTribeWovenBridles" }
3760 size_t size
= sizeof(names
)/sizeof(names
[0]);
3761 for (size_t i
=0; i
<size
; ++i
)
3763 nldebug("%s -> %s", names
[i
][0].c_str(), fameFactionToScriptFaction(names
[i
][0]).c_str());
3764 nlassert( names
[i
][1] == fameFactionToScriptFaction(names
[i
][0]) );
3765 nldebug("%s -> %s", names
[i
][1].c_str(), scriptFactionToFameFaction(names
[i
][1]).c_str());
3766 nlassert( names
[i
][0] == scriptFactionToFameFaction(names
[i
][1]) );
3772 bool CGrpProfileFaction::entityHavePartOfFactions(CAIEntityPhysical
const* entity
, AITYPES::CPropertySetWithExtraList
<TAllianceId
> const& factions
)
3774 H_AUTO(CGrpProfileFaction_entityHavePartOfFactions
);
3775 switch (entity
->getRyzomType())
3777 case RYZOMID::player
:
3780 if (factions
.have(AITYPES::CPropertyId("Player")))
3782 // nldebug("Entity has faction Player");
3785 // Test if the entity is involved in an outpost war
3786 if (entity
->outpostAlias()!=0)
3788 if (factions
.have(NLMISC::toString("outpost:%s:%s", LigoConfig
.aliasToString(entity
->outpostAlias()).c_str(), entity
->outpostSide()?"attacker":"defender")))
3791 // Test entity fame value
3792 std::set
<TStringId
> factionsSet
= factions
.properties();
3793 std::set
<TStringId
>::const_iterator it
, end
= factionsSet
.end();
3794 for (it
=factionsSet
.begin(); it
!=end
; ++it
)
3796 string factionInfos
= CStringMapper::unmap(*it
);
3797 string fameFaction
= scriptFactionToFameFaction(factionInfos
);
3798 // sint32 fame = CFameInterface::getInstance().getFameOrCivilisationFame(entity->getEntityId(), CStringMapper::map(fameFaction));
3799 sint32
const fame
= entity
->getFame(fameFaction
);
3800 sint32
const value
= scriptFactionToFameFactionValue(factionInfos
);
3801 bool gt
= scriptFactionToFameFactionGreaterThan(factionInfos
);
3802 if ((fame
!= NO_FAME
&& gt
&& fame
> value
) ||
3803 (fame
!= NO_FAME
&& !gt
&& fame
< value
))
3805 // nldebug("Entity has faction %s", CStringMapper::unmap(*it).c_str());
3813 CSpawnBotNpc
const* const sbnEntity
= NLMISC::safe_cast
<CSpawnBotNpc
const*>(entity
);
3814 CGroupNpc
*const gnEntityGroup
= NLMISC::safe_cast
<CGroupNpc
*>(&sbnEntity
->getPersistent().getGroup());
3815 return gnEntityGroup
->faction().containsPartOfStrict(factions
);
3817 case RYZOMID::creature
:
3819 CSpawnBotFauna
const* const sbnEntity
= NLMISC::safe_cast
<CSpawnBotFauna
const*>(entity
);
3820 CGrpFauna
* const gnEntityGroup
= NLMISC::safe_cast
<CGrpFauna
*>(&sbnEntity
->getPersistent().getGroup());
3821 return gnEntityGroup
->faction().containsPartOfStrict(factions
);
3830 std::string
CGrpProfileFaction::scriptFactionToFameFaction(std::string name
)
3832 if (name
.find("Famous")!=0)
3834 std::string ret
= "";
3835 for (size_t i
=6; i
<name
.length(); ++i
)
3837 if (i
==6 && name
[i
]>='A' && name
[i
]<='Z')
3838 ret
+= name
[i
]-'A'+'a';
3839 else if (name
[i
]>='A' && name
[i
]<='Z')
3842 ret
+= name
[i
]-'A'+'a';
3844 else if (name
[i
] == '>' || name
[i
] == '<')
3856 bool CGrpProfileFaction::scriptFactionToFameFactionGreaterThan(string name
)
3858 if (name
.find("<") != string::npos
)
3864 sint32
CGrpProfileFaction::scriptFactionToFameFactionValue(string name
)
3866 size_t start
= name
.find(">");
3867 if (start
== string::npos
)
3869 start
= name
.find("<");
3870 if (start
== string::npos
)
3875 NLMISC::fromString(name
.substr(start
+1), value
);
3879 std::string
CGrpProfileFaction::fameFactionToScriptFaction(std::string name
)
3881 std::string ret
= "Famous";
3882 for (size_t i
=0; i
<name
.length(); ++i
)
3884 if (i
==0 && name
[i
]>='a' && name
[i
]<='z')
3885 ret
+= name
[i
]-'a'+'A';
3886 else if (name
[i
]=='_' && name
[i
+1]>='a' && name
[i
+1]<='z')
3887 ret
+= name
[++i
]-'a'+'A';
3894 void CGrpProfileFaction::aggroEntity(CAIEntityPhysical
const* entity
)
3896 _Grp
->setAggroMinimumFor(entity
->dataSetRow(), 0.5f
, false);
3899 void CGrpProfileFaction::checkTargetsAround()
3901 if (!_checkTargetTimer
.test())
3904 CGroupNpc
& thisGrpNpc
= _Grp
->getPersistent();
3906 _checkTargetTimer
.set(thisGrpNpc
._UpdateNbTicks
+CAIS::rand16(2)); // every _UpdateNbTicks+1 seconds.
3909 CPropertySetWithExtraList
<TAllianceId
> const& thisFaction
= thisGrpNpc
.faction();
3910 CPropertySetWithExtraList
<TAllianceId
> const& thisFriendFactions
= thisGrpNpc
.friendFaction();
3911 CPropertySetWithExtraList
<TAllianceId
> const& thisEnnemyFactions
= thisGrpNpc
.ennemyFaction();
3913 // We don't assist or attack players if our friends/ennemies are not in factions
3914 bool const assistPlayers
= (thisFriendFactions
.containsPartOfStrictFilter("Famous*") || thisFriendFactions
.have(AITYPES::CPropertyId("Player")));
3915 bool const assistBots
= !thisFriendFactions
.empty() && !bNoAssist
;
3916 bool const attackPlayers
= (!thisEnnemyFactions
.extraSetEmpty()) || thisEnnemyFactions
.containsPartOfStrictFilter("Famous*") || thisEnnemyFactions
.have(AITYPES::CPropertyId("Player")) || thisEnnemyFactions
.containsPartOfStrictFilter("outpost:*");
3917 bool const attackBots
= !thisEnnemyFactions
.empty();
3919 CAIVision
<CPersistentOfPhysical
> Vision
;
3922 CAIVector centerPos
;
3923 if (!_Grp
->calcCenterPos(centerPos
)) // true if there's some bots in the group.
3926 const uint32 playerRadius
=assistPlayers
||attackPlayers
?thisGrpNpc
._AggroRange
:0;
3927 const uint32 botRadius
=assistBots
||attackBots
?thisGrpNpc
._AggroRange
:0;
3930 for (CCont
<CBot
>::iterator itBot
=_Grp
->bots().begin(), itEnd
=_Grp
->bots().end(); itBot
!=itEnd
; ++itBot
)
3932 uint32 cellValue
= 0;
3936 CSpawnBot
* spawnBot
= bot
->getSpawnObj();
3939 CMirrorPropValueRO
<uint32
> cell( TheDataset
, spawnBot
->dataSetRow(), DSPropertyCELL
);
3941 Vision
.updateBotsAndPlayers(thisGrpNpc
.getAIInstance(), centerPos
, playerRadius
, botRadius
, cellValue
);
3952 FOREACHC (itAssisted
, std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >, Vision
.players())
3954 // Get assisted entity
3955 CPersistentOfPhysical
const* const popAssisted
= (*itAssisted
);
3956 CAIEntityPhysical
* const epAssisted
= popAssisted
->getSpawnObj();
3957 // If entity is not alive skip it
3958 if (!epAssisted
|| !epAssisted
->isAlive() || epAssisted
->currentHitPoints()<=0.f
)
3960 // If entity is not a friend skip it
3961 if (!entityHavePartOfFactions(epAssisted
, thisFriendFactions
))
3963 // For each targeter of the assisted entity
3964 CAIEntityPhysical
const* epAttacker
= epAssisted
->firstTargeter();
3967 // If attacker is not in our faction attack him
3968 if (!entityHavePartOfFactions(epAttacker
, thisFaction
))
3969 aggroEntity(epAttacker
);
3970 epAttacker
= epAttacker
->nextTargeter();
3977 FOREACHC (itAssisted
, std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >, Vision
.bots())
3979 // Get assisted entity
3980 const CPersistentOfPhysical
*const popAssisted
= (*itAssisted
);
3981 CAIEntityPhysical
*const epAssisted
= popAssisted
->getSpawnObj();
3982 // If entity is not alive skip it
3983 if (!epAssisted
|| !epAssisted
->isAlive() || epAssisted
->currentHitPoints()<=0.f
)
3985 // If entity is not a npc skip it
3986 if (epAssisted
->getRyzomType()!=RYZOMID::npc
)
3988 // If entity is not a friend skip it
3989 if (!entityHavePartOfFactions(epAssisted
, thisFriendFactions
))
3991 // For each targeter of the assisted entity
3992 CAIEntityPhysical
const* epAttacker
= epAssisted
->firstTargeter();
3995 // If attacker is not in our faction attack him
3996 if (!entityHavePartOfFactions(epAttacker
, thisFaction
))
3998 const CSpawnBot
* spwBot
= dynamic_cast<const CSpawnBot
*>(epAssisted
);
4001 if (spwBot
->haveAggroWithEntity(epAttacker
->dataSetRow()))
4002 aggroEntity(epAttacker
);
4005 epAttacker
= epAttacker
->nextTargeter();
4012 FOREACHC (itAttacked
, TPersistentList
, Vision
.players())
4014 // Get attacked entity
4015 CPersistentOfPhysical
const* const popAttacked
= (*itAttacked
);
4016 CAIEntityPhysical
const* const epAttacked
= popAttacked
->getSpawnObj();
4017 // If entity is not alive skip it
4018 if (!epAttacked
|| !epAttacked
->isAlive() || epAttacked
->currentHitPoints()<=0.f
)
4020 // If entity is not an ennemy skip it
4021 if (!entityHavePartOfFactions(epAttacked
, thisEnnemyFactions
))
4023 // If entity is a friend skip it
4024 if (entityHavePartOfFactions(epAttacked
, thisFriendFactions
))
4026 // If entity is in our faction skip it
4027 if (entityHavePartOfFactions(epAttacked
, thisFaction
))
4029 // If player is in safe zone skip it
4030 CRootCell
const* const rootCell
= epAttacked
->wpos().getRootCell();
4031 if (rootCell
&& rootCell
->getFlag()!=0) // Safe Zone ?
4034 aggroEntity(epAttacked
);
4040 FOREACHC (itAttacked
, TPersistentList
, Vision
.bots())
4042 // Get attacked entity
4043 CPersistentOfPhysical
const* const popAttacked
= (*itAttacked
);
4044 CAIEntityPhysical
const* const epAttacked
= popAttacked
->getSpawnObj();
4045 // If entity is not alive skip it
4046 if (!epAttacked
|| !epAttacked
->isAlive() || epAttacked
->currentHitPoints()<=0.f
)
4048 // If entity is not an ennemy skip it
4049 if (!entityHavePartOfFactions(epAttacked
, thisEnnemyFactions
))
4051 // If entity is a friend skip it
4052 if (entityHavePartOfFactions(epAttacked
, thisFriendFactions
))
4054 // If entity is in our faction skip it
4055 if (entityHavePartOfFactions(epAttacked
, thisFaction
))
4058 aggroEntity(epAttacked
);
4063 void CGrpProfileFaction::updateProfile(uint ticksSinceLastUpdate
)
4065 checkTargetsAround();
4066 CGrpProfileNormal::updateProfile(ticksSinceLastUpdate
);
4069 string
CGrpProfileFaction::getOneLineInfoString() const
4071 return "faction profile";
4074 //////////////////////////////////////////////////////////////////////////////
4075 // Profile factories implementation //
4076 //////////////////////////////////////////////////////////////////////////////
4078 //- Singleton profiles (stateless ones) --------------------------------------
4080 CBotProfileStandAtPosFactory BotProfileStandAtPosFactory
;
4081 CBotProfileForageFactory BotProfileForageFactory
;
4082 CGrpProfileFightFactory GrpProfileFightFactory
;
4084 //- Factory registering ------------------------------------------------------
4086 // CGrpProfileGuardFactory
4087 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileGuardFactory
, "guard");
4089 // CGrpProfileTribuFactory
4090 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileTribuFactory
, "tribu");
4092 // CGrpProfileIdleFactory
4093 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileIdleFactory
, "idle");
4095 // CGrpProfileStandAtStartPointFactory
4096 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileStandAtStartPointFactory
, "stand_on_start_point");
4098 // CGrpProfileEscortedFactory
4099 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileEscortedFactory
, "escorted");
4101 // CGrpProfileGuardEscorted Factory
4102 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileGuardEscortedFactory
, "guard_escorted");
4104 // CGrpProfileSquadFactory
4105 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileSquadFactory
, "squad");
4107 // CGrpProfileFactionFactory
4108 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileFactionFactory
, "faction");
4110 // CGrpProfileStandOnVerticesFactory
4111 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileStandOnVerticesFactory
, "stand_on_vertices");
4113 // CGrpProfileWanderFactory
4114 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileWanderFactory
, "wander");
4116 // CGrpProfileNormalFactory
4117 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileNormalFactory
, "normal");
4119 // CGrpProfileFollowRouteFactory
4120 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileFollowRouteFactory
, "follow_route");
4122 // CGrpProfileNoChangeFactory
4123 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileNoChangeFactory
, "no_change");
4125 // CGrpProfileBanditFactory
4126 NLMISC::CSmartPtr
<IAIProfile
> CGrpProfileBanditFactory::createAIProfile(CProfileOwner
* owner
)
4128 LOG("bandit group profile factory create");
4129 static bool firstCall
= true;
4132 CConfigFile::CVar
*v
= IService::getInstance()->ConfigFile
.getVarPtr("DefaultBanditAggroRange");
4134 _DefaultAggroRange
= v
->asFloat();
4136 _DefaultAggroRange
= 15.0f
;
4139 return new CGrpProfileBandit(owner
);
4141 float CGrpProfileBanditFactory::getDefaultBanditAggroRange()
4143 return _DefaultAggroRange
;
4145 float CGrpProfileBanditFactory::_DefaultAggroRange
;
4146 RYAI_REGISTER_PROFILE_FACTORY(CGrpProfileBanditFactory
, "bandit");
4148 // Global profile factory stuff. This should be put in some profile.cpp since it's common with fauna profiles.
4149 IAIProfileFactory
* lookupAIGrpProfile(const char *name
)
4151 IAIProfileFactory
*ret
= CAiFactoryIndirect
<IAIProfileFactory
, std::string
>::instance().getFactory(std::string(name
));
4153 nlwarning("Can't find activity '%s', returning NULL", name
);
4156 RYAI_IMPLEMENT_FACTORY_INDIRECT(IAIProfileFactory
, std::string
);
4158 //***************************************************************************/
4159 /* Below that line is magical ununderstandable stuff */
4160 //***************************************************************************/
4162 float getDistBetWeen(CAIEntityPhysical
& creat1
, CAIEntityPhysical
& creat2
)
4164 // coz player position is not updated really 'goodly' as it can be in a invalid ai map position.
4165 float angTo
= (creat1
.pos().angleTo(creat2
.pos())).asRadians();
4167 return creat1
.getCollisionDist(angTo
) + creat2
.getCollisionDist(-angTo
);
4170 //////////////////////////////////////////////////////////////////////////////
4171 // CBotProfileMoveTo //
4172 //////////////////////////////////////////////////////////////////////////////
4174 CBotProfileMoveTo::CBotProfileMoveTo(AITYPES::TVerticalPos verticalPos
, RYAI_MAP_CRUNCH::CWorldPosition
const& dest
, CProfileOwner
* owner
)
4176 , _VerticalPos(verticalPos
)
4178 , _PathCont(NLMISC::safe_cast
<CSpawnBotNpc
*>(owner
)->getAStarFlag())
4179 , _PathPos(NLMISC::safe_cast
<CSpawnBotNpc
*>(owner
)->theta())
4180 , _Bot(NLMISC::safe_cast
<CSpawnBotNpc
*>(owner
))
4182 PROFILE_LOG("bot", "move_to", "ctor", "");
4187 nlassert(dest
.x()!=0 || dest
.y()!=0);
4191 void CBotProfileMoveTo::beginProfile()
4193 PROFILE_LOG("bot", "move_to", "begin", "");
4194 _LastPos
= CAIVector(_Bot
->pos());
4195 _PathCont
.setDestination(_VerticalPos
, _Dest
);
4196 _Status
= CFollowPath::FOLLOWING
;
4199 void CBotProfileMoveTo::endProfile()
4201 PROFILE_LOG("bot", "move_to", "end", "");
4204 void CBotProfileMoveTo::updateProfile(uint ticksSinceLastUpdate
)
4206 H_AUTO(BotMoveToProfileUpdate
);
4207 CFollowPathContext
fpcBotMoveToProfileUpdate("BotMoveToProfileUpdate");
4209 if (!_Bot
->canMove())
4212 if (_Status
!= CFollowPath::FOLLOW_ARRIVED
)
4214 static const std::string
runParameter("running");
4216 if (_Bot
->getPersistent().getOwner()->getSpawnObj()->checkProfileParameter(runParameter
))
4217 dist
=_Bot
->runSpeed()*ticksSinceLastUpdate
;
4219 dist
=_Bot
->walkSpeed()*ticksSinceLastUpdate
;
4221 _Status
= CFollowPath::getInstance()->followPath(
4228 if (_Status
==CFollowPath::FOLLOW_NO_PATH
)
4230 // get a base pointer to allow virtual call to work
4232 //nlwarning("Follow No Path : %s", _Bot->getPersistent().getOneLineInfoString().c_str());
4237 bool CBotProfileMoveTo::destinationReach() const
4239 return _Status
== CFollowPath::FOLLOW_ARRIVED
4240 || _Status
==CFollowPath::FOLLOW_NO_PATH
;
4243 std::string
CBotProfileMoveTo::getOneLineInfoString() const
4245 return "move_to bot profile";
4248 //////////////////////////////////////////////////////////////////////////////
4249 // CBotProfileFollowPos //
4250 //////////////////////////////////////////////////////////////////////////////
4252 CBotProfileFollowPos::CBotProfileFollowPos(CBotProfileFollowPos
const& other
)
4254 , _PathPos(const_cast<CBotProfileFollowPos
&>(other
)._PathPos
._Angle
) // Just to debug...
4255 , _Bot(const_cast<CBotProfileFollowPos
&>(other
)._Bot
)
4256 , _PathCont(const_cast<CBotProfileFollowPos
&>(other
)._PathCont
)
4257 , _MaxWalkSpeed(FLT_MAX
)
4258 , _MaxRunSpeed(FLT_MAX
)
4261 PROFILE_LOG("bot", "follow_pos", "ctor", "");
4267 CBotProfileFollowPos::CBotProfileFollowPos(CPathCont
* pathCont
, CProfileOwner
* owner
)
4269 , _PathPos(NLMISC::safe_cast
<CSpawnBotNpc
*>(owner
)->theta())
4270 , _Bot(NLMISC::safe_cast
<CSpawnBotNpc
*>(owner
))
4271 , _PathCont(pathCont
)
4272 , _MaxWalkSpeed(FLT_MAX
)
4273 , _MaxRunSpeed(FLT_MAX
)
4276 PROFILE_LOG("bot", "follow_pos", "ctor", "");
4282 void CBotProfileFollowPos::beginProfile()
4284 PROFILE_LOG("bot", "follow_pos", "begin", "");
4285 _Status
= CFollowPath::FOLLOWING
;
4288 void CBotProfileFollowPos::endProfile()
4290 PROFILE_LOG("bot", "follow_pos", "end", "");
4293 void CBotProfileFollowPos::updateProfile(uint ticksSinceLastUpdate
)
4295 H_AUTO(BotFollowPosProfileUpdate
);
4296 CFollowPathContext
fpcBotFollowPosProfileUpdate("BotFollowPosProfileUpdate");
4298 if (!_Bot
->canMove() || _Stop
)
4301 static const std::string
runParameter("running");
4304 if (_Bot
->getPersistent().getOwner()->getSpawnObj()->checkProfileParameter(runParameter
))
4305 speed
= std::min(_Bot
->runSpeed(), _MaxRunSpeed
);
4307 speed
= std::min(_Bot
->walkSpeed(), _MaxWalkSpeed
);
4309 dist
= speed
*ticksSinceLastUpdate
;
4311 CPathCont
&pathContRef
=*_PathCont
;
4312 if (_Status
!=CFollowPath::FOLLOW_NO_PATH
)
4314 _Status
= CFollowPath::getInstance()->followPath(
4322 if (_Status
==CFollowPath::FOLLOW_NO_PATH
)
4324 // R2_PRIMITIVE_LAXITY
4325 if (!IsRingShard
.get())
4327 nlwarning("Follow No Path for '%s'%s",
4328 _Bot
->getPersistent().getAliasFullName().c_str(),
4329 _Bot
->getPersistent().getAliasString().c_str());
4334 std::string
CBotProfileFollowPos::getOneLineInfoString() const
4336 std::string info
= "follow_pos bot profile";
4337 info
+= " stop=" + NLMISC::toString(_Stop
);
4338 info
+= " max_walk_speed=" + NLMISC::toString(_MaxWalkSpeed
);
4339 info
+= " max_run_speed=" + NLMISC::toString(_MaxRunSpeed
);
4343 void CBotProfileFollowPos::setMaxSpeeds(float walkSpeed
, float runSpeed
)
4345 _MaxWalkSpeed
= walkSpeed
;
4346 _MaxRunSpeed
= runSpeed
;
4349 void CBotProfileFollowPos::setStop(bool stop
)
4354 //////////////////////////////////////////////////////////////////////////////
4355 // CBotProfileWanderBase //
4356 //////////////////////////////////////////////////////////////////////////////
4358 CBotProfileWanderBase::CBotProfileWanderBase()
4361 PROFILE_LOG("bot", "wander_base", "ctor", "");
4364 void CBotProfileWanderBase::setTimer(uint32 ticks
)
4369 bool CBotProfileWanderBase::testTimer() const
4371 return _Timer
.test();
4374 //////////////////////////////////////////////////////////////////////////////
4375 // CBotProfileStandAtPos //
4376 //////////////////////////////////////////////////////////////////////////////
4378 CBotProfileStandAtPos::CBotProfileStandAtPos(CProfileOwner
* owner
)
4379 : CBotProfileWanderBase()
4380 , _Bot(NLMISC::safe_cast
<CSpawnBotNpc
*>(owner
))
4382 PROFILE_LOG("bot", "stand_at_pos", "ctor", "");
4388 void CBotProfileStandAtPos::beginProfile()
4390 PROFILE_LOG("bot", "stand_at_pos", "begin", "");
4393 void CBotProfileStandAtPos::endProfile()
4395 PROFILE_LOG("bot", "stand_at_pos", "end", "");
4398 void CBotProfileStandAtPos::updateProfile(uint ticksSinceLastUpdate
)
4402 std::string
CBotProfileStandAtPos::getOneLineInfoString() const
4404 return "stand_at_pos bot profile";
4407 //////////////////////////////////////////////////////////////////////////////
4408 // CBotProfileForage //
4409 //////////////////////////////////////////////////////////////////////////////
4411 CBotProfileForage::CBotProfileForage(CProfileOwner
* owner
)
4412 : CBotProfileWanderBase()
4413 , _Bot(NLMISC::safe_cast
<CSpawnBotNpc
*>(owner
))
4414 , _TemporarySheetUsed(false)
4416 PROFILE_LOG("bot", "forage", "ctor", "");
4423 CBotProfileForage::~CBotProfileForage()
4425 PROFILE_LOG("bot", "forage", "dtor", "");
4427 nlassert(_TemporarySheetUsed
==false);
4429 if (_TemporarySheetUsed
)
4431 setOldSheet(); // if this leads to a virtual pure call somewhere,
4432 // try to ask profileOwner to flush its profile in Bot dtor,
4433 // which is a proper way to delete objects.
4437 void CBotProfileForage::beginProfile()
4439 PROFILE_LOG("bot", "forage", "begin", "");
4440 // begin first forage in 3-10 second
4441 _ForageTimer
.set(30+CAIS::rand32(70));
4443 static const NLMISC::CSheetId
forageTool("itforage.sitem");
4445 AISHEETS::ICreature *cs = new AISHEETS::CCreature(*_Bot->getPersistent().getSheet());
4446 _OldSheet = _Bot->getPersistent().getSheet();
4447 cs->LeftItem = NLMISC::CSheetId();
4448 cs->RightItem = forageTool;
4449 _Bot->getPersistent().setSheet(cs);
4450 _Bot->getPersistent().sendVPA();
4451 _TemporarySheetUsed = true;
4453 nlerror("This profile has been broken (above block commented), it shouldn't be used");
4456 _Bot
->setBehaviour(MBEHAV::PROSPECTING
);
4459 void CBotProfileForage::endProfile()
4461 PROFILE_LOG("bot", "forage", "end", "");
4462 // stop foraging if needed
4463 if (_Bot
->getBehaviour() == MBEHAV::EXTRACTING
)
4464 _Bot
->setBehaviour(MBEHAV::EXTRACTING_END
);
4465 else if (_Bot
->getBehaviour() == MBEHAV::PROSPECTING
)
4466 _Bot
->setBehaviour(MBEHAV::PROSPECTING_END
);
4470 nlerror("This profile has been broken (above block commented), it shouldn't be used");
4473 void CBotProfileForage::updateProfile(uint ticksSinceLastUpdate
)
4475 H_AUTO(BotForageProfileUpdate
);
4476 CFollowPathContext
fpcBotForageProfileUpdate("BotForageProfileUpdate");
4478 if (_ForageTimer
.test())
4480 // somethink to do :)
4481 if (_Bot
->getBehaviour() != MBEHAV::EXTRACTING
)
4484 CAngle a
= _Bot
->theta();
4485 CAngle
newAngle(CAIS::randPlusMinus(CAngle::PI
/4));
4486 _Bot
->setTheta(a
+newAngle
);
4489 _Bot
->setBehaviour(MBEHAV::EXTRACTING
);
4491 // forage for 10 to 15 sec
4492 _ForageTimer
.set(100+CAIS::rand32(50));
4494 else if (_Bot
->getBehaviour() == MBEHAV::EXTRACTING
)
4497 _Bot
->setBehaviour(MBEHAV::PROSPECTING
);
4499 // wait 20-30s before next forage
4500 _ForageTimer
.set(250+CAIS::rand32(50));
4505 void CBotProfileForage::setOldSheet()
4507 AISHEETS::ICreatureCPtr cs
= _Bot
->getPersistent().getSheet();
4508 _Bot
->getPersistent().setSheet(_OldSheet
);
4509 _Bot
->getPersistent().sendVPA();
4510 _TemporarySheetUsed
= false;
4511 // delete const_cast<AISHEETS::ICreature*>(cs);
4512 nlerror("This profile has been broken (above line commented), it shouldn't be used");
4515 std::string
CBotProfileForage::getOneLineInfoString() const
4517 return "forage bot profile";
4520 //////////////////////////////////////////////////////////////////////////////
4521 // CGrpProfileNormal //
4522 //////////////////////////////////////////////////////////////////////////////
4524 CGrpProfileNormal::CGrpProfileNormal(CProfileOwner
* owner
)
4525 : _Grp(NLMISC::safe_cast
<CSpawnGroupNpc
*>(owner
))
4526 //, _GroupFighting(false) // :KLUDGE: Replaced by a bug simulation
4528 PROFILE_LOG("group", "normal", "ctor", "");
4529 // This should be part of init list, but can't do conditionnal init
4532 /* Following statement was missing in initialization list. */
4536 _GroupFighting
= false;
4540 bool CGrpProfileNormal::isGroupFighting() const
4542 return _GroupFighting
;
4545 void CGrpProfileNormal::setGroupFighting(bool groupFighting
)
4547 if (_GroupFighting
!=groupFighting
)
4549 _GroupFighting
=groupFighting
;
4551 CGroupNpc
&grp
=_Grp
->getPersistent();
4553 grp
.processStateEvent(grp
.getEventContainer().EventGroupBeginFight
);
4555 grp
.processStateEvent(grp
.getEventContainer().EventGroupEndFight
);
4559 //////////////////////////////////////////////////////////////////////////////
4561 //////////////////////////////////////////////////////////////////////////////
4563 CSlaveProfile::CSlaveProfile(CProfileOwner
* owner
)
4564 : _Grp(NLMISC::safe_cast
<CSpawnGroupNpc
*>(owner
))
4566 PROFILE_LOG("base", "slave", "ctor", "");
4569 void CSlaveProfile::beginProfile()
4571 PROFILE_LOG("base", "slave", "begin", "");
4572 FOREACH(itBot
, CCont
<CBot
>, _Grp
->bots())
4575 CSpawnBot
* spawnBot
= bot
->getSpawnObj();
4576 if (!spawnBot
|| !spawnBot
->isAlive())
4582 void CSlaveProfile::updateProfile(uint ticksSinceLastUpdate
)
4586 //////////////////////////////////////////////////////////////////////////////
4588 //////////////////////////////////////////////////////////////////////////////
4590 CMoveProfile::CMoveProfile(CProfileOwner
* owner
)
4591 : CSlaveProfile(owner
)
4592 , _MaxRunSpeed(FLT_MAX
)
4593 , _MaxWalkSpeed(FLT_MAX
)
4595 PROFILE_LOG("base", "move", "ctor", "");
4598 void CMoveProfile::resumeBot(CBot
const* bot
)
4600 CSpawnBot
* spawnBot
= bot
->getSpawnObj();
4604 CPathCont
* pathCont
= getPathCont(bot
);
4608 spawnBot
->setAIProfile(new CBotProfileFollowPos(pathCont
, spawnBot
));
4611 //////////////////////////////////////////////////////////////////////////////
4613 //////////////////////////////////////////////////////////////////////////////
4615 CFightProfile::CFightProfile(CProfileOwner
* owner
)
4616 : CSlaveProfile(owner
)
4618 PROFILE_LOG("base", "fight", "ctor", "");
4621 //////////////////////////////////////////////////////////////////////////////
4622 // CGrpProfileFollowRoute //
4623 //////////////////////////////////////////////////////////////////////////////
4625 CGrpProfileFollowRoute::~CGrpProfileFollowRoute()
4627 PROFILE_LOG("group", "follow_route", "dtor", "");
4628 FOREACH(itBot
, CCont
<CBot
>, _Grp
->bots())
4632 CGrpProfileFollowRoute::CBotFollower::CBotFollower()
4637 CGrpProfileFollowRoute::CBotFollower::~CBotFollower()
4641 void CGrpProfileFollowRoute::CBotFollower::setBotAtDest(bool atDest
)
4643 _BotAtDest
= atDest
;
4646 const bool& CGrpProfileFollowRoute::CBotFollower::isBotAtDest() const
4651 bool CGrpProfileFollowRoute::getDirection()
4653 return _FollowForward
;
4657 CPathCont
* CGrpProfileFollowRoute::getPathCont(CBot
const* bot
)
4662 std::string
CGrpProfileFollowRoute::getOneLineInfoString() const
4664 std::string info
= "follow_route group profile";
4665 info
+= " stop_npc=" + NLMISC::toString(_StopNpc
);
4669 bool CGrpProfileFollowRoute::profileTerminated() const
4671 return _ProfileTerminated
;
4674 void CGrpProfileFollowRoute::stopNpc(bool stop
)
4679 //////////////////////////////////////////////////////////////////////////////
4680 // CGrpProfileStandOnVertices //
4681 //////////////////////////////////////////////////////////////////////////////
4683 CGrpProfileStandOnVertices::CBotPositionner::CBotPositionner(RYAI_MAP_CRUNCH::TAStarFlag flags
)
4688 CGrpProfileStandOnVertices::CBotPositionner::CBotPositionner(uint32 geomIndex
, RYAI_MAP_CRUNCH::TAStarFlag flags
)
4690 , _GeomIndex(geomIndex
)
4695 void CGrpProfileStandOnVertices::CBotPositionner::setBotAtDest(bool atDest
)
4700 bool CGrpProfileStandOnVertices::CBotPositionner::isBotAtDest() const
4705 CGrpProfileStandOnVertices::CGrpProfileStandOnVertices(CProfileOwner
* owner
)
4706 : CMoveProfile(owner
)
4707 , _DenyFlags(NLMISC::safe_cast
<CSpawnGroup
*>(owner
)->getPersistent().getAStarFlag())
4709 PROFILE_LOG("group", "stand_on_vertices", "ctor", "");
4712 CGrpProfileStandOnVertices::~CGrpProfileStandOnVertices()
4714 PROFILE_LOG("group", "stand_on_vertices", "dtor", "");
4715 for (CCont
<CBot
>::iterator it
=_Grp
->bots().begin(), itEnd
=_Grp
->bots().end();it
!=itEnd
;++it
)
4721 void CGrpProfileStandOnVertices::endProfile()
4723 PROFILE_LOG("group", "stand_on_vertices", "end", "");
4726 std::string
CGrpProfileStandOnVertices::getOneLineInfoString() const
4728 std::string info
= "stand_on_vertices group profile";
4729 info
+= " finished=" + NLMISC::toString(_Finished
);
4734 //- Complex profile factories ------------------------------------------------
4736 // CBotProfileMoveToFactory (with specialization)
4737 typedef CAIGenericProfileFactory
<CBotProfileMoveTo
> CBotProfileMoveToFactory
;
4739 NLMISC::CSmartPtr
<IAIProfile
> CAIGenericProfileFactory
<CBotProfileMoveTo
>::createAIProfile(CProfileOwner
* owner
)
4741 nlerror("This profile factory (CBotProfileMoveToFactory) can't be used");
4745 // CBotProfileFollowPosFactory (with specialization)
4746 typedef CAIGenericProfileFactory
<CBotProfileFollowPos
> CBotProfileFollowPosFactory
;
4748 NLMISC::CSmartPtr
<IAIProfile
> CAIGenericProfileFactory
<CBotProfileFollowPos
>::createAIProfile(CProfileOwner
* owner
)
4750 nlerror("This profile factory (CBotProfileFollowPosFactory) can't be used");
4754 #include "event_reaction_include.h"