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 "family_behavior.h"
21 #include "game_share/fame.h"
22 #include "continent.h"
23 #include "ai_instance.h"
24 #include "ai_grp_npc.h"
25 #include "ai_grp_fauna.h"
27 #include "continent_inline.h"
28 #include "dyn_grp_inline.h"
30 using namespace MULTI_LINE_FORMATER
;
33 using namespace NLMISC
;
34 using namespace NLNET
;
35 using namespace AITYPES
;
39 CFamilyBehavior::CFamilyBehavior(CCellZone
*owner
, const CGroupFamily
*grpFamily
)
40 : CChild
<CCellZone
>(owner
)
46 ,_LastUpdateTime(CTimeInterface::gameCycle()+CAIS::rand32(100))
48 ,_GrpFamily(grpFamily
)
50 // create the family behavior
51 _FamilyProfile
= IFamilyProfile::createFamilyProfile(grpFamily
->profileName(),IFamilyProfile::CtorParam(this));
53 _ManagerNpc
= new CMgrNpc(this, 0, getName()+":npc_manager", "");
54 _ManagerFauna
= new CMgrFauna(this, 0, getName()+":fauna_manager", "");
56 _ManagerFauna
->spawn();
57 for (uint32 i
=0;i
<4;i
++ )
63 nlinfo("creating new family beahviour, activities : ");
66 std::set<NLMISC::TStringId> &props = grpFamily->getProfileProperty("food").properties();
67 std::set<NLMISC::TStringId>::iterator it;
68 for (it = props.begin(); it != props.end(); ++it)
70 nlinfo(NLMISC::CStringMapper::unmap(*it).c_str());
75 std::set<NLMISC::TStringId> &props = grpFamily->getProfileProperty("rest").properties();
76 std::set<NLMISC::TStringId>::iterator it;
77 for (it = props.begin(); it != props.end(); ++it)
79 nlinfo(NLMISC::CStringMapper::unmap(*it).c_str());
86 std::string
CFamilyBehavior::getName() const
88 return _GrpFamily
->getName();
92 CAIInstance
* CFamilyBehavior::getAIInstance() const
94 return getOwner()->getAIInstance();
98 const std::string
&getLevelString (const uint32
&levelIndex
)
100 static std::string
s0("0-25");
101 static std::string
s1("25-50");
102 static std::string
s2("50-75");
103 static std::string
s3("75-100");
104 static std::string
invalid("InvalidLevel");
121 uint32
CFamilyBehavior::energyScale (uint32 levelIndex
) const
124 levelIndex
=getLevelIndex();
126 return (uint32
)(_GrpFamily
->levelEnergyValue(levelIndex
)*(double)_Modifier
[levelIndex
]*(double)AITYPES::ENERGY_SCALE
);
129 void CFamilyBehavior::displayLogOld (CStringWriter
&stringWriter
, bool detailled
)
132 string res="in "+getCellZone()->getAliasFullName();
133 res+=", GroupFamily"+getName();
134 res+="\t NrjLvl="+toString(getLevelIndex());
135 res+=":"+getLevelString(getLevelIndex());
136 res+="("+toString(effectiveLevel()/(float)ENERGY_SCALE);
137 res+=") CurNrjScale="+toString(_CurrentLevel/(float)ENERGY_SCALE);
138 res+=" FinalNrjScale["+getLevelString(getLevelIndex());
139 res+="]="+toString(energyScale()/(float)ENERGY_SCALE);
140 res+=" (NrjScale="+toString(_GrpFamily->levelEnergyValue(getLevelIndex()));
141 res+="*Modifier="+toString(_Modifier[getLevelIndex()]);
142 res+=") Theorical="+toString(_TheoricalLevel/(float)ENERGY_SCALE);
144 stringWriter.append(res);
149 for (uint32 i=0;i<4;i++)
151 stringWriter.append(" > "+getLevelString(i)+" \t: FinalEnergyScale "
152 +toString(energyScale(i)/(float)ENERGY_SCALE)
153 +" (EnergyScale="+toString(_GrpFamily->levelEnergyValue(i))
154 +" Modifier="+toString(_Modifier[i])
159 string
const& celZon
= getCellZone()->getAliasFullName();
160 string
const& grpFam
= getName();
161 string
const& lvlIdx
= toString(getLevelIndex());
162 string
const& lvlIdxStr
= getLevelString(getLevelIndex());
163 string
const& effLvl
= toString(effectiveLevel()/(float)ENERGY_SCALE
);
164 string
const& curLvl
= toString(_CurrentLevel
/(float)ENERGY_SCALE
);
165 string
const& finLvl
= toString(energyScale()/(float)ENERGY_SCALE
);
166 string
const& teoLvl
= toString(_TheoricalLevel
/(float)ENERGY_SCALE
);
167 string
const& lvlNrgVal
= toString(_GrpFamily
->levelEnergyValue(getLevelIndex()));
168 string
const& modifier
= toString(_Modifier
[getLevelIndex()]);
171 "in "+celZon
+", GroupFamily"+grpFam
+"\t NrjLvl="+lvlIdx
+":"+lvlIdxStr
+"("+effLvl
+") CurNrjScale="+curLvl
172 +" FinalNrjScale["+lvlIdxStr
+"]="+finLvl
+" (NrjScale="+lvlNrgVal
+"*Modifier="+modifier
+") Theorical="+teoLvl
;
174 stringWriter
.append(log
);
179 for (uint32 i
=0;i
<4;i
++)
181 stringWriter
.append(" > "+getLevelString(i
)+" \t: FinalEnergyScale "
182 +toString(energyScale(i
)/(float)ENERGY_SCALE
)
183 +" (EnergyScale="+toString(_GrpFamily
->levelEnergyValue(i
))
184 +" Modifier="+toString(_Modifier
[i
])
189 void CFamilyBehavior::displayLogHeaders(CStringWriter
& stringWriter
, int index
, bool detailled
, std::vector
<size_t> widths
)
191 vector
<string
> cols(9, "");
192 cols
[0] = "CellZone";
193 cols
[1] = "GroupFamily";
194 cols
[2] = "Levels for";
195 cols
[3] = "effective";
198 cols
[6] = "theorical";
200 cols
[8] = "modifier";
202 for (size_t j
=0; j
<cols
.size(); ++j
)
203 for (size_t i
=cols
[j
].length(); i
<widths
[j
]; ++i
)
206 string log
= string("| ")+cols
[0]+" | "+cols
[1]+" | "+cols
[2]+" | "+cols
[3]+" | "+cols
[4]+" | "+cols
[5]+" | "+cols
[6]+" | "+cols
[7]+" | "+cols
[8]+" |";
207 stringWriter
.append(log
);
210 void CFamilyBehavior::displayLogLine(CStringWriter
& stringWriter
, int index
, bool detailled
, std::vector
<size_t> widths
)
212 vector
<string
> cols(9, "");
214 for (size_t j
=0; j
<cols
.size(); ++j
)
215 for (size_t i
=cols
[j
].length(); i
<widths
[j
]; ++i
)
218 string log
= string("+-")+cols
[0]+"-+-"+cols
[1]+"-+-"+cols
[2]+"-+-"+cols
[3]+"-+-"+cols
[4]+"-+-"+cols
[5]+"-+-"+cols
[6]+"-+-"+cols
[7]+"-+-"+cols
[8]+"-+";
219 stringWriter
.append(log
);
222 void CFamilyBehavior::displayLog(CStringWriter
& stringWriter
, int index
, bool detailled
, std::vector
<size_t> widths
)
224 vector
<string
> cols(9, "");
225 cols
[0] = getCellZone()->getAliasFullName();
227 cols
[2] = toString(getLevelIndex()) + ":" + getLevelString(getLevelIndex());
228 cols
[3] = toString(effectiveLevel()/(float)ENERGY_SCALE
);
229 cols
[4] = toString(_CurrentLevel
/(float)ENERGY_SCALE
);
230 cols
[5] = toString(energyScale()/(float)ENERGY_SCALE
);
231 cols
[6] = toString(_TheoricalLevel
/(float)ENERGY_SCALE
);
232 cols
[7] = toString(_GrpFamily
->levelEnergyValue(getLevelIndex()));
233 cols
[8] = toString(_Modifier
[getLevelIndex()]);
235 for (size_t j
=0; j
<cols
.size(); ++j
)
236 for (size_t i
=cols
[j
].length(); i
<widths
[j
]; ++i
)
239 string log
= string("| ")+cols
[0]+" | "+cols
[1]+" | "+cols
[2]+" | "+cols
[3]+" | "+cols
[4]+" | "+cols
[5]+" | "+cols
[6]+" | "+cols
[7]+" | "+cols
[8]+" |";
241 stringWriter
.append(log
);
246 for (uint32 i=0;i<4;i++)
248 stringWriter.append(" > "+getLevelString(i)+" \t: FinalEnergyScale "
249 +toString(energyScale(i)/(float)ENERGY_SCALE)
250 +" (EnergyScale="+toString(_GrpFamily->levelEnergyValue(i))
251 +" Modifier="+toString(_Modifier[i])
257 void CFamilyBehavior::checkLogHeadersWidths(std::vector
<size_t>& widths
, int index
, bool detailled
)
259 vector
<string
> cols(9, "");
260 cols
[0] = "CellZone";
261 cols
[1] = "GroupFamily";
262 cols
[2] = "Levels for";
263 cols
[3] = "effective";
266 cols
[6] = "theorical";
268 cols
[8] = "modifier";
270 for (size_t j
=0; j
<cols
.size(); ++j
)
271 widths
[j
] = std::max(widths
[j
], cols
[j
].length());
274 void CFamilyBehavior::checkLogWidths(std::vector
<size_t>& widths
, int index
, bool detailled
)
276 vector
<string
> cols(9, "");
277 cols
[0] = getCellZone()->getAliasFullName();
279 cols
[2] = toString(getLevelIndex()) + ":" + getLevelString(getLevelIndex());
280 cols
[3] = toString(effectiveLevel()/(float)ENERGY_SCALE
);
281 cols
[4] = toString(_CurrentLevel
/(float)ENERGY_SCALE
);
282 cols
[5] = toString(energyScale()/(float)ENERGY_SCALE
);
283 cols
[6] = toString(_TheoricalLevel
/(float)ENERGY_SCALE
);
284 cols
[7] = toString(_GrpFamily
->levelEnergyValue(getLevelIndex()));
285 cols
[8] = toString(_Modifier
[getLevelIndex()]);
287 for (size_t j
=0; j
<cols
.size(); ++j
)
288 widths
[j
] = std::max(widths
[j
], cols
[j
].length());
291 std::string
CFamilyBehavior::getIndexString() const
293 return getOwner()->getIndexString()+toString(":fb%u", getChildIndex());
296 std::string
CFamilyBehavior::getOneLineInfoString() const
298 return std::string("Family behaviour '") + getName() + "'";
301 std::vector
<std::string
> CFamilyBehavior::getMultiLineInfoString() const
303 std::vector
<std::string
> container
;
306 pushTitle(container
, "CFamilyBehavior");
307 pushEntry(container
, "id=" + getIndexString());
308 container
.back() += " name=" + getName();
309 pushFooter(container
);
315 std::string
CFamilyBehavior::getManagerIndexString(const CManager
*child
) const
317 if (child
== _ManagerNpc
)
318 return getIndexString() + ":mnpc";
320 if (child
== _ManagerFauna
)
321 return getIndexString() + ":mfauna";
323 return getIndexString() + ":munknown";
326 void CFamilyBehavior::updateManagers()
328 // update the manager
329 // NLMEMORY::CheckHeap(true);
331 mgrFauna()->update();
332 // NLMEMORY::CheckHeap(true);
336 void CFamilyBehavior::getNpcFlags(AITYPES::CPropertySet
&flags
)
338 flags
= grpFamily()->getProfileProperty(string("npc"));
341 void CFamilyBehavior::getActivities (CPropertySet
&food
, CPropertySet
&rest
/*,bool &plante, const CGroupDesc<CGroupFamily>*const gd*/) const
343 food
=grpFamily()->getProfileProperty(string("food"));
344 rest
=grpFamily()->getProfileProperty(string("rest"));
347 extern CVariable
<TGameCycle
> DynamicMaxUpdatePeriod
;
348 void CFamilyBehavior::update(uint32 nbTicks
)
350 // calcs _UpdatePeriod to avoid pingpong problems ..
353 if (energyScale()==0)
355 _UpdatePeriod
=1+DynamicMaxUpdatePeriod
;
359 double delta
=((double)((sint32
)energyScale()-(sint32
)_TheoricalLevel
))/((double)energyScale());
360 clamp(delta
,0.0,1.0);
365 _UpdatePeriod
=1+(uint32
)(delta
*DynamicMaxUpdatePeriod
);
370 IAliasCont
*cont0
, *cont1
;
371 cont0
= mgrNpc()->getAliasCont(AITypeGrp
);
372 cont1
= mgrFauna()->getAliasCont(AITypeGrp
);
373 Manager
=(cont0
->size()>cont1
->size())?NLMISC::safe_cast
<CManager
*>(mgrNpc()):NLMISC::safe_cast
<CManager
*>(mgrFauna());
377 // TODO : reactivate group deletion
378 // delete group that are dead
379 while (!_GroupToDelete
.empty())
381 // NLMEMORY::CheckHeap(true);
382 CGroup
*const grp
=(CGroup
*)_GroupToDelete
.back();
383 _GroupToDelete
.pop_back();
384 grp
->getManager().getAliasCont(AITypeGrp
)->removeChildByIndex(grp
->getChildIndex());
385 // NLMEMORY::CheckHeap(true);
389 // check to despawn groups that are no more valid in current energy or season
392 H_AUTO(FamilyDespawnGroup
)
394 const IGroupDesc
*gd
= NULL
;
399 const uint32 nbGroups
=Manager
->groups().size();
404 grp
= Manager
->getGroup(CAIS::rand16(nbGroups
));
408 CDynGrpBase
*const grpDynBase
=grp
->getGrpDynBase();
410 nlassert(grpDynBase
!=NULL
);
413 || grpDynBase
->getDiscardable())
414 gd
=grpDynBase
->getGroupDesc();
421 || !grp
->isSpawned())
424 // add a check if group is valid related to used regions flags to know if we need to despawn it
426 bool alreadyDespawned
=false;
429 CGrpFauna
*const grpFauna
=dynamic_cast<CGrpFauna
*>(grp
);
433 const CFaunaZone
*faunaZone
;
434 CPropertySet food
, rest
;
436 getActivities (food
, rest
/*, plante, gd*/);
439 // nlwarning("there is a problem with getActivities for %s", gd->getFullName().c_str());
444 const CAIPlace
*place
=grpFauna
->places()[CGrpFauna::EAT_PLACE
];
445 place
=NLMISC::safe_cast
<const CAIRefPlaceXYR
*>(place
)->getZone();
446 faunaZone
=NLMISC::safe_cast
<const CFaunaZone
*>(place
);
455 if (!faunaZone
->haveActivity(food
))
457 grp
->getSpawnObj()->despawnBots(true); // not ok, despawn this group ..
458 alreadyDespawned
=true;
462 place
=grpFauna
->places()[CGrpFauna::EAT_PLACE
];
463 place
=NLMISC::safe_cast
<const CAIRefPlaceXYR
*>(place
)->getZone();
464 faunaZone
=NLMISC::safe_cast
<const CFaunaZone
*>(place
);
473 if (!faunaZone
->haveActivity(rest
))
475 grp
->getSpawnObj()->despawnBots(true); // not ok, despawn this group ..
476 alreadyDespawned
=true;
481 // deals with npcs dyn groups
484 CGroupNpc
*const grpNpc
=dynamic_cast<CGroupNpc
*>(grp
);
488 const CNpcZone
*npcZone
= grpNpc
->getSpawnZone();
492 if (!npcZone
|| !npcZone
->properties().containsAllOf(flags
))
494 // must despawn group
495 grp
->getSpawnObj()->despawnBots(true); // not ok, despawn this group ..
496 alreadyDespawned
=true;
501 if (alreadyDespawned
)
504 if (gd
->getWeightForEnergy(getLevelIndex())!=0)
507 const EGSPD::CSeason::TSeason season
=CTimeInterface::season();
509 if ( season
<EGSPD::CSeason::Invalid
// if valid season
510 && gd
->isValidForSeason(season
) )
511 break; // no reason to despawn
513 if (!alreadyDespawned
)
514 grp
->getSpawnObj()->despawnBots(false); // not ok, despawn this group ..
517 // check for spawning new group to equilibrate energy level.
521 if (_TheoricalLevel
< energyScale())
523 H_AUTO(FamilyGroupeSpawn
)
524 // need to spawn some group ?
526 _FamilyProfile
->spawnGroup();
530 // or check for despawning
532 if (_TheoricalLevel
<= (energyScale()+(uint32
)(0.01*(double)ENERGY_SCALE
)))
536 const IGroupDesc
*gd
= NULL
;
537 // need to despawn some group ?
540 H_AUTO(FamilyGroupDespawn
)
542 // try to despawn some group in the manager
543 const uint32 start
= CAIS::rand16(Manager
->groups().size());
545 grp
= Manager
->getGroup(start
);
547 grp
= Manager
->groups().getNextValidChild(grp
);
551 CDynGrpBase
*const grpDynBase
=grp
->getGrpDynBase();
553 && grp
->getSpawnObj()
554 && grpDynBase
->getDiscardable())
556 gd
=grpDynBase
->getGroupDesc();
562 Manager
->groups().setChildSize(start
); // There's no group after start, so we can resize the group.
570 H_AUTO(FamilyGroupDespawn
)
572 if ((_TheoricalLevel
- gd
->groupEnergyValue()) >= energyScale())
574 // ok, we can despawn this group
575 grp
->despawnBots(false);
583 H_AUTO(FamilyProfileUpdate
);
584 CFollowPathContext
fpcFamilyProfileUpdate("FamilyProfileUpdate");
586 // update the family profile (if any)
588 _FamilyProfile
->update();
593 void CFamilyBehavior::fillOutpostNames(std::vector
<NLMISC::TStringId
> outpostNames
)
596 _FamilyProfile
->fillOutpostNames(outpostNames
);
600 void CFamilyBehavior::outpostAdd(NLMISC::TStringId outpostName
)
603 _FamilyProfile
->outpostAdd(outpostName
);
605 void CFamilyBehavior::outpostRemove(NLMISC::TStringId outpostName
)
608 _FamilyProfile
->outpostRemove(outpostName
);
611 void CFamilyBehavior::outpostEvent(NLMISC::TStringId outpostName
, ZCSTATE::TZcState state
)
614 _FamilyProfile
->outpostEvent(outpostName
,state
);
617 void CFamilyBehavior::spawnBoss(NLMISC::TStringId outpostName
)
620 _FamilyProfile
->spawnBoss(outpostName
);
624 void CFamilyBehavior::groupDead(CGroup
*grp
)
627 for (uint32 i
=0;i
<_GroupToDelete
.size();i
++)
629 nlassert(_GroupToDelete
[i
].ptr() != grp
);
632 // ok, we can delete this group
633 _GroupToDelete
.push_back(grp
);
636 void CFamilyBehavior::addEnergy (uint32 energy
)
638 _CurrentLevel
+= energy
;
641 void CFamilyBehavior::removeEnergy (uint32 energy
)
644 nlassert(_CurrentLevel
>=energy
);
646 _CurrentLevel
-= energy
;
650 void CFamilyBehavior::serviceEvent (const CServiceEvent
&info
)
652 mgrNpc()->serviceEvent (info
);
653 mgrFauna()->serviceEvent (info
);
657 CGroupNpc
*CFamilyBehavior::createNpcGroup(const CNpcZone
*const zone
, const CGroupDesc
<CGroupFamily
> *const groupDesc
)
659 // const TPopulationFamily &family=getFamily()
660 // if ( family.FamilyTag == family_fauna_herbivore
661 // || family.FamilyTag == family_fauna_carnivore
662 // || family.FamilyTag == family_flora
663 // || family.FamilyTag == family_kitin
664 // || family.FamilyTag == family_kitin_invasion
665 // || family.FamilyTag == family_degen
666 // || family.FamilyTag == family_goo )
668 // nlwarning("CRegion::createGroup can't create a npc group for family '%s', energy level %f in region '%s'", family.getFamilyName().c_str(), effectiveLevel(), getOwner()->getOwner()->getAliasFullName().c_str());
672 CGroupNpc
*grp
=groupDesc
->createNpcGroup (mgrNpc(), zone
->midPos());
676 grp
->initDynGrp (groupDesc
, this);
677 grp
->setSpawnZone(zone
);
682 bool CFamilyBehavior::spawn()
685 _ManagerNpc
->spawn();
687 _ManagerFauna
->spawn();
688 // We should check individual errors, but fake success here :)
692 bool CFamilyBehavior::despawn()
695 _ManagerNpc
->despawnMgr();
697 _ManagerFauna
->despawnMgr();
698 // We should check individual errors, but fake success here :)