Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / ai_service / nf_grp.cpp
blob43d5711578fda1f8e12a7187e1466d20e1991765
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
17 #include "stdpch.h"
19 #include "script_compiler.h"
21 #include "ai_grp_npc.h"
22 #include "group_profile.h"
23 #include "ai_generic_fight.h"
24 #include "server_share/msg_brick_service.h"
26 #include "continent_inline.h"
27 #include "dyn_grp_inline.h"
29 #include "ai_script_data_manager.h"
31 #include "nf_helpers.h"
32 #include "ai_aggro.h"
33 #include "game_share/send_chat.h"
34 #include "game_share/string_manager_sender.h"
35 #include <time.h>
38 using std::string;
39 using std::vector;
40 using namespace NLMISC;
41 using namespace AIVM;
42 using namespace AICOMP;
43 using namespace AITYPES;
44 using namespace RYAI_MAP_CRUNCH;
47 //----------------------------------------------------------------------------
48 /** @page code
50 @subsection spawn__
51 Spawns the current group.
53 Arguments: ->
56 // CGroup
57 void spawn__(CStateInstance* entity, CScriptStack& stack)
59 if (!entity)
61 nlwarning("spawnInstance failed");
62 return;
64 CGroup const* const grp = entity->getGroup();
65 if (grp)
67 if (grp->isSpawned())
68 grp->getSpawnObj()->spawnBots();
72 //----------------------------------------------------------------------------
73 /** @page code
75 @subsection despawn_f_
76 Depawns the current group.
78 Arguments: f(Immediatly) ->
79 @param Immediatly is whether the groups spawns immediatly (1) or not (0)
81 @code
82 ()despawn(0); // despawn
83 ()despawn(1); // despawn immediatement
84 @endcode
87 // CGroup
88 void despawn_f_(CStateInstance* entity, CScriptStack& stack)
90 float const immediatly = stack.top();
91 stack.pop();
93 if (!entity)
95 nlwarning("despawnInstance failed");
96 return;
99 CGroup* const grp = entity->getGroup();
100 if (!grp)
102 nlwarning("despawn : entity '%s'%s is not a group ? ",
103 entity->aliasTreeOwner()->getAliasFullName().c_str(),
104 entity->aliasTreeOwner()->getAliasString().c_str());
105 return;
107 grp->despawnBots(immediatly!=0);
110 //----------------------------------------------------------------------------
111 /** @page code
113 @subsection spawnBot_fsssffff_
114 Spawn new bots in the current group.
116 Arguments: f(NbrBots), s(Sheet), s(Name), s(Look), f(x), f(y), f(orientation), f(dispersion) ->
118 @code
120 @endcode
123 // CGroup
124 void spawnBot_fsssffff_(CStateInstance* entity, CScriptStack& stack)
126 double dispersionRadius = (double)(float)stack.top();
127 stack.pop();
128 double orientation = (double)(float)stack.top();
129 stack.pop();
130 double y = (double)(float)stack.top();
131 stack.pop();
132 double x = (double)(float)stack.top();
133 stack.pop();
134 string look = (string)stack.top();
135 stack.pop();
136 string name = (string)stack.top();
138 stack.pop();
139 CSheetId sheetId((string)stack.top());
140 stack.pop();
141 uint nbBots = (uint)(float)stack.top();
142 stack.pop();
144 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
145 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
146 if (!aiInstance)
147 return;
149 CGroupNpc* grp = dynamic_cast<CGroupNpc*>(entity->getGroup());
150 if (grp)
151 aiInstance->eventCreateNpcBot(grp, nbBots, true, sheetId, CAIVector(x, y), name, orientation, dispersionRadius, look);
152 return;
157 //----------------------------------------------------------------------------
158 /** @page code
160 @subsection isAlived__f
161 Test if the group is alived
163 Arguments: -> f(Immediatly)
164 @return 1 if group is spawned
166 @code
167 (alive)isAlived();
168 @endcode
171 // CGroup
172 void isAlived__f(CStateInstance* entity, CScriptStack& stack)
175 if (!entity)
177 stack.push(0.0f);
178 return;
181 CGroup* const grp = entity->getGroup();
182 if (!grp)
184 nlwarning("isAlived__f : entity '%s'%s is not a group ? ",
185 entity->aliasTreeOwner()->getAliasFullName().c_str(),
186 entity->aliasTreeOwner()->getAliasString().c_str());
187 stack.push(0.0f);
188 return;
191 if (!grp->isSpawned())
193 stack.push(0.0f);
194 return;
198 for (uint i=0; i<grp->bots().size(); ++i)
200 const CBot *const bot = grp->getBot(i);
201 if ( !bot
202 || !bot->isSpawned())
203 continue;
206 CAIEntityPhysical *const ep=bot->getSpawnObj();
207 if (ep->isAlive())
209 stack.push(1.0f);
210 return;
214 stack.push(0.0f);
215 return;
218 //----------------------------------------------------------------------------
219 /** @page code
221 @subsection newNpcChildGroupPos_ssfff_c
222 Used to create a dynamic npc group (a parent/children relation is defined).
224 Arguments: s(GroupTemplate), s(StateMachine), f(x), f(y), f(Dispersion) -> c(Group)
225 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
226 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
227 @param[in] x position of the spawned group on x axis
228 @param[in] y position of the spawned group on y axis
229 @param[in] Dispersion is the dispersion radius in meters when spawning a group
230 @param[out] Group is the newly created group
232 @code
233 (@grp)newNpcChildGroupPos("class_forager", "state_machine_1", x, y, 30);
234 @endcode
237 // CGroup not in a family behaviour
238 void newNpcChildGroupPos_ssfff_c(CStateInstance* entity, CScriptStack& stack)
240 double dispersionRadius = (double)(float)stack.top();
241 stack.pop();
242 float const y = stack.top();
243 stack.pop();
244 float const x = stack.top();
245 stack.pop();
247 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
248 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
249 if (!aiInstance)
250 return;
252 if (dispersionRadius<0.)
253 dispersionRadius = 0.;
254 stack.push(spawnNewGroup(entity, stack, aiInstance, CAIVector(x, y), -1, dispersionRadius));
257 //----------------------------------------------------------------------------
258 /** @page code
260 @subsection newNpcChildGroupPos_ssfff_
261 Used to create a dynamic npc group (a parent/children relation is defined).
263 Arguments: s(GroupTemplate), s(StateMachine), f(x), f(y), f(Dispersion) ->
264 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
265 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
266 @param[in] x position of the spawned group on x axis
267 @param[in] y position of the spawned group on y axis
268 @param[in] Dispersion is the dispersion radius in meters when spawning a group
270 @code
271 ()newNpcChildGroupPos("class_forager", "state_machine_1", x, y, 30);
272 @endcode
275 // CGroup not in a family behaviour
276 void newNpcChildGroupPos_ssfff_(CStateInstance* entity, CScriptStack& stack)
278 double dispersionRadius = (double)(float)stack.top();
279 stack.pop();
280 float const y = stack.top();
281 stack.pop();
282 float const x = stack.top();
283 stack.pop();
285 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
286 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
287 if (!aiInstance)
288 return;
290 if (dispersionRadius<0.)
291 dispersionRadius = 0.;
292 spawnNewGroup(entity, stack, aiInstance, CAIVector(x, y), -1, dispersionRadius);
295 //----------------------------------------------------------------------------
296 /** @page code
298 @subsection newNpcChildGroupPos_ssff_c
299 Used to create a dynamic npc group (a parent/children relation is defined).
301 Arguments: s(GroupTemplate), s(StateMachine), f(x), f(y) -> c(Group)
302 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
303 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
304 @param[in] x position of the spawned group on x axis
305 @param[in] y position of the spawned group on y axis
306 @param[out] Group is the newly created group
308 @code
309 (@grp)newNpcChildGroupPos("class_forager", "state_machine_1", x, y);
310 @endcode
313 // CGroup not in a family behaviour
314 void newNpcChildGroupPos_ssff_c(CStateInstance* entity, CScriptStack& stack)
316 stack.push((float)-1.0f);
317 newNpcChildGroupPos_ssfff_c(entity, stack);
320 //----------------------------------------------------------------------------
321 /** @page code
323 @subsection newNpcChildGroupPos_ssff_
324 Used to create a dynamic npc group (a parent/children relation is defined).
326 Arguments: s(GroupTemplate), s(StateMachine), f(x), f(y) ->
327 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
328 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
329 @param[in] x position of the spawned group on x axis
330 @param[in] y position of the spawned group on y axis
332 @code
333 ()newNpcChildGroupPos("class_forager", "state_machine_1", x, y);
334 @endcode
337 // CGroup not in a family behaviour
338 void newNpcChildGroupPos_ssff_(CStateInstance* entity, CScriptStack& stack)
340 stack.push((float)-1.0f);
341 newNpcChildGroupPos_ssfff_(entity, stack);
344 //----------------------------------------------------------------------------
345 /** @page code
347 @subsection newNpcChildGroupPosMl_ssffff_c
348 Used to create a multilevel dynamic npc group (a parent/children relation is defined).
350 Arguments: s(GroupTemplate), s(StateMachine), f(x), f(y), f(BaseLevel), f(Dispersion) -> c(Group)
351 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
352 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
353 @param[in] x position of the spawned group on x axis
354 @param[in] y position of the spawned group on y axis
355 @param[in] BaseLevel is the base level of the spawned group
356 @param[in] Dispersion is the dispersion radius in meters when spawning a group
357 @param[out] Group is the newly created group
359 @code
360 (@grp)newNpcChildGroupPosMl("class_forager", "state_machine_1", x, y, 13, 7.5);
361 @endcode
364 // CGroup not in a family behaviour
365 void newNpcChildGroupPosMl_ssffff_c(CStateInstance* entity, CScriptStack& stack)
367 double dispersionRadius = (double)(float)stack.top();
368 stack.pop();
369 float const y = stack.top();
370 stack.pop();
371 float const x = stack.top();
372 stack.pop();
374 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
375 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
376 if (!aiInstance)
377 return;
379 if (dispersionRadius<0.)
380 dispersionRadius = 0.;
381 stack.push(spawnNewGroup(entity, stack, aiInstance, CAIVector(x,y), -1, dispersionRadius));
384 //----------------------------------------------------------------------------
385 /** @page code
387 @subsection newNpcChildGroupPosMl_ssffff_
388 Used to create a multilevel dynamic npc group (a parent/children relation is defined).
390 Arguments: s(GroupTemplate), s(StateMachine), f(x), f(y), f(BaseLevel), f(Dispersion) ->
391 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
392 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
393 @param[in] x position of the spawned group on x axis
394 @param[in] y position of the spawned group on y axis
395 @param[in] BaseLevel is the base level of the spawned group
396 @param[in] Dispersion is the dispersion radius in meters when spawning a group
398 @code
399 ()newNpcChildGroupPosMl("class_forager", "state_machine_1", x, y, 13, 7.5);
400 @endcode
403 // CGroup not in a family behaviour
404 void newNpcChildGroupPosMl_ssffff_(CStateInstance* entity, CScriptStack& stack)
406 double dispersionRadius = (double)(float)stack.top();
407 stack.pop();
408 float const y = stack.top();
409 stack.pop();
410 float const x = stack.top();
411 stack.pop();
413 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
414 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
415 if (!aiInstance)
416 return;
418 if (dispersionRadius<0.)
419 dispersionRadius = 0.;
420 spawnNewGroup(entity, stack, aiInstance, CAIVector(x,y), -1, dispersionRadius);
423 //----------------------------------------------------------------------------
424 /** @page code
426 @subsection newNpcChildGroupPosMl_ssfff_c
427 Used to create a multilevel dynamic npc group (a parent/children relation is defined).
429 Arguments: s(GroupTemplate), s(StateMachine), f(x), f(y), f(BaseLevel) -> c(Group)
430 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
431 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
432 @param[in] x position of the spawned group on x axis
433 @param[in] y position of the spawned group on y axis
434 @param[in] BaseLevel is the base level of the spawned group
435 @param[out] Group is the newly created group
437 @code
438 (@grp)newNpcChildGroupPosMl("class_forager", "state_machine_1", x, y, 13);
439 @endcode
442 // CGroup not in a family behaviour
443 void newNpcChildGroupPosMl_ssfff_c(CStateInstance* entity, CScriptStack& stack)
445 stack.push((float)-1.0f);
446 newNpcChildGroupPosMl_ssffff_c(entity, stack);
449 //----------------------------------------------------------------------------
450 /** @page code
452 @subsection newNpcChildGroupPosMl_ssfff_
453 Used to create a multilevel dynamic npc group (a parent/children relation is defined).
455 Arguments: s(GroupTemplate), s(StateMachine), f(x), f(y), f(BaseLevel) ->
456 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
457 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
458 @param[in] x position of the spawned group on x axis
459 @param[in] y position of the spawned group on y axis
460 @param[in] BaseLevel is the base level of the spawned group
462 @code
463 ()newNpcChildGroupPosMl("class_forager", "state_machine_1", x, y, 13);
464 @endcode
467 // CGroup not in a family behaviour
468 void newNpcChildGroupPosMl_ssfff_(CStateInstance* entity, CScriptStack& stack)
470 stack.push((float)-1.0f);
471 newNpcChildGroupPosMl_ssffff_(entity, stack);
474 //----------------------------------------------------------------------------
475 /** @page code
477 @subsection getMidPos__ff
478 Returns the position (x, y) of the current group.
480 Arguments: -> f(x), f(y)
481 @param[out] x position of the group on x axis
482 @param[out] y position of the group on y axis
484 @code
485 (x, y)getMidPos();
486 @endcode
489 // CGroup
490 void getMidPos__ff(CStateInstance* entity, CScriptStack& stack)
492 CGroup* const group = entity->getGroup();
494 CAIVector vect;
495 if (group->isSpawned())
497 if (!group->getSpawnObj()->calcCenterPos(vect))
498 group->getSpawnObj()->calcCenterPos(vect, true);
501 float x((float)vect.x().asDouble());
502 float y((float)vect.y().asDouble());
504 stack.push(y);
505 stack.push(x);
508 //----------------------------------------------------------------------------
509 /** @page code
511 @subsection newNpcChildGroup_sssf_c
512 Used to create dynamic npc group (a parent/children relation is defined).
514 Arguments: s(GroupTemplate), s(StateMachine), s(Zone), f(Dispersion) -> c(Group)
515 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
516 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
517 @param[in] Zone is returned by the getZoneWithFlags methods
518 @param[in] Dispersion is the dispersion radius in meters when spawning a group
519 @param[out] Group is the newly created group
521 @code
522 (@grp)newNpcChildGroup("class_forager", "state_machine_1", $zone, 10);
523 @endcode
526 // CGroup not in a family behaviour
527 void newNpcChildGroup_sssf_c(CStateInstance* entity, CScriptStack& stack)
529 double dispersionRadius = (double)(float)stack.top();
530 stack.pop();
531 TStringId const zoneName = CStringMapper::map(stack.top());
532 stack.pop();
534 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
535 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
536 if (!aiInstance)
537 return;
539 CNpcZone const* spawnZone = aiInstance->getZone(zoneName);
540 if (!spawnZone)
542 string StateMachine = stack.top();
543 stack.pop();
544 stack.pop();
545 nlwarning("newNpcChildGroup failed : spawnZone Not Found ! for StateMachine : %s", StateMachine.c_str());
546 return;
548 if (dispersionRadius<0.)
550 dispersionRadius = 0.;
551 CNpcZonePlace const* spawnZonePlace = dynamic_cast<CNpcZonePlace const*>(spawnZone);
552 if (spawnZonePlace!=NULL)
553 dispersionRadius = spawnZonePlace->getRadius();
555 stack.push(spawnNewGroup(entity, stack, aiInstance, spawnZone->midPos(), -1, dispersionRadius));
558 //----------------------------------------------------------------------------
559 /** @page code
561 @subsection newNpcChildGroup_sssf_
562 Used to create dynamic npc group (a parent/children relation is defined).
564 Arguments: s(GroupTemplate), s(StateMachine), s(Zone), f(Dispersion) ->
565 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
566 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
567 @param[in] Zone is returned by the getZoneWithFlags methods
568 @param[in] Dispersion is the dispersion radius in meters when spawning a group
570 @code
571 ()newNpcChildGroup("class_forager", "state_machine_1", $zone, 10);
572 @endcode
575 // CGroup not in a family behaviour
576 void newNpcChildGroup_sssf_(CStateInstance* entity, CScriptStack& stack)
578 double dispersionRadius = (double)(float)stack.top();
579 stack.pop();
580 TStringId const zoneName = CStringMapper::map(stack.top());
581 stack.pop();
583 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
584 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
585 if (!aiInstance)
586 return;
588 CNpcZone const* spawnZone = aiInstance->getZone(zoneName);
589 if (!spawnZone)
591 string StateMachine = stack.top();
592 stack.pop();
593 stack.pop();
594 nlwarning("newNpcChildGroup failed : spawnZone Not Found ! for StateMachine : %s", StateMachine.c_str());
595 return;
597 if (dispersionRadius<0.)
599 dispersionRadius = 0.;
600 CNpcZonePlace const* spawnZonePlace = dynamic_cast<CNpcZonePlace const*>(spawnZone);
601 if (spawnZonePlace!=NULL)
602 dispersionRadius = spawnZonePlace->getRadius();
604 spawnNewGroup(entity, stack, aiInstance, spawnZone->midPos(), -1, dispersionRadius);
607 //----------------------------------------------------------------------------
608 /** @page code
610 @subsection newNpcChildGroup_sss_c
611 Used to create dynamic npc group (a parent/children relation is defined).
613 Arguments: s(GroupTemplate), s(StateMachine), s(Zone), f(Dispersion) -> c(Group)
614 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
615 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
616 @param[in] Zone is returned by the getZoneWithFlags methods
617 @param[out] Group is the newly created group
619 @code
620 (@grp)newNpcChildGroup("class_forager", "state_machine_1", $zone);
621 @endcode
624 // CGroup not in a family behaviour
625 void newNpcChildGroup_sss_c(CStateInstance* entity, CScriptStack& stack)
627 stack.push((float)-1.0f);
628 newNpcChildGroup_sssf_c(entity, stack);
631 //----------------------------------------------------------------------------
632 /** @page code
634 @subsection newNpcChildGroup_sss_
635 Used to create dynamic npc group (a parent/children relation is defined).
637 Arguments: s(GroupTemplate), s(StateMachine), s(Zone), f(Dispersion) ->
638 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
639 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
640 @param[in] Zone is returned by the getZoneWithFlags methods
642 @code
643 ()newNpcChildGroup("class_forager", "state_machine_1", $zone);
644 @endcode
647 // CGroup not in a family behaviour
648 void newNpcChildGroup_sss_(CStateInstance* entity, CScriptStack& stack)
650 stack.push((float)-1.0f);
651 newNpcChildGroup_sssf_(entity, stack);
654 //----------------------------------------------------------------------------
655 /** @page code
657 @subsection newNpcChildGroupMl_sssff_c
658 Used to create multilevel dynamic npc group (a parent/children relation is defined).
660 Arguments: s(GroupTemplate), s(StateMachine), s(Zone), f(BaseLevel), f(Dispersion) -> c(Group)
661 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
662 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
663 @param[in] Zone is returned by the getZoneWithFlags methods
664 @param[in] BaseLevel is the base level of the spawned group
665 @param[in] Dispersion is the dispersion radius in meters when spawning a group
666 @param[out] Group is the newly created group
668 @code
669 (@grp)newNpcChildGroupMl("class_forager", "state_machine_1", $zone, 2, 50);
670 @endcode
673 // CGroup not in a family behaviour
674 void newNpcChildGroupMl_sssff_c(CStateInstance* entity, CScriptStack& stack)
676 double dispersionRadius = (double)(float)stack.top();
677 stack.pop();
678 int baseLevel = (int)(float)stack.top();
679 stack.pop();
680 TStringId const zoneName = CStringMapper::map(stack.top());
681 stack.pop();
683 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
684 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
685 if (!aiInstance)
686 return;
688 CNpcZone const* spawnZone = aiInstance->getZone(zoneName);
689 if (!spawnZone)
691 string StateMachine = stack.top();
692 stack.pop();
693 stack.pop();
694 nlwarning("newNpcChildGroup failed : spawnZone Not Found ! for StateMachine : %s", StateMachine.c_str());
695 return;
697 if (dispersionRadius<0.)
699 dispersionRadius = 0.;
700 CNpcZonePlace const* spawnZonePlace = dynamic_cast<CNpcZonePlace const*>(spawnZone);
701 if (spawnZonePlace!=NULL)
702 dispersionRadius = spawnZonePlace->getRadius();
704 stack.push(spawnNewGroup(entity, stack, aiInstance, spawnZone->midPos(), baseLevel, dispersionRadius));
707 //----------------------------------------------------------------------------
708 /** @page code
710 @subsection newNpcChildGroupMl_sssff_
711 Used to create multilevel dynamic npc group (a parent/children relation is defined).
713 Arguments: s(GroupTemplate), s(StateMachine), s(Zone), f(BaseLevel), f(Dispersion) ->
714 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
715 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
716 @param[in] Zone is returned by the getZoneWithFlags methods
717 @param[in] BaseLevel is the base level of the spawned group
718 @param[in] Dispersion is the dispersion radius in meters when spawning a group
720 @code
721 ()newNpcChildGroupMl("class_forager", "state_machine_1", $zone, 2, 50);
722 @endcode
725 // CGroup not in a family behaviour
726 void newNpcChildGroupMl_sssff_(CStateInstance* entity, CScriptStack& stack)
728 double dispersionRadius = (double)(float)stack.top();
729 stack.pop();
730 int baseLevel = (int)(float)stack.top();
731 stack.pop();
732 TStringId const zoneName = CStringMapper::map(stack.top());
733 stack.pop();
735 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
736 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
737 if (!aiInstance)
738 return;
740 CNpcZone const* spawnZone = aiInstance->getZone(zoneName);
741 if (!spawnZone)
743 string StateMachine = stack.top();
744 stack.pop();
745 stack.pop();
746 nlwarning("newNpcChildGroup failed : spawnZone Not Found ! for StateMachine : %s", StateMachine.c_str());
747 return;
749 if (dispersionRadius<0.)
751 dispersionRadius = 0.;
752 CNpcZonePlace const* spawnZonePlace = dynamic_cast<CNpcZonePlace const*>(spawnZone);
753 if (spawnZonePlace!=NULL)
754 dispersionRadius = spawnZonePlace->getRadius();
756 spawnNewGroup (entity, stack, aiInstance, spawnZone->midPos(), baseLevel, dispersionRadius);
759 //----------------------------------------------------------------------------
760 /** @page code
762 @subsection newNpcChildGroupMl_sssf_c
763 Used to create multilevel dynamic npc group (a parent/children relation is defined).
765 Arguments: s(GroupTemplate), s(StateMachine), s(Zone), f(BaseLevel) -> c(Group)
766 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
767 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
768 @param[in] Zone is returned by the getZoneWithFlags methods
769 @param[in] BaseLevel is the base level of the spawned group
770 @param[out] Group is the newly created group
772 @code
773 (@grp)newNpcChildGroupMl("class_forager", "state_machine_1", $zone, 12);
774 @endcode
777 // CGroup not in a family behaviour
778 void newNpcChildGroupMl_sssf_c(CStateInstance* entity, CScriptStack& stack)
780 stack.push((float)-1.0f);
781 newNpcChildGroupMl_sssff_c(entity, stack);
784 //----------------------------------------------------------------------------
785 /** @page code
787 @subsection newNpcChildGroupMl_sssf_
788 Used to create multilevel dynamic npc group (a parent/children relation is defined).
790 Arguments: s(GroupTemplate), s(StateMachine), s(Zone), f(BaseLevel) ->
791 @param[in] GroupTemplate is the name of a template npc group defined in the same AIInstance
792 @param[in] StateMachine is the name of a state machine defined in the same AIInstance
793 @param[in] Zone is returned by the getZoneWithFlags methods
794 @param[in] BaseLevel is the base level of the spawned group
796 @code
797 ()newNpcChildGroupMl("class_forager", "state_machine_1", $zone, 12);
798 @endcode
801 // CGroup not in a family behaviour
802 void newNpcChildGroupMl_sssf_(CStateInstance* entity, CScriptStack& stack)
804 stack.push((float)-1.0f);
805 newNpcChildGroupMl_sssff_(entity, stack);
808 //----------------------------------------------------------------------------
809 /** @page code
811 @subsection spawnManager_s_
812 Spawns a manager.
814 Arguments: s(ManagerName) ->
815 @param[in] ManagerName is the name of the manager to spawn
817 @code
818 ()spawnManager("NPC Manager"); // Spawns all the NPCs in the NPC manager called "NPC Manager"
819 @endcode
822 // CGroup not in a family behaviour
823 void spawnManager_s_(CStateInstance* entity, CScriptStack& stack)
825 string ManagerName = stack.top();
826 stack.pop();
828 breakable
830 if (!entity)
832 nlwarning("SpawnManager error entity not spawned");
833 break;
836 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
837 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
838 if (!aiInstance)
840 nlwarning("SpawnManager error AIInstance not Found");
841 break;
843 /** :TODO: If CStringFilter is available use it here and test the whole */
844 string/*CStringFilter*/ managerFilter(ManagerName);
845 FOREACH(itManager, CAliasCont<CManager>, aiInstance->managers())
847 CManager* manager = *itManager;
848 if (manager && managerFilter==manager->getName())
850 manager->spawn();
853 return;
855 nlwarning("SpawnManager error");
858 //----------------------------------------------------------------------------
859 /** @page code
861 @subsection despawnManager_s_
862 Despawns a manager.
864 Arguments: s(ManagerName) ->
865 @param[in] ManagerName is the name of the manager to despawn
867 @code
868 ()despawnManager("NPC Manager"); // Despawns all the NPCs in the NPC manager called "NPC Manager"
869 @endcode
872 // CGroup not in a family behaviour
873 void despawnManager_s_(CStateInstance* entity, CScriptStack& stack)
875 string ManagerName = stack.top();
876 stack.pop();
878 breakable
880 if (!entity)
882 nlwarning("DespawnManager error entity not spawned");
883 break;
886 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
887 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
888 if (!aiInstance)
890 nlwarning("DespawnManager error AIInstance not Found");
891 break;
893 // :TODO: If CStringFilter is available use it here and test the whole
894 string/*CStringFilter*/ managerFilter(ManagerName);
895 FOREACH(itManager, CAliasCont<CManager>, aiInstance->managers())
897 CManager *manager=*itManager;
898 if (manager && managerFilter==manager->getName())
900 manager->despawnMgr();
903 return;
907 //----------------------------------------------------------------------------
908 /** @page code
910 @subsection getGroupTemplateWithFlags_sss_s
911 Returns the name of a randomly chosen group template corresponding to specified flags.
913 Arguments: s(OneOf), s(Mandatory), s(ExceptFlags) -> s(GroupTemplate)
914 @param[in] OneOf is a '|' separated list of flags
915 @param[in] Mandatory is a '|' separated list of flags
916 @param[in] ExceptFlags is a '|' separated list of flags
917 @param[out] GroupTemplate is a group template matching at least one of OneOf flags, all Manadatory flags and none of ExceptFlags
919 @code
920 ($group)getGroupTemplateWithFlags("food|rest", "invasion|outpost"); // Get a group which matches 'invasion', 'outpost' and either 'food' or 'rest' flags.
921 @endcode
924 // CGroup not in a family behaviour
925 void getGroupTemplateWithFlags_sss_s(CStateInstance* entity, CScriptStack& stack)
927 string exceptProperties = stack.top();
928 stack.pop();
929 string mandatoryProperties = stack.top();
930 stack.pop();
931 string oneOfProperties = stack.top();
932 stack.pop();
934 // If no AI instance return
935 IManagerParent* managerParent = entity->getGroup()->getOwner()->getOwner();
936 CAIInstance* aiInstance = dynamic_cast<CAIInstance*>(managerParent);
937 if (!aiInstance)
939 stack.push(string());
940 return;
943 // Fill the property sets.
944 AITYPES::CPropertySet oneOfSet = readSet(oneOfProperties);
945 AITYPES::CPropertySet mandatorySet = readSet(mandatoryProperties);
946 AITYPES::CPropertySet exceptSet = readSet(exceptProperties);
948 vector<CGroupDesc<CGroupFamily> const*> groupDescs;
949 FOREACH (itCont, CCont<CContinent>, aiInstance->continents())
951 FOREACH (itRegion, CCont<CRegion>, itCont->regions())
953 FOREACH (itFamily, CCont<CGroupFamily>, itRegion->groupFamilies())
955 FOREACH (itGroupDesc, CCont<CGroupDesc<CGroupFamily> >, itFamily->groupDescs())
957 // Skip groups not meeting the criteria
958 if (!itGroupDesc->properties().containsPartOfNotStrict(oneOfSet))
959 continue;
960 if (!itGroupDesc->properties().containsAllOf(mandatorySet))
961 continue;
962 if (itGroupDesc->properties().containsPartOfStrict(exceptSet))
963 continue;
964 groupDescs.push_back(*itGroupDesc);
970 if (groupDescs.size()==0)
972 nlwarning("getGroupTemplateWithFlags failed: no group template found that contains all of '%s' and a part of'%s' ", mandatoryProperties.c_str(), oneOfProperties.c_str());
973 stack.push(string());
974 return;
977 CGroupDesc<CGroupFamily> const* groupDesc = groupDescs[CAIS::rand16((uint32)groupDescs.size())];
978 stack.push(groupDesc->getFullName());
979 return;
982 //----------------------------------------------------------------------------
983 /** @page code
985 @subsection getGroupTemplateWithFlags_ss_s
986 Returns the name of a randomly chosen group template corresponding to specified flags.
988 Arguments: s(OneOf), s(Mandatory) -> s(GroupTemplate)
989 @param[in] OneOf is a '|' separated list of flags
990 @param[in] Mandatory is a '|' separated list of flags
991 @param[out] GroupTemplate is a group template matching at least one of OneOf flags and all Manadatory flags
993 @code
994 ($group)getGroupTemplateWithFlags("food|rest", "invasion|outpost"); // Get a group which matches 'invasion', 'outpost' and either 'food' or 'rest' flags.
995 @endcode
998 // CGroup not in a family behaviour
999 void getGroupTemplateWithFlags_ss_s(CStateInstance* entity, CScriptStack& stack)
1001 stack.push(std::string(""));
1002 getGroupTemplateWithFlags_sss_s(entity, stack);
1005 //----------------------------------------------------------------------------
1006 /** @page code
1008 @subsection getZoneWithFlags_ssss_s
1009 The first parameter is a list of 'one match enough' zone flags. The zones must
1010 have at least one of these flags to be selected. The second parameter is a
1011 list of 'all required' zone flag. The zones must have all these flags to be
1012 selected. The fourth parameter is a list of 'all forbidden' zone flag. The
1013 zones must not have any of these flags to be selected. Additionnaly the
1014 returned zone cannot be ExceptZone. Last argument specifies a list of flags
1015 that the selected zone cannot have.
1017 With the list of selectable zone, the system then select a zone based on
1018 entity density in each selected zone. The system will select the least
1019 populated zone. It then returns the zone name.
1021 Priority is given to current Cell, and after that to all cells.
1023 Arguments: s(OneOf), s(Mandatory), s(ExceptZone), s(ExceptProperties) -> s(Zone)
1024 @param[in] OneOf is a '|' separated list of flags
1025 @param[in] Mandatory is a '|' separated list of flags
1026 @param[in] ExceptZone is a zone name
1027 @param[in] ExceptProperties is a '|' separated list of flags
1028 @param[out] Zone is a zone matching at least one of OneOf flags, all Manadatory flags and can't be ExceptZone
1030 @code
1031 ($zone)getZoneWithFlags("food|rest", "invasion|outpost", $oldzone); // Get a zone which matches invasion, outpost and either food or rest flags with the best score except $oldzone.
1032 ($zone)getZoneWithFlags("boss", "", $oldzone); // Get a zone which matches boss flag with the best score except the $oldzone
1033 @endcode
1036 // CGroup not in a family behaviour
1037 void getZoneWithFlags_ssss_s(CStateInstance* entity, CScriptStack& stack)
1039 string exceptProperties = stack.top();
1040 stack.pop();
1041 TStringId curZoneId= CStringMapper::map(stack.top());
1042 stack.pop();
1043 string mandatoryProperties = stack.top();
1044 stack.pop();
1045 string oneOfProperties = stack.top();
1046 stack.pop();
1048 // If no AI instance return
1049 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
1050 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
1051 if (!aiInstance)
1053 stack.push(string());
1054 return;
1057 // Fill the property sets.
1058 AITYPES::CPropertySet oneOfSet = readSet(oneOfProperties);
1059 AITYPES::CPropertySet mandatorySet = readSet(mandatoryProperties);
1060 AITYPES::CPropertySet exceptSet = readSet(exceptProperties);
1061 // Get current zone
1062 CNpcZone const* const curZone = aiInstance->getZone(curZoneId);
1063 // Create the scorer
1064 CZoneScorerMandatoryAndOneOfPlusExcept const scorer(oneOfSet, mandatorySet, exceptSet, curZone);
1066 getZoneWithFlags_helper(entity, stack, aiInstance, scorer);
1069 //----------------------------------------------------------------------------
1070 /** @page code
1072 @subsection getZoneWithFlags_sss_s
1073 @sa @ref getZoneWithFlags_ssss_s
1075 Arguments: s(OneOf), s(Mandatory), s(ExceptZone) -> s(Zone)
1076 @param[in] OneOf is a '|' separated list of flags
1077 @param[in] Mandatory is a '|' separated list of flags
1078 @param[in] ExceptZone is a zone name
1079 @param[out] Zone is a zone matching at least one of OneOf flags, all Manadatory flags and can't be ExceptZone
1081 @code
1082 ($zone)getZoneWithFlags("food|rest", "invasion|outpost", $oldzone); // Get a zone which matches invasion, outpost and either food or rest flags with the best score except $oldzone.
1083 ($zone)getZoneWithFlags("boss", "", $oldzone); // Get a zone which matches boss flag with the best score except the $oldzone
1084 @endcode
1087 // CGroup not in a family behaviour
1088 void getZoneWithFlags_sss_s(CStateInstance* entity, CScriptStack& stack)
1090 stack.push(std::string(""));
1091 getZoneWithFlags_ssss_s(entity, stack);
1094 //----------------------------------------------------------------------------
1095 /** @page code
1097 @subsection getNearestZoneWithFlags_ffsss_s
1098 @sa @ref getZoneWithFlags_ssss_s
1100 The zone returned by this function is the nearest from the specified point and taking into account the zone free space.
1102 Arguments: f(X), f(Y), s(OneOf), s(Mandatory), s(ExceptProperties) -> s(Zone)
1103 @param[in] X is the position of the zone we are looking for on the X axis
1104 @param[in] Y is the position of the zone we are looking for on the X axis
1105 @param[in] OneOf is a '|' separated list of flags
1106 @param[in] Mandatory is a '|' separated list of flags
1107 @param[in] ExceptProperties is a '|' separated list of flags
1108 @param[out] Zone is a zone matching at least one of OneOf flags, all Manadatory flags and can't be ExceptZone
1110 @code
1111 ($zone)getNearestZoneWithFlags(x, y, "food|rest", "invasion|outpost", "stayaway");
1112 @endcode
1115 // CGroup not in a family behaviour
1116 void getNearestZoneWithFlags_ffsss_s(CStateInstance* entity, CScriptStack& stack)
1118 string exceptProperties = stack.top();
1119 stack.pop();
1120 string mandatoryProperties = stack.top();
1121 stack.pop();
1122 string oneOfProperties = stack.top();
1123 stack.pop();
1124 float const y = stack.top();
1125 stack.pop();
1126 float const x = stack.top();
1127 stack.pop();
1129 // If no AI instance return
1130 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
1131 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
1132 if (!aiInstance)
1134 stack.push(string());
1135 return;
1138 // Fill the property sets.
1139 AITYPES::CPropertySet oneOfSet = readSet(oneOfProperties);
1140 AITYPES::CPropertySet mandatorySet = readSet(mandatoryProperties);
1141 AITYPES::CPropertySet exceptSet = readSet(exceptProperties);
1142 // Create the scorer
1143 CZoneScorerMandatoryAndOneOfAndDistAndSpace const scorer(oneOfSet, mandatorySet, exceptSet, CAIVector(x, y));
1145 getZoneWithFlags_helper(entity, stack, aiInstance, scorer);
1148 //----------------------------------------------------------------------------
1149 /** @page code
1151 @subsection getNearestZoneWithFlags_ffss_s
1152 @sa @ref getZoneWithFlags_sss_s
1154 The zone returned by this function is the nearest from the specified point and taking into account the zone free space.
1156 Arguments: f(X), f(Y), s(OneOf), s(Mandatory), s(ExceptProperties) -> s(Zone)
1157 @param[in] X is the position of the zone we are looking for on the X axis
1158 @param[in] Y is the position of the zone we are looking for on the X axis
1159 @param[in] OneOf is a '|' separated list of flags
1160 @param[in] Mandatory is a '|' separated list of flags
1161 @param[out] Zone is a zone matching at least one of OneOf flags, all Manadatory flags and can't be ExceptZone
1163 @code
1164 ($zone)getNearestZoneWithFlags(x, y, "food|rest", "invasion|outpost");
1165 @endcode
1168 // CGroup not in a family behaviour
1169 void getNearestZoneWithFlags_ffss_s(CStateInstance* entity, CScriptStack& stack)
1171 stack.push(std::string(""));
1172 getNearestZoneWithFlags_ffsss_s(entity, stack);
1175 //----------------------------------------------------------------------------
1176 /** @page code
1178 @subsection getNearestZoneWithFlagsStrict_ffsss_s
1179 @sa @ref getZoneWithFlags_ssss_s
1181 The zone returned by this function is the nearest from the specified point without taking into account the zone free space.
1183 Arguments: f(X), f(Y), s(OneOf), s(Mandatory), s(ExceptProperties) -> s(Zone)
1184 @param[in] X is the position of the zone we are looking for on the X axis
1185 @param[in] Y is the position of the zone we are looking for on the X axis
1186 @param[in] OneOf is a '|' separated list of flags
1187 @param[in] Mandatory is a '|' separated list of flags
1188 @param[in] ExceptProperties is a '|' separated list of flags
1189 @param[out] Zone is a zone matching at least one of OneOf flags, all Manadatory flags and can't be ExceptZone
1191 @code
1192 ($zone)getNearestZoneWithFlagsStrict(x, y, "food|rest", "invasion|outpost", "stayaway");
1193 @endcode
1196 // CGroup not in a family behaviour
1197 void getNearestZoneWithFlagsStrict_ffsss_s(CStateInstance* entity, CScriptStack& stack)
1199 string exceptProperties = stack.top();
1200 stack.pop();
1201 string mandatoryProperties = stack.top();
1202 stack.pop();
1203 string oneOfProperties = stack.top();
1204 stack.pop();
1205 float const y = stack.top();
1206 stack.pop();
1207 float const x = stack.top();
1208 stack.pop();
1210 // If no AI instance return
1211 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
1212 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
1213 if (!aiInstance)
1215 stack.push(string());
1216 return;
1219 // Fill the property sets.
1220 AITYPES::CPropertySet oneOfSet = readSet(oneOfProperties);
1221 AITYPES::CPropertySet mandatorySet = readSet(mandatoryProperties);
1222 AITYPES::CPropertySet exceptSet = readSet(exceptProperties);
1223 // Create the scorer
1224 const CZoneScorerMandatoryAndOneOfAndDist scorer(oneOfSet, mandatorySet, exceptSet, CAIVector(x, y));
1226 getZoneWithFlags_helper(entity, stack, aiInstance, scorer);
1229 //----------------------------------------------------------------------------
1230 /** @page code
1232 @subsection getNearestZoneWithFlagsStrict_ffss_s
1233 @sa @ref getZoneWithFlags_sss_s
1235 The zone returned by this function is the nearest from the specified point without taking into account the zone free space.
1237 Arguments: f(X), f(Y), s(OneOf), s(Mandatory), s(ExceptProperties) -> s(Zone)
1238 @param[in] X is the position of the zone we are looking for on the X axis
1239 @param[in] Y is the position of the zone we are looking for on the X axis
1240 @param[in] OneOf is a '|' separated list of flags
1241 @param[in] Mandatory is a '|' separated list of flags
1242 @param[out] Zone is a zone matching at least one of OneOf flags, all Manadatory flags and can't be ExceptZone
1244 @code
1245 ($zone)getNearestZoneWithFlagsStrict(x, y, "food|rest", "invasion|outpost");
1246 @endcode
1249 // CGroup not in a family behaviour
1250 void getNearestZoneWithFlagsStrict_ffss_s(CStateInstance* entity, CScriptStack& stack)
1252 stack.push(std::string(""));
1253 getNearestZoneWithFlagsStrict_ffsss_s(entity, stack);
1256 //----------------------------------------------------------------------------
1257 /** @page code
1259 @subsection getNeighbourZoneWithFlags_ssss_s
1260 @sa @ref getZoneWithFlags_ssss_s
1262 Here priority is given to current Cell, after that to neighbour Cells, and
1263 finally to all cells. CurrentZone cannot be returned.
1265 Arguments: s(CurrentZone), s(OneOf), s(Mandatory), s(ExceptProperties) -> s(Zone)
1266 @param[in] CurrentZone is a zone name
1267 @param[in] OneOf is a '|' separated list of flags
1268 @param[in] Mandatory is a '|' separated list of flags
1269 @param[in] ExceptProperties is a '|' separated list of flags
1270 @param[out] Zone is a zone matching the specified flags
1272 @code
1273 ($zone1)getNeighbourZoneWithFlags($zone, "boss", "", $exceptflag); // Get the zone in the neighbour cells of the one containing $zone which matches specified flags
1274 @endcode
1277 // CGroup not in a family behaviour
1278 void getNeighbourZoneWithFlags_ssss_s(CStateInstance* entity, CScriptStack& stack)
1280 string exceptProperties = stack.top();
1281 stack.pop();
1282 string mandatoryProperties = stack.top();
1283 stack.pop();
1284 string oneOfProperties = stack.top();
1285 stack.pop();
1286 TStringId curZoneId = CStringMapper::map(stack.top());
1287 stack.pop();
1289 // If no AI instance return
1290 IManagerParent* const managerParent = entity->getGroup()->getOwner()->getOwner();
1291 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
1292 if (!aiInstance)
1294 stack.push(string());
1295 return;
1298 // If curzone is invalid return
1299 CNpcZone const* const curZone = aiInstance->getZone(curZoneId);
1300 if (!curZone)
1302 nlwarning("getNeighbourZoneWithFlags failed: current zone is invalid!");
1303 nlwarning(" - current zone: %s", CStringMapper::unmap(curZoneId).c_str());
1304 nlwarning(" - oneOfProperties: %s", oneOfProperties.c_str());
1305 nlwarning(" - mandatoryProperties: %s", mandatoryProperties.c_str());
1306 nlwarning(" - exceptProperties: %s", exceptProperties.c_str());
1307 stack.push(string());
1308 return;
1311 // Fill the property sets.
1312 AITYPES::CPropertySet oneOfSet = readSet(oneOfProperties);
1313 AITYPES::CPropertySet mandatorySet = readSet(mandatoryProperties);
1314 AITYPES::CPropertySet exceptSet = readSet(exceptProperties);
1315 // Create the scorer
1316 CZoneScorerMandatoryAndOneOfPlusExcept const scorer(oneOfSet, mandatorySet, exceptSet, curZone);
1318 vector<CCell*> cells;
1319 curZone->getOwner()->getNeighBourgCellList(cells);
1320 cells.push_back(curZone->getOwner());
1321 std::random_shuffle(cells.begin(), cells.end());
1323 CNpcZone const* const newZone = CCellZone::lookupNpcZoneScorer(cells, scorer);
1325 if (newZone)
1327 stack.push(newZone->getAliasTreeOwner().getAliasFullName());
1328 return;
1330 nlwarning("getNeighbourgZoneWithFlags failed: no zone found");
1331 nlwarning(" - current zone: %s", CStringMapper::unmap(curZoneId).c_str());
1332 nlwarning(" - oneOfProperties: %s", oneOfProperties.c_str());
1333 nlwarning(" - mandatoryProperties: %s", mandatoryProperties.c_str());
1334 nlwarning(" - exceptProperties: %s", exceptProperties.c_str());
1336 stack.push(string());
1337 return;
1340 //----------------------------------------------------------------------------
1341 /** @page code
1343 @subsection getNeighbourZoneWithFlags_sss_s
1344 @sa @ref getZoneWithFlags_sss_s
1346 Here priority is given to current Cell, after that to neighbour Cells, and
1347 finally to all cells. CurrentZone cannot be returned.
1349 Arguments: s(CurrentZone), s(OneOf), s(Mandatory) -> s(Zone)
1350 @param[in] CurrentZone is a zone name
1351 @param[in] OneOf is a '|' separated list of flags
1352 @param[in] Mandatory is a '|' separated list of flags
1353 @param[out] Zone is a zone matching the specified flags
1355 @code
1356 ($zone1)getNeighbourZoneWithFlags($zone, "boss", ""); // Get the zone in the neighbour cells of the one containing $zone which matches specified flags
1357 @endcode
1360 // CGroup not in a family behaviour
1361 void getNeighbourZoneWithFlags_sss_s(CStateInstance* entity, CScriptStack& stack)
1363 stack.push(std::string(""));
1364 getNeighbourZoneWithFlags_ssss_s(entity, stack);
1367 //----------------------------------------------------------------------------
1368 /** @page code
1370 @subsection setAggro_ff_
1371 Sets aggro parameters of current group.
1373 Arguments: f(Range), f(NbTicks) ->
1374 @param[in] Range is a aggro range in meters
1375 @param[in] NbTicks is a aggro update period in ticks
1377 @code
1378 ()setAggro(Range, NbTicks); // Sets the aggro range of the group to Range, updated every NbTicks ticks
1379 @endcode
1382 // CGroup
1383 void setAggro_ff_(CStateInstance* entity, CScriptStack& stack)
1385 sint32 updateNbTicks = (sint32)(float)stack.top();
1386 stack.pop();
1387 uint32 aggroRange = (uint32)(float)stack.top();
1388 stack.pop();
1390 CGroup* const grp = entity->getGroup();
1391 if (grp)
1393 grp->_AggroRange = aggroRange;
1394 if (updateNbTicks>0)
1395 grp->_UpdateNbTicks = updateNbTicks;
1399 //----------------------------------------------------------------------------
1400 /** @page code
1402 @subsection setCanAggro_f_
1403 Let a bot aggro or prevent it from aggroing.
1405 Arguments: f(CanAggro) ->
1406 @param[in] CanAggro tells whether the bot can aggro (!=0) or not (==0)
1408 @code
1409 ()setCanAggro(0);
1410 @endcode
1413 // CGroup
1414 void setCanAggro_f_(CStateInstance* entity, CScriptStack& stack)
1416 bool canAggro = ((float)stack.top())!=0.f;
1417 stack.pop();
1419 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1421 if (!bot->isSpawned())
1422 continue;
1423 CSpawnBot* spBot = bot->getSpawnObj();
1424 if (spBot)
1425 spBot->setCanAggro(canAggro);
1429 //----------------------------------------------------------------------------
1430 /** @page code
1432 @subsection clearAggroList_f_
1433 Reset the aggrolist of a bot.
1435 Arguments: f(bool don't send lost aggro message to EGS) ->
1437 @code
1438 ()clearAggroList(0/1);
1439 @endcode
1442 // CGroup
1443 void clearAggroList_f_(CStateInstance* entity, CScriptStack& stack)
1445 bool sendAggroLostMessage = ((float)stack.top())==0.f;
1446 stack.pop();
1448 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1450 if (!bot->isSpawned())
1451 continue;
1452 CSpawnBot* spBot = bot->getSpawnObj();
1453 if (spBot)
1454 spBot->clearAggroList(sendAggroLostMessage);
1458 //----------------------------------------------------------------------------
1459 /** @page code
1461 @subsection clearAggroList__
1462 Reset the aggrolist of a bot.
1464 Arguments: ->
1466 @code
1467 ()clearAggroList();
1468 @endcode
1471 // CGroup
1472 void clearAggroList__(CStateInstance* entity, CScriptStack& stack)
1474 stack.push((float)0.f);
1475 clearAggroList_f_(entity, stack);
1478 //----------------------------------------------------------------------------
1479 /** @page code
1481 @subsection setMode_s_
1482 Sets the mode of every bot of the group. Valid modes are:
1483 - Normal
1484 - Sit
1485 - Eat
1486 - Rest
1487 - Alert
1488 - Hungry
1489 - Death
1491 Arguments: s(Mode) ->
1492 @param[in] Mode is the mode name to set
1494 @code
1495 ()setMode("Alert");
1496 @endcode
1499 // CGroup
1500 void setMode_s_(CStateInstance* entity, CScriptStack& stack)
1502 string NewMode = stack.top();
1503 stack.pop();
1505 MBEHAV::EMode mode = MBEHAV::stringToMode(NewMode);
1506 if (mode==MBEHAV::UNKNOWN_MODE)
1507 return;
1509 FOREACH(botIt, CCont<CBot>, entity->getGroup()->bots())
1511 if (botIt->getSpawnObj())
1512 botIt->getSpawnObj()->setMode(mode);
1517 //----------------------------------------------------------------------------
1518 /** @page code
1520 @subsection setAutoSpawn_f_
1521 Determine if the current group should respawn automatically after despawn.
1523 Arguments: f(AutoSpawn) ->
1524 @param[in] AutoSpawn is whether the group automatically rewpawns (1) or not (0)
1526 @code
1527 ()setAutoSpawn(1);
1528 @endcode
1531 // CGroup
1532 void setAutoSpawn_f_(CStateInstance* entity, CScriptStack& stack)
1534 float const autoSpawn = stack.top();
1535 stack.pop();
1537 CGroup* group = entity->getGroup();
1539 group->setAutoSpawn(autoSpawn!=0.f);
1542 //----------------------------------------------------------------------------
1543 // HP related methods
1544 /** @page code
1546 @subsection setMaxHP_ff_
1547 Sets the Max HP level of each bot of the group.
1549 Arguments: f(MaxHp) f(SetFull) ->
1550 @param[in] MaxHP is the new maximum HP for each bot
1551 @param[in] SetFull if not 0, will set the HP to the new maximum
1553 @code
1554 ()setMaxHP(50000,1);
1555 @endcode
1558 // CGroup
1559 void setMaxHP_ff_(CStateInstance* entity, CScriptStack& stack)
1561 bool setFull = ((float)stack.top() != 0.f); stack.pop();
1562 float maxHp = ((float)stack.top()); stack.pop();
1564 CChangeCreatureMaxHPMsg& msgList = CAIS::instance().getCreatureChangeMaxHP();
1566 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1568 if (!bot->isSpawned())
1569 continue;
1571 if (maxHp > 0)
1573 CSpawnBot* const sbot = bot->getSpawnObj();
1574 msgList.Entities.push_back(sbot->dataSetRow());
1575 msgList.MaxHp.push_back((uint32)(maxHp));
1576 msgList.SetFull.push_back((uint8)(setFull?1:0));
1578 bot->setCustomMaxHp((uint32)maxHp);
1582 /** @page code
1584 @subsection setHPLevel_f_
1585 Sets the current HP level of each bot of the group.
1587 Arguments: f(Coef) ->
1588 @param[in] Coef is the percentage of its max HP each creature will have
1590 @code
1591 ()setHPLevel(0.8);
1592 @endcode
1595 // CGroup
1596 void setHPLevel_f_(CStateInstance* entity, CScriptStack& stack)
1598 float coef = stack.top();
1599 stack.pop();
1601 CChangeCreatureHPMsg& msgList = CAIS::instance().getCreatureChangeHP();
1603 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1605 if (!bot->isSpawned())
1606 continue;
1608 CSpawnBot* const sbot = bot->getSpawnObj();
1610 msgList.Entities.push_back(sbot->dataSetRow());
1611 msgList.DeltaHp.push_back((sint32)(sbot->maxHitPoints()*coef));
1618 //----------------------------------------------------------------------------
1619 // HP related methods
1620 /** @page code
1622 @subsection setHPScale_f__f_
1623 Sets the current HP level of level of each bot of the group. its maxHitPoints
1625 for a bot HP = 850 and MaxHP = 1000
1626 ()setHPScale_f_(0); HP will be 0 so DeltaHp = 850
1627 ()setHPScale_f_(1); HP will be 100 so DeltaHp = 150
1628 ()setHPScale_f_(0.5); HP will be 500 so DeltaHp = 350
1629 if bot HP = 840 and Max abd setHpRatio(0) HP will be 0
1632 Arguments: f(Coef) ->
1633 @param[in] Coef is the percentage of its max HP each creature will *BE*
1635 @code
1636 ()setHPLevel(0.8);
1637 @endcode
1640 // CGroup
1641 void setHPScale_f_(CStateInstance* entity, CScriptStack& stack)
1643 float coef = stack.top();
1644 stack.pop();
1646 CChangeCreatureHPMsg& msgList = CAIS::instance().getCreatureChangeHP();
1648 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1650 if (!bot->isSpawned())
1651 continue;
1653 CSpawnBot* const sbot = bot->getSpawnObj();
1655 msgList.Entities.push_back(sbot->dataSetRow());
1656 msgList.DeltaHp.push_back((sint32)( sbot->maxHitPoints() *coef - sbot->currentHitPoints()) );
1660 //----------------------------------------------------------------------------
1661 // Url related method
1662 /** @page code
1664 @subsection setUrl_ss_
1665 Sets the name and url of right-click action
1667 Arguments: s(actionName),s(url) ->
1668 @param[in] actionName of action when player mouse over
1669 @param[in] url of action when player mouse over
1671 @code
1672 ()setUrl("Click on Me", "http://www.domain.com/script.php");
1673 @endcode
1676 // CGroup
1677 void setUrl_ss_(CStateInstance* entity, CScriptStack& stack)
1679 CGroup* group = entity->getGroup();
1681 std::string url = (std::string)stack.top();stack.pop();
1682 std::string actionName = (std::string)stack.top();stack.pop();
1684 CCreatureSetUrlMsg msg;
1685 FOREACH(botIt, CCont<CBot>, group->bots())
1687 CSpawnBot* pbot = botIt->getSpawnObj();
1688 if (pbot!=NULL)
1690 msg.Entities.push_back(pbot->dataSetRow());
1693 CSpawnGroup* spawnGroup = group->getSpawnObj();
1694 spawnGroup->setActionName(actionName);
1695 spawnGroup->setUrl(url);
1696 msg.ActionName = actionName;
1697 msg.Url = url;
1698 msg.send(egsString);
1703 /** @page code
1705 @subsection scaleHP_f_
1706 Scales the bots HP.
1708 Arguments: f(Coef) ->
1709 @param[in] Coef is the percentage of its current HP each creature will have
1711 @code
1712 ()scaleHP(2);
1713 @endcode
1716 // CGroup
1717 void scaleHP_f_(CStateInstance* entity, CScriptStack& stack)
1719 float coef = stack.top();
1720 stack.pop();
1722 CChangeCreatureHPMsg& msgList = CAIS::instance().getCreatureChangeHP();
1724 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1726 if (!bot->isSpawned())
1727 continue;
1729 CSpawnBot* const sbot = bot->getSpawnObj();
1731 msgList.Entities.push_back(sbot->dataSetRow());
1732 msgList.DeltaHp.push_back((sint32)(sbot->currentHitPoints()*coef));
1737 /** @page code
1739 @subsection setBotHPScaleByAlias_fs_
1740 Same as setHpSacale but only on a specific bot of a groupe from the current group by its bot alias
1742 Arguments: f(alias),f(Coef), ->
1743 @param[in] alias is the alias of the bot
1744 @param[in] Coef is the percentage of its current HP each creature will have
1747 @code
1748 ()scaleHpByAlias(2, '(A:1000:10560)');
1749 @endcode
1752 // CGroup
1753 void setBotHPScaleByAlias_fs_(CStateInstance* entity, CScriptStack& stack)
1755 uint32 alias = LigoConfig.aliasFromString((string)stack.top()) ; stack.pop();
1757 float coef = stack.top(); stack.pop();
1759 CChangeCreatureHPMsg& msgList = CAIS::instance().getCreatureChangeHP();
1761 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1764 if (bot->getAlias() != alias) { continue; }
1765 if (!bot->isSpawned()) return;
1767 CSpawnBot* const sbot = bot->getSpawnObj();
1769 msgList.Entities.push_back(sbot->dataSetRow());
1770 msgList.DeltaHp.push_back((sint32)( sbot->maxHitPoints() *coef - sbot->currentHitPoints()) );
1775 /** @page code
1777 @subsection downScaleHP_f_
1778 Scales the bots HP down.
1780 Arguments: f(Coef) ->
1781 @param[in] Coef is a value
1783 @code
1784 ()downScaleHP(2);
1785 @endcode
1788 // CGroup
1789 void downScaleHP_f_(CStateInstance* entity, CScriptStack& stack)
1791 float coef = stack.top();
1792 stack.pop();
1794 CChangeCreatureHPMsg& msgList = CAIS::instance().getCreatureChangeHP();
1796 clamp(coef, 0.f, 1.f);
1797 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1799 if (!bot->isSpawned())
1800 continue;
1802 CSpawnBot* const sbot = bot->getSpawnObj();
1804 msgList.Entities.push_back(sbot->dataSetRow());
1805 msgList.DeltaHp.push_back((sint32)(sbot->currentHitPoints()*(coef-1)));
1809 /** @page code
1811 @subsection upScaleHP_f_
1812 Scales the bots HP up.
1814 Arguments: f(Coef) ->
1815 @param[in] Coef is a value
1817 @code
1818 ()upScaleHP(2);
1819 @endcode
1822 // CGroup
1823 void upScaleHP_f_(CStateInstance* entity, CScriptStack& stack)
1825 float coef = stack.top();
1826 stack.pop();
1828 CChangeCreatureHPMsg& msgList = CAIS::instance().getCreatureChangeHP();
1830 clamp(coef, 0.f, 1.f);
1831 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1833 if (!bot->isSpawned())
1834 continue;
1835 CSpawnBot* spBot = bot->getSpawnObj();
1836 if (spBot)
1838 msgList.Entities.push_back(spBot->dataSetRow());
1839 msgList.DeltaHp.push_back((sint32)((spBot->maxHitPoints()-spBot->currentHitPoints())*coef));
1844 /** @page code
1846 @subsection addHP_f_
1847 Add HP to the bots.
1849 Arguments: f(HP) ->
1850 @param[in] HP is the amount of hit points to add to each bot
1852 @code
1853 ()addHP(500);
1854 @endcode
1857 // CGroup
1858 void addHP_f_(CStateInstance* entity, CScriptStack& stack)
1860 float addHP = stack.top();
1861 stack.pop();
1863 CChangeCreatureHPMsg& msgList = CAIS::instance().getCreatureChangeHP();
1865 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1867 if (!bot->isSpawned())
1868 continue;
1870 CSpawnBot* const sbot = bot->getSpawnObj();
1872 msgList.Entities.push_back(sbot->dataSetRow());
1873 msgList.DeltaHp.push_back((sint32)(sbot->currentHitPoints()+addHP));
1877 void giveHP_f_(CStateInstance* entity, CScriptStack& stack)
1879 float addHP = stack.top();
1880 stack.pop();
1882 CChangeCreatureHPMsg& msgList = CAIS::instance().getCreatureChangeHP();
1884 FOREACH(bot, CCont<CBot>, entity->getGroup()->bots())
1886 if (!bot->isSpawned())
1887 continue;
1889 CSpawnBot* const sbot = bot->getSpawnObj();
1891 msgList.Entities.push_back(sbot->dataSetRow());
1892 msgList.DeltaHp.push_back((sint32)(addHP));
1896 //----------------------------------------------------------------------------
1897 /** @page code
1899 @subsection aiAction_s_
1900 Triggers an AI action, defined by its sheet name, on the current target.
1902 Arguments: s(actionSheetId) ->
1903 @param[in] actionSheetId is a the sheet name of the action
1905 @code
1906 ()aiAction("kick_his_ass.aiaction");
1907 @endcode
1910 // CGroup
1911 void aiAction_s_(CStateInstance* entity, CScriptStack& stack)
1913 std::string actionName = stack.top();
1914 stack.pop();
1915 NLMISC::CSheetId sheetId(actionName);
1916 if (sheetId==NLMISC::CSheetId::Unknown)
1918 nlwarning("Action SheetId Unknown %s", actionName.c_str());
1919 return;
1921 AISHEETS::IAIActionCPtr action = AISHEETS::CSheets::getInstance()->lookupAction(sheetId);
1922 if (action.isNull())
1924 nlwarning("Action SheetId Unknown %s", actionName.c_str());
1925 return;
1928 FOREACH(botIt, CCont<CBot>, entity->getGroup()->bots())
1930 CSpawnBot* pbot = botIt->getSpawnObj();
1931 if (pbot!=NULL)
1933 CSpawnBot& bot = *pbot;
1934 if (!bot.getAIProfile())
1935 continue; // OK
1937 CBotProfileFight* profile = dynamic_cast<CBotProfileFight*>(bot.getAIProfile());
1938 if (!profile)
1939 continue; // OK
1941 if (!profile->atAttackDist())
1942 continue; // NOT OK
1944 TDataSetRow dataSetRow;
1945 if ((CAIEntityPhysical*)bot.getTarget())
1946 dataSetRow = bot.getTarget()->dataSetRow();
1948 CEGSExecuteAiActionMsg msg(bot.dataSetRow(), dataSetRow, action->SheetId(), bot._DamageCoef, bot._DamageSpeedCoef);
1949 msg.send(egsString);
1950 bot.setActionFlags(RYZOMACTIONFLAGS::Attacks);
1951 // OK
1956 //----------------------------------------------------------------------------
1957 /** @page code
1959 @subsection aiActionSelf_s_
1960 Triggers an AI action, defined by its sheet name, on the bot itself.
1962 Arguments: s(actionSheetId) ->
1963 @param[in] actionSheetId is a the sheet name of the action
1965 @code
1966 ()aiActionSelf("defensive_aura.aiaction");
1967 @endcode
1970 // CGroup
1971 void aiActionSelf_s_(CStateInstance* entity, CScriptStack& stack)
1973 std::string actionName = stack.top();
1974 stack.pop();
1975 NLMISC::CSheetId sheetId(actionName);
1976 if (sheetId==NLMISC::CSheetId::Unknown)
1978 nlwarning("Action SheetId Unknown %s", actionName.c_str());
1979 return;
1981 AISHEETS::IAIActionCPtr action = AISHEETS::CSheets::getInstance()->lookupAction(sheetId);
1982 if (action.isNull())
1984 nlwarning("Action SheetId Unknown %s", actionName.c_str());
1985 return;
1988 FOREACH(botIt, CCont<CBot>, entity->getGroup()->bots())
1990 CSpawnBot* pbot = botIt->getSpawnObj();
1991 if (pbot!=NULL)
1993 CSpawnBot& bot = *pbot;
1994 CEGSExecuteAiActionMsg msg(bot.dataSetRow(), bot.dataSetRow(), action->SheetId(), bot._DamageCoef, bot._DamageSpeedCoef);
1995 msg.send(egsString);
1996 bot.setActionFlags(RYZOMACTIONFLAGS::Attacks);
1997 // OK
2002 //----------------------------------------------------------------------------
2003 /** @page code
2005 @subsection addProfileParameter_s_
2006 Adds a profile parameter to the current group.
2008 Arguments: s(parameterName) ->
2009 @param[in] parameterName is a the id of the parameter to add
2011 @code
2012 ()addProfileParameter("running"); // equivalent to "running" parameter in group primitive
2013 @endcode
2016 // CGroup
2017 void addProfileParameter_s_(CStateInstance* entity, CScriptStack& stack)
2019 std::string name = (std::string)stack.top();
2020 stack.pop();
2022 CGroup* group = entity->getGroup();
2024 if (group->isSpawned())
2025 group->getSpawnObj()->addProfileParameter(name, "", 0.f);
2029 //----------------------------------------------------------------------------
2030 /** @page code
2032 @subsection addProfileParameter_ss_
2033 Adds a profile parameter to the current group.
2035 Arguments: s(parameterName),s(parameterContent) ->
2036 @param[in] parameterName is a the id of the parameter to add
2037 @param[in] parameterContent is the value of the parameter
2039 @code
2040 ()addProfileParameter("foo", "bar"); // equivalent to "foo:bar" parameter in group primitive
2041 @endcode
2044 // CGroup
2045 void addProfileParameter_ss_(CStateInstance* entity, CScriptStack& stack)
2047 std::string value = (std::string)stack.top();
2048 stack.pop();
2049 std::string name = (std::string)stack.top();
2050 stack.pop();
2052 CGroup* group = entity->getGroup();
2054 if (group->isSpawned())
2055 group->getSpawnObj()->addProfileParameter(name, value, 0.f);
2058 //----------------------------------------------------------------------------
2059 /** @page code
2061 @subsection addProfileParameter_sf_
2062 Adds a profile parameter to the current group.
2064 Arguments: s(parameterName),f(parameterContent) ->
2065 @param[in] parameterName is a the id of the parameter to add
2066 @param[in] parameterContent is the value of the parameter
2068 @code
2069 ()addProfileParameter("foo", 0.5); // equivalent to "foo:0.5" parameter in group primitive
2070 @endcode
2073 // CGroup
2074 void addProfileParameter_sf_(CStateInstance* entity, CScriptStack& stack)
2076 float value = (float)stack.top();
2077 stack.pop();
2078 std::string name = (std::string)stack.top();
2079 stack.pop();
2081 CGroup* group = entity->getGroup();
2083 if (group->isSpawned())
2084 group->getSpawnObj()->addProfileParameter(name, "", value);
2087 //----------------------------------------------------------------------------
2088 /** @page code
2090 @subsection removeProfileParameter_s_
2091 removes a profile parameter from the current group.
2093 Arguments: s(parameterName) ->
2094 @param[in] parameterName is a the id of the parameter to remove
2096 @code
2097 ()removeProfileParameter("running"); // remove "running" or "running:<*>" parameter from group
2098 @endcode
2101 // CGroup
2102 void removeProfileParameter_s_(CStateInstance* entity, CScriptStack& stack)
2104 std::string name = (std::string)stack.top();
2105 stack.pop();
2107 CGroup* group = entity->getGroup();
2109 if (group->isSpawned())
2110 group->getSpawnObj()->removeProfileParameter(name);
2113 //----------------------------------------------------------------------------
2114 /** @page code
2116 @subsection addPersistentProfileParameter_s_
2117 Adds a profile parameter to the current group.
2119 Arguments: s(parameterName) ->
2120 @param[in] parameterName is a the id of the parameter to add
2122 @code
2123 ()addProfileParameter("running"); // equivalent to "running" parameter in group primitive
2124 @endcode
2127 // CGroup
2128 void addPersistentProfileParameter_s_(CStateInstance* entity, CScriptStack& stack)
2130 std::string name = (std::string)stack.top();
2131 stack.pop();
2133 CGroup* group = entity->getGroup();
2135 if (group->isSpawned())
2136 group->getSpawnObj()->addProfileParameter(name, "", 0.f);
2138 group->addProfileParameter(name, "", 0.f);
2141 //----------------------------------------------------------------------------
2142 /** @page code
2144 @subsection addPersistentProfileParameter_ss_
2145 Adds a profile parameter to the current group.
2147 Arguments: s(parameterName),s(parameterContent) ->
2148 @param[in] parameterName is a the id of the parameter to add
2149 @param[in] parameterContent is the value of the parameter
2151 @code
2152 ()addPersistentProfileParameter("foo", "bar"); // equivalent to "foo:bar" parameter in group primitive
2153 @endcode
2156 // CGroup
2157 void addPersistentProfileParameter_ss_(CStateInstance* entity, CScriptStack& stack)
2159 std::string value = (std::string)stack.top();
2160 stack.pop();
2161 std::string name = (std::string)stack.top();
2162 stack.pop();
2164 CGroup* group = entity->getGroup();
2166 if (group->isSpawned())
2167 group->getSpawnObj()->addProfileParameter(name, value, 0.f);
2169 group->addProfileParameter(name, value, 0.f);
2172 //----------------------------------------------------------------------------
2173 /** @page code
2175 @subsection addPersistentProfileParameter_sf_
2176 Adds a profile parameter to the current group.
2178 Arguments: s(parameterName),f(parameterContent) ->
2179 @param[in] parameterName is a the id of the parameter to add
2180 @param[in] parameterContent is the value of the parameter
2182 @code
2183 ()addPersistentProfileParameter("foo", 0.5); // equivalent to "foo:0.5" parameter in group primitive
2184 @endcode
2187 // CGroup
2188 void addPersistentProfileParameter_sf_(CStateInstance* entity, CScriptStack& stack)
2190 float value = (float)stack.top();
2191 stack.pop();
2192 std::string name = (std::string)stack.top();
2193 stack.pop();
2195 CGroup* group = entity->getGroup();
2196 if (group->isSpawned())
2197 group->getSpawnObj()->addProfileParameter(name, "", value);
2199 group->addProfileParameter(name, "", value);
2202 //----------------------------------------------------------------------------
2203 /** @page code
2205 @subsection removePersistentProfileParameter_s_
2206 removes a profile parameter from the current group.
2208 Arguments: s(parameterName) ->
2209 @param[in] parameterName is a the id of the parameter to remove
2211 @code
2212 ()removeProfileParameter("running"); // remove "running" or "running:<*>" parameters from group
2213 @endcode
2216 // CGroup
2217 void removePersistentProfileParameter_s_(CStateInstance* entity, CScriptStack& stack)
2219 std::string name = (std::string)stack.top();
2220 stack.pop();
2222 CGroup* group = entity->getGroup();
2223 if (group->isSpawned())
2224 group->getSpawnObj()->removeProfileParameter(name);
2226 group->removeProfileParameter(name);
2228 //----------------------------------------------------------------------------
2229 /** @page code
2231 @subsection getOutpostState__s
2232 Returns the name of the current outpost state (group must be in an outpost).
2234 Arguments: -> s(StateName)
2235 @param[out] StateName is the name of the current outpost state
2237 @code
2238 ($name)getOutpostState();
2239 @endcode
2242 // CGroup
2243 void getOutpostStateName__s(CStateInstance* si, CScriptStack& stack)
2245 string str;
2247 breakable
2249 if (!si)
2250 break;
2252 CGroup* group = si->getGroup();
2253 if (!group)
2254 break;
2256 COutpostManager* manager = dynamic_cast<COutpostManager*>(group->getOwner());
2257 if (!manager)
2258 break;
2260 str = static_cast<COutpost*>(manager->getOwner())->getStateName();
2263 stack.push(str);
2266 //----------------------------------------------------------------------------
2267 /** @page code
2269 @subsection isOutpostTribeOwner__f
2270 Returns whether the current outpost owner is a tribe (group must be in an outpost).
2272 Arguments: -> f(TribeOwner)
2273 @param[out] TribeOwner is whether the current outpost owner is a tribe (1) or not (0)
2275 @code
2276 (tribeOwner)isOutpostTribeOwner();
2277 @endcode
2280 // CGroup
2281 void isOutpostTribeOwner__f(CStateInstance* si, CScriptStack& stack)
2283 float tribeOwner = 0.f;
2285 breakable
2287 if (!si)
2288 break;
2290 CGroup* group = si->getGroup();
2291 if (!group)
2292 break;
2294 COutpostManager* manager = dynamic_cast<COutpostManager*>(group->getOwner());
2295 if (!manager)
2296 break;
2298 if (!static_cast<COutpost*>(manager->getOwner())->isBelongingToAGuild())
2299 tribeOwner = 1.f;
2302 stack.push(tribeOwner);
2305 //----------------------------------------------------------------------------
2306 /** @page code
2308 @subsection isOutpostGuildOwner__f
2309 Returns whether the current outpost owner is a guild (group must be in an outpost).
2311 Arguments: -> f(TribeOwner)
2312 @param[out] TribeOwner is whether the current outpost owner is a guild (1) or not (0)
2314 @code
2315 (guildOwner)isOutpostGuildOwner();
2316 @endcode
2319 // CGroup
2320 void isOutpostGuildOwner__f(CStateInstance* si, CScriptStack& stack)
2322 float guildOwner = 0.f;
2324 breakable
2326 if (!si)
2327 break;
2329 CGroup* group = si->getGroup();
2330 if (!group)
2331 break;
2333 COutpostManager* manager = dynamic_cast<COutpostManager*>(group->getOwner());
2334 if (!manager)
2335 break;
2337 if (static_cast<COutpost*>(manager->getOwner())->isBelongingToAGuild())
2338 guildOwner = 1.f;
2341 stack.push(guildOwner);
2344 //----------------------------------------------------------------------------
2345 /** @page code
2347 @subsection getEventParam_f_f
2348 Returns the content of a param
2350 Arguments: f(paramIndex) -> f(value)
2351 @param[in] paramIndex is the parameter index passed by EGS ai_event message
2352 @param[out] value is a the value of the parameter
2354 @code
2355 (val)getEventParam(2);
2356 @endcode
2359 // CGroup
2360 void getEventParam_f_f(CStateInstance* entity, CScriptStack& stack)
2362 uint32 varId = (uint32)((float)stack.top());
2364 CGroup* group = entity->getGroup();
2366 stack.top() = group->getEventParamFloat(varId);
2369 //----------------------------------------------------------------------------
2370 /** @page code
2372 @subsection getEventParam_f_s
2373 Returns the content of a param
2375 Arguments: f(paramIndex) -> s(value)
2376 @param[in] paramIndex is the parameter index passed by EGS ai_event message
2377 @param[out] value is a the value of the parameter
2379 @code
2380 ($val)getEventParam(2);
2381 @endcode
2384 // CGroup
2385 void getEventParam_f_s(CStateInstance* entity, CScriptStack& stack)
2387 uint32 varId = (uint32)((float)stack.top());
2389 CGroup* group = entity->getGroup();
2391 stack.top() = group->getEventParamString(varId);
2396 // -- Boss functions
2398 //----------------------------------------------------------------------------
2399 /** @page code
2401 @subsection getPlayerStat_ss_f
2402 Get some player stat.
2404 A player EntityId is used to identify the player. This EntityId is passed as string as argument. The EntityId can be obtains via getCurrentPlayerAggroListTarget or getRandomPlayerAggroListTarget.
2405 The player must be in the same AI Instance (same continent).
2406 If the player is not in the same Ai Instance or the input string is empty the function return zero and *display* a warning message on the log. You can think of using isPlayerAlived to be sure that the id is still a valid value.
2407 If param is not one of "HP", "MaxHp", "RatioHp" zero is return and a warning message is printed on the log.
2408 - The "Hp" stat is the property CURRENT_HIT_POINTS as seen in the mirror.
2409 - The "MaxHp" stat is the property MAX_HIT_POINTS as seen in the mirror.
2410 - The "RatioHp" stat is (Hp * 100) / MaxHp
2411 Be careful the argument is case sensitive.
2413 Arguments: s(playerEidAsString), s(statName) -> s(result)
2414 @param[in] playerEidAsString is EntityId as string from the player we want infos
2415 @param[in] statName is the name of the property (can be "HP", "MaxHp", "RatioHp")
2416 @param[out] value is a the value of the parameter
2418 @code
2419 ($playerEid)getCurrentPlayerEid();
2420 print($playerEid); //log (0x00001fbd50:00:00:81)
2421 (maxHp)getPlayerStat($playerEid, "MaxHp");
2422 @endcode
2424 void getPlayerStat_ss_f(CStateInstance* entity, CScriptStack& stack)
2426 std::string funName = "getPlayerStat_ss_f";
2427 // reaed input
2428 std::string statName = ((std::string)stack.top()); stack.pop();
2429 std::string playerEidStr = ((std::string)stack.top()); stack.pop();
2432 // get Dataset of the player to have access to mirror values
2433 NLMISC::CEntityId playerEid;
2434 playerEid.fromString(playerEidStr.c_str());
2435 TDataSetRow playerRow = TheDataset.getDataSetRow( playerEid );
2436 if (! TheDataset.isAccessible( playerRow ) )
2438 nlwarning("Try to call %s with on a player '%s' that is not accessible. The isPlayerAlived function must be called to be sure that the palyer is still alived.", funName.c_str(), playerEidStr.c_str() );
2439 stack.push((float)0);
2440 return;
2443 if (statName == "Hp" )
2445 // return DSPropertyCURRENT_HIT_POINTS Mirror value
2446 CMirrorPropValue<sint32> mirrorSymbol( TheDataset, playerRow, DSPropertyCURRENT_HIT_POINTS );
2447 stack.push((float)mirrorSymbol.getValue());
2448 return;
2450 else if (statName == "MaxHp")
2452 // return DSPropertyMAX_HIT_POINTS Mirror value
2453 CMirrorPropValue<sint32> mirrorSymbol( TheDataset, playerRow, DSPropertyMAX_HIT_POINTS );
2454 stack.push((float)mirrorSymbol.getValue());
2455 return;
2457 else if (statName == "RatioHp")
2459 // return percentage of live (read from mirror values)
2460 CMirrorPropValue<sint32> mirrorSymbol( TheDataset, playerRow, DSPropertyCURRENT_HIT_POINTS );
2461 CMirrorPropValue<sint32> mirrorSymbol2( TheDataset, playerRow, DSPropertyMAX_HIT_POINTS );
2463 stack.push((float)(100.0*mirrorSymbol.getValue() / mirrorSymbol2.getValue()));
2464 return;
2466 else
2468 nlwarning("Try to call %s with wrong state %s", funName.c_str(), statName.c_str() );
2470 stack.push((float)0);
2471 return;
2475 //----------------------------------------------------------------------------
2476 /** @page code
2478 @subsection getPlayerPosition_ss_ff
2479 Get player position (x or y).
2481 Arguments: s(playerEidAsString), s(statName) -> s(result)
2482 @param[in] playerEidAsString is EntityId as string from the player we want infos
2483 @param[in] axis ("X" or "Y")
2484 @param[out] value is a the value of the parameter
2486 @code
2487 ($playerEid)getCurrentPlayerEid();
2488 (x, y)getPlayerPosition($playerEid);
2489 @endcode
2491 void getPlayerPosition_s_ff(CStateInstance* entity, CScriptStack& stack)
2493 std::string funName = "getPlayerPosition_s_ff";
2494 // reaed input
2495 std::string statName = ((std::string)stack.top()); stack.pop();
2496 std::string playerEidStr = ((std::string)stack.top()); stack.pop();
2499 // get Dataset of the player to have access to mirror values
2500 NLMISC::CEntityId playerEid;
2501 playerEid.fromString(playerEidStr.c_str());
2502 TDataSetRow playerRow = TheDataset.getDataSetRow( playerEid );
2503 if (! TheDataset.isAccessible( playerRow ) )
2505 nlwarning("Try to call %s with on a player '%s' that is not accessible. The isPlayerAlived function must be called to be sure that the palyer is still alived.", funName.c_str(), playerEidStr.c_str() );
2506 stack.push((float)0);
2507 return;
2510 CMirrorPropValue<sint32> mirrorSymbol( TheDataset, playerRow, DSPropertyPOSY );
2511 stack.push((float)mirrorSymbol.getValue());
2512 CMirrorPropValue<sint32> mirrorSymbol2( TheDataset, playerRow, DSPropertyPOSX );
2513 stack.push((float)mirrorSymbol2.getValue());
2514 return;
2518 /** @page code
2520 @subsection getPlayerDistance_fs_f
2521 Get the distance between a player and a bot in meters.
2523 A player EntityId is used to identify the player. This EntityId is passed as string as argument. The EntityId can be obtains via getCurrentPlayerAggroListTarget or getRandomPlayerAggroListTarget.
2524 The player must be in the same AI Instance (same continent).
2525 If the player is not in the same Ai Instance or the input string is empty the function return -1 and display a warning message on the log. You can think of using isPlayerAlived to be sure that the player id is still a valid value.
2527 A bot index is used to identify the bot. If there is only one spawned bot in a group then the index value is 0. If we want the bot index of a specific bot the getBotIndexByName function can be used. The function getBotCount can be used to know the number of bot in a group. The function isGroupAlived or isBotAlived can be used to verify if the index is valid.
2528 If no bot are identified by the bot index the function returns -1 and display a warning message. You can this of using isBotAlived to be sure that the bot index is still a valid value.
2530 Arguments: s(playerEidAsString), f(botIndex) -> s(result)
2531 @param[in] playerEidAsString is EntityId as string from the player we want infos
2532 @param[in] botIndex is the index of an bot member of the current group
2533 @param[out] value is a the distance between the player on the bot (or -1 if error)
2535 @code
2536 ($playerEid)getCurrentPlayerEid();
2537 (index)getBotIndexByName("toto");
2538 (distance)getPlayerDistance(index, $playerEid);
2539 @endcode
2541 void getPlayerDistance_fs_f(CStateInstance* entity, CScriptStack& stack)
2543 std::string funName = "getPlayerDistance_is_f";
2545 // read input params
2546 std::string playerEidStr = ((std::string)stack.top()); stack.pop();
2547 sint32 botIndex = (sint32)((float)stack.top()); stack.pop();
2549 // get the player Eid
2550 NLMISC::CEntityId playerEid;
2551 playerEid.fromString(playerEidStr.c_str());
2553 // get the Spawn bot by its index
2554 CGroup* group = entity->getGroup();
2555 if (!group)
2557 nlwarning("%s on a non Npc Group, doesn't work", funName.c_str());
2558 stack.push((float) -1);
2559 return;
2561 if (!group->isSpawned() || botIndex <0 || group->bots().size() <= static_cast<uint32>(botIndex))
2563 nlwarning("%s used bad index %d/%d (or group not spawn)", funName.c_str(), botIndex, group->bots().size());
2564 stack.push((float)-1);
2565 return;
2567 CBot* bot = group->getBot(botIndex);
2568 CSpawnBot* spBot = bot?bot->getSpawnObj():0;
2569 if (!spBot)
2571 nlwarning("%s used bad index %d/%d (or bot not spawn)", funName.c_str(), botIndex, group->bots().size());
2572 stack.push((float)-1);
2573 return;
2576 // get DataSetRow of player to read mirro values
2577 TDataSetRow playerRow = TheDataset.getDataSetRow( playerEid );
2578 if (! TheDataset.isAccessible( playerRow ) )
2580 nlwarning("Try to call %s with on a player '%s' that is not accessible. The isPlayerAlived function must be called to be sure that the player is still alived.", funName.c_str(), playerEidStr.c_str() );
2581 stack.push((float)-1);
2582 return;
2585 // calculate the size between position of the player (from mirro) to position of the spawn bot.
2586 CMirrorPropValue<sint32> mirrorSymbol( TheDataset, playerRow, DSPropertyPOSX );
2587 CMirrorPropValue<sint32> mirrorSymbol2( TheDataset, playerRow, DSPropertyPOSY );
2588 const double dx = double (mirrorSymbol.getValue()) - double(spBot->x().asInt());
2589 const double dy = double (mirrorSymbol2.getValue()) - double(spBot->y().asInt());
2590 const double dist2 = (dx*dx + dy*dy) / 1000000.0;
2591 const double dist = sqrt(dist2);
2593 stack.push(float(dist));
2595 return;
2601 /** @page code
2603 @subsection getCurrentPlayerAggroListTarget_f_s
2604 Get the player entity id (as string) that has the most aggro in the aggro list of a bot.
2606 A bot index is used to identify the bot. If there is only one spawned bot in a group then the index value is 0. If we want the bot index of a specific bot the getBotIndexByName function can be used. The function getBotCount can be used to know the number of bot in a group. The function isGroupAlived or isBotAlived can be used to verify if the index is valid.
2607 If no bot are identified by the bot index (or bot not spawaned) the function returns an empty string and display a warning message. You can this of using isBotAlived to be sure that the bot index is still a valid value.
2609 A player EntityId is used to identify the player. This EntityId is returned as result. If the aggro list is empty an empty string is returned (but *NO* warning messages)
2612 Arguments: f(botIndex) -> s(playerEidAsString)
2613 @param[in] botIndex is the index of an bot member of the current group
2614 @param[out] playerEidAsString is EntityId as string from the player we want infos
2616 @code
2617 ($playerId)getCurrentPlayerAggroListTarget(4);
2618 (distance)getPlayerDistance(4, $playerId);
2619 @endcode
2623 void getCurrentPlayerAggroListTarget_f_s(CStateInstance* entity, CScriptStack& stack)
2626 std::string funName = "getCurrentPlayerAggroListTarget_f_s";
2628 // get input params
2629 sint32 botIndex = (sint32)((float)stack.top()); stack.pop();
2631 // get spawn Bot
2632 CGroup* group = entity->getGroup();
2633 if (!group)
2635 nlwarning("%s on a non Npc Group, doesn't work", funName.c_str());
2636 stack.push(std::string(""));
2637 return;
2639 if (!group->isSpawned() || botIndex <0 || group->bots().size() <= static_cast<uint32>(botIndex))
2641 nlwarning("%s used bad index %d/%d (or group not spawn)", funName.c_str(), botIndex, group->bots().size());
2642 stack.push(std::string(""));
2644 return;
2646 CBot* bot = group->getBot(botIndex);
2647 CSpawnBot* spBot = bot?bot->getSpawnObj():0;
2648 if (!spBot)
2650 nlwarning("%s used bad index %d/%d (or bot not spawn)", funName.c_str(), botIndex, group->bots().size());
2651 stack.push(std::string(""));
2652 return;
2655 // iteratre throug aggro list to have the eid with max aggro
2656 CBotAggroOwner::TBotAggroList const& aggroList = spBot->getBotAggroList();
2657 CBotAggroOwner::TBotAggroList::const_iterator aggroIt(aggroList.begin()), aggroEnd(aggroList.end());
2658 TDataSetRow foundRow = TDataSetRow();
2659 float foundAggro = 0;
2660 for (; aggroIt != aggroEnd; ++aggroIt)
2662 float aggro = aggroIt->second->finalAggro();
2663 if (aggro > foundAggro)
2665 if (CMirrors::getEntityId(aggroIt->first).getType() != RYZOMID::player)
2667 continue;
2669 CAIEntityPhysical* ep = CAIS::instance().getEntityPhysical(aggroIt->first);
2670 if (!ep)
2672 continue;
2675 CBotPlayer const* const player = NLMISC::safe_cast<CBotPlayer const*>(ep);
2676 if (!player)
2678 continue;
2680 if (!player->isAggroable())
2682 continue;
2684 foundAggro = aggro;
2685 foundRow = aggroIt->first;
2689 if ( foundRow == TDataSetRow())
2690 { // Empty aggro list so no warning displayed
2691 stack.push(std::string(""));
2692 return;
2695 const NLMISC::CEntityId& found = CMirrors::getEntityId(foundRow);
2696 stack.push(std::string(found.toString()));
2702 /** @page code
2704 @subsection getRandomPlayerAggroListTarget_f_s
2705 Get a player entity id (as string) from the aggro list of a bot.
2707 A bot index is used to identify the bot. If there is only one spawned bot in a group then the index value is 0. If we want the bot index of a specific bot the getBotIndexByName function can be used. The function getBotCount can be used to know the number of bot in a group. The function isGroupAlived or isBotAlived can be used to verify if the index is valid.
2708 If no bot are identified by the bot index (or bot not spawaned) the function returns an empty string and display a warning message. You can this of using isBotAlived to be sure that the bot index is still a valid value.
2710 A player EntityId is used to identify the player. This EntityId is returned as result. If the aggro list is empty an empty string is returned (but *NO* warning messages)
2713 Arguments: f(botIndex) -> s(playerEidAsString)
2714 @param[in] botIndex is the index of an bot member of the current group
2715 @param[out] playerEidAsString is EntityId as string from the player we want infos
2717 @code
2718 ($playerId)getRandomPlayerAggroListTarget(4);
2719 ()setAggroListTarget(4, $playerId);
2720 @endcode
2724 void getRandomPlayerAggroListTarget_f_s(CStateInstance* entity, CScriptStack& stack)
2727 std::string funName = "getRandomPlayerAggroListTarget_f_s";
2729 // test botIndex
2730 uint32 botIndex = (uint32)((float)stack.top()); stack.pop();
2732 // get Spawn bot
2733 CGroup* group = entity->getGroup();
2734 if (!group || !group->isSpawned() || botIndex <0 || group->bots().size() <= static_cast<uint32>(botIndex))
2736 nlwarning("%s used bad index %d/%d (or group not spawn)", funName.c_str(), botIndex, group->bots().size());
2737 stack.push(std::string(""));
2738 return;
2740 CBot* bot = group->getBot(botIndex);
2741 CSpawnBot* spBot = bot?bot->getSpawnObj():0;
2742 if (!spBot)
2744 nlwarning("%s used bad index %d/%d (or bot not spawn)", funName.c_str(), botIndex, group->bots().size());
2745 stack.push(std::string(""));
2746 return;
2749 // make a vector of aggroable player
2750 CBotAggroOwner::TBotAggroList const& aggroList = spBot->getBotAggroList();
2751 //typedef std::map<TDataSetRow, TAggroEntryPtr> TBotAggroList;
2752 CBotAggroOwner::TBotAggroList::const_iterator aggroIt(aggroList.begin()), aggroEnd(aggroList.end());
2753 TDataSetRow foundRow = TDataSetRow();
2754 std::vector<TDataSetRow> playerAggroable;
2755 for (; aggroIt != aggroEnd; ++aggroIt)
2757 if (CMirrors::getEntityId(aggroIt->first).getType() != RYZOMID::player)
2759 continue;
2761 CAIEntityPhysical* ep = CAIS::instance().getEntityPhysical(aggroIt->first);
2762 if (!ep)
2764 continue;
2767 CBotPlayer const* const player = NLMISC::safe_cast<CBotPlayer const*>(ep);
2768 if (!player)
2770 continue;
2772 if (!player->isAggroable())
2774 continue;
2776 playerAggroable.push_back(aggroIt->first);
2781 if ( playerAggroable.empty())
2783 stack.push(std::string(""));
2784 return;
2786 // chose a randomly a player among the container
2787 uint32 index = static_cast<uint32>( static_cast<double>(playerAggroable.size())*rand()/(RAND_MAX+1.0) );
2789 const NLMISC::CEntityId& found = CMirrors::getEntityId(playerAggroable[ index ]);
2790 stack.push(std::string(found.toString()));
2794 /** @page code
2796 @subsection getAggroListElement_ff_s
2797 Get a player entity id (as string) from the aggro list of a bot by it aggro list index.
2799 A bot index is used to identify the bot. If there is only one spawned bot in a group then the index value is 0. If we want the bot index of a specific bot the getBotIndexByName function can be used. The function getBotCount can be used to know the number of bot in a group. The function isGroupAlived or isBotAlived can be used to verify if the index is valid.
2800 If no bot are identified by the bot index (or bot not spawaned) the function returns an empty string and display a warning message. You can this of using isBotAlived to be sure that the bot index is still a valid value.
2802 A aggro list index is used to identified the player in the aggro list. The size of the aggro list is given by getAggroListSize_f_s
2806 Arguments: f(botIndex), f(aggroListIndex) -> s(playerEidAsString)
2807 @param[in] botIndex is the index of an bot member of the current group
2808 @param[in] aggroListIndex is the index of a aggroable player in the aggro list of the bot identified by botIndex
2809 @param[out] playerEidAsString is EntityId as string from the player we want infos
2811 @code
2812 (aggroSize)getAggorListSize(0);
2813 // to much player are attacking the boss
2814 if (aggoroSize > 10)
2816 ($player1)getAggroListElement(0);
2817 ($player2)getAggroListElement(1);
2818 ($player3)getAggroListElement(2);
2819 // so the boss teleport 3 person from its aggro list at the end of the world
2820 teleportPlayer($player1, 14233, 123123, 0, 0);
2821 teleportPlayer($player2, 14233, 123123, 0, 0);
2822 teleportPlayer($player2, 14233, 123123, 0, 0);
2823 clearAggroList();
2826 @endcode
2828 void getAggroListElement_ff_s(CStateInstance* entity, CScriptStack& stack)
2831 std::string funName = "getAggroListElement_ff_s";
2835 // get params
2836 uint32 elementIndex = (uint32)((float)stack.top()); stack.pop();
2837 sint32 botIndex = (uint32)((float)stack.top()); stack.pop();
2839 // get spawn bot by its index
2840 CGroup* group = entity->getGroup();
2841 if (!group || !group->isSpawned() || botIndex <0 || group->bots().size() <= static_cast<uint32>(botIndex))
2843 nlwarning("%s used bad index %d/%d (or group not spawn)", funName.c_str(), botIndex, group->bots().size());
2844 stack.push(std::string(""));
2845 return;
2847 CBot* bot = group->getBot(botIndex);
2848 CSpawnBot* spBot = bot?bot->getSpawnObj():0;
2849 if (!spBot)
2851 nlwarning("%s used bad index %d/%d (or bot not spawn)", funName.c_str(), botIndex, group->bots().size());
2852 stack.push(std::string(""));
2853 return;
2856 // make a vector of aggroable player
2857 CBotAggroOwner::TBotAggroList const& aggroList = spBot->getBotAggroList();
2858 //typedef std::map<TDataSetRow, TAggroEntryPtr> TBotAggroList;
2859 CBotAggroOwner::TBotAggroList::const_iterator aggroIt(aggroList.begin()), aggroEnd(aggroList.end());
2860 TDataSetRow foundRow = TDataSetRow();
2862 std::vector<TDataSetRow> playerAggroable;
2863 for (; aggroIt != aggroEnd; ++aggroIt)
2865 if (CMirrors::getEntityId(aggroIt->first).getType() != RYZOMID::player)
2867 continue;
2869 CAIEntityPhysical* ep = CAIS::instance().getEntityPhysical(aggroIt->first);
2870 if (!ep)
2872 continue;
2875 CBotPlayer const* const player = NLMISC::safe_cast<CBotPlayer const*>(ep);
2876 if (!player)
2878 continue;
2880 if (!player->isAggroable())
2882 continue;
2884 playerAggroable.push_back(aggroIt->first);
2889 if ( playerAggroable.empty())
2891 stack.push(std::string(""));
2892 return;
2894 // if index outside return "";
2895 if (0 > elementIndex && elementIndex >= playerAggroable.size())
2897 stack.push(std::string(""));
2898 return;
2901 const NLMISC::CEntityId& found = CMirrors::getEntityId(playerAggroable[ uint32(elementIndex) ]);
2902 stack.push(std::string(found.toString()));
2906 /** @page code
2908 @subsection getAggroListSize_f_f
2909 Get a size of the aggro lsit of a bot (list of aggroable PLAYER)
2911 A bot index is used to identify the bot. If there is only one spawned bot in a group then the index value is 0. If we want the bot index of a specific bot the getBotIndexByName function can be used. The function getBotCount can be used to know the number of bot in a group. The function isGroupAlived or isBotAlived can be used to verify if the index is valid.
2912 If no bot are identified by the bot index (or bot not spawaned) the function returns an empty string and display a warning message. You can this of using isBotAlived to be sure that the bot index is still a valid value.
2914 A number is used to indicate the size of the aggro lsit
2916 Arguments: f(aggroListIndex) -> f(sizeOfAggroList)
2917 @param[in] botIndex is the index of an bot member of the current group.
2918 @param[out] sizeOfAggroList The size of the aggro list index.
2920 @code
2921 (aggroSize)getAggorListSize(0);
2922 // to much player are attacking the boss
2923 if (aggoroSize > 10)
2925 ($player1)getAggroListElement(0);
2926 ($player2)getAggroListElement(1);
2927 ($player3)getAggroListElement(2);
2928 // so the boss teleport 3 person from its aggro list at the end of the world
2929 teleportPlayer($player1, 14233, 123123, 0, 0);
2930 teleportPlayer($player2, 14233, 123123, 0, 0);
2931 teleportPlayer($player2, 14233, 123123, 0, 0);
2932 clearAggroList();
2935 @endcode
2937 void getAggroListSize_f_f(CStateInstance* entity, CScriptStack& stack)
2940 std::string funName = "getRandomPlayerAggroListTarget_f_s";
2944 // input params
2945 uint32 botIndex = (uint32)((float)stack.top()); stack.pop();
2947 // get spawn bot by index of the bot
2948 CGroup* group = entity->getGroup();
2949 if (!group || !group->isSpawned() || botIndex <0 || group->bots().size() <= static_cast<uint32>(botIndex))
2951 nlwarning("%s used bad index %d/%d (or group not spawn)", funName.c_str(), botIndex, group->bots().size());
2952 stack.push(float(0) );
2953 return;
2955 CBot* bot = group->getBot(botIndex);
2956 CSpawnBot* spBot = bot?bot->getSpawnObj():0;
2957 if (!spBot)
2959 nlwarning("%s used bad index %d/%d (or bot not spawn)", funName.c_str(), botIndex, group->bots().size());
2960 stack.push(float(0) );
2961 return;
2964 // make a vector of aggroable player
2965 CBotAggroOwner::TBotAggroList const& aggroList = spBot->getBotAggroList();
2966 //typedef std::map<TDataSetRow, TAggroEntryPtr> TBotAggroList;
2967 CBotAggroOwner::TBotAggroList::const_iterator aggroIt(aggroList.begin()), aggroEnd(aggroList.end());
2968 TDataSetRow foundRow = TDataSetRow();
2970 std::vector<TDataSetRow> playerAggroable;
2971 for (; aggroIt != aggroEnd; ++aggroIt)
2973 if (CMirrors::getEntityId(aggroIt->first).getType() != RYZOMID::player)
2975 continue;
2977 CAIEntityPhysical* ep = CAIS::instance().getEntityPhysical(aggroIt->first);
2978 if (!ep)
2980 continue;
2983 CBotPlayer const* const player = NLMISC::safe_cast<CBotPlayer const*>(ep);
2984 if (!player)
2986 continue;
2988 if (!player->isAggroable())
2990 continue;
2992 playerAggroable.push_back(aggroIt->first);
2997 // return the size of the aggro list
2998 stack.push(float(playerAggroable.size()));
3002 /** @page code
3004 @subsection setAggroListTarget_fs_
3006 Maximize the Aggro of a target from the Aggro list of one bot (this id can be given by getRandomPlayerAggroListTarget)..
3008 A bot index is used to identify the bot. If there is only one spawned bot in a group then the index value is 0. If we want the bot index of a specific bot the getBotIndexByName function can be used. The function getBotCount can be used to know the number of bot in a group. The function isGroupAlived or isBotAlived can be used to verify if the index is valid.
3009 If no bot are identified by the bot index (or bot not spawaned) the function display a warning message. You can this of using isBotAlived to be sure that the bot index is still a valid value.
3011 A player EntityId is used to identify the player. If the entityId is not from the aggro list then a warning message is shown in the log. If the entityId is a empty string nothing no message are displayed.
3013 Arguments: f(botIndex) >s(playerEidAsString) >
3014 @param[in] botIndex is the index of an bot member of the current group
3015 @param[in] playerEidAsString is EntityId of the player that will be attacked
3017 @code
3018 ($playerId)getRandomPlayerAggroListTarget(4);
3019 ()setAggroListTarget(4, $playerId);
3020 @endcode
3023 void setAggroListTarget_fs_(CStateInstance* entity, CScriptStack& stack)
3026 std::string funName = "setAggroListTarget_fs_";
3030 std::string playerEidStr = ((std::string)stack.top()); stack.pop();
3031 sint32 botIndex = (sint32)((float)stack.top());stack.pop();
3033 // get the entity id
3034 NLMISC::CEntityId playerEid;
3035 playerEid.fromString(playerEidStr.c_str());
3037 // get the spawn bot by its indesx
3038 CGroup* group = entity->getGroup();
3039 if (!group || !group->isSpawned() || botIndex <0 || group->bots().size() <= static_cast<uint32>(botIndex))
3041 nlwarning("%s used bad index %d/%d (or group not spawn)", funName.c_str(), botIndex, group->bots().size());
3042 return;
3044 CBot* bot = group->getBot(botIndex);
3045 CSpawnBot* spBot = bot?bot->getSpawnObj():0;
3046 if (!spBot)
3048 nlwarning("%s used bad index %d/%d (or bot not spawn)", funName.c_str(), botIndex, group->bots().size());
3049 return;
3053 // test if player eid is ok
3054 if (playerEidStr.empty()) { return; }
3055 TDataSetRow playerRow = TheDataset.getDataSetRow( playerEid );
3056 bool accessible = TheDataset.isAccessible( playerRow );
3057 bool pj = playerEid.getType() == RYZOMID::player;
3058 CAIEntityPhysical* ep = accessible && pj ? CAIS::instance().getEntityPhysical(playerRow):0;
3059 CBotPlayer const* const player = ep ? NLMISC::safe_cast<CBotPlayer const*>(ep):0;
3060 if (!ep || !player ||!player->isAggroable() )
3062 nlwarning("Try to call %s with on a player '%s' that is not accessible (or not aggroable). The isPlayerAlived function must be called to be sure that the player is still alived.", funName.c_str(), playerEidStr.c_str() );
3063 return;
3067 // maximize aggro from the bot for the player
3068 spBot->maximizeAggroFor(playerRow);
3072 /** @page code
3074 @subsection setGroupAggroListTarget_s_
3076 Maximize the Aggro of a target from the Aggro list of one bot to his group (this id can be given by getRandomPlayerAggroListTarget)..
3078 A player EntityId is used to identify the player. If the entityId is not from the aggro list then a warning message is shown in the log. If the entityId is a empty string nothing no message are displayed.
3080 Arguments: s(playerEidAsString) >
3081 @param[in] playerEidAsString is EntityId of the player that will be attacked by the group
3083 @code
3084 ($playerId)getRandomPlayerAggroListTarget(4);
3085 ()setGroupAggroListTarget($playerId);
3086 @endcode
3089 void setGroupAggroListTarget_s_(CStateInstance* entity, CScriptStack& stack)
3092 std::string funName = "setGroupAggroListTarget_s_";
3094 // read params
3095 std::string playerEidStr = ((std::string)stack.top()); stack.pop();
3097 // read eid of the player
3098 NLMISC::CEntityId playerEid;
3099 playerEid.fromString(playerEidStr.c_str());
3102 // test if player eid is ok
3103 if (playerEidStr.empty()) { return; }
3104 TDataSetRow playerRow = TheDataset.getDataSetRow( playerEid );
3105 bool accessible = TheDataset.isAccessible( playerRow );
3106 bool pj = playerEid.getType() == RYZOMID::player;
3107 CAIEntityPhysical* ep = accessible && pj ? CAIS::instance().getEntityPhysical(playerRow):0;
3108 CBotPlayer const* const player = ep ? NLMISC::safe_cast<CBotPlayer const*>(ep):0;
3109 if (!ep || !player ||!player->isAggroable() )
3111 nlwarning("Try to call %s with on a player '%s' that is not accessible (or not aggroable). The isPlayerAlived function must be called to be sure that the player is still alived.", funName.c_str(), playerEidStr.c_str() );
3112 return;
3115 // test if group is spawn
3116 CGroup* group = entity->getGroup();
3117 if (!group || !group->isSpawned() || group->bots().isEmpty() )
3119 nlwarning("Call %s on a empty/not spawned group", funName.c_str() );
3120 return;
3123 // apply maximizeAggroFor on all member of the group
3124 CCont<CBot>::iterator itBot = group->bots().begin();
3125 CCont<CBot>::iterator itEnd = group->bots().end();
3127 for (; itBot != itEnd; ++itBot)
3130 CSpawnBot* spBot = itBot->getSpawnObj();
3131 if (!spBot) { continue; }
3132 spBot->maximizeAggroFor(playerRow);
3137 /** @page code
3139 @subsection setManagerAggroListTarget_ss_
3141 Maximize the Aggro of a target of one bot to some groups of his manage.
3143 A player EntityId is used to identify the player. If the entityId is not from the aggro list then a warning message is shown in the log. If the entityId is a empty string nothing no message are displayed.
3145 A string is used to select groups of the manager (groups name must contains this string)
3147 Arguments: f(botIndex), s(playerEidAsString) >
3148 @param[in] playerId is EntityId of the player
3149 @param[in] nameElement The element of the name of all group we are interest in.
3151 @code
3152 ($playerId)getRandomPlayerAggroListTarget(0);
3153 ()setManagerAggroListTarget($playerId, "group_bandit_"); // all group that have name like "group_bandit_*" will attack the player
3154 @endcode
3157 void setManagerAggroListTarget_ss_(CStateInstance* entity, CScriptStack& stack)
3160 std::string funName = "setManagerAggroListTarget_ss_";
3163 // read params
3164 std::string playerEidStr = ((std::string)stack.top()); stack.pop();
3165 std::string groupNameStr = ((std::string)stack.top()); stack.pop();
3168 // test if player eid is ok
3169 NLMISC::CEntityId playerEid;
3170 playerEid.fromString(playerEidStr.c_str());
3172 if (playerEidStr.empty()) { return; }
3173 TDataSetRow playerRow = TheDataset.getDataSetRow( playerEid );
3174 bool accessible = TheDataset.isAccessible( playerRow );
3175 bool pj = playerEid.getType() == RYZOMID::player;
3176 CAIEntityPhysical* ep = accessible && pj ? CAIS::instance().getEntityPhysical(playerRow):0;
3177 CBotPlayer const* const player = ep ? NLMISC::safe_cast<CBotPlayer const*>(ep):0;
3178 if (!ep || !player ||!player->isAggroable() )
3180 nlwarning("Try to call %s with on a player '%s' that is not accessible (or not aggroable). The isPlayerAlived function must be called to be sure that the player is still alived.", funName.c_str(), playerEidStr.c_str() );
3181 return;
3185 CGroup* group = entity->getGroup();
3186 if (!group )
3188 nlwarning("Call %s on a non exisiting group", funName.c_str() );
3189 return;
3191 // get the manager of the group
3192 CManager* manager = group->getOwner();
3193 if (!manager)
3195 nlwarning("Call %s on a non exisiting manager", funName.c_str() );
3196 return;
3198 // for all group of the manager maximize aaggro *IF* the group name contains groupNameStr
3199 group=manager->getNextValidGroupChild();
3200 while (group!=NULL)
3202 if ( ! (!group || !group->isSpawned() || group->bots().isEmpty() ) && group->getName().find(groupNameStr) != std::string::npos )
3204 // apply maximizeAggroFor on all member of the group
3205 CCont<CBot>::iterator itBot = group->bots().begin();
3206 CCont<CBot>::iterator itEnd = group->bots().end();
3208 for (; itBot != itEnd; ++itBot)
3211 CSpawnBot* spBot = itBot->getSpawnObj();
3212 if (!spBot) { continue; }
3213 spBot->maximizeAggroFor(playerRow);
3216 group = manager->getNextValidGroupChild(group);
3223 /** @page code
3225 @subsection getBotIndexByName_s_f
3227 Get the index of a bot of a group by its name (or return -1). Mainly useful for scripted boss.
3229 botIndex begins at zero for the first member of the group, -1 if the bot is not found.
3231 Arguments:, s(botName) > f(botIndex)
3233 @param[in] name is the name of the bot
3234 @param[out] botIndex is the index of an bot member of the current group
3236 @code
3237 (botIndex)getBotIndexByName("boss_random_aggro");
3238 ($playerId)getRandomPlayerAggroListTarget(botIndex);
3239 ()setAggroListTarget(botIndex, $playerId);
3241 @endcode
3243 void getBotIndexByName_s_f(CStateInstance* entity, CScriptStack& stack)
3245 std::string funName = "getBotIndexByName_s_f";
3247 // read params
3248 std::string botName = (std::string)stack.top(); stack.pop();
3250 // test if group is spawned
3251 CGroup* group = entity->getGroup();
3252 if (!group || group->bots().isEmpty() )
3254 nlwarning("Call %s on a empty group", funName.c_str() );
3255 stack.push((float)-1);
3256 return;
3260 // Search on all persistent bot of the groupe the bot that have the searched name
3261 CCont<CBot>::iterator itBot = group->bots().begin();
3262 CCont<CBot>::iterator itEnd = group->bots().end();
3264 sint32 index = -1;
3265 for (; itBot != itEnd; ++itBot)
3267 ++index;
3268 const std::string& name = itBot->getName();
3269 if (name == botName)
3271 stack.push((float)index);
3272 return;
3276 // Bot not found
3277 stack.push((float)-1);
3278 return;
3282 /** @page code
3284 @subsection isGroupAlived__f
3286 Test if a group is alived (at least one member is alived)
3288 A bot index is used to identify the bot. If there is only one spawned bot in a group then the index value is 0. If we want the bot index of a specific bot the getBotIndexByName function can be used. The function getBotCount can be used to know the number of bot in a group. The function isGroupAlived or isBotAlived can be used to verify if the index is valid.
3289 If no bot are identified by the bot index (or bot not spawaned) the function display a warning message. You can this of using isBotAlived to be sure that the bot index is still a valid value.
3292 Arguments: s(playerid) > f(success)
3294 @param[out] sucess is 1.0f if there is at least one member of the group alived (0.0f if not alived bot are found)
3296 @code
3297 ($alived)isGroupAlived();
3298 if ($alived == 1.0f) {
3300 @endcode
3303 void isGroupAlived__f(CStateInstance* entity, CScriptStack& stack)
3305 isAlived__f(entity, stack);
3309 /** @page code
3311 @subsection isBotAlived_f_f
3313 Test if a bot of the current group is alived. The bot is identified by its index.
3315 Arguments: f(botIndex) > f(success)
3317 @param[int] botIndex the index of the bot.
3318 @param[out] sucess is 1.0f if there is at least one member of the group alived (0.0f if not alived bot are found)
3320 @code
3321 ($botIndex)getBotIndexByName("boss_3");
3322 $alived)isBotAlived($botIndex);
3323 if (alived == 1.0f) {
3325 @endcode
3328 void isBotAlived_f_f(CStateInstance* entity, CScriptStack& stack)
3330 std::string funName = "isBotAlived_f_f";
3331 // get input index
3332 sint32 botIndex = (sint32)((float)stack.top()); stack.pop();
3334 // get Spawn Bot
3335 CGroup* group = entity->getGroup();
3336 if (!group)
3338 nlwarning("%s on a non Npc Group, doesn't work", funName.c_str());
3339 stack.push((float)0);
3340 return;
3342 if (!group->isSpawned() || group->bots().isEmpty() || botIndex < 0 || group->bots().size() < static_cast<uint32>(botIndex))
3344 stack.push(0.0f);return;
3346 const CBot *const bot = group->getBot(botIndex);
3347 if ( !bot || !bot->isSpawned()) { stack.push(0.0f); return;};
3348 CAIEntityPhysical *const ep=bot->getSpawnObj();
3349 if ( !ep) { stack.push(0.0f); return;};
3351 // test if spawn bot is alive
3352 if (ep->isAlive()) { stack.push(1.0f); return;}
3354 stack.push(0.0f);
3355 return;
3359 /** @page code
3361 @subsection isPlayerAlived_s_f
3363 Test if a a player is is alived.
3365 A player EntityId is used to identify the player. If the player is not connected, not in the same continent, or dead 0 is returned.
3367 Arguments: s(playerId) > f(success)
3369 @param[in] palyerId
3370 @param[out] success is 1.0f if the entity id of a player is alived.
3372 @code
3373 ($botIndex)getBotIndexByName("boss_3");
3374 ($playerId)getCurrentPlayerAggroListTarget($botIndex):
3375 (alived)isPlayerlived($playerId);
3376 if (alived == 1.0f) {
3378 @endcode
3380 void isPlayerAlived_s_f(CStateInstance* entity, CScriptStack& stack)
3382 // get input data
3383 std::string playerEidStr = (std::string)stack.top(); stack.pop();
3385 //get CAIEntityPhysical of the player
3386 NLMISC::CEntityId playerEid;
3387 playerEid.fromString(playerEidStr.c_str());
3388 TDataSetRow playeDataSetRow = TheDataset.getDataSetRow( playerEid) ;
3389 if (playerEidStr.empty() || !TheDataset.isAccessible( playeDataSetRow ) || playerEid.getType() != RYZOMID::player )
3391 stack.push(0.0f); return;
3393 CAIEntityPhysical* ep = CAIS::instance().getEntityPhysical(playeDataSetRow);
3394 if (!ep)
3397 stack.push(0.0f); return;
3399 // test if the player is alived
3400 if (ep->isAlive())
3402 stack.push(1.0f); return;
3405 stack.push(0.0f); return;
3409 /** @page code
3410 @subsection getServerTimeStr__s
3412 Gets the server time as string "eg 21:17:14 the x"
3413 This function is useful for stat purpose or debug (to know when a boss is down)
3415 Arguments: > s(serverTime)
3418 @param[out] The server time as debug string
3420 @code
3421 ($serverTime)getServerTimeAsString();
3422 @endcode
3425 void getServerTimeStr__s(CStateInstance* entity, CScriptStack& stack)
3427 //get the server time (as debug string)
3428 time_t currentTime;
3429 time( &currentTime );
3430 std::string str = NLMISC::toString("%s", asctime(localtime(&currentTime)));
3431 stack.push(str);
3434 /** @page code
3435 @subsection getServerTime__s
3437 Gets the server time as number (it is the number of seconde since 1970). This value is useful for saving the server date on a file
3439 Arguments: > s(serverTime)
3441 @param[out] The server time as string (a float is not sharp enough
3443 @code
3444 ($serverTime)getServerTime();
3445 @endcode
3448 void getServerTime__s(CStateInstance* entity, CScriptStack& stack)
3450 //get the server time (as time stamp)
3451 time_t currentTime;
3452 time( &currentTime );
3453 std::string ret = NLMISC::toString("%d", currentTime);
3454 // convert to string
3455 stack.push((std::string)ret);
3460 /** @page code
3461 @subsection getRyzomDateStr__s
3463 Gets the ryzom date as string
3464 Arguments: > s(ryzomDateStr)
3466 @param[out] ryzomTimeAndDateAsString The time and date of the ryzom univers as debug string.
3468 @code
3469 ($ryzomDateStr)getRyzomDateStr);
3470 @endcode
3472 void getRyzomDateStr__s(CStateInstance* entity, CScriptStack& stack)
3474 // Display time using ryzom style
3475 std::string result;
3476 const CRyzomTime &rt = CTimeInterface::getRyzomTime();
3477 result = NLMISC::toString("%d:%d:00", (int) floorf(rt.getRyzomTime()) , (int) floorf(60.f * fmodf(rt.getRyzomTime(), 1.f)));
3479 uint32 month = rt.getRyzomMonth();
3480 MONTH::EMonth monthInCycle = rt.getRyzomMonthInCurrentCycle();
3481 std::string monthName = MONTH::toString((MONTH::EMonth) monthInCycle);
3482 uint32 dayOfMonth = rt.getRyzomDayOfMonth();
3483 std::string dayName = WEEKDAY::toString((WEEKDAY::EWeekDay) rt.getRyzomDayOfWeek());
3484 result += NLMISC::toString(" / %s %d %s(%d) %d",
3485 dayName.c_str(),
3486 (int) (dayOfMonth + 1),
3487 monthName.c_str(),
3488 (int) (month + 1),
3489 (int) rt.getRyzomYear());
3491 stack.push( result );
3494 /** @page code
3495 @subsection getRyzomDate__s
3497 Gets the ryzom tick game cycle. Useful for computing difference of time.
3498 The return value is a string and not a float because float is not sharp enought?
3499 Arguments: > s(tickGameCycle)
3501 @param[out] TickGameCycle The time of the ryzom univers (stops when server stops). 10 tick is 1 second.
3503 @code
3504 ($tickGameCycle)getRyzomDate();
3505 @endcode
3507 void getRyzomDate__s(CStateInstance* entity, CScriptStack& stack)
3509 //get GameTickCycle
3510 const NLMISC::TGameCycle ryzomTime= CTickEventHandler::getGameCycle();
3511 std::string ret = NLMISC::toString("%d", ryzomTime);
3512 // convert to string
3513 stack.push((std::string)ret);
3518 class CPhraseParameters
3520 public:
3521 enum TMode {NpcMsg, SystemMsg, EmoteMsg};
3522 TVectorParamCheck Values;
3525 CPhraseParameters PhraseParameters;
3527 //----------------------------------------------------------------------------
3528 /** @page code
3530 @subsection phraseBegin__
3531 Clear the parameters stack.
3533 Used when creating a customized msg via phraseEndSystemMsg_fss_, phraseEndNpcMsg_fss_, phraseEndSystemMsg_fss_.
3534 It Must be called at start of phrase if we are not sure that the parameter stack is clean.
3536 Parameter stack is unclean when someone has called a phrasePush* function but *not* a phraseEnd function before (which is *very* bad).
3538 Arguments: ->
3540 @code
3541 ()phraseBegin();
3542 ()phrasePushValue("money", 15);
3543 ()phrasePushValue("integer", 15);
3544 ()phrasePushValue("time", 15);
3545 ()phraseEndSystemMsg(0, "say", "PHRASE_FROM_PHRASE_WITH_3_PARAMETERS");
3546 @endcode
3549 // CGroup
3550 void phraseBegin__(CStateInstance* entity, CScriptStack& stack)
3552 PhraseParameters.Values.clear();
3555 //----------------------------------------------------------------------------
3556 /** @page code
3558 @subsection phrasePushValue_sf_
3559 This function push a value as number on the parameter stack. This stack is used by phraseEndSystemMsg_fss_, phraseEndNpcMsg_fss_, phraseEndSystemMsg_fss_ functions.
3560 @see phraseBegin__
3561 @see phrasePushString_ss_
3562 @see phraseEndSystemMsg_fss_
3563 @see phraseEndNpcMsg_fss_
3564 @see phraseEndSystemMsg_fss_
3567 The value *Must* be an number and only few type are handled.
3568 - money
3569 - integer
3570 - time
3572 Some value other can be handled *BUT* the value *MUST* be the C++ code enum value. So LD must ask to coder to do a scripting fonction that have as input a string that contains enum value as string eg "matis" and that return the C++ enum value as int (eg 4).
3573 - skill
3574 - faction
3575 - power_type
3576 - race
3577 - damage_type
3578 - characteristic
3579 - score
3580 - body_part
3582 Arguments: s(paramType), f(value) ->
3583 @param[in] paramType the type of the parameter
3584 @param[in] value the value of the parameter
3587 @code
3588 ()phraseBegin();
3589 ()phrasePushValue("money", 15);
3590 ()phrasePushValue("integer", 15);
3591 ()phrasePushValue("time", 15);
3592 ()phraseEndSystemMsg(0, "say", "PHRASE_WITH_3_PARAMETERS");
3593 @endcode
3596 // CGroup
3597 void phrasePushValue_sf_(CStateInstance* entity, CScriptStack& stack)
3599 float f = (float)stack.top();stack.pop(); // get the value as float
3600 std::string typeStr = (std::string)stack.top(); stack.pop(); // get the param type
3601 // create the good STRING_MANAGER::TParam in fonction of its type and is value
3602 STRING_MANAGER::TParamType type = STRING_MANAGER::stringToParamType(typeStr);
3603 STRING_MANAGER::TParam param;
3604 param.Type = type;
3605 switch( type )
3608 case STRING_MANAGER::money:
3610 param.Money = static_cast<uint64>(f);
3611 break;
3615 case STRING_MANAGER::integer:
3617 param.Int = static_cast<sint32>(f);
3618 break;
3621 case STRING_MANAGER::time:
3623 param.Time = static_cast<uint32>(f);
3624 break;
3627 case STRING_MANAGER::skill:
3628 case STRING_MANAGER::faction:
3629 case STRING_MANAGER::power_type:
3630 case STRING_MANAGER::race:
3631 case STRING_MANAGER::damage_type:
3632 case STRING_MANAGER::characteristic:
3633 case STRING_MANAGER::score:
3634 case STRING_MANAGER::body_part:
3636 param.Enum = static_cast<uint32>( f );
3637 break;
3640 default:
3641 param.Type = STRING_MANAGER::invalid_value;
3643 break;
3646 PhraseParameters.Values.push_back(param);
3650 //----------------------------------------------------------------------------
3651 /** @page code
3653 @subsection phrasePushString_ss_
3654 This function push a value as string on the parameter stack. This stack is used by phraseEndSystemMsg_fss_, phraseEndNpcMsg_fss_, phraseEndSystemMsg_fss_ functions.
3655 @see phraseBegin__
3656 @see phrasePushValue_sf_
3657 @see phraseEndSystemMsg_fss_
3658 @see phraseEndNpcMsg_fss_
3659 @see phraseEndSystemMsg_fss_
3662 The value *Must* be a string.
3663 The string is internal converted to number, sheetId, entityId when needed.
3665 Input as a number:
3666 - money
3667 - integer
3668 - time
3670 Input as string literal
3671 - literal
3673 Input as an entityId (obtains via getCurrentPlayerAggroListTarget_f_s, getRandomPlayerAggroListTarget_f_s, getBotEid_f_s, getCurrentSpeakerEid__s, getAggroListElement_ff_s)
3674 - player
3675 - bot
3676 - entity
3678 Input as sheetId name (example: "toto.sbrick", "toto.sitem", "toto.creature")
3679 - item
3680 - outpost
3681 - creature_model
3682 - creature
3683 - sphrase
3684 - sbrick
3686 Input as string identifier
3687 - place
3688 - event_faction
3689 - title
3690 - bot_name
3692 Input as stringId (number): *WARNING* LD must as coder to do function that return string_id if they want to use that type
3693 - dyn_string_id
3694 - string_id
3697 Input must be a enum value:
3698 Some value other can be handled *BUT* the value *MUST* be the C++ code enum value. So LD must ask to coder to do a scripting fonction that have as input a string that contains enum value as string eg "matis" and that return the C++ enum value as int (eg 4).
3699 - skill
3700 - faction
3701 - power_type
3702 - race
3703 - damage_type
3704 - characteristic
3705 - score
3706 - body_part
3708 Arguments: s(paramType), f(value) ->
3709 @param[in] paramType the type of the parameter
3710 @param[in] value the value of the parameter
3713 @code
3714 ($playerEid)getCurrentPlayerEid();
3715 ($botEid)group3.getBotEid(4);
3716 ()phraseBegin();
3717 ()phrasePushValue("integer", 15);
3718 ()phrasePushString("integer", "15");
3719 ()phrasePushString("literal", "Test 123");
3720 ()phrasePushString("player", $playerEid);
3721 ()phrasePushString("bot", $botEid);
3722 ()phrasePushString("item", "abc.sitem");
3723 ()phrasePushString("sbrick", "toto.sbrick");
3724 ()phrasePushString("creature_model", "toto.creature");
3725 ()phraseEndSystemMsg(0, "say", "PHRASE_WITH_SOME_PARAMETERS");
3726 @endcode
3728 void phrasePushString_ss_(CStateInstance* entity, CScriptStack& stack )
3730 std::string s = (std::string)stack.top(); stack.pop(); // get the param value
3731 std::string typeStr = (std::string)stack.top(); stack.pop(); // get the param type
3733 // construct a STRING_MANAGER::TParam in fonction of its type and its value
3734 STRING_MANAGER::TParamType type = STRING_MANAGER::stringToParamType(typeStr);
3735 STRING_MANAGER::TParam param;
3736 param.Type = type;
3737 switch( type )
3740 case STRING_MANAGER::money:
3742 NLMISC::fromString(s, param.Money);
3743 break;
3746 case STRING_MANAGER::player:
3747 case STRING_MANAGER::bot:
3748 case STRING_MANAGER::entity:
3751 NLMISC::CEntityId id;
3752 uint32 alias = 0;
3753 id.fromString(s.c_str());
3754 CAIEntityPhysical* entityPhysical=CAIS::instance().getEntityPhysical(TheDataset.getDataSetRow(id));
3755 if (entityPhysical)
3757 switch( entityPhysical->getRyzomType())
3759 case RYZOMID::creature:
3760 case RYZOMID::npc:
3763 CSpawnBot* sb = NLMISC::safe_cast<CSpawnBot*>(entityPhysical);
3764 alias = sb->getPersistent().getAlias();
3765 break;
3767 default:
3769 // player or other have no alias
3772 param.setEIdAIAlias( id, alias );
3774 break;
3776 case STRING_MANAGER::integer:
3778 NLMISC::fromString(s, param.Int);
3779 break;
3782 case STRING_MANAGER::time:
3784 NLMISC::fromString(s, param.Time);
3785 break;
3789 case STRING_MANAGER::item:
3790 case STRING_MANAGER::outpost:
3791 case STRING_MANAGER::creature_model:
3792 case STRING_MANAGER::creature:
3793 case STRING_MANAGER::sphrase:
3794 case STRING_MANAGER::sbrick:
3796 if (s.empty())
3798 nlwarning("Sheet name expected but not found in script");
3799 param.SheetId= CSheetId();
3801 else
3803 param.SheetId = CSheetId(s);
3805 break;
3809 case STRING_MANAGER::place:
3810 case STRING_MANAGER::event_faction:
3811 case STRING_MANAGER::title:
3812 case STRING_MANAGER::bot_name:
3814 param.Identifier = s;
3815 break;
3818 case STRING_MANAGER::skill:
3819 case STRING_MANAGER::faction:
3820 case STRING_MANAGER::power_type:
3821 case STRING_MANAGER::race:
3822 case STRING_MANAGER::damage_type:
3823 case STRING_MANAGER::characteristic:
3824 case STRING_MANAGER::score:
3825 case STRING_MANAGER::body_part:
3827 NLMISC::fromString(s, param.Enum);
3828 break;
3831 case STRING_MANAGER::literal:
3832 param.Literal.fromUtf8(s);
3833 break;
3835 case STRING_MANAGER::dyn_string_id:
3836 case STRING_MANAGER::string_id:
3837 NLMISC::fromString(s, param.StringId);
3838 break;
3840 case STRING_MANAGER::self:
3841 case STRING_MANAGER::role:
3842 case STRING_MANAGER::compass:
3843 case STRING_MANAGER::guild:
3844 case STRING_MANAGER::ecosystem:
3845 case STRING_MANAGER::classification_type:
3846 default:
3847 param.Type = STRING_MANAGER::invalid_value;
3849 break;
3852 PhraseParameters.Values.push_back(param);
3857 static void phraseEnd(CStateInstance* entity, CScriptStack& stack, CPhraseParameters::TMode mode)
3859 std::string funName = "phraseEnd";
3861 // get Function parameters
3863 std::string phraseId = (std::string)stack.top();stack.pop();
3864 std::string sayMode;
3865 if (mode != CPhraseParameters::EmoteMsg)
3867 sayMode = (std::string)stack.top();stack.pop();
3869 sint32 botIndex = (sint32)((float)stack.top());stack.pop();
3872 // Verify is bot is alived
3875 CGroup* group = entity->getGroup();
3876 if (!group)
3878 nlwarning("%s on a non Npc Group, doesn't work", funName.c_str());
3879 PhraseParameters.Values.clear();
3880 return;
3882 if (!group->isSpawned() || group->bots().isEmpty() || botIndex < 0 || group->bots().size() < static_cast<uint32>(botIndex))
3884 PhraseParameters.Values.clear();
3885 return;
3887 const CBot *const bot = group->getBot(botIndex);
3888 if ( !bot || !bot->isSpawned())
3890 PhraseParameters.Values.clear();
3891 return;
3893 CSpawnBot *const sp= bot->getSpawnObj();
3894 if ( !sp || !sp->isAlive() )
3896 PhraseParameters.Values.clear();
3897 return;
3900 // parse type of chat
3901 CChatGroup::TGroupType groupType;
3902 if (mode != CPhraseParameters::EmoteMsg)
3904 groupType = CChatGroup::stringToGroupType(sayMode);
3907 // verify phraseId validity
3908 if (phraseId.empty())
3910 nlwarning("%s %d: Phrase identifier is empty", funName.c_str(),static_cast<uint32>(mode));
3911 return;
3914 // send chat to client
3915 switch (mode)
3917 case CPhraseParameters::NpcMsg:
3918 npcChatParamToChannel(sp->dataSetRow(), groupType, phraseId.c_str(), PhraseParameters.Values);
3919 break;
3920 case CPhraseParameters::SystemMsg:
3921 STRING_MANAGER::sendSystemStringToClientAudience(sp->dataSetRow(),std::vector<NLMISC::CEntityId>(), groupType, phraseId.c_str(), PhraseParameters.Values);
3922 break;
3924 case CPhraseParameters::EmoteMsg:
3925 STRING_MANAGER::sendCustomEmoteTextToClientAudience(sp->dataSetRow(),std::vector<NLMISC::CEntityId>(), phraseId.c_str(), PhraseParameters.Values);
3926 break;
3929 PhraseParameters.Values.clear();
3932 //----------------------------------------------------------------------------
3933 /** @page code
3935 @subsection phraseEndNpcMsg_fss_
3936 Send a message with parameter through a bot says.
3937 Parameters are taken from the parameters stack.
3938 @see phrasePushValue_sf_
3939 @see phrasePushString_ss_
3941 Arguments: s(botIndex), s(sayType), s(phraseIdentifier) ->
3942 @param[in] botIndex the Position of the bot in the group ( see getBotIndexByName_s_f)
3943 @param[in] sayType Is the type of the say dialog ("say", "shout", "civilization", "territory", "universe", "arround", "system", "region")
3944 @param[in] phraseIdentifier Is the identifier phrase as seen in phrase_wk.uxt
3946 @code
3947 ()phrasePushString("literal", "text non traduit");
3948 ()groupOf5Bot.phraseEndNpcMsg(4, "say", "PHRASE_TOTO");
3949 @endcode
3951 WARNING
3952 In this case in the phrase_wk.txt PHRASE_TOTO must be defined as
3953 @code
3954 PHRASE_TOTO(bot b, literal l)
3956 [I am $b$, on this text is not translated $l$ ]
3958 @endcode
3960 The first parameter is ALWAYS the bot that says the text (value is automaticaly set)
3962 void phraseEndNpcMsg_fss_(CStateInstance* entity, CScriptStack& stack)
3964 phraseEnd(entity, stack, CPhraseParameters::NpcMsg);
3967 //----------------------------------------------------------------------------
3968 /** @page code
3970 @subsection phraseEndSystemMsg_fss_
3971 Send a message with parameter through system braodcast msg.
3972 Parameters are taken from the parameters stack.
3973 @see phrasePushValue_sf_
3974 @see phrasePushString_ss_
3976 Arguments: s(botIndex), s(sayType), s(phraseIdentifier) ->
3977 @param[in] botIndex the Position of the bot in the group ( see getBotIndexByName_s_f)
3978 @param[in] sayType Is the type of the say dialog ("say", "shout", "civilization", "territory", "universe", "arround", "system", "region")
3979 @param[in] phraseIdentifier Is the identifier phrase as seen in phrase_wk.uxt
3981 @code
3982 ()phrasePushString("literal", "Test des levels designer");
3983 ()groupOf5Bot.phraseEndSystemMsg(4, "say", "PHRASE_TOTO");
3984 @endcode
3986 *WARNING*
3987 In this case in the phrase_wk.txt PHRASE_TOTO must be defined as
3988 @code
3989 PHRASE_TOTO(literal l)
3991 [$l$]
3993 @endcode
3994 The first parameter is *NOT* automaticaly set to the bot that send the system msg as phraseEndNpcMsg_fss_.
3996 Because the msg can be send as "around". The broadcas msg must be send by a bot (that have a valid position)
3998 void phraseEndSystemMsg_fss_(CStateInstance* entity, CScriptStack& stack)
4000 phraseEnd(entity, stack, CPhraseParameters::SystemMsg);
4004 //----------------------------------------------------------------------------
4005 /** @page code
4007 @subsection phraseEndEmoteMsg_fs_
4008 Send a custom emote message with parameter through system braodcast msg.
4009 Parameters are taken from the parameters stack.
4010 @see phrasePushValue_sf_
4011 @see phrasePushString_ss_
4013 Arguments: s(botIndex), s(phraseIdentifier) ->
4014 @param[in] botIndex the Position of the bot in the group ( see getBotIndexByName_s_f)
4015 @param[in] phraseIdentifier Is the identifier phrase as seen in phrase_wk.uxt
4017 @code
4018 ($playerEid)getCurrentPlayerEid();
4019 ($botEid)getCurrentSpeakerEid();
4021 ()phrasePushString("player", $playerEid);
4022 ()groupOf5Bot.phraseEndEmoteMsg(,"PHRASE_TOTO1");
4024 ()phrasePushString("bot", $botEid);
4025 ()groupOf5Bot.phraseEndEmoteMsg(,"PHRASE_TOTO2");
4026 @endcode
4028 *WARNING*
4029 In this case in the phrase_wk.txt PHRASE_TOTO must be defined as
4030 @code
4031 PHRASE_TOTO1(player p)
4033 [$p$ is laughing ]
4035 PHRASE_TOTO2(bot b)
4037 [$b$ is sad ]
4039 @endcode
4040 The first parameter is NOT automaticaly the bot that says the text as phraseEndNpcMsg_fss_ because a bot can make a player doing a emote text.
4042 The emote msg must be send by a bot (that have a valid position).
4044 void phraseEndEmoteMsg_fs_(CStateInstance* entity, CScriptStack& stack)
4046 phraseEnd(entity, stack, CPhraseParameters::EmoteMsg);
4050 //----------------------------------------------------------------------------
4051 /** @page code
4053 @subsection queryEgs_sscfs_
4054 Send a query msg to egs to know infos on a player.
4055 Answer is asynchronous so we have to indicates a group and a user event that will be triggered when answer will come back to AIS
4057 Possible info to know are
4058 - Name
4059 - Hp
4060 - MaxHp
4061 - RatioHp
4062 - Sap
4063 - MaxSap
4064 - RatioSap
4065 - Focus
4066 - MaxFocus
4067 - RatioFocus
4068 - Stamina
4069 - MaxStamina
4070 - RatioStamina
4073 Arguments: s(botIndex), s(query), c(groupThatWillBeTriggered), f(idOfTheUserEvent), s(msgId)
4074 @param[in] botIndex the Position of the bot in the group ( see getBotIndexByName_s_f)
4075 @param[in] query The query we want to send
4076 @param[in] groupThatWillBeTriggered The group that will receive a user_event when the answer will come
4077 @param[in] idOfTheUserEvent The number of the user event that will be triggered
4078 @param[in] msgId The id of the msg
4080 Answer will be given by the getParam
4082 @code
4083 //Sening msg to EGS
4084 (@groupToNotify)boss_group.context();
4085 ()queryEgs("Name", $playerEid, @groupToNotify, 4, "MSG_NAME");
4086 ()queryEgs("Hp", $playerEid, @groupToNotify, 4, "msg1");
4087 ()queryEgs("MaxHp", $playerEid, @groupToNotify, 4, "msg2");
4088 ()queryEgs("RatioHp", $playerEid, @groupToNotify, 4, "msg3");
4089 ()queryEgs("Sap", $playerEid, @groupToNotify, 4, "msg4");
4090 ()queryEgs("MaxSap", $playerEid, @groupToNotify, 4, "msg5");
4091 ()queryEgs("RatioSap", $playerEid, @groupToNotify, 4, "msg6");
4092 ()queryEgs("Focus", $playerEid, @groupToNotify, 4, "msg7");
4093 ()queryEgs("MaxFocus", $playerEid, @groupToNotify, 4, "msg8");
4094 ()queryEgs("RatioFocus", $playerEid, @groupToNotify, 4, "msg9");
4095 ()queryEgs("Stamina", $playerEid, @groupToNotify, 4, "msg10");
4096 ()queryEgs("MaxStamina", $playerEid, @groupToNotify, 4, "msg11");
4097 ()queryEgs("RatioStamina", $playerEid, @groupToNotify, 4, "msg12");
4098 ()queryEgs("BestSkillLevel", $playerEid, @groupToNotify, 4, "msg13");
4099 @endcode
4100 Answer of the EGS
4101 @code
4102 // the user_event 4 of groupToNotify will be trigered
4103 ($msgName)getEventParam(0); // the msg name
4104 ($ret)getEventParam(1); // the return
4105 ($funName)getEventParam(2); // the name of the function
4106 ($playerEid)getEventParam(3); // the id of the player
4107 ($param1)getEventParam(4); // empty ot item, or sbrick or botEid
4109 if ($msgName == "MSG_NAME") {
4110 ()phrasePushString("literal", $ret);
4111 ()phrasePushString("player", $playerEid);
4112 ()boss_group.phraseEndNpcMsg(0, "say", "TEST_BOSS_TEST_MSG");
4114 else
4116 ()phrasePushString("player", $playerEid);
4117 ()phrasePushString("literal", $funName);
4118 ()phrasePushString("literal", $msgName);
4119 ()phrasePushString("integer", $ret);
4120 ()boss_group.phraseEndNpcMsg(0, "say", "TEST_BOSS_TEST_EGS_QUERY");
4123 @endcode
4126 void queryEgs_sscfs_(CStateInstance* entity, CScriptStack& stack)
4128 std::string funName = "queryEgs_sscfs_";
4129 // read input params
4130 string literal = (string)stack.top(); stack.pop();
4131 float useEventId = (float)stack.top(); stack.pop();
4132 CGroupNpc* const groupToNotify = dynamic_cast<CGroupNpc*>( (IScriptContext*)stack.top() ); stack.pop();
4133 string param1 = (string)stack.top(); stack.pop();
4134 string func = (string)stack.top(); stack.pop();
4136 // create a CUserEventMsg to send to EGS
4137 CGroup* const group = entity ? entity->getGroup() : 0;
4138 IManagerParent* const managerParent = (group&& group->getOwner()) ? group->getOwner()->getOwner():0;
4139 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
4140 if (aiInstance == NULL)
4142 nlwarning("%s failed: the AI instance of the entity is NULL", funName.c_str());
4143 DEBUG_STOP;
4144 return;
4146 CQueryEgs msg;
4147 msg.InstanceId = aiInstance->getInstanceNumber();
4148 msg.GroupAlias = groupToNotify->getAlias();
4149 msg.EventId = (int)useEventId;
4150 msg.Params.push_back(literal);
4151 msg.Params.push_back(func);
4152 msg.Params.push_back(param1);
4153 msg.send("EGS");
4158 @subsection queryEgs_ssscfs_
4159 Send a query msg to egs to know infos on a player.
4160 Answer is asynchronous so we have to indicates a group and a user event that will be triggered when answer will come back to AIS
4162 Possible info to know are:
4163 - KnowBrick (to knwo if the player know a specific brick); return value is 0 or 1 (if the player know the brick)
4164 - IsInInventory (to knwo has an item in inventory of in equipement); return value is 0, 1(item in equipment), 2(item in bag)
4165 - Target (to know if a player target a bot; return value is 0, 1(player target the bot)
4167 Arguments: s(botIndex), s(query), s(queryParam), c(groupThatWillBeTriggered), f(idOfTheUserEvent), s(msgId)
4168 @param[in] botIndex the Position of the bot in the group ( see getBotIndexByName_s_f)
4169 @param[in] query The query we want to send
4170 @param[in] queryParam Is the paramter of the query (a .creature of IsInInventory, a .sbrick for KnowBrick, a Bot EntityId for Target
4171 @param[in] groupThatWillBeTriggered The group that will receive a user_event when the answer will come
4172 @param[in] idOfTheUserEvent The number of the user event that will be triggered
4173 @param[in] msgId The id of the msg
4175 Answer will be given by the getParam
4176 @code
4177 //Sening msg to EGS
4178 //($playerEid)getCurrentPlayerEid();
4179 (@groupToNotify)boss_group.context();
4180 ()queryEgs("KnowBrick", $playerEid, "bfma01.sbrick", @groupToNotify, 4, "MSG_BRICK");
4181 ()queryEgs("IsInInventory", $playerEid, "iccm1bm.sitem", @groupToNotify, 4, "MSG_ITEM");
4182 ()queryEgs("Target", $playerEid, $botEid, @groupToNotify, 4, "msg14");
4183 @endcode
4185 Answer of the EGS
4186 @code
4187 ($msgName)getEventParam(0); // the msg name
4188 ($ret)getEventParam(1); // the return
4189 ($funName)getEventParam(2); // the name of the function
4190 ($playerEid)getEventParam(3); // the id of the player
4191 ($param1)getEventParam(4); // empty ot item, or sbrick or botEid
4193 if ($msgName == "MSG_ITEM")
4195 ()phrasePushString("item", $param1);
4196 ()phrasePushString("integer", $ret);
4197 ()boss_group.phraseEndNpcMsg(0, "say", "TEST_BOSS_TEST_EGS_QUERY_ITEM");
4198 } else if ($msgName == "MSG_BRICK") {
4199 ()phrasePushString("sbrick", $param1);
4200 ()phrasePushString("integer", $ret);
4201 ()boss_group.phraseEndNpcMsg(0, "say", "TEST_BOSS_TEST_EGS_QUERY_BRICK");
4203 } else if ($msgName == "MSG_NAME") {
4204 ()phrasePushString("literal", $ret);
4205 ()phrasePushString("player", $playerEid);
4206 ()boss_group.phraseEndNpcMsg(0, "say", "TEST_BOSS_TEST_MSG");
4208 else
4210 ()phrasePushString("player", $playerEid);
4211 ()phrasePushString("literal", $funName);
4212 ()phrasePushString("literal", $msgName);
4213 ()phrasePushString("integer", $ret);
4214 ()boss_group.phraseEndNpcMsg(0, "say", "TEST_BOSS_TEST_EGS_QUERY");
4217 @endcode
4219 void queryEgs_ssscfs_(CStateInstance* entity, CScriptStack& stack)
4221 std::string funName = "queryEgs_ssscfs_";
4222 // get input params
4223 string literal = (string)stack.top(); stack.pop();
4224 float useEventId = (float)stack.top(); stack.pop();
4225 CGroupNpc* const groupToNotify = dynamic_cast<CGroupNpc*>( (IScriptContext*)stack.top() ); stack.pop();
4226 string param2 = (string)stack.top(); stack.pop();
4227 string param1 = (string)stack.top(); stack.pop();
4228 string func = (string)stack.top(); stack.pop();
4230 // create CQueryEgs to send to egs
4231 CGroup* const group = entity ? entity->getGroup() : 0;
4232 IManagerParent* const managerParent = (group&& group->getOwner()) ? group->getOwner()->getOwner():0;
4233 CAIInstance* const aiInstance = dynamic_cast<CAIInstance*>(managerParent);
4234 if (aiInstance == NULL)
4236 nlwarning("%s failed: the AI instance of the entity is NULL", funName.c_str());
4237 DEBUG_STOP;
4238 return;
4240 CQueryEgs msg;
4241 msg.InstanceId = aiInstance->getInstanceNumber();
4242 msg.GroupAlias = groupToNotify->getAlias();
4243 msg.EventId = (int)useEventId;
4244 msg.Params.push_back(literal);
4245 msg.Params.push_back(func);
4246 msg.Params.push_back(param1);
4247 msg.Params.push_back(param2);
4248 msg.send("EGS");
4253 /** @page code
4255 @subsection summonPlayer_fs_
4257 Summon a player to a bot.
4259 Can be used by a boss to teleport a player. Or the create a teleporter.
4261 A player EntityId is used to identify the player.
4262 A index is used to identified the bot (index for the current group)
4265 Arguments: f(botIndex), s(playerEid) >
4266 @param[in] botIndex is the index of the bot in the current group(static group)
4267 @param[in] playerEid The entityId of the player
4269 @code
4270 ($playerId)getRandomPlayerAggroListTarget(0);
4271 ()teleportPlayer(0, $playerEid); // teleport player to the boss.
4272 @endcode
4274 void summonPlayer_fs_(CStateInstance* entity, CScriptStack& stack)
4277 std::string funName = "summonPlayer_fffs_";
4278 std::string playerEidStr = ((std::string)stack.top()); stack.pop();
4279 sint32 botIndex = (sint32)((float)stack.top()); stack.pop();
4282 // Verify is bot is alived
4283 CGroup* group = entity->getGroup();
4284 if (!group)
4286 nlwarning("%s on a non Npc Group, doesn't work", funName.c_str());
4287 return;
4289 if (!group->isSpawned() || group->bots().isEmpty() || botIndex < 0 || group->bots().size() < static_cast<uint32>(botIndex))
4291 return;
4293 const CBot *const bot = group->getBot(botIndex);
4294 if ( !bot || !bot->isSpawned())
4296 return;
4298 CSpawnBot *const sp= bot->getSpawnObj();
4299 if ( !sp || !sp->isAlive() )
4301 return;
4305 // Read position for mirror
4306 TDataSetRow row = sp->dataSetRow();
4307 if (! TheDataset.isAccessible( row ) )
4309 return;
4312 CMirrorPropValue<sint32> mirrorSymbolX( TheDataset, row, DSPropertyPOSX );
4313 CMirrorPropValue<sint32> mirrorSymbolY( TheDataset, row, DSPropertyPOSY );
4315 // retrieve the CBotPlayer
4316 NLMISC::CEntityId playerEid;
4317 playerEid.fromString(playerEidStr.c_str());
4318 CAIEntityPhysical *charEntity=CAIS::instance().getEntityPhysical(TheDataset.getDataSetRow(playerEid));
4319 if (!charEntity)
4320 return;
4322 // do nothing if one of them is dead
4323 if (!charEntity->isAlive() )
4325 return;
4329 // send teleport MSG
4330 TDataSetRow CharacterRowId = charEntity->dataSetRow();
4332 NLMISC::CEntityId player = CMirrors::getEntityId(CharacterRowId);
4334 if (player != NLMISC::CEntityId::Unknown)
4336 sint32 x2 = mirrorSymbolX.getValue();
4337 sint32 y2 = mirrorSymbolY.getValue();
4338 sint32 z2 = 0;
4339 float t = 0; // TODO direction to mob?
4341 NLNET::CMessage msgout( "TELEPORT_PLAYER" );
4342 nlWrite(msgout, serial, player );
4343 msgout.serial( const_cast<sint32 &>(x2) );
4344 msgout.serial( const_cast<sint32 &>(y2) );
4345 msgout.serial( const_cast<sint32 &>(z2) );
4346 msgout.serial( const_cast<float &>(t) );
4347 sendMessageViaMirror( "EGS", msgout );
4353 /** @page code
4355 @subsection teleportPlayer_sffff_
4357 Teleport a player to a position
4359 A player EntityId is used to identify the player.
4360 The position is identified by the value x,y,z and the heading
4363 Arguments: s(playerId), f(x), f(y), f(z), f(heading) >
4364 @param[in] playerId is EntityId of the player
4365 @param[in] x,y,z,heading is the new position of the player
4367 @code
4368 ($playerId)getRandomPlayerAggroListTarget(0);
4369 ()teleportPlayer($playerEid, 1000, 1000, 100, 0);
4370 @endcode
4372 void teleportPlayer_sffff_(CStateInstance* entity, CScriptStack& stack)
4374 // get player and position parameters
4375 float t = (float)stack.top(); stack.pop(); // heading
4376 float z = (float)stack.top(); stack.pop();
4377 float y = (float)stack.top(); stack.pop();
4378 float x = (float)stack.top(); stack.pop();
4379 std::string playerEidStr = (std::string)stack.top(); stack.pop();
4380 NLMISC::CEntityId playerEid;
4381 playerEid.fromString(playerEidStr.c_str());
4383 // retrieve the CBotPlayer
4384 CAIEntityPhysical *charEntity=CAIS::instance().getEntityPhysical(TheDataset.getDataSetRow(playerEid));
4385 if (!charEntity)
4386 return;
4388 // do nothing if one of them is dead
4389 if (!charEntity->isAlive() )
4391 return;
4394 // teleport player to position
4395 if (playerEid != NLMISC::CEntityId::Unknown)
4397 sint32 x2 = static_cast<sint32>(x*1000);
4398 sint32 y2 = static_cast<sint32>(y*1000);
4399 sint32 z2 = static_cast<sint32>(z*1000);
4401 NLNET::CMessage msgout( "TELEPORT_PLAYER" );
4402 msgout.serial( const_cast<CEntityId &>(playerEid) );
4403 msgout.serial( const_cast<sint32 &>(x2) );
4404 msgout.serial( const_cast<sint32 &>(y2) );
4405 msgout.serial( const_cast<sint32 &>(z2) );
4406 msgout.serial( const_cast<float &>(t) );
4407 sendMessageViaMirror( "EGS", msgout );
4411 //----------------------------------------------------------------------------
4412 /** @page code
4414 @subsection getBotEid_f_s
4415 Get the bot EntityId by its Index.
4416 Arguments: f(botIndex) -> s(botEid)
4418 @param[in] botIndex the Position of the bot in the group
4419 @param[out] botEid The entity Id given by the bot (or empty) if the indexed bot is not from the group
4421 @code
4422 (index)getBotIndexByName("bot_toto");
4423 ($botEid)getBotEid(index);
4424 if (index != -1)
4426 ()phrasePushValue("entity", $botEid);
4427 ()phraseEndEmoteMsg(index, "PHRASE_YOUR_ARE_CLICKING_ON_ME");
4429 @endcode
4432 void getBotEid_f_s(CStateInstance* entity, CScriptStack& stack)
4434 std::string funName = "getBotEid_f_s";
4435 // get spawn Bot by its index
4436 CGroup* group = entity->getGroup();
4437 if (!group)
4439 nlwarning("%s on a non Npc Group, doesn't work", funName.c_str());
4440 stack.push(std::string(CEntityId::Unknown.toString()));
4441 return;
4443 sint32 botIndex = (sint32)((float)stack.top());stack.pop();
4444 if (!group->isSpawned() || group->bots().isEmpty() || botIndex < 0 || group->bots().size() < static_cast<uint32>(botIndex))
4446 stack.push(std::string(CEntityId::Unknown.toString()));
4447 return;
4450 const CBot *const bot = group->getBot(botIndex);
4451 if ( !bot || !bot->isSpawned()) { stack.push(std::string(CEntityId::Unknown.toString())); return;}
4454 CSpawnBot *const sb= bot->getSpawnObj();
4455 if ( !sb ||!sb->isAlive()) {stack.push(std::string(CEntityId::Unknown.toString())); return;};
4457 // return the entity id of the spawn bot
4458 CEntityId id= sb->getEntityId();
4459 stack.push(std::string(id.toString()));
4463 //----------------------------------------------------------------------------
4464 /** @page code
4466 @subsection getBotIndex_s_f
4467 Get the bot Index by its entityId.
4468 Entity Id of a bot can be given via getCurrentSpeackerEid().
4469 It can be useful to Known the index of the bot in the group with the EntityId.
4471 Arguments: s(botEid) -> f(botIndex),
4473 @param[in] botEid The entity Id given by the bot
4474 @param[out] botIndex the Position of the bot in the group (or -1 if the entity_id is not from a bot of the group)
4476 @code
4477 ($botEid)getCurrentSpeakerEid();
4478 (index)getBotIndex($botEid);
4479 if (index != -1)
4481 ()phrasePushValue("entity", $botEid);
4482 ()phraseEndNpcg(index, "PHRASE_YOUR_ARE_CLICKING_ON_ME");
4484 @endcode
4486 void getBotIndex_s_f(CStateInstance* entity, CScriptStack& stack)
4488 std::string funName = "getBotEid_f_s";
4489 CGroup* group = entity->getGroup();
4490 if (!group)
4492 nlwarning("%s on a non Npc Group, doesn't work", funName.c_str());
4493 stack.push(std::string(CEntityId::Unknown.toString()));
4494 return;
4496 std::string botEid = (std::string)stack.top(); stack.pop();
4498 // look in the group if the bot is alived
4499 uint32 botIndex = 0, last = group->bots().size();
4500 for ( ;botIndex != last; ++botIndex)
4502 if (!group->isSpawned() || group->bots().isEmpty() || group->bots().size() < static_cast<uint32>(botIndex))
4504 continue;
4507 const CBot *const bot = group->getBot(botIndex);
4508 if ( !bot || !bot->isSpawned()) { continue; }
4511 CSpawnBot *const sb= bot->getSpawnObj();
4512 if ( !sb ||!sb->isAlive()) {continue;};
4513 CEntityId id= sb->getEntityId();
4514 // if bot is alived return its index
4515 if (botEid == id.toString())
4517 stack.push((float)botIndex);
4518 return;
4522 stack.push((float)-1);
4523 return;
4527 /** @page code
4529 @subsection getCurrentPlayerEid__s
4530 Get the entity id of the player that is clicking on a bot.
4532 WARNING the function is only valid when called from an player_target_npc event.
4535 Arguments: -> s(playerEidAsString),
4536 @param[out] playerEidAsString is EntityId as string from the player.
4538 @code
4539 ($playerEid)getCurrentPlayerEid();
4540 (index)getBotIndexByName("toto");
4541 (distance)getPlayerDistance(index, $playerEid);
4542 phrasePushString("player", $playerEid);
4543 phrasePushValue("interger", distance);
4544 phraseEndNpcMsg(index, "say", "MSG_BOT_B_SAYS_THE_PLAYER_P_IS_AT_DISTANCE_D");\x13
4545 @endcode
4547 void getCurrentPlayerEid__s(CStateInstance* entity, CScriptStack& stack)
4549 std::string funName = "getCurrentPlayerEid__s";
4550 CEntityId id = CEntityId::Unknown;
4551 // if we are in player_target_npc event TempPlayer is valid
4552 if (!TempPlayer)
4554 //TempPlayer is invalid so return Unkwn eid
4555 std::string s = id.toString();
4556 stack.push(s);
4557 return;
4559 // TempPlayer is valid so return eid
4560 id = TempPlayer->getEntityId();
4561 std::string s = id.toString();
4562 stack.push(s);
4563 return;
4567 /** @page code
4569 @subsection getCurrentSpeakerEid__s
4570 Get the entity id of the bot at which the player as that is clicking at.
4572 WARNING the function is only valid when called from an player_target_npc event.
4575 Arguments: -> s(botEidAsString),
4576 @param[out] botEidAsString is EntityId as string from the bot.
4578 @code
4579 ($botEid)getCurrentSpeakerEid();
4580 ($playerEid)getCurrentSpeakerEid();
4582 phrasePushString("player", $playerEid);
4583 phrasePushValue("bot", $botEid);
4584 phraseEndEmotMsg(index, "EMOT_PLAYER_INSULT_BOT");
4585 @endcode
4587 void getCurrentSpeakerEid__s(CStateInstance* entity, CScriptStack& stack)
4589 std::string funName = "getCurrentSpeakerEid__s";
4590 CEntityId id = CEntityId::Unknown;
4591 // if we are in player_target_npc event TempSpeaker is valid
4592 if (!TempSpeaker)
4594 //TempSpeaker is invalid so return Unkwn eid
4595 std::string s = id.toString();
4596 stack.push(s);
4597 return;
4599 //TempSpeaker is valid so return correct eid
4600 id = TempSpeaker->getEntityId();
4601 std::string s = id.toString();
4602 stack.push(s);
4603 return;
4606 //----------------------------------------------------------------------------
4607 /** @page code
4609 @subsection setSheet_s_
4610 Change the sheet of a creature
4612 Arguments: -> s(sheetName)
4614 @code
4615 ()setSheet('ccdeb2');
4617 @endcode
4620 void setSheet_s_(CStateInstance* entity, CScriptStack& stack)
4622 string sheetname = stack.top();
4623 stack.pop();
4625 CSheetId sheetId(sheetname+".creature");
4626 if (sheetId==CSheetId::Unknown)
4627 return;
4629 FOREACH(itBot, CCont<CBot>, entity->getGroup()->bots())
4631 CBot* bot = *itBot;
4632 if (bot)
4634 AISHEETS::ICreatureCPtr const sheet = AISHEETS::CSheets::getInstance()->lookup(sheetId);
4635 if (!sheet.isNull())
4636 bot->triggerSetSheet(sheet);
4641 //----------------------------------------------------------------------------
4642 /** @page code
4644 @subsection setClientSheet_s_
4645 Change the client sheet of a creature
4647 Arguments: -> s(sheetName)
4649 @code
4650 ()setClientSheet('ccdeb2');
4652 @endcode
4655 void setClientSheet_s_(CStateInstance* entity, CScriptStack& stack)
4657 string sheetname = stack.top();
4658 stack.pop();
4660 if (sheetname.find(".creature") == string::npos)
4661 sheetname += ".creature";
4663 FOREACH(itBot, CCont<CBot>, entity->getGroup()->bots())
4665 CBot* bot = *itBot;
4666 if (bot)
4668 bot->setClientSheet(sheetname);
4673 /****************************************************************************/
4675 //----------------------------------------------------------------------------
4676 /** @page code
4678 @subsection setHealer_f_
4679 Make the group healer (need test)
4681 Arguments: -> f(isHealer)
4683 @code
4684 ()setHealer(1);
4686 @endcode
4689 void setHealer_f_(CStateInstance* entity, CScriptStack& stack)
4691 bool value = ((float)stack.top())!=0.f;
4692 stack.pop();
4694 CGroup* group = entity->getGroup();
4696 if (group->isSpawned())
4698 FOREACH(itBot, CCont<CBot>, group->bots())
4700 CBot* bot = *itBot;
4701 if (bot)
4703 bot->setHealer(value);
4704 // break; // :NOTE: Only set first bot as a healer
4710 /****************************************************************************/
4712 //----------------------------------------------------------------------------
4713 /** @page code
4715 @subsection sitDown__
4716 Make the group sit Down
4718 Arguments: ->
4720 @code
4721 ()sitDown();
4723 @endcode
4726 // CStateInstance
4727 void sitDown__(CStateInstance* entity, CScriptStack& stack)
4730 CGroup* group = entity->getGroup();
4732 if (!group)
4734 nlwarning("sitDown__ failed");
4735 return;
4738 CAILogicActionSitDownHelper::sitDown(group);
4742 //----------------------------------------------------------------------------
4743 /** @page code
4745 @subsection standUp
4746 Make the group stand up (if was previously stand down)
4748 Arguments: ->
4750 @code
4751 ()standUp();
4753 @endcode
4756 // CStateInstance
4757 void standUp__(CStateInstance* entity, CScriptStack& stack)
4759 CGroup* group = entity->getGroup();
4760 if (!group)
4762 nlwarning("standUp__ failed");
4763 return;
4766 CAILogicActionSitDownHelper::standUp(group);
4769 //----------------------------------------------------------------------------
4770 /** @page code
4772 @subsection standUp
4773 Use to implement setConditionRet
4775 Arguments: ->
4777 @code
4778 ()setConditionRet(1);
4780 @endcode
4783 // CStateInstance
4784 void setConditionSuccess_f_(CStateInstance* entity, CScriptStack& stack)
4786 bool conditionState = (uint32)((float)stack.top()) != 0;
4787 CGroup* group = entity->getGroup();
4788 if (!group)
4790 nlwarning("setConditionSuccess_f_ failed");
4791 return;
4794 CAILogicDynamicIfHelper::setConditionSuccess(conditionState);
4797 inline
4798 static float randomAngle()
4800 uint32 const maxLimit = CAngle::PI*2;
4801 float val = (float)CAIS::rand32(maxLimit);
4802 return val;
4805 //----------------------------------------------------------------------------
4806 /** @page code
4808 @subsection facing_f_
4810 The npc will face the given direction
4813 Arguments: f(direction)
4814 @param[in] direction is the new angle of the bot in radians
4816 @code
4817 ()facing(3.14);
4818 @endcode
4822 // CStateInstance
4823 void facing_f_(CStateInstance* entity, CScriptStack& stack)
4825 float const theta = (float)stack.top(); stack.pop();
4826 CGroup* group = entity->getGroup();
4828 bool bRandomAngle = false;
4829 if (theta > (NLMISC::Pi * 2.0) || theta < (-NLMISC::Pi * 2.0))
4830 bRandomAngle = true;
4832 if (group->isSpawned())
4834 FOREACH(itBot, CCont<CBot>, group->bots())
4836 CBot* bot = *itBot;
4837 if (bot)
4839 if (bot->isSpawned())
4841 CSpawnBot *spawnBot = bot->getSpawnObj();
4843 if (bRandomAngle)
4844 spawnBot->setTheta(randomAngle());
4845 else
4846 spawnBot->setTheta(theta);
4854 std::map<std::string, FScrptNativeFunc> nfGetGroupNativeFunctions()
4856 std::map<std::string, FScrptNativeFunc> functions;
4858 #define REGISTER_NATIVE_FUNC(cont, func) cont.insert(std::make_pair(std::string(#func), &func))
4860 REGISTER_NATIVE_FUNC(functions, spawn__);
4861 REGISTER_NATIVE_FUNC(functions, despawn_f_);
4862 REGISTER_NATIVE_FUNC(functions, isAlived__f);
4863 REGISTER_NATIVE_FUNC(functions, spawnBot_fsssffff_);
4864 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupPos_ssfff_c);
4865 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupPos_ssfff_);
4866 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupPos_ssff_c);
4867 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupPos_ssff_);
4868 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupPosMl_ssffff_c);
4869 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupPosMl_ssffff_);
4870 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupPosMl_ssfff_c);
4871 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupPosMl_ssfff_);
4872 REGISTER_NATIVE_FUNC(functions, newNpcChildGroup_sssf_c);
4873 REGISTER_NATIVE_FUNC(functions, newNpcChildGroup_sssf_);
4874 REGISTER_NATIVE_FUNC(functions, newNpcChildGroup_sss_c);
4875 REGISTER_NATIVE_FUNC(functions, newNpcChildGroup_sss_);
4876 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupMl_sssff_c);
4877 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupMl_sssff_);
4878 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupMl_sssf_c);
4879 REGISTER_NATIVE_FUNC(functions, newNpcChildGroupMl_sssf_);
4880 REGISTER_NATIVE_FUNC(functions, spawnManager_s_);
4881 REGISTER_NATIVE_FUNC(functions, sitDown__);
4882 REGISTER_NATIVE_FUNC(functions, standUp__);
4883 REGISTER_NATIVE_FUNC(functions, despawnManager_s_);
4884 REGISTER_NATIVE_FUNC(functions, getMidPos__ff);
4885 REGISTER_NATIVE_FUNC(functions, getGroupTemplateWithFlags_sss_s);
4886 REGISTER_NATIVE_FUNC(functions, getGroupTemplateWithFlags_ss_s);
4887 REGISTER_NATIVE_FUNC(functions, getZoneWithFlags_ssss_s);
4888 REGISTER_NATIVE_FUNC(functions, getZoneWithFlags_sss_s);
4889 REGISTER_NATIVE_FUNC(functions, getNearestZoneWithFlags_ffsss_s);
4890 REGISTER_NATIVE_FUNC(functions, getNearestZoneWithFlags_ffss_s);
4891 REGISTER_NATIVE_FUNC(functions, getNearestZoneWithFlagsStrict_ffsss_s);
4892 REGISTER_NATIVE_FUNC(functions, getNearestZoneWithFlagsStrict_ffss_s);
4893 REGISTER_NATIVE_FUNC(functions, getNeighbourZoneWithFlags_ssss_s);
4894 REGISTER_NATIVE_FUNC(functions, getNeighbourZoneWithFlags_sss_s);
4895 REGISTER_NATIVE_FUNC(functions, setAggro_ff_);
4896 REGISTER_NATIVE_FUNC(functions, setCanAggro_f_);
4897 REGISTER_NATIVE_FUNC(functions, clearAggroList_f_);
4898 REGISTER_NATIVE_FUNC(functions, clearAggroList__);
4899 REGISTER_NATIVE_FUNC(functions, setMode_s_);
4900 REGISTER_NATIVE_FUNC(functions, setAutoSpawn_f_);
4901 REGISTER_NATIVE_FUNC(functions, setMaxHP_ff_);
4902 REGISTER_NATIVE_FUNC(functions, setHPLevel_f_);
4903 REGISTER_NATIVE_FUNC(functions, setHPScale_f_);
4904 REGISTER_NATIVE_FUNC(functions, scaleHP_f_);
4905 REGISTER_NATIVE_FUNC(functions, setBotHPScaleByAlias_fs_);
4906 REGISTER_NATIVE_FUNC(functions, downScaleHP_f_);
4907 REGISTER_NATIVE_FUNC(functions, upScaleHP_f_);
4908 REGISTER_NATIVE_FUNC(functions, addHP_f_);
4909 REGISTER_NATIVE_FUNC(functions, giveHP_f_);
4910 REGISTER_NATIVE_FUNC(functions, aiAction_s_);
4911 REGISTER_NATIVE_FUNC(functions, aiActionSelf_s_);
4912 REGISTER_NATIVE_FUNC(functions, addProfileParameter_s_);
4913 REGISTER_NATIVE_FUNC(functions, addProfileParameter_ss_);
4914 REGISTER_NATIVE_FUNC(functions, addProfileParameter_sf_);
4915 REGISTER_NATIVE_FUNC(functions, removeProfileParameter_s_);
4916 REGISTER_NATIVE_FUNC(functions, addPersistentProfileParameter_s_);
4917 REGISTER_NATIVE_FUNC(functions, addPersistentProfileParameter_ss_);
4918 REGISTER_NATIVE_FUNC(functions, addPersistentProfileParameter_sf_);
4919 REGISTER_NATIVE_FUNC(functions, removePersistentProfileParameter_s_);
4920 REGISTER_NATIVE_FUNC(functions, getOutpostStateName__s);
4921 REGISTER_NATIVE_FUNC(functions, isOutpostTribeOwner__f);
4922 REGISTER_NATIVE_FUNC(functions, isOutpostGuildOwner__f);
4923 REGISTER_NATIVE_FUNC(functions, getEventParam_f_f);
4924 REGISTER_NATIVE_FUNC(functions, getEventParam_f_s);
4925 REGISTER_NATIVE_FUNC(functions, setSheet_s_);
4926 REGISTER_NATIVE_FUNC(functions, setClientSheet_s_);
4927 REGISTER_NATIVE_FUNC(functions, setHealer_f_);
4928 REGISTER_NATIVE_FUNC(functions, setConditionSuccess_f_);
4929 REGISTER_NATIVE_FUNC(functions, facing_f_);
4930 REGISTER_NATIVE_FUNC(functions, setUrl_ss_);
4932 // Boss functions (custom text)
4933 REGISTER_NATIVE_FUNC(functions, phraseBegin__);
4934 REGISTER_NATIVE_FUNC(functions, phrasePushValue_sf_);
4935 REGISTER_NATIVE_FUNC(functions, phrasePushString_ss_);
4936 REGISTER_NATIVE_FUNC(functions, phraseEndNpcMsg_fss_);
4937 REGISTER_NATIVE_FUNC(functions, phraseEndSystemMsg_fss_);
4938 REGISTER_NATIVE_FUNC(functions, phraseEndEmoteMsg_fs_);
4940 // Boss functions (Bot infos)
4941 REGISTER_NATIVE_FUNC(functions, getBotIndex_s_f);
4942 REGISTER_NATIVE_FUNC(functions, getBotEid_f_s);
4943 REGISTER_NATIVE_FUNC(functions, getCurrentSpeakerEid__s);
4944 REGISTER_NATIVE_FUNC(functions, getBotIndexByName_s_f);
4945 REGISTER_NATIVE_FUNC(functions, isGroupAlived__f);
4946 REGISTER_NATIVE_FUNC(functions, isBotAlived_f_f);
4948 // Boss functions (Player infos)
4949 REGISTER_NATIVE_FUNC(functions, isPlayerAlived_s_f);
4950 REGISTER_NATIVE_FUNC(functions, getPlayerStat_ss_f);
4951 REGISTER_NATIVE_FUNC(functions, getPlayerPosition_s_ff);
4952 REGISTER_NATIVE_FUNC(functions, getPlayerDistance_fs_f);
4953 REGISTER_NATIVE_FUNC(functions, getCurrentPlayerEid__s);
4954 REGISTER_NATIVE_FUNC(functions, queryEgs_sscfs_);
4955 REGISTER_NATIVE_FUNC(functions, queryEgs_ssscfs_);
4957 // Boss functions (Aggro list)
4958 REGISTER_NATIVE_FUNC(functions, getCurrentPlayerAggroListTarget_f_s);
4959 REGISTER_NATIVE_FUNC(functions, getRandomPlayerAggroListTarget_f_s);
4960 REGISTER_NATIVE_FUNC(functions, getAggroListElement_ff_s);
4961 REGISTER_NATIVE_FUNC(functions, getAggroListSize_f_f);
4962 REGISTER_NATIVE_FUNC(functions, setAggroListTarget_fs_);
4963 REGISTER_NATIVE_FUNC(functions, setGroupAggroListTarget_s_);
4964 REGISTER_NATIVE_FUNC(functions, setManagerAggroListTarget_ss_);
4966 // Boss functions (Time infos)
4967 REGISTER_NATIVE_FUNC(functions, getServerTimeStr__s);
4968 REGISTER_NATIVE_FUNC(functions, getServerTime__s);
4969 REGISTER_NATIVE_FUNC(functions, getRyzomDateStr__s);
4970 REGISTER_NATIVE_FUNC(functions, getRyzomDate__s);
4972 // Boss function (teleport actions)
4973 REGISTER_NATIVE_FUNC(functions, teleportPlayer_sffff_);
4974 REGISTER_NATIVE_FUNC(functions, summonPlayer_fs_);
4977 #undef REGISTER_NATIVE_FUNC
4979 return functions;