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/>.
20 #include "nel/misc/smart_ptr.h"
21 #include "family_profile.h"
22 #include "continent.h"
23 #include "ai_grp_fauna.h"
24 #include "ai_grp_npc.h"
25 #include "ai_mgr_fauna.h"
26 #include "ai_mgr_npc.h"
27 #include "group_profile.h"
28 #include "family_behavior.h"
29 #include "family_profile_tribe.h"
31 #include "continent_inline.h"
34 using namespace NLMISC
;
35 using namespace AITYPES
;
36 using namespace RYAI_MAP_CRUNCH
;
38 CAiFactory
<IFamilyProfile
, CFamilyProfileTribe
> _singleProfileTribe
;
39 IAiFactory
<IFamilyProfile
> *_ProfileTribe
=&_singleProfileTribe
;
43 //CPropertyId act_fz_spawn("activity_fauna_spawn");
45 //CPropertyId act_fz_food_herb("activity_fauna_food_herb");
46 //CPropertyId act_fz_food_carn("activity_fauna_food_carn");
47 //CPropertyId act_fz_rest_herb("activity_fauna_rest_herb");
48 //CPropertyId act_fz_rest_carn("activity_fauna_rest_carn");
50 //CPropertyId act_nz_harvest("activity_npc_harvest");
51 //CPropertyId act_nz_ambush("activity_npc_ambush");
52 //CPropertyId act_nz_rest("activity_npc_rest");
53 //CPropertyId act_nz_outpost("activity_npc_outpost");
54 //CPropertyId act_nz_spawn("activity_npc_spawn");
55 //CPropertyId act_nz_outpost_def("activity_npc_outpost_def");
56 //CPropertyId act_nz_outpost_atk("activity_npc_outpost_atk");
57 //CPropertyId act_nz_kami_wander("activity_npc_kami_wander");
58 //CPropertyId act_nz_escort("activity_npc_escort");
59 //CPropertyId act_nz_convoy("activity_npc_convoy");
60 //CPropertyId act_nz_contact("activity_npc_contact");
61 //CPropertyId act_nz_fight("activity_npc_fight");
63 //CPropertyId act_nz_contact_camp("activity_npc_contact_camp");
64 //CPropertyId act_nz_contact_outpost("activity_npc_contact_outpost");
65 //CPropertyId act_nz_contact_city("activity_npc_contact_city");
66 //// CPropertyId act_nz_contact_city("activity_npc_fight_boss"); problem ?
67 //CPropertyId act_nz_fight_boss("act_nz_fight_boss");
69 //CPropertyId act_fz_food_kitin("act_fz_food_kitin");
70 //CPropertyId act_fz_food_kitin_invasion("act_fz_food_kitin_invasion");
71 //CPropertyId act_fz_rest_kitin_invasion("act_fz_rest_kitin_invasion");
72 //CPropertyId act_fz_food_degen("act_fz_food_degen");
73 //CPropertyId act_fz_plant("act_fz_plant");
74 //CPropertyId act_fz_rest_kitin("act_fz_rest_kitin");
75 //CPropertyId act_fz_rest_degen("act_fz_rest_degen");
79 // +faire gaffe à l'init du CGrpProfileFollowRoute dans le cadre statique .. :\ (adapter?)//
80 // (done)+ dynCamping n'a pas une bonne current zone, -> à mettre.
81 // (done)+ problème d'ordre des points pour le suivit de chemin.
82 // + vérifier que les comportements statiques fonctionnent toujours avec le nouveau code (régression).
84 // - Choisir le comportement au spawn des groupes.
85 // - Mettre des activités dans les événements d'OutPosts. (pas de chianlie..).
86 // - Vérifer la logique des comportements (pas de trous).
87 // - Vérifier que currentZone est bien géré dans les classes.
89 // - Death report / OutPosts.
90 // - getGeometry (forced by the unconceptualized finite state machine script implementation legacy in the leveldesign :( ).
92 // - mettre un coup de boule dans le mur pour se calmer.
94 void COutpostInfo::checkDespawnGroupList ()
97 while (_DespawnList
.size()>0)
99 CGroupNpc
*grpNpc
=_DespawnList
.back();
100 _DespawnList
.pop_back();
103 TGroupList::iterator it
=_FightGroup
.begin();
104 const TGroupList::iterator itEnd
=_FightGroup
.end();
106 for (;(it
!=itEnd
) && ((*it
).ptr()!=grpNpc
);++it
);
111 _FightGroup
.erase(it
);
118 TGroupList::iterator it
=_ContactGroups
.begin();
119 const TGroupList::iterator itEnd
=_ContactGroups
.end();
121 for (;(it
!=itEnd
) && ((*it
).ptr()!=grpNpc
);++it
);
126 _ContactGroups
.erase(it
);
132 nlassert(true==false); // unknown group.
139 void COutpostInfo::spawnBoss ()
143 void COutpostInfo::outpostEvent (ZCSTATE::TZcState state
)
145 if (_ZoneNpc
.isNULL())
150 // sets group presence in the outpost.
153 case ZCSTATE::Tribe
: // no charge
159 case ZCSTATE::TribeInWar
: // tribe got the outpost, tribe is in war
160 case ZCSTATE::GuildInWar
: // Guild got the outpost, Guild is in war
163 contactGroups(false);
166 case ZCSTATE::GuildInPeace
: // Guild got the outpost, Guild is in peace
169 contactGroups(false);
175 void COutpostInfo::fightGroups(bool exist
)
181 // if (_FightGroupExist) // if no groups, spawn them ..
184 // CCellZone &cellZone=_FamilyBehavior->getOwner();
186 // for (uint i=0; i<10; ++i)
188 // // look for a fight group
189 // const CGroupDesc *const gd = cellZone.getOwner()->getProportionalGroupDesc(_FamilyBehavior, act_nz_fight, act_nz_fight_boss);
193 // // set the npc of the group attackable
194 // gd->setAttackable(true);
196 // // look for a spawn point
197 // const CNpcZone *const spawnZone = cellZone.lookupNpcZone(/*_FamilyBehavior->getFamily(),*/ act_nz_spawn);
201 // // Look for a defense zone
202 // const CNpcZone *const defZone = cellZone.lookupNpcZone(/*_FamilyBehavior->getFamily(),*/ act_nz_outpost_def);
206 // CGroupNpc *const grp = _FamilyProfileTribe->createNpcGroup(spawnZone,gd);
210 // grp->setDiscardable (false);
211 // // this group will run !
212 // grp->mergeProfileParameter (CProfileParameters::TProfileParameter("running", "", 0));
214 // CGrpProfileDynFight *dynFight=new CGrpProfileDynFight(grp->getSpawnObj(),_FamilyProfileTribe, spawnZone, this);
215 // grp->getSpawnObj()->activityProfile().setAIProfile (dynFight);
216 // dynFight->gotoZone(defZone, act_nz_outpost_atk+act_nz_contact_camp);
217 // _FightGroup.push_back(grp);
223 // if (!_FightGroupExist)
226 // for (TGroupList::iterator it=_FightGroup.begin(), itEnd=_FightGroup.end();it!=itEnd;++it)
228 // NLMISC::CDbgPtr<CGroupNpc> &dbgPtr=*it;
230 // nlassert(!dbgPtr.isNULL());
232 // CGrpProfileDynFight *dynFight=safe_cast<CGrpProfileDynFight*>(dbgPtr->getSpawnObj()->activityProfile().getAIProfile());
233 // dynFight->gotoZone(_FamilyProfileTribe->getCampZone(),CPropertySet());
237 // _FightGroupExist=exist;
241 void COutpostInfo::bossGroups(bool exist
) // not implemented yet.
243 _BossGroupExist
=exist
;
246 void COutpostInfo::contactGroups(bool exist
) // contact groups ..
251 // if (_ContactGroupExist)
254 // // try to create a contact group
257 // const CGroupDesc *gd = _FamilyBehavior->getOwner()->getOwner()->getProportionalGroupDesc(_FamilyBehavior, act_nz_contact+act_nz_contact_camp, act_nz_escort+act_nz_convoy+act_nz_fight_boss);
261 // CGroupNpc *const grp=_FamilyProfileTribe->createNpcGroup(_FamilyProfileTribe->getCampZone(),gd);
265 // grp->getSpawnObj()->activityProfile().setAIProfile(new CGrpProfileDynContact(grp->getSpawnObj(), _FamilyProfileTribe, this, true));
266 // _ContactGroups.push_back(grp);
269 // // 2 other contacts
270 // for (uint32 i=0;i<2;i++)
272 // // try to create a contact group
273 // const CGroupDesc *gd = _FamilyBehavior->getOwner()->getOwner()->getProportionalGroupDesc(_FamilyBehavior, act_nz_contact+act_nz_contact_outpost, act_nz_escort+act_nz_convoy);
277 // CGroupNpc *const grp=_FamilyProfileTribe->createNpcGroup(_FamilyProfileTribe->getCampZone(),gd);
281 // grp->getSpawnObj()->activityProfile().setAIProfile(new CGrpProfileDynContact(grp->getSpawnObj(), _FamilyProfileTribe, this));
282 // _ContactGroups.push_back(grp);
289 // if (!_ContactGroupExist)
292 // for (TGroupList::iterator it=_ContactGroups.begin(), itEnd=_ContactGroups.end();it!=itEnd;++it)
294 // NLMISC::CDbgPtr<CGroupNpc> &dbgPtr=*it;
295 // CGrpProfileDynFight *dynFight=safe_cast<CGrpProfileDynFight*>(dbgPtr->getSpawnObj()->activityProfile().getAIProfile());
296 // dynFight->gotoZone(_FamilyProfileTribe->getCampZone(),CPropertySet());
300 // _ContactGroupExist=exist;
304 void COutpostInfo::updateOutPostInfo ()
306 checkDespawnGroupList ();
311 CFamilyProfileTribe::CFamilyProfileTribe (const CtorParam
&ctorParam
)
312 :IFamilyProfile(ctorParam
)
314 // choose a camp zone.
315 // need to choose a camp zone
316 static CPropertyId
act_nz_rest("activity_rest");
317 _CampZone
= _FamilyBehavior
->getOwner()->lookupNpcZone(_FamilyBehavior
->getFamilyTag()+act_nz_rest
, _FamilyBehavior
->grpFamily()->getSubstitutionId());
321 const NLMISC::CVirtualRefCount
*const param
=ctorParam
.familyBehavior()->grpFamily()->getProfileParams("aggro_groups");
322 const CAggroGroupContainer
*const aggroGroupContainer
=type_cast
<const CAggroGroupContainer
*>(param
);
323 if (aggroGroupContainer
)
324 _AggroGroupIds
=aggroGroupContainer
->aggroGroupIds
;
329 void CFamilyProfileTribe::setDefaultProfile(const CNpcZone
*const zone
, CGroupNpc
*grp
)
334 static CPropertyId
act_nz_harvest("activity_harvest");
335 CSpawnGroupNpc
*const spawnGrp
=grp
->getSpawnObj();
336 const CNpcZone
*const dest
= getFamilyBehavior()->getOwner()->lookupNpcZone(act_nz_harvest
, getFamilyBehavior()->grpFamily()->getSubstitutionId());
340 spawnGrp
->activityProfile().setAIProfile(new CGrpProfileDynWaitInZone(spawnGrp
,zone
));
343 spawnGrp
->activityProfile().setAIProfile(new CGrpProfileDynHarvest(spawnGrp
,this,dest
,zone
));
346 void CFamilyProfileTribe::outpostAdd(NLMISC::TStringId outpostName
)
348 if (_OutpostInfos
.find(outpostName
) != _OutpostInfos
.end())
354 nldebug("OUTPOST: adding outpost '%s' to tribe '%s' control in '%s'",
355 CStringMapper::unmap(outpostName
).c_str(),
356 _FamilyBehavior
->getName().c_str(),
357 _FamilyBehavior
->getOwner()->getAliasFullName().c_str());
360 CSmartPtr
<COutpostInfo
> outPost
=COutpostInfo::createOutpost(_FamilyBehavior
,this,outpostName
);
363 static map
<CFamilyProfileTribe
*, set
<TStringId
> > warnOnce
;
364 if (warnOnce
[this].find(outpostName
) == warnOnce
[this].end())
366 nlwarning("OUTPOST: no zone found for outpost '%s'", CStringMapper::unmap(outpostName
).c_str());
367 warnOnce
[this].insert(outpostName
);
371 _OutpostInfos
.insert(make_pair(outpostName
, outPost
));
374 void CFamilyProfileTribe::outpostRemove(NLMISC::TStringId outpostName
)
376 TOutpostContainer::iterator
it(_OutpostInfos
.find(outpostName
));
377 if (it
==_OutpostInfos
.end())
380 // nlassert(it != _OutpostInfos.end());
383 nldebug("OUTPOST: Removing outpost '%s' to tribe 'ss' control in '%s'",
384 CStringMapper::unmap(outpostName
).c_str(),
385 /*_FamilyBehavior->getFamily().getFamilyName().c_str(),*/
386 _FamilyBehavior
->getOwner()->getAliasFullName().c_str());
388 _OutpostInfos
.erase(it
);
391 void CFamilyProfileTribe::spawnBoss(NLMISC::TStringId outpostName
)
393 TOutpostContainer::iterator
it(_OutpostInfos
.find(outpostName
));
394 if (it
==_OutpostInfos
.end())
397 // nlassert(it != _OutpostInfos.end());
398 it
->second
->spawnBoss();
401 void CFamilyProfileTribe::spawnGroup()
403 H_AUTO(FamilySpawnTribe
)
404 static CPropertyId
act_nz_spawn("activity_spawn");
406 if (getCampZone().isNull())
409 static CPropertyId
act_nz_rest("activity_rest");
410 const CNpcZone
*const spawn
= _FamilyBehavior
->getOwner()->lookupNpcZone(/*_FamilyBehavior->getFamily(),*/ act_nz_spawn
+act_nz_rest
, _FamilyBehavior
->grpFamily()->getSubstitutionId());
415 static CPropertyId
act_nz_escort("activity_escort");
416 static CPropertyId
act_nz_contact("activity_contact");
417 static CPropertyId
act_nz_fight_boss("act_nz_fight_boss");
419 // CCellZone &cellZone=_FamilyBehavior->getOwner();
420 const CGroupDesc
<CGroupFamily
> *const gd
= _FamilyBehavior
->grpFamily()->getProportionalGroupDesc(_FamilyBehavior
, CPropertySet(), act_nz_contact
+act_nz_fight_boss
+act_nz_escort
);
425 // set the npc of the group attackable
426 // gd->setAttackable(true);
427 // set the npc of the group vulnerable
428 // gd->setVulnerable(true);
430 const CGroupNpc
*const grp
=createNpcGroup(spawn
,gd
);
435 grp
->getSpawnObj()->spawnBotOfGroup();
439 /// The main update for the profile. Called aprox every 10 s (100 ticks)
440 void CFamilyProfileTribe::update()
442 H_AUTO(FamilyTribeUpdate
)
445 TOutpostContainer::iterator
first(_OutpostInfos
.begin()), last(_OutpostInfos
.end());
446 for (; first
!= last
; ++first
)
447 first
->second
->updateOutPostInfo();
451 /************************************************************************/
453 /************************************************************************/
455 //---------------------------------------------------------------------------------
456 // CGrpProfileDynContact
457 //---------------------------------------------------------------------------------
459 void CGrpProfileDynContact::beginProfile()
461 static CPropertyId
act_nz_rest("activity_rest");
462 static CPropertyId
act_nz_outpost("activity_outpost");
463 _Grp
->movingProfile().setAIProfile(new CGrpProfileDynFollowPath(_Grp
, _CurrentZone
, _FamilyProfile
->getCampZone(), act_nz_outpost
+ act_nz_rest
));
466 // routine called just before bot starts to use a new profile or when a bot dies
467 void CGrpProfileDynContact::endProfile()
471 // routine called every time the bot is updated (frequency depends on player proximity, etc)
473 // there's a coherence problem about the activity.
474 void CGrpProfileDynContact::updateProfile(uint ticksSinceLastUpdate
)
477 // this is a contact group, special treatment
478 switch (_Grp
->movingProfile().getAIProfileType())
481 // we must be in a city or in an outpost, just check the date to return to camp.
482 if (CTimeInterface::timeOfDay()!=CRyzomTime::nightfall
)
485 // go back to the camp.
486 CGrpProfileDynWaitInZone
const* const waitProfile
= safe_cast
<CGrpProfileDynWaitInZone
*>(_Grp
->movingProfile().getAIProfile());
487 _Grp
->movingProfile().setAIProfile(new CGrpProfileDynFollowPath(_Grp
, waitProfile
->currentZone(), _FamilyProfile
->getCampZone(), CPropertySet()));
492 // the group is camping, if the day rise, send them to an outpost or city
493 if (CTimeInterface::timeOfDay()!=CRyzomTime::dawn
)
497 static CPropertyId
act_nz_outpost("activity_outpost");
498 // time to go work childrens!
499 const CNpcZone
*dest
= _FamilyProfile
->getFamilyBehavior()->getOwner()->lookupNpcZone(/*_FamilyProfile->getFamilyBehavior()->getFamily(),*/ act_nz_outpost
, _FamilyProfile
->getFamilyBehavior()->grpFamily()->getSubstitutionId());
502 CGrpProfileDynCamping
const* const campingProfile
= safe_cast
<CGrpProfileDynCamping
*>(_Grp
->movingProfile().getAIProfile());
503 _Grp
->movingProfile().setAIProfile(new CGrpProfileDynFollowPath(_Grp
, campingProfile
->currentZone(), dest
, CPropertySet()));
508 case MOVE_DYN_FOLLOW_PATH
:
510 CGrpProfileDynFollowPath
* profile
= NLMISC::safe_cast
<CGrpProfileDynFollowPath
*>(_Grp
->movingProfile().getAIProfile());
513 if (!profile
->destinationReach())
516 if (!_OutPostInfo
->_ContactGroupExist
)
518 _OutPostInfo
->addToDespawnGroupList(_Grp
);
522 // ok, we are at the road end, what should we do now ?
523 if (_isTheContactGroup
)
524 _Grp
->activityProfile().setAIProfile(new CGrpProfileDynCamping(_Grp
,profile
->currentZone()));
526 _Grp
->activityProfile().setAIProfile(new CGrpProfileDynWaitInZone(_Grp
,profile
->currentZone()));
531 nlassert(true==false);
536 CGrpProfileNormal::updateProfile(ticksSinceLastUpdate
);
539 void CGrpProfileDynContact::gotoZone(const CNpcZone
*const zone
, const CPropertySet
&flags
)
541 _Grp
->movingProfile().setAIProfile(new CGrpProfileDynFollowPath(_Grp
, _CurrentZone
, zone
, flags
));
544 string
CGrpProfileDynContact::buildDebugString() const
549 //---------------------------------------------------------------------------------
550 // CGrpProfileDynHarvest
551 //---------------------------------------------------------------------------------
554 void CGrpProfileDynHarvest::beginProfile()
556 static CPropertyId
act_nz_rest("activity_rest");
557 static CPropertyId
act_nz_harvest("activity_harvest");
558 static CPropertyId
act_nz_outpost("activity_outpost");
559 _Grp
->movingProfile().setAIProfile(new CGrpProfileDynFollowPath(_Grp
, _CurrentZone
, _HarvestZone
, act_nz_outpost
+ act_nz_rest
));
562 // routine called just before bot starts to use a new profile or when a bot dies
563 void CGrpProfileDynHarvest::endProfile()
567 // routine called every time the bot is updated (frequency depends on player proximity, etc)
570 void CGrpProfileDynHarvest::checkTargetsAround ()
572 if (!_checkTargetTimer
.test())
575 _checkTargetTimer
.set(10+CAIS::rand16(2)); // every 11 seconds.
577 if (_FamilyProfile
->_AggroGroupIds
.size()==0)
580 // check if we have a player property.
582 const std::vector
<uint32
> &aggroList
=_FamilyProfile
->_AggroGroupIds
;
583 if (std::find(aggroList
.begin(), aggroList
.end(), AISHEETS::CSheets::getInstance()->playerGroupIndex())==aggroList
.end())
587 CAIVision
<CPersistentOfPhysical
> Vision
;
592 if (!_Grp
->calcCenterPos(centerPos
)) // true if there's some bots in the group.
595 const uint32 playerRadius
=30; // _AggroRange);
596 const uint32 botRadius
=0; // _AggroRange);
598 const uint32 minRadius
=playerRadius
>botRadius
?botRadius
:playerRadius
;
600 Vision
.updateBotsAndPlayers(_Grp
->getPersistent().getAIInstance(), centerPos
, playerRadius
, botRadius
);
604 const std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> > &players
= Vision
.players();
606 std::vector
<NLMISC::CDbgPtr
<CPersistentOfPhysical
> >::const_iterator
first(players
.begin()), last(players
.end());
607 for (; first
!= last
; ++first
)
609 const CPersistentOfPhysical
*const player
= (*first
);
610 const CAIEntityPhysical
*const ep
= player
->getSpawnObj();
613 || ep
->currentHitPoints()<=0.f
)
616 const CRootCell
*const rootCell
=ep
->wpos().getRootCell();
618 && rootCell
->getFlag()!=0 ) // Safe Zone ?
621 _Grp
->setAggroMinimumFor(ep
->dataSetRow(), 0.5f
, false);
626 // there's a coherence problem about the activity.
627 void CGrpProfileDynHarvest::updateProfile(uint ticksSinceLastUpdate
)
629 static CPropertyId
act_nz_harvest("activity_harvest");
630 CProfilePtr
&movingProfile
=_Grp
->movingProfile();
632 // this is a contact group, special treatment
633 switch (movingProfile
.getAIProfileType())
635 // Camping -> Moving(Wandering(Harvesting))
638 // the group is resting in the camp, check activity timeout
639 CGrpProfileDynCamping
const* const profile
= safe_cast
<CGrpProfileDynCamping
*>(movingProfile
.getAIProfile());
640 if (!profile
->timeOut())
643 // send the group to a harvest point
644 const CNpcZone
*const dest
= _FamilyProfile
->getFamilyBehavior()->getOwner()->lookupNpcZone(/*_FamilyProfile->getFamilyBehavior()->getFamily(),*/ act_nz_harvest
, _FamilyProfile
->getFamilyBehavior()->grpFamily()->getSubstitutionId());
646 if (dest
==profile
->currentZone()) // are we already at the right place ?
648 // then lets camp again ..
649 _Grp
->movingProfile().setAIProfile(new CGrpProfileDynCamping(_Grp
,dest
));
653 // send the group to an harvest site.
654 movingProfile
.setAIProfile(new CGrpProfileDynFollowPath(_Grp
, profile
->currentZone(), dest
, CPropertySet()));
660 // Moving -> Wandering(Harvesting)|Camping
661 case MOVE_DYN_FOLLOW_PATH
:
663 CGrpProfileDynFollowPath
const* const fp
= safe_cast
<CGrpProfileDynFollowPath
*>(movingProfile
.getAIProfile());
665 if (!fp
->destinationReach())
668 if (fp
->currentZone()==_FamilyProfile
->getCampZone())
670 // the group just enter the camp, do a camping for some time
671 _Grp
->movingProfile().setAIProfile(new CGrpProfileDynCamping(_Grp
,fp
->currentZone()));
675 // ok the group has reach a destination that is not the camp ..
677 // set the group in wander/forage mode (with zone in param)
678 CGrpProfileWander
*profile
=new CGrpProfileWander(_Grp
,fp
->currentZone());
679 _Grp
->movingProfile().setAIProfile(profile
);
682 profile
->setBotStandProfile(BOT_FORAGE
, &BotProfileForageFactory
);
683 profile
->setTimer(60*10+CAIS::rand32(30*10)); // between 1 to 1:30 minute long ..
687 // Harvesting -> Moving(Camping)
690 // this is a harvest group doing foraging
691 const CGrpProfileWander
* const profile
=safe_cast
<CGrpProfileWander
*>(movingProfile
.getAIProfile());
692 if (!profile
->testTimer())
695 // send the group to a harvest point
696 const CNpcZone
*dest
=NULL
;
699 || dest
==profile
->currentZone())
701 if (CAIS::rand32(9)==0)
702 dest
=_FamilyProfile
->getCampZone();
704 dest
=_FamilyProfile
->getFamilyBehavior()->getOwner()->lookupNpcZone(/*_FamilyProfile->getFamilyBehavior()->getFamily(),*/ act_nz_harvest
, _FamilyProfile
->getFamilyBehavior()->grpFamily()->getSubstitutionId());
707 // send the group to the camp.
708 movingProfile
.setAIProfile(new CGrpProfileDynFollowPath(_Grp
, profile
->currentZone(), dest
, CPropertySet()));
712 default: // don't think we have to be there ..
714 nlassert(true==false);
718 checkTargetsAround ();
719 CGrpProfileNormal::updateProfile(ticksSinceLastUpdate
);
722 string
CGrpProfileDynHarvest::buildDebugString() const
729 //---------------------------------------------------------------------------------
730 // CGrpProfileDynFight
731 //---------------------------------------------------------------------------------
733 void CGrpProfileDynFight::beginProfile()
735 static CPropertyId
act_nz_rest("activity_rest");
736 static CPropertyId
act_nz_harvest("activity_harvest");
737 static CPropertyId
act_nz_outpost("activity_outpost");
739 const CNpcZone
*const dest
= _FamilyProfile
->getFamilyBehavior()->getOwner()->lookupNpcZone(/*_FamilyProfile->getFamilyBehavior()->getFamily(),*/ act_nz_harvest
, _FamilyProfile
->getFamilyBehavior()->grpFamily()->getSubstitutionId());
740 _Grp
->movingProfile().setAIProfile(new CGrpProfileDynFollowPath(_Grp
, _CurrentZone
, dest
, act_nz_outpost
+ act_nz_rest
+ act_nz_harvest
));
743 // routine called just before bot starts to use a new profile or when a bot dies
744 void CGrpProfileDynFight::endProfile()
748 // routine called every time the bot is updated (frequency depends on player proximity, etc)
750 // there's a coherence problem about the activity.
751 void CGrpProfileDynFight::updateProfile(uint ticksSinceLastUpdate
)
753 static CPropertyId
act_nz_outpost("activity_outpost");
754 CProfilePtr
&movingProfile
=_Grp
->movingProfile();
756 // this is a contact group, special treatment
757 switch (movingProfile
.getAIProfileType())
759 // Camping -> Moving(Wandering(Fighting))
762 // the group is resting in the camp, check activity timeout
763 CGrpProfileDynCamping
const* const profile
= safe_cast
<CGrpProfileDynCamping
*>(movingProfile
.getAIProfile());
765 nlassert(_CurrentZone
==profile
->currentZone());
767 if (!profile
->timeOut())
770 // send the group to a harvest point
771 const CNpcZone
*const dest
= _FamilyProfile
->getFamilyBehavior()->getOwner()->lookupNpcZone(/*_FamilyProfile->getFamilyBehavior()->getFamily(),*/ act_nz_outpost
, _FamilyProfile
->getFamilyBehavior()->grpFamily()->getSubstitutionId());
772 // send the group to an harvest site.
773 movingProfile
.setAIProfile(new CGrpProfileDynFollowPath(_Grp
, profile
->currentZone(), dest
, CPropertySet()));
778 // Moving -> Wandering(Fighting)|Camping
779 case MOVE_DYN_FOLLOW_PATH
:
781 CGrpProfileDynFollowPath
const* const fp
= safe_cast
<CGrpProfileDynFollowPath
*>(movingProfile
.getAIProfile());
783 _CurrentZone
=fp
->currentZone();
785 if (!fp
->destinationReach())
788 if (!_OutPostInfo
->_FightGroupExist
)
790 _OutPostInfo
->addToDespawnGroupList(_Grp
);
794 if (fp
->currentZone()==_FamilyProfile
->getCampZone())
796 // the group just enter the camp, do a camping for some time
797 _Grp
->movingProfile().setAIProfile(new CGrpProfileDynCamping(_Grp
,fp
->currentZone()));
801 // ok the group has reach a destination that is not the camp ..
803 // set the group in wander/forage mode (with zone in param)
804 CGrpProfileWander
* profile
= new CGrpProfileWander(_Grp
,fp
->currentZone());
805 _Grp
->movingProfile().setAIProfile(profile
);
807 profile
->setTimer(30*60*10+CAIS::rand32(15*50*10));
811 // Fighting -> Moving(Camping)
814 // this is a harvest group doing foraging
815 CGrpProfileWander
const* const profile
= safe_cast
<CGrpProfileWander
*>(movingProfile
.getAIProfile());
817 nlassert(_CurrentZone
==profile
->currentZone());
820 if (!profile
->testTimer())
823 // send the group to the camp.
824 movingProfile
.setAIProfile(new CGrpProfileDynFollowPath(_Grp
, profile
->currentZone(), _FamilyProfile
->getCampZone(), CPropertySet()));
828 default: // don't think we have to be there ..
830 nlassert(true==false);
834 CGrpProfileNormal::updateProfile(ticksSinceLastUpdate
);
838 void CGrpProfileDynFight::gotoZone(const CNpcZone
*const zone
, const CPropertySet
&flags
)
840 _Grp
->movingProfile().setAIProfile(new CGrpProfileDynFollowPath(_Grp
, _CurrentZone
, zone
, flags
));
843 string
CGrpProfileDynFight::buildDebugString() const