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/>.
21 #include "group_profile.h"
23 #include "family_behavior.h"
26 using namespace NLMISC
;
27 using namespace AITYPES
;
29 int CGrpProfileDynFollowPath::_InstanceCounter
= 0;
31 /// Overload for IDynFollowPath interface
32 void CGrpProfileDynFollowPath::setPath(CNpcZone
const* const start
, CNpcZone
const* const end
, CPropertySet
const& zoneFilter
)
36 _ZoneFilter
= zoneFilter
;
43 void CGrpProfileDynFollowPath::calcPath()
45 if ( _StartZone
.isNull()
51 if (!::pathFind(_StartZone
, _EndZone
, _ZoneFilter
, _Path
, false))
53 ::pathFind(_StartZone
, _EndZone
, CPropertySet(), _Path
); // search without flags.
60 // nlwarning("calcPath failed: for group '%s', can't find path between zones:", _Grp->getPersistent().getAliasFullName().c_str());
61 // nlwarning(" - from %s", _StartZone->getAliasTreeOwner().getAliasFullName().c_str());
62 // nlwarning(" - to %s", _EndZone->getAliasTreeOwner().getAliasFullName().c_str());
63 RYAI_MAP_CRUNCH::CWorldPosition startPos
;
64 CWorldContainer::getWorldMap().setWorldPosition(vp_auto
, startPos
, _StartZone
->midPos());
65 RYAI_MAP_CRUNCH::CWorldPosition endPos
;
66 CWorldContainer::getWorldMap().setWorldPosition(vp_auto
, endPos
, _EndZone
->midPos());
67 _FollowRoute
.setAIProfile(new CGrpProfileGoToPoint(_Grp
, startPos
, endPos
, true));
70 nlassert(_PathCursor
< _Path
.size());
71 _CurrentRoad
=_Path
[_PathCursor
];
72 _CurrentZone
=_StartZone
;
74 _FollowRoute
.setAIProfile(new CGrpProfileFollowRoute(_Grp
, _CurrentRoad
->coords(), _CurrentRoad
->verticalPos(), true));
75 CGrpProfileFollowRoute
*const fr
= static_cast<CGrpProfileFollowRoute
*>(_FollowRoute
.getAIProfile());
77 nlassert(_CurrentZone
==_CurrentRoad
->startZone() || _CurrentZone
==_CurrentRoad
->endZone());
78 fr
->setDirection(_CurrentRoad
->startZone()==_CurrentZone
);
81 void CGrpProfileDynFollowPath::beginProfile()
84 CMoveProfile::beginProfile();
87 void CGrpProfileDynFollowPath::endProfile()
90 _StartZone
= _EndZone
= NULL
;
91 if( _FollowRoute
.getAIProfile() != NULL
)
92 _FollowRoute
.getAIProfile()->endProfile();
96 bool CGrpProfileDynFollowPath::destinationReach() const
98 return _CurrentZone
==_EndZone
;
101 // routine called every time the bot is updated (frequency depends on player proximity, etc)
102 void CGrpProfileDynFollowPath::updateProfile(uint ticksSinceLastUpdate
)
104 H_AUTO(GrpDynFollowProfileUpdate
)
105 CFollowPathContext
fpcGrpDynFollowProfileUpdate("GrpDynFollowProfileUpdate");
107 if (destinationReach())
110 if (_FollowRoute
.getAIProfile() == NULL
)
113 CGroupNpc
&persGrp
=*safe_cast
<CGroupNpc
*>(&_Grp
->getPersistent());
115 if (_FollowRoute
.getAIProfileType() == AITYPES::MOVE_FOLLOW_ROUTE
)
117 if (_CurrentZone
.isNULL())
120 // update the follow route until all bots reach the end
121 _FollowRoute
.updateProfile(ticksSinceLastUpdate
);
122 CGrpProfileFollowRoute
*fr
= safe_cast
<CGrpProfileFollowRoute
*>(_FollowRoute
.getAIProfile());
124 if (fr
->profileTerminated())
127 _CurrentZone
=fr
->getDirection()?_CurrentRoad
->endZone():_CurrentRoad
->startZone();
129 if (_PathCursor
< _Path
.size())
131 _CurrentRoad
=_Path
[_PathCursor
];
134 fr
= new CGrpProfileFollowRoute(_Grp
, _CurrentRoad
->coords(), _CurrentRoad
->verticalPos(), true);
136 _FollowRoute
.setAIProfile(fr
);
138 // pay attention to CGrpProfileFollowRouteSpawn init in static case .. :\ (to adapt ?)
140 nlassert(_CurrentZone
==_CurrentRoad
->startZone() || _CurrentZone
==_CurrentRoad
->endZone());
142 fr
->setDirection(_CurrentRoad
->startZone()==_CurrentZone
); // CurrentZone);
146 _CurrentZone
=_EndZone
;
147 // Message Event for StateMachine.
148 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedFirst
);
149 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedAll
);
155 else if (_FollowRoute
.getAIProfileType() == AITYPES::MOVE_GOTO_POINT
)
157 // update the follow route until all bots reach the end
158 _FollowRoute
.updateProfile(ticksSinceLastUpdate
);
159 CGrpProfileGoToPoint
* fr
= safe_cast
<CGrpProfileGoToPoint
*>(_FollowRoute
.getAIProfile());
161 if (fr
->profileTerminated())
163 _CurrentZone
=_EndZone
;
164 // Message Event for StateMachine.
165 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedFirst
);
166 persGrp
.processStateEvent(persGrp
.mgr().EventDestinationReachedAll
);
179 // routine used to build a debug string for detailed information on a bot's status (with respect to their aiProfile)
180 std::string
CGrpProfileDynFollowPath::getOneLineInfoString() const
182 return NLMISC::toString("");
183 // // CAIStatePositional *grpState=(CAIStatePositional *)bot->spawnGrp().getCAIState();
184 // return NLMISC::toString("stand_on_start_point(%s)%s",
185 // bot->getPersistent().getStartPos().toString().c_str(),
186 // (bot->getPersistent().getStartPos() != bot->posxy())? " EN ROUTE": " ARRIVED"
190 void CGrpProfileDynCamping::beginProfile()
192 // choose a random point in the camp to group around
193 CGroup
&persGrp
=_Grp
->getPersistent();
194 if (!_CurrentZone
.isNull())
196 RYAI_MAP_CRUNCH::CWorldPosition wp
;
197 _CurrentZone
->getPlaceRandomPos().getRandomPos(wp
);
200 // try to place all the npc around the camp pos.
201 const uint32 count
= persGrp
.bots().size();
202 const float requiredSpace
= 2.f
;
203 const float radius
= float(count
*(requiredSpace
/(2.f
*NLMISC::Pi
)));
205 for (uint i
=0; i
<count
; ++i
)
207 const CBot
*const bot
= persGrp
.bots()[i
];
211 CSpawnBot
*const spawnBot
=bot
->getSpawnObj();
215 CAIVector
pos(_CampPos
.toAIVector());
216 pos
.setX(pos
.x() + radius
* cos(2.0f
*NLMISC::Pi
*(float(i
)/count
)));
217 pos
.setY(pos
.y() + radius
* sin(2.0f
*NLMISC::Pi
*(float(i
)/count
)));
219 RYAI_MAP_CRUNCH::CWorldPosition newPos
;
220 TVerticalPos vertPos
=_CurrentZone
->getPlaceRandomPos().getVerticalPos(); // persGrp.getCurrentNpcZone()->getVerticalPos();
222 if (!CWorldContainer::calcNearestWPosFromPosAnRadius(vertPos
, newPos
, pos
, 6, 100, CWorldContainer::CPosValidatorDefault()))
225 spawnBot
->setAIProfile(new CBotProfileMoveTo(vertPos
, newPos
, spawnBot
));
229 // set the timer for end of camping to 5 à 10 mn
230 _EndOfCamping
.set(5*60*10 + CAIS::rand32(5*60*10));
233 void CGrpProfileDynCamping::endProfile()
235 const CCont
<CBot
> &bots
=_Grp
->getPersistent().bots();
237 for (uint i
=0; i
<bots
.size(); ++i
)
239 const CBot
*const bot
= /*dynamic_cast<CBotNpc*>(*/bots
[i
]/*)*/;
243 CSpawnBot
*const spawnBot
= bot
->getSpawnObj();
247 if (spawnBot
->getAIProfileType() == BOT_MOVE_TO
)
249 // set an idle activity
250 spawnBot
->setAIProfile(new CBotProfileStandAtPos(spawnBot
));
254 // bot already at destination, stand up the bot
255 spawnBot
->setMode(MBEHAV::NORMAL
);
262 void CGrpProfileDynCamping::updateProfile(uint ticksSinceLastUpdate
)
264 H_AUTO(GrpCampingProfileUpdate
)
265 CFollowPathContext
fpcGrpCampingProfileUpdate("GrpCampingProfileUpdate");
267 const CCont
<CBot
> &bots
=_Grp
->getPersistent().bots();
269 // turn the bot to the group center then sit them
270 for (uint i
=0; i
<bots
.size(); ++i
)
272 const CBot
*const bot
= bots
[i
];
276 CSpawnBot
*const spawnBot
= bot
->getSpawnObj();
280 if (spawnBot
->getAIProfileType()!=BOT_MOVE_TO
)
283 CBotProfileMoveTo
const* const bp
= safe_cast
<CBotProfileMoveTo
*>(spawnBot
->getAIProfile());
285 if (!bp
->destinationReach())
288 // ok, turn the bot to face the group center
289 spawnBot
->setTheta(CAngle(bot
->getSpawnObj()->pos().angleTo(_CampPos
)));
290 // set an idle activity
291 spawnBot
->setAIProfile(new CBotProfileStandAtPos(spawnBot
));
293 spawnBot
->setMode(MBEHAV::SIT
);
298 std::string
CGrpProfileDynCamping::getOneLineInfoString() const
300 return string("dyn_camping");
304 ///////////////////////////////////////////////////////////////////////////
305 void CGrpProfileDynWaitInZone::beginProfile()
307 CGroupNpc
&persGrp
=_Grp
->getPersistent();
309 // choose a random point in the camp to group around
312 if (_CurrentZone
.isNull())
314 if (_CurrentZone
->getPlaceRandomPos().getRandomPosCount()==0)
316 nlwarning("No Random Pos in _CurrentZone %s", _CurrentZone
->getAliasTreeOwner().getAliasFullName().c_str());
320 RYAI_MAP_CRUNCH::CWorldPosition wp
;
321 _CurrentZone
->getPlaceRandomPos().getRandomPos(wp
);
326 // try to place all the npc around the camp pos.
327 const uint32 count
= persGrp
.bots().size();
328 const float requiredSpace
= 2.f
;
329 const float radius
= float(count
*(requiredSpace
/(2.f
*NLMISC::Pi
)));
331 for (uint i
=0; i
<count
; ++i
)
333 const CBot
*const bot
= persGrp
.bots()[i
];
337 CSpawnBot
*const spawnBot
= bot
->getSpawnObj();
341 CAIVector pos
= WaitPos
.toAIVector();
342 pos
.setX(pos
.x() + radius
* cos(2.0f
*NLMISC::Pi
*(float(i
)/count
)));
343 pos
.setY(pos
.y() + radius
* sin(2.0f
*NLMISC::Pi
*(float(i
)/count
)));
345 RYAI_MAP_CRUNCH::CWorldPosition newPos
;
346 TVerticalPos vertPos
=_CurrentZone
->getPlaceRandomPos().getVerticalPos();
348 if (!CWorldContainer::calcNearestWPosFromPosAnRadius(vertPos
, newPos
, pos
, 6, 100, CWorldContainer::CPosValidatorDefault()))
351 spawnBot
->setAIProfile(new CBotProfileMoveTo(vertPos
, newPos
, spawnBot
));
355 StartOfWait
= CTimeInterface::gameCycle();
358 void CGrpProfileDynWaitInZone::endProfile()
362 void CGrpProfileDynWaitInZone::updateProfile(uint ticksSinceLastUpdate
)
364 H_AUTO(GrpDynWaitProfileUpdate
)
365 CFollowPathContext
fpcGrpDynWaitProfileUpdate("GrpDynWaitProfileUpdate");
367 const CCont
<CBot
> &bots
=_Grp
->getPersistent().bots();
369 // turn the bot to the group center
370 for (uint i
=0; i
<bots
.size(); ++i
)
372 const CBot
*const bot
= bots
[i
];
376 CSpawnBot
*const spawnBot
= bot
->getSpawnObj();
380 if (spawnBot
->getAIProfileType() != BOT_MOVE_TO
)
383 CBotProfileMoveTo
const* const bp
= safe_cast
<CBotProfileMoveTo
*>(spawnBot
->getAIProfile());
384 if (!bp
->destinationReach())
387 // ok, turn the bot to face the group center
388 spawnBot
->setTheta(CAngle(spawnBot
->pos().angleTo(WaitPos
)));
389 // set an idle activity
390 spawnBot
->setAIProfile(new CBotProfileStandAtPos(spawnBot
));
395 std::string
CGrpProfileDynWaitInZone::getOneLineInfoString() const
397 return string("dyn_wait_in_zone profile");
400 #include "event_reaction_include.h"