1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "script_compiler.h"
24 #include "ai_grp_npc.h"
25 #include "group_profile.h"
26 #include "ai_generic_fight.h"
27 #include "server_share/msg_brick_service.h"
29 #include "continent_inline.h"
30 #include "dyn_grp_inline.h"
32 #include "ai_player.h"
34 #include "ai_script_data_manager.h"
35 #include "ais_control.h"
39 using namespace NLMISC
;
41 using namespace AICOMP
;
42 using namespace AITYPES
;
43 using namespace RYAI_MAP_CRUNCH
;
45 // a big bad global var !
46 extern CAIEntityPhysical
*TempSpeaker
;
47 extern CBotPlayer
*TempPlayer
;
49 /****************************************************************************/
50 /* CGroupNpc methods */
51 /****************************************************************************/
53 //----------------------------------------------------------------------------
57 @subsection setFactionProp_ss_
58 Set a property of the faction profile. Valid values for Property are:
63 There are special faction that are automatically attributed to entities.
67 - Famous<faction> where faction is the name of a Ryzom faction with uppercase
68 initials and without underscores (ie: tribe_beachcombers ->
69 FamousTribeBeachcombers), it represents players with a positive fame with the
71 - outpost:<id>:<side> where id is the outpost alias as an int, and side is
72 either attacker ou defender (these faction may see their format change soon
73 and shouldn't be used without prior discussion with the responsible coder), it
74 represents players and squads fighting in an outpost conflict
76 Arguments: s(Property),s(Content) ->
77 @param Property is the property to modify
78 @param Content is a '|' seperated list of faction names
81 ()setFactionProp("ennemyFaction", "Player");
86 void setFactionProp_ss_(CStateInstance
* entity
, CScriptStack
& stack
)
88 std::string params
= stack
.top(); // ToChange
90 TStringId
const factionType
= CStringMapper::map(stack
.top());
93 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
96 nlwarning("setFactionProp on a non Npc Group, doesnt work");
100 static TStringId factionStrId
= CStringMapper::map("faction");
101 static TStringId ennemyFactionStrId
= CStringMapper::map("ennemyFaction");
102 static TStringId friendFactionStrId
= CStringMapper::map("friendFaction");
105 CPropertySetWithExtraList
<TAllianceId
> tmpSet
;
106 CStringSeparator
const sep(params
,"|");
107 while (sep
.hasNext())
108 tmpSet
.addProperty(AITYPES::CPropertyId::create(sep
.get()));
110 if (factionType
==factionStrId
)
112 grpNpc
->faction() = tmpSet
;
115 if (factionType
==ennemyFactionStrId
)
117 grpNpc
->ennemyFaction() = tmpSet
;
120 if (factionType
==friendFactionStrId
)
122 grpNpc
->friendFaction() = tmpSet
;
125 nlwarning("'%s' is not a correct faction name", CStringMapper::unmap(factionType
).c_str());
130 void setOupostMode_ss_(CStateInstance
* entity
, CScriptStack
& stack
)
132 std::string sideStr
= stack
.top(); stack
.pop();
133 std::string aliasStr
= stack
.top();
134 CGroupNpc
* const npcGroup
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
137 nlwarning("setOutpostMode on a non Npc Group, doesnt work");
141 OUTPOSTENUMS::TPVPSide side
;
142 if (sideStr
== "attacker")
144 side
= OUTPOSTENUMS::OutpostAttacker
;
146 else if (sideStr
== "owner")
148 side
= OUTPOSTENUMS::OutpostOwner
;
152 nlwarning("setOutpostMode: invalid side");
155 npcGroup
->setOutpostSide(side
);
156 npcGroup
->setOutpostFactions(aliasStr
, side
);
157 FOREACH(botIt
, CCont
<CBot
>, npcGroup
->bots())
160 CBotNpc
* botNpc
= NLMISC::safe_cast
<CBotNpc
*>(bot
);
163 CSpawnBotNpc
* spawnBotNpc
= botNpc
->getSpawn();
166 spawnBotNpc
->setOutpostSide(side
);
167 spawnBotNpc
->setOutpostAlias(LigoConfig
.aliasFromString(aliasStr
));
171 if (npcGroup
->isSpawned())
172 npcGroup
->getSpawnObj()->sendInfoToEGS();
175 //----------------------------------------------------------------------------
178 @subsection moveToZone_ss_
179 Moves the current group from one zone to another.
181 Arguments: s(From), s(To) ->
182 @param[in] From is a zone name
183 @param[in] To is a zone name
186 ()moveToZone($zone1, $zone2); // Move the current group from $zone1 to $zone2
190 // Spawned CGroupNpc not in a family behaviour
191 void moveToZone_ss_(CStateInstance
* entity
, CScriptStack
& stack
)
193 TStringId
const zoneDest
= CStringMapper::map(stack
.top());
195 TStringId
const zoneSrc
= CStringMapper::map(stack
.top());
198 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
199 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
205 nlwarning("moveToZone failed: no state instance!");
206 nlwarning(" - from %s", CStringMapper::unmap(zoneSrc
).c_str());
207 nlwarning(" - to %s", CStringMapper::unmap(zoneDest
).c_str());
211 CGroupNpc
* group
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
214 nlwarning("moveToZone failed: no NPC group!");
215 nlwarning(" - from %s", CStringMapper::unmap(zoneSrc
).c_str());
216 nlwarning(" - to %s", CStringMapper::unmap(zoneDest
).c_str());
219 CSpawnGroupNpc
* spawnGroup
= group
->getSpawnObj();
222 nlwarning("moveToZone failed: no spawned group!");
223 nlwarning(" - from %s", CStringMapper::unmap(zoneSrc
).c_str());
224 nlwarning(" - to %s", CStringMapper::unmap(zoneDest
).c_str());
228 CNpcZone
const* const destZone
= aiInstance
->getZone(zoneDest
);
229 CNpcZone
const* const srcZone
= aiInstance
->getZone(zoneSrc
);
233 nlwarning("moveToZone: getZone destination failed!");
234 nlwarning(" - from %s", CStringMapper::unmap(zoneSrc
).c_str());
235 nlwarning(" - to %s", CStringMapper::unmap(zoneDest
).c_str());
239 nlwarning("moveToZone: getZone source failed!");
240 nlwarning(" - from %s", CStringMapper::unmap(zoneSrc
).c_str());
241 nlwarning(" - to %s", CStringMapper::unmap(zoneDest
).c_str());
243 if (!destZone
|| !srcZone
)
246 if (destZone
==srcZone
)
248 nlwarning("Trying to find a path between two same zones in %s, aborting moveToZone", entity
->getActiveState()->getAliasFullName().c_str());
249 nlwarning(" - from %s", CStringMapper::unmap(zoneSrc
).c_str());
250 nlwarning(" - to %s", CStringMapper::unmap(zoneDest
).c_str());
254 spawnGroup
->movingProfile().setAIProfile(new CGrpProfileDynFollowPath(spawnGroup
, srcZone
, destZone
, AITYPES::CPropertySet()));
257 //----------------------------------------------------------------------------
260 @subsection setActivity_s_
261 Changes the activity of the group. Valid activities are:
268 - "faction_no_assist"
271 Arguments: s(Activity) ->
272 @param[in] Activity is an activity name the group will take
275 ()setActivity("bandit"); // Gives a bandit activity to the group
279 // Spawned CGroupNpc not in a family behaviour
280 void setActivity_s_(CStateInstance
* entity
, CScriptStack
& stack
)
282 string activity
= stack
.top();
285 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
286 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
290 if (!entity
) { nlwarning("setActivity failed!"); return; }
292 CGroupNpc
* group
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
294 { nlwarning("setActivity failed: no NPC group");
297 CSpawnGroupNpc
* spawnGroup
= group
->getSpawnObj();
299 { nlwarning("setActivity failed: no spawned group");
305 if (activity
=="no_change")
308 if (activity
=="escorted")
310 spawnGroup
->activityProfile().setAIProfile(new CGrpProfileEscorted(spawnGroup
));
313 if (activity
=="guard")
315 spawnGroup
->activityProfile().setAIProfile(new CGrpProfileGuard(spawnGroup
));
318 if (activity
=="guard_escorted")
320 spawnGroup
->activityProfile().setAIProfile(new CGrpProfileGuardEscorted(spawnGroup
));
324 if (activity
=="normal")
326 spawnGroup
->activityProfile().setAIProfile(new CGrpProfileNormal(spawnGroup
));
329 if (activity
=="faction")
331 spawnGroup
->activityProfile().setAIProfile(new CGrpProfileFaction(spawnGroup
));
334 if (activity
=="faction_no_assist")
336 CGrpProfileFaction
* grpPro
= new CGrpProfileFaction(spawnGroup
);
338 spawnGroup
->activityProfile().setAIProfile(grpPro
);
341 if (activity
=="bandit")
343 spawnGroup
->activityProfile().setAIProfile(new CGrpProfileBandit(spawnGroup
));
347 nlwarning("trying to set activity profile to an unknown profile name");
351 //----------------------------------------------------------------------------
354 @subsection waitInZone_s_
355 Makes the group wander in the specified zone. It's useful to prevent the group
356 from looping previous movement profile).
358 Arguments: s(Zone) ->
359 @param[in] Zone is a zone name
362 ()waitInZone($zone); // Makes the group wander in $zone
366 // Spawned CGroupNpc not in a family behaviour
367 void waitInZone_s_(CStateInstance
* entity
, CScriptStack
& stack
)
369 std::string zoneName
= stack
.top();
370 TStringId
const zoneDest
= CStringMapper::map(zoneName
);
375 nlwarning("waitInZone failed!");
379 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
380 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
383 // :TODO: Check is that warning was a flood
384 //nlwarning("waitInZone failed!");
388 CGroupNpc
* group
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
391 nlwarning("waitInZone failed: no NPC group");
394 CSpawnGroupNpc
* spawnGroup
= group
->getSpawnObj();
397 nlwarning("waitInZone failed: no spawned group");
401 CNpcZone
const* const destZone
= aiInstance
->getZone(zoneDest
);
405 nlwarning("waitInZone: getZone destination failed! (%s)", zoneName
.c_str());
408 spawnGroup
->movingProfile().setAIProfile(new CGrpProfileWander(spawnGroup
, destZone
));
411 //----------------------------------------------------------------------------
414 @subsection stopMoving__
415 Makes the group stop moving and stand at its current position.
420 ()stopMoving(); // Makes the group stop moving
424 // Spawned CGroupNpc not in a family behaviour
425 void stopMoving__(CStateInstance
* entity
, CScriptStack
& stack
)
429 nlwarning("stopMoving failed!");
433 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
434 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
438 CGroupNpc
* group
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
441 nlwarning("stopMoving failed: no NPC group");
444 CSpawnGroupNpc
* spawnGroup
= group
->getSpawnObj();
447 nlwarning("stopMoving failed: no spawned group");
451 spawnGroup
->movingProfile().setAIProfile(new CGrpProfileIdle(spawnGroup
));
454 //----------------------------------------------------------------------------
457 @subsection startWander_f_
458 Set activity to wander in current pos:
460 Arguments: f(Radius) ->
461 @param[in] Radius dispersion of wander activity
464 ()startWander(100); // Gives a wander activity to the group with dispersion of 100
468 // Spawned CGroupNpc not in a family behaviour
469 void startWander_f_(CStateInstance
* entity
, CScriptStack
& stack
)
471 uint32 dispersionRadius
= (uint32
)(float&)stack
.top();
474 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
475 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
479 if (!entity
) { nlwarning("setActivity failed!"); return; }
481 CGroupNpc
* group
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
483 { nlwarning("startWander failed: no NPC group");
486 CSpawnGroupNpc
* spawnGroup
= group
->getSpawnObj();
488 { nlwarning("startWander failed: no spawned group");
493 if (!spawnGroup
->calcCenterPos(centerPos
)) // true if there's some bots in the group.
494 { nlwarning("startWander failed: no center pos");
498 NLMISC::CSmartPtr
<CNpcZonePlaceNoPrim
> destZone
= NLMISC::CSmartPtr
<CNpcZonePlaceNoPrim
>(new CNpcZonePlaceNoPrim());
499 destZone
->setPosAndRadius(AITYPES::vp_auto
, CAIPos(centerPos
, 0, 0), (uint32
)(dispersionRadius
*1000.));
500 spawnGroup
->movingProfile().setAIProfile(new CGrpProfileWanderNoPrim(spawnGroup
, destZone
));
503 //----------------------------------------------------------------------------
506 @subsection startMoving_fff_
507 Set activity to wander in current pos:
509 Arguments: f(Radius) ->
510 @param[in] Radius dispersion of wander activity
513 ()startMoving(100,-100,10); // Moves the group to 100,-100 with radius of 10
517 // Spawned CGroupNpc not in a family behaviour
518 void startMoving_fff_(CStateInstance
* entity
, CScriptStack
& stack
)
520 uint32 dispersionRadius
= (uint32
)(float&)stack
.top();
522 float const y
= (float&)stack
.top();
524 float const x
= (float&)stack
.top();
527 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
528 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
532 if (!entity
) { nlwarning("setActivity failed!"); return; }
534 CGroupNpc
* group
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
536 { nlwarning("setActivity failed: no NPC group");
539 CSpawnGroupNpc
* spawnGroup
= group
->getSpawnObj();
541 { nlwarning("setActivity failed: no spawned group");
545 NLMISC::CSmartPtr
<CNpcZonePlaceNoPrim
> destZone
= NLMISC::CSmartPtr
<CNpcZonePlaceNoPrim
>(new CNpcZonePlaceNoPrim());
546 destZone
->setPosAndRadius(AITYPES::vp_auto
, CAIPos(CAIVector(x
, y
), 0, 0), (uint32
)(dispersionRadius
*1000.));
547 spawnGroup
->movingProfile().setAIProfile(new CGrpProfileWanderNoPrim(spawnGroup
, destZone
));
552 //----------------------------------------------------------------------------
555 @subsection followPlayer_sf_
556 Set activity to follow the given player
558 Arguments: s(PlayerEid) f(Radius) ->
559 @param[in] PlayerEid id of player to follow
560 @param[in] Radius dispersion of wander activity
563 ()followPlayer("(0x0002015bb4:01:88:88)",10);
567 // Spawned CGroupNpc not in a family behaviour
568 void followPlayer_sf_(CStateInstance
* entity
, CScriptStack
& stack
)
570 uint32 dispersionRadius
= (uint32
)(float&)stack
.top(); stack
.pop();
571 NLMISC::CEntityId playerId
= NLMISC::CEntityId((std::string
)stack
.top());
573 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
574 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
578 if (!entity
) { nlwarning("followPlayer failed!"); return; }
580 CGroupNpc
* group
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
582 { nlwarning("followPlayer failed: no NPC group");
585 CSpawnGroupNpc
* spawnGroup
= group
->getSpawnObj();
587 { nlwarning("followPlayer failed: no spawned group");
591 if (playerId
== CEntityId::Unknown
)
593 nlwarning("followPlayer failed: unknown player");
598 spawnGroup
->movingProfile().setAIProfile(new CGrpProfileFollowPlayer(spawnGroup
, TheDataset
.getDataSetRow(playerId
), dispersionRadius
));
604 //----------------------------------------------------------------------------
608 Makes the group wander in the current npc state zone.
613 ()wander(); // Makes the group wander
617 // Spawned CGroupNpc not in a family behaviour
618 void wander__(CStateInstance
* entity
, CScriptStack
& stack
)
622 nlwarning("wander failed!");
626 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
627 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
631 CGroupNpc
* group
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
634 nlwarning("wander failed: no NPC group");
637 CSpawnGroupNpc
* spawnGroup
= group
->getSpawnObj();
640 nlwarning("wander failed: no spawned group");
644 spawnGroup
->movingProfile().setAIProfile(new CGrpProfileWander(spawnGroup
));
647 //----------------------------------------------------------------------------
650 @subsection setAttackable_f_
651 Sets the group as being attackable (or not) by bots and players. 0 means not
652 attackable, 1 means attackable.
654 Arguments: f(Attackable) ->
655 @param[in] Attackable tells whether the group is attackable
658 ()setAttackable(1); // Make the group attackable by players and bots
663 void setAttackable_f_(CStateInstance
* entity
, CScriptStack
& stack
)
665 bool const attackable
= (float&)stack
.top()!=0.0f
;
668 CGroup
* group
= entity
->getGroup();
670 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
672 npcGroup
->setPlayerAttackable(attackable
);
673 npcGroup
->setBotAttackable(attackable
);
675 if (npcGroup
->isSpawned())
676 npcGroup
->getSpawnObj()->sendInfoToEGS();
679 //----------------------------------------------------------------------------
682 @subsection setPlayerAttackable_f_
683 Sets the group as being attackable (or not) by players. 0 means not
684 attackable, 1 means attackable.
686 Arguments: f(Attackable) ->
687 @param[in] Attackable tells whether the group is attackable
690 ()setPlayerAttackable(1); // Make the group attackable by players
695 void setPlayerAttackable_f_(CStateInstance
* entity
, CScriptStack
& stack
)
697 bool attackable
= (float&)stack
.top()!=0.0f
;
700 CGroup
* group
= entity
->getGroup();
701 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
703 npcGroup
->setPlayerAttackable(attackable
);
705 if (npcGroup
->isSpawned())
706 npcGroup
->getSpawnObj()->sendInfoToEGS();
709 //----------------------------------------------------------------------------
710 // setBotAttackable_f_
711 // Arguments: f(Attackable) ->
714 @subsection setBotAttackable_f_
715 Sets the group as being attackable (or not) by bots. 0 means not attackable, 1
718 Arguments: f(Attackable) ->
719 @param[in] Attackable tells whether the group is attackable
722 ()setBotAttackable(0); // Make the group not attackable by bots
727 void setBotAttackable_f_(CStateInstance
* entity
, CScriptStack
& stack
)
729 bool attackable
= (float&)stack
.top()!=0.0f
;
732 CGroup
* group
= entity
->getGroup();
733 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
735 npcGroup
->setBotAttackable(attackable
);
737 if (npcGroup
->isSpawned())
738 npcGroup
->getSpawnObj()->sendInfoToEGS();
741 //----------------------------------------------------------------------------
742 // setFactionAttackableAbove_sff_
743 // Arguments: s(Faction),f(Threshold),f(Attackable) ->
746 @subsection setFactionAttackableAbove_sff_
747 Sets the group as being attackable (or not) by players having their fame
748 matching the specified condition. If player fame for Faction is above
749 specified Threshold the bot will be attackable by that player or not depending
750 on Attackable parameter, 0 meaning not attackable, 1 meaning attackable.
752 Note: Bots must not be player attackable for the faction to be taken into
755 Arguments: s(Faction),f(Threshold),f(Attackable) ->
756 @param[in] Faction tells the faction against which player fame will be tested
757 @param[in] Threshold is the test threshold above which player will be able to attack
758 @param[in] Attackable tells whether the group is attackable or not
761 ()setFactionAttackableAbove("TribeNightTurners", 0, 1); // Make the group attackable by players with positive tribe_night_turners fame
766 void setFactionAttackableAbove_sff_(CStateInstance
* entity
, CScriptStack
& stack
)
768 bool attackable
= (float&)stack
.top()!=0.0f
;
770 sint32 threshold
= (sint32
)(float&)stack
.top();
772 std::string faction
= (std::string
&)stack
.top();
775 CGroup
* group
= entity
->getGroup();
776 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
778 npcGroup
->setFactionAttackableAbove(faction
, threshold
, attackable
);
780 if (npcGroup
->isSpawned())
781 npcGroup
->getSpawnObj()->sendInfoToEGS();
784 //----------------------------------------------------------------------------
785 // setFactionAttackableBelow_sff_
786 // Arguments: s(Faction),f(Threshold),f(Attackable) ->
789 @subsection setFactionAttackableBelow_sff_
790 Sets the group as being attackable (or not) by players having their fame
791 matching the specified condition. If player fame for Faction is below
792 specified Threshold the bot will be attackable by that player or not depending
793 on Attackable parameter, 0 meaning not attackable, 1 meaning attackable.
795 Note: Bots must not be player attackable for the faction to be taken into
798 Arguments: s(Faction),f(Threshold),f(Attackable) ->
799 @param[in] Faction tells the faction against which player fame will be tested
800 @param[in] Threshold is the test threshold below which player will be able to attack
801 @param[in] Attackable tells whether the group is attackable or not
804 ()setFactionAttackableBelow("TribeMatisianBorderGuards", 0, 1); // Make the group attackable by players with negative tribe_matisian_border_guards fame
809 void setFactionAttackableBelow_sff_(CStateInstance
* entity
, CScriptStack
& stack
)
811 bool attackable
= (float&)stack
.top()!=0.0f
;
813 sint32 threshold
= (sint32
)(float&)stack
.top();
815 std::string faction
= (std::string
&)stack
.top();
818 CGroup
* group
= entity
->getGroup();
819 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
821 npcGroup
->setFactionAttackableBelow(faction
, threshold
, attackable
);
823 if (npcGroup
->isSpawned())
824 npcGroup
->getSpawnObj()->sendInfoToEGS();
827 //----------------------------------------------------------------------------
830 @subsection addBotChat_s_
831 Add an entry in the botchat menu of every bot of the group. Specified text ID
832 can be created dynamically with setSimplePhrase (@ref setSimplePhrase_ss_).
834 Arguments: s(BotChat) ->
835 @param[in] BotChat is a text ID
838 ()addBotChat("menu:QUESTION:REPONSE");
843 void addBotChat_s_(CStateInstance
* entity
, CScriptStack
& stack
)
845 string
const botChat
= (string
)stack
.top();
848 CGroup
* group
= entity
->getGroup();
849 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
851 FOREACH(botIt
, CCont
<CBot
>, group
->bots())
854 CBotNpc
* botNpc
= NLMISC::safe_cast
<CBotNpc
*>(bot
);
857 if (!botNpc
->getChat())
859 botNpc
->getChat()->add(botNpc
->getAIInstance(), botChat
);
860 CSpawnBotNpc
* spawnBotNpc
= botNpc
->getSpawn();
863 spawnBotNpc
->setCurrentChatProfile(botNpc
->getChat());
867 if (npcGroup
->isSpawned())
868 npcGroup
->getSpawnObj()->sendInfoToEGS();
871 //----------------------------------------------------------------------------
874 @subsection clearBotChat__
875 Removes all entries from the botchat menu of every bot of the group.
885 void clearBotChat__(CStateInstance
* entity
, CScriptStack
& stack
)
887 CGroup
* group
= entity
->getGroup();
888 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
890 FOREACH(botIt
, CCont
<CBot
>, group
->bots())
893 CBotNpc
* botNpc
= NLMISC::safe_cast
<CBotNpc
*>(bot
);
896 if (!botNpc
->getChat())
898 botNpc
->getChat()->clear();
899 CSpawnBotNpc
* spawnBotNpc
= botNpc
->getSpawn();
902 spawnBotNpc
->setCurrentChatProfile(botNpc
->getChat());
906 if (npcGroup
->isSpawned())
907 npcGroup
->getSpawnObj()->sendInfoToEGS();
910 //----------------------------------------------------------------------------
913 @subsection ignoreOffensiveActions_f_
914 Make the bots of the group ignore offensive actions issued on them.
916 Arguments: f(IgnoreOffensiveActions) ->
917 @param[in] IgnoreOffensiveActions is tells whethere to ignore offensive actions (1) or not (0)
920 ()ignoreOffensiveActions(1);
925 void ignoreOffensiveActions_f_(CStateInstance
* entity
, CScriptStack
& stack
)
927 bool const ignoreOffensiveActions
= ((float)stack
.top())!=0.f
;
930 CGroup
* group
= entity
->getGroup();
931 FOREACH(botIt
, CCont
<CBot
>, group
->bots())
935 bot
->setIgnoreOffensiveActions(ignoreOffensiveActions
);
939 //----------------------------------------------------------------------------
942 @subsection setDespawnTime_f_
943 Sets the time before current group being despawned.
945 Arguments: f(DespawnTime) ->
946 @param[in] DespawnTime is the despawn time in ticks (-1 will set "pseudo-infinite")
949 ()setDespawnTime(80);
950 ()setDespawnTime(-1);
955 void setDespawnTime_f_(CStateInstance
* entity
, CScriptStack
& stack
)
957 float time
= stack
.top();
960 CGroup
* group
= entity
->getGroup();
961 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
963 uint32 despawntime
= (uint32
)(sint32
)time
; // -1 => ~0
964 // TODO:kxu: fix CAITimer!
965 if (despawntime
> 0x7fffffff)
966 despawntime
= 0x7fffffff; // AI timers do not treat properly delta times greater than the max signed int
967 npcGroup
->despawnTime() = despawntime
;
973 @subsection despawnBotByAlias_s_
974 Despawn a specific Bot by its alias
976 Arguments: f(alias), ->
977 @param[in] alias is the alias of the bot
981 ()despawnBotByAlias('(A:1000:10560)');
986 void despawnBotByAlias_s_(CStateInstance
* entity
, CScriptStack
& stack
)
988 uint32 alias
= LigoConfig
.aliasFromString((string
)stack
.top()); stack
.pop();
989 CGroup
* group
= entity
->getGroup();
990 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
992 FOREACH(botIt
, CCont
<CBot
>, group
->bots())
997 if (bot
->getAlias() != alias
) { continue; }
998 if (!bot
->isSpawned()) return;
999 if (bot
->getRyzomType() == RYZOMID::npc
)
1001 CBotNpc
* botNpc
= NLMISC::safe_cast
<CBotNpc
*>(bot
);
1002 CSpawnBotNpc
* spawnBotNpc
= botNpc
->getSpawn();
1003 spawnBotNpc
->spawnGrp().addBotToDespawnAndRespawnTime(&spawnBotNpc
->getPersistent(), 1, spawnBotNpc
->spawnGrp().getPersistent().respawnTime());
1009 //----------------------------------------------------------------------------
1012 @subsection setRespawnTime_f_
1013 Sets the time in game cycles before current group being respawned.
1015 Arguments: f(RespawnTime) ->
1016 @param[in] RespawnTime is the respawn time in ticks (-1 will set "pseudo-infinite")
1019 ()setRespawnTime(80);
1020 ()setRespawnTime(-1);
1025 void setRespawnTime_f_(CStateInstance
* entity
, CScriptStack
& stack
)
1027 float const time
= stack
.top();
1030 CGroup
* group
= entity
->getGroup();
1031 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
1033 uint32 respawntime
= (uint32
)(sint32
)time
; // -1 => ~0
1034 // TODO:kxu: fix CAITimer!
1035 if (respawntime
> 0x7fffffff)
1036 respawntime
= 0x7fffffff; // AI timers do not treat properly delta times greater than the max signed int
1037 npcGroup
->respawnTime() = respawntime
;
1040 //----------------------------------------------------------------------------
1043 @subsection addHpUpTrigger_ff_
1044 Registers a trigger on HP increases. Whenever the HP level of a bot upcross
1045 the threshold it triggers the specified user event. Several triggers can be
1046 registered on the same group, even with the same threshold and event.
1048 Arguments: f(threshold),f(user_event_n) ->
1049 @param[in] threshold is a HP threshold
1050 @param[in] user_event_n is the user event to trigger
1053 ()addHpUpTrigger(0.5, 4);
1058 void addHpUpTrigger_ff_(CStateInstance
* entity
, CScriptStack
& stack
)
1060 int eventId
= (int)(float)stack
.top();
1062 float threshold
= (float)stack
.top();
1064 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1067 nlwarning("Trying to add a hp up trigger (%f) listener (user event %d) in a group which is not an NPC group.", threshold
, eventId
);
1070 grpNpc
->addHpUpTrigger(threshold
, eventId
);
1073 //----------------------------------------------------------------------------
1076 @subsection delHpUpTrigger_ff_
1077 Unregisters a trigger on HP increases. The same values used when registering
1078 the trigger must be passed. If several triggers were defined with the same
1079 parameters only one is removed.
1081 Arguments: f(threshold),f(user_event_n) ->
1082 @param[in] threshold is a HP threshold
1083 @param[in] user_event_n is the user event to trigger
1086 ()delHpUpTrigger(0.5, 4);
1091 void delHpUpTrigger_ff_(CStateInstance
* entity
, CScriptStack
& stack
)
1093 int eventId
= (int)(float)stack
.top();
1095 float threshold
= (float)stack
.top();
1097 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1100 nlwarning("Trying to delete a hp up trigger (%f) listener (user event %d) in a group which is not an NPC group.", threshold
, eventId
);
1103 grpNpc
->delHpUpTrigger(threshold
, eventId
);
1106 //----------------------------------------------------------------------------
1109 @subsection addHpDownTrigger_ff_
1110 Registers a trigger on HP decreases. Whenever the HP level of a bot downcross
1111 the threshold it triggers the specified user event. Several triggers can be
1112 registered on the same group, even with the same threshold and event.
1114 Arguments: f(threshold),f(user_event_n) ->
1115 @param[in] threshold is a HP threshold
1116 @param[in] user_event_n is the user event to trigger
1119 ()addHpDownTrigger(0.5, 5);
1124 void addHpDownTrigger_ff_(CStateInstance
* entity
, CScriptStack
& stack
)
1126 int eventId
= (int)(float)stack
.top();
1128 float threshold
= (float)stack
.top();
1130 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1133 nlwarning("Trying to add a hp down trigger (%f) listener (user event %d) in a group which is not an NPC group.", threshold
, eventId
);
1136 grpNpc
->addHpDownTrigger(threshold
, eventId
);
1139 //----------------------------------------------------------------------------
1142 @subsection delHpDownTrigger_ff_
1143 Unregisters a trigger on HP decreases. The same values used when registering
1144 the trigger must be passed. If several triggers were defined with the same
1145 parameters only one is removed.
1147 Arguments: f(threshold),f(user_event_n) ->
1148 @param[in] threshold is a HP threshold
1149 @param[in] user_event_n is the user event to trigger
1152 ()delHpDownTrigger(0.5, 5);
1157 void delHpDownTrigger_ff_(CStateInstance
* entity
, CScriptStack
& stack
)
1159 int eventId
= (int)(float)stack
.top();
1161 float threshold
= (float)stack
.top();
1163 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1166 nlwarning("Trying to delete a hp down trigger (%f) listener (user event %d) in a group which is not an NPC group.", threshold
, eventId
);
1169 grpNpc
->delHpDownTrigger(threshold
, eventId
);
1172 //----------------------------------------------------------------------------
1175 @subsection addHpUpTrigger_fs_
1176 @sa @ref addHpUpTrigger_ff_
1178 These triggers call a script function instead of trigger a user event.
1180 Arguments: f(threshold),s(callback) ->
1181 @param[in] threshold is a HP threshold
1182 @param[in] callback is the script callback to trigger
1185 ()addHpUpTrigger(0.5, "onHPIncrease");
1190 void addHpUpTrigger_fs_(CStateInstance
* entity
, CScriptStack
& stack
)
1192 std::string cbFunc
= (std::string
)stack
.top();
1194 float threshold
= (float)stack
.top();
1196 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1199 nlwarning("Trying to add a hp up trigger (%f) listener (%s) in a group which is not an NPC group.", threshold
, cbFunc
.c_str());
1202 grpNpc
->addHpUpTrigger(threshold
, cbFunc
);
1205 //----------------------------------------------------------------------------
1208 @subsection delHpUpTrigger_fs_
1209 @sa @ref delHpUpTrigger_ff_
1211 This function is used to remove script function triggers.
1213 Arguments: f(threshold),s(callback) ->
1214 @param[in] threshold is a HP threshold
1215 @param[in] callback is the script callback to trigger
1218 ()delHpUpTrigger(0.5, "onHPIncrease");
1223 void delHpUpTrigger_fs_(CStateInstance
* entity
, CScriptStack
& stack
)
1225 std::string cbFunc
= (std::string
)stack
.top();
1227 float threshold
= (float)stack
.top();
1229 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1232 nlwarning("Trying to delete a hp up trigger (%f) listener (%s) in a group which is not an NPC group.", threshold
, cbFunc
.c_str());
1235 grpNpc
->delHpUpTrigger(threshold
, cbFunc
);
1238 //----------------------------------------------------------------------------
1241 @subsection addHpDownTrigger_fs_
1242 @sa @ref addHpDownTrigger_ff_
1244 These triggers call a script function instead of trigger a user event.
1246 Arguments: f(threshold),s(callback) ->
1247 @param[in] threshold is a HP threshold
1248 @param[in] callback is the script callback to trigger
1251 ()addHpDownTrigger(0.5, "onHPDecrease");
1256 void addHpDownTrigger_fs_(CStateInstance
* entity
, CScriptStack
& stack
)
1258 std::string cbFunc
= (std::string
)stack
.top();
1260 float threshold
= (float)stack
.top();
1262 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1265 nlwarning("Trying to add a hp down trigger (%f) listener (%s) in a group which is not an NPC group.", threshold
, cbFunc
.c_str());
1268 grpNpc
->addHpDownTrigger(threshold
, cbFunc
);
1271 //----------------------------------------------------------------------------
1274 @subsection delHpDownTrigger_fs_
1275 @sa @ref delHpDownTrigger_ff_
1277 This function is used to remove script function triggers.
1279 Arguments: f(threshold),s(callback) ->
1280 @param[in] threshold is a HP threshold
1281 @param[in] callback is the script callback to trigger
1284 ()delHpDownTrigger(0.5, "onHPDecrease");
1289 void delHpDownTrigger_fs_(CStateInstance
* entity
, CScriptStack
& stack
)
1291 std::string cbFunc
= (std::string
)stack
.top();
1293 float threshold
= (float)stack
.top();
1295 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1298 nlwarning("Trying to delete a hp down trigger (%f) listener (%s) in a group which is not an NPC group.", threshold
, cbFunc
.c_str());
1301 grpNpc
->delHpDownTrigger(threshold
, cbFunc
);
1304 //----------------------------------------------------------------------------
1307 @subsection addNamedEntityListener_ssf_
1308 Associates a listeners with a named entity property. Whenever that field
1309 changes the specified user event is triggered. Valid property names are:
1313 Name of the entity cannot be listened, because it cannot change. Several
1314 listeners (even with the same parameters) can be associated to each property.
1316 Arguments: s(name),s(prop),f(event) ->
1317 @param[in] name is a the name of the named entity to listen
1318 @param[in] prop is a the property of the named entity to listen
1319 @param[in] event is a the user event to trigger
1322 ()addNamedEntityListener("Invasion", "state", 6);
1327 void addNamedEntityListener_ssf_(CStateInstance
* entity
, CScriptStack
& stack
)
1329 int event
= (int)(float)stack
.top();
1331 std::string prop
= (std::string
)stack
.top();
1333 std::string name
= (std::string
)stack
.top();
1336 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1339 nlwarning("Trying to create a named entity (%s:%s) listener (user event %d) in a group which is not an NPC group.", name
.c_str(), prop
.c_str(), event
);
1342 grpNpc
->addNamedEntityListener(name
, prop
, event
);
1345 //----------------------------------------------------------------------------
1348 @subsection delNamedEntityListener_ssf_
1349 Removes a listener from a named entity property. If several listeners with the
1350 same parameters are registered, only one is removed.
1352 Arguments: s(name),s(prop),f(event) ->
1353 @param[in] name is a the name of the named entity to listen
1354 @param[in] prop is a the property of the named entity to listen
1355 @param[in] event is a the user event to trigger
1358 ()delNamedEntityListener("Invasion", "state", 6);
1363 void delNamedEntityListener_ssf_(CStateInstance
* entity
, CScriptStack
& stack
)
1365 int event
= (int)(float)stack
.top();
1367 std::string prop
= (std::string
)stack
.top();
1369 std::string name
= (std::string
)stack
.top();
1372 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1375 nlwarning("Trying to delete a named entity (%s:%s) listener (user event %d) in a group which is not an NPC group.", name
.c_str(), prop
.c_str(), event
);
1378 grpNpc
->delNamedEntityListener(name
, prop
, event
);
1381 //----------------------------------------------------------------------------
1384 @subsection addNamedEntityListener_sss_
1385 @sa @ref addNamedEntityListener_ssf_
1387 These listeners call a script function instead of triggering a user event.
1389 Arguments: s(name),s(prop),s(cbFunc) ->
1390 @param[in] name is a the name of the named entity to listen
1391 @param[in] prop is a the property of the named entity to listen
1392 @param[in] cbFunc is a the callback to trigger
1395 ()addNamedEntityListener("Invasion", "state", "onStateChange");
1400 void addNamedEntityListener_sss_(CStateInstance
* entity
, CScriptStack
& stack
)
1402 std::string cbFunc
= (std::string
)stack
.top();
1404 std::string prop
= (std::string
)stack
.top();
1406 std::string name
= (std::string
)stack
.top();
1409 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1412 nlwarning("Trying to create a named entity (%s:%s) listener (%s) in a group which is not an NPC group.", name
.c_str(), prop
.c_str(), cbFunc
.c_str());
1415 grpNpc
->addNamedEntityListener(name
, prop
, cbFunc
);
1418 //----------------------------------------------------------------------------
1421 @subsection delNamedEntityListener_sss_
1422 @sa @ref delNamedEntityListener_ssf_
1424 This function removes script function listeners.
1426 Arguments: s(name),s(prop),s(cbFunc) ->
1427 @param[in] name is a the name of the named entity to listen
1428 @param[in] prop is a the property of the named entity to listen
1429 @param[in] cbFunc is a the callback to trigger
1432 ()delNamedEntityListener("Invasion", "state", "onStateChange");
1437 void delNamedEntityListener_sss_(CStateInstance
* entity
, CScriptStack
& stack
)
1439 std::string cbFunc
= (std::string
)stack
.top();
1441 std::string prop
= (std::string
)stack
.top();
1443 std::string name
= (std::string
)stack
.top();
1446 CGroupNpc
* const grpNpc
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
1449 nlwarning("Trying to delete a named entity (%s:%s) listener (%s) in a group which is not an NPC group.", name
.c_str(), prop
.c_str(), cbFunc
.c_str());
1452 grpNpc
->delNamedEntityListener(name
, prop
, cbFunc
);
1455 //----------------------------------------------------------------------------
1458 @subsection setPlayerController_ss_
1460 Make a player control a npc.
1462 Arguments: s(botId),s(playerId) ->
1463 @param[in] botId is the entity id of the bot the player will control
1464 @param[in] playerId is the entity id of the player that will control the bot
1467 ()setPlayerController("(0x0002015bb4:01:88:88)", "(0x0000004880:00:00:00)");
1472 void setPlayerController_ss_(CStateInstance
* entity
, CScriptStack
& stack
)
1474 NLMISC::CEntityId playerId
= NLMISC::CEntityId((std::string
)stack
.top());
1476 NLMISC::CEntityId botId
= NLMISC::CEntityId((std::string
)stack
.top());
1478 if (botId
!= NLMISC::CEntityId::Unknown
)
1481 CSpawnBotNpc
* bot
= NULL
;
1482 CAIEntityPhysicalLocator
*inst
= CAIEntityPhysicalLocator::getInstance();
1485 CAIEntityPhysical
*botEntity
= inst
->getEntity(botId
);
1488 if ((bot
= dynamic_cast<CSpawnBotNpc
*>(botEntity
)) && (&bot
->getPersistent().getGroup())==entity
->getGroup())
1490 if (playerId
!= NLMISC::CEntityId::Unknown
)
1492 CAIEntityPhysical
*playerEntity
= inst
->getEntity(playerId
);
1493 CBotPlayer
* player
= NULL
;
1494 if (playerEntity
&& (player
= dynamic_cast<CBotPlayer
*>(playerEntity
)))
1495 bot
->setPlayerController(player
);
1498 bot
->setPlayerController(NULL
);
1502 nlwarning("Bot entity not found");
1505 nlwarning("Instance not found");
1509 //----------------------------------------------------------------------------
1512 @subsection clearPlayerController_s_
1514 Stop the control of a npc by a player.
1516 Arguments: s(botId) ->
1517 @param[in] botId is the entity id of the bot
1520 ()clearPlayerController("(0x0002015bb4:01:88:88)");
1525 void clearPlayerController_s_(CStateInstance
* entity
, CScriptStack
& stack
)
1527 NLMISC::CEntityId botId
= NLMISC::CEntityId((std::string
)stack
.top());
1529 if (botId
!=NLMISC::CEntityId::Unknown
)
1532 CSpawnBotNpc
* bot
= NULL
;
1533 if ((bot
= dynamic_cast<CSpawnBotNpc
*>(CAIEntityPhysicalLocator::getInstance()->getEntity(botId
)))
1534 && (&bot
->getPersistent().getGroup())==entity
->getGroup())
1536 bot
->setPlayerController(NULL
);
1541 //----------------------------------------------------------------------------
1544 @subsection activateEasterEgg_fffsffffsss_
1546 Call the EGS function CCharacterControl::activateEasterEgg
1548 Arguments: f(easterEggId), f(scenarioId), f(actId), s(items), f(x), f(y), f(z),f(heading), f(groupname), f(name), f(clientSheet)->
1549 @param[in] items is the sheet/quantity vector (a string of format "item1:qty1;item2:qty2;...")
1552 ()activateEasterEgg(2, 1601, 4, "toto.sitem:2;tata.sitem:1;titi.sitem:3", 1247, 4627, 0, 0);
1556 void activateEasterEgg_fffsffffsss_(CStateInstance
* si
, CScriptStack
& stack
)
1558 std::string clientSheet
= (std::string
)stack
.top(); stack
.pop();
1559 std::string name
= (std::string
)stack
.top(); stack
.pop();
1560 std::string grpCtrl
= (std::string
)stack
.top(); stack
.pop();
1561 float heading
= (float)stack
.top(); stack
.pop();
1562 float z
= (float)stack
.top(); stack
.pop();
1563 float y
= (float)stack
.top(); stack
.pop();
1564 float x
= (float)stack
.top(); stack
.pop();
1566 string items
= (string
)stack
.top(); stack
.pop();
1567 uint32 actId
= static_cast<uint32
>( (float)stack
.top()); stack
.pop();
1568 TSessionId
scenarioId( static_cast<uint32
>( (float)stack
.top())); stack
.pop();
1569 uint32 easterEgg
= static_cast<uint32
>( (float)stack
.top()); stack
.pop();
1571 IAisControl::getInstance()->activateEasterEgg(easterEgg
, scenarioId
, actId
, items
, x
, y
, z
, heading
, grpCtrl
, name
, clientSheet
);
1574 //----------------------------------------------------------------------------
1577 @subsection deactivateEasterEgg_fff_
1579 Call the EGS function CCharacterControl::deactivateEasterEgg
1581 Arguments: f(easterEggId), f(scenarioId), f(actId) ->
1584 ()deactivateEasterEgg(0, 4);
1588 void deactivateEasterEgg_fff_(CStateInstance
* si
, CScriptStack
& stack
)
1590 uint32 actId
= static_cast<uint32
>( (float)stack
.top()); stack
.pop();
1591 TSessionId
scenarioId( static_cast<uint32
>( (float)stack
.top())); stack
.pop();
1592 uint32 easterEgg
= static_cast<uint32
>( (float)stack
.top()); stack
.pop();
1594 IAisControl::getInstance()->deactivateEasterEgg(easterEgg
, scenarioId
, actId
);
1597 //----------------------------------------------------------------------------
1600 @subsection receiveMissionItems_ssc_
1602 The npc will ask mission items to the targeter player.
1604 A new entry of the npc contextual menu will propose to the targeter player
1605 to give mission items to the npc if he has the requested items.
1607 Then user events are triggered on the group to inform it about what happens:
1608 - user_event_1: triggered if the player has the requested mission items.
1609 - user_event_2: triggered if the player hasn't the requested mission items.
1610 - user_event_3: triggered after the player has given the mission items to the npc.
1612 Warning: this function can only be called after the event "player_target_npc".
1614 Arguments: s(missionItems), s(missionText), c(groupToNotify) ->
1615 @param[in] missionItems is the list of mission items, the string format is "item1:qty1;item2:qty2;...".
1616 @param[in] missionText is the text which will appear in the npc contextual menu.
1617 @param[in] groupToNotify is the npc group which will receive the user events.
1620 (@groupToNotify)group_name.context();
1621 ()receiveMissionItems("toto.sitem:2;tata.sitem:1;titi.sitem:3", "Mission text", @groupToNotify);
1626 void receiveMissionItems_ssc_(CStateInstance
* entity
, CScriptStack
& stack
)
1628 CGroupNpc
* const groupToNotify
= dynamic_cast<CGroupNpc
*>( (IScriptContext
*)stack
.top() );
1630 string missionText
= (string
)stack
.top();
1632 string missionItems
= (string
)stack
.top();
1635 if (groupToNotify
== NULL
)
1637 nlwarning("receiveMissionItems failed: groupToNotify is NULL");
1642 if (missionItems
.empty())
1644 nlwarning("receiveMissionItems failed: missionItems is empty");
1649 nlassert(entity
!= NULL
);
1650 CGroup
* const group
= entity
->getGroup();
1651 IManagerParent
* const managerParent
= group
->getOwner()->getOwner();
1652 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
1653 if (aiInstance
== NULL
)
1655 nlwarning("receiveMissionItems failed: the AI instance of the entity is NULL");
1660 CBotPlayer
* const talkingPlayer
= TempPlayer
;
1661 CSpawnBotNpc
* const talkingNpc
= dynamic_cast<CSpawnBotNpc
*>(TempSpeaker
);
1662 if ( talkingPlayer
== NULL
1663 || talkingNpc
== NULL
1664 || talkingNpc
->getPersistent().getOwner() != group
) // check if the talking npc is in this group
1666 nlwarning("receiveMissionItems failed: invalid interlocutors");
1671 // do nothing if one of them is dead
1672 if (!talkingPlayer
->isAlive() || !talkingNpc
->isAlive())
1677 // turn the npc to face the player
1678 talkingNpc
->setTheta(talkingNpc
->pos().angleTo(talkingPlayer
->pos()));
1680 // send the request to the EGS
1681 CGiveItemRequestMsg msg
;
1682 msg
.InstanceId
= aiInstance
->getInstanceNumber();
1683 msg
.GroupAlias
= groupToNotify
->getAlias();
1684 msg
.CharacterRowId
= talkingPlayer
->dataSetRow();
1685 msg
.CreatureRowId
= talkingNpc
->dataSetRow();
1686 msg
.MissionText
= missionText
;
1688 // extract items and quantities from the missionItems string
1689 std::vector
<std::string
> itemAndQtyList
;
1690 NLMISC::splitString(missionItems
, ";", itemAndQtyList
);
1691 if (itemAndQtyList
.empty())
1693 nlwarning("receiveMissionItems failed: the provided mission items string is invalid");
1697 FOREACHC(it
, std::vector
<std::string
>, itemAndQtyList
)
1699 std::vector
<std::string
> itemAndQty
;
1700 NLMISC::splitString(*it
, ":", itemAndQty
);
1701 if (itemAndQty
.size() != 2)
1703 nlwarning("receiveMissionItems failed: the provided mission items string is invalid");
1708 const CSheetId
sheetId(itemAndQty
[0]);
1709 if (sheetId
== CSheetId::Unknown
)
1711 nlwarning("receiveMissionItems failed: invalid mission item sheet '%s'", itemAndQty
[0].c_str());
1715 // if LD use this the function outside a ring shard
1718 // Here we destroy the item: so we do not want that a user create a scenario where we destroy
1719 // other players precious items
1721 static std::set
<CSheetId
> r2PlotItemSheetId
; // :TODO: use R2Share::CRingAccess
1722 // lazy intialisation
1723 if (r2PlotItemSheetId
.empty())
1725 for (uint32 i
= 0 ; i
<= 184 ; ++i
)
1727 r2PlotItemSheetId
.insert( CSheetId( NLMISC::toString("r2_plot_item_%d.sitem", i
)));
1731 // A npc give a mission to take an item given by another npc
1732 // but the item instead of being a r2_plot_item is a normal item like system_mp or big armor
1733 if ( r2PlotItemSheetId
.find(sheetId
) == r2PlotItemSheetId
.end())
1735 nlwarning("!!!!!!!!!!!!");
1736 nlwarning("!!!!!!!!!!!! Someone is trying to hack us");
1737 nlwarning("!!!!!!!!!!!!");
1738 nlwarning("ERROR/HACK : an npc is trying to give to a player a item that is not a plot item SheetId='%s' sheetIdAsInt=%u",sheetId
.toString().c_str(), sheetId
.asInt());
1739 nlwarning("His ai instanceId is %u, use log to know the sessionId and the user ", msg
.InstanceId
);
1740 nlwarning("!!!!!!!!!!!!");
1741 nlwarning("!!!!!!!!!!!!");
1747 NLMISC::fromString(itemAndQty
[1], quantity
);
1750 nlwarning("receiveMissionItems failed: invalid quantity '%s'", itemAndQty
[1].c_str());
1755 msg
.Items
.push_back(sheetId
);
1756 msg
.Quantities
.push_back(quantity
);
1758 nlassert(!msg
.Items
.empty());
1759 nlassert(msg
.Items
.size() == msg
.Quantities
.size());
1764 //----------------------------------------------------------------------------
1767 @subsection giveMissionItems_ssc_
1769 The npc will give mission items to the targeter player.
1771 A new entry of the npc contextual menu will propose to the targeter player
1772 to receive mission items from the npc.
1774 Then user events are triggered on the group to inform it about what happens:
1775 - user_event_1: triggered after the player has received the mission items from the npc.
1777 Warning: this function can only be called after the event "player_target_npc".
1779 Arguments: s(missionItems), s(missionText), c(groupToNotify) ->
1780 @param[in] missionItems is the list of mission items, the string format is "item1:qty1;item2:qty2;...".
1781 @param[in] missionText is the text which will appear in the npc contextual menu.
1782 @param[in] groupToNotify is the npc group which will receive the user events.
1785 (@groupToNotify)group_name.context();
1786 ()giveMissionItems("toto.sitem:2;tata.sitem:1;titi.sitem:3", "Mission text", @groupToNotify);
1791 void giveMissionItems_ssc_(CStateInstance
* entity
, CScriptStack
& stack
)
1793 CGroupNpc
* const groupToNotify
= dynamic_cast<CGroupNpc
*>( (IScriptContext
*)stack
.top() );
1795 string missionText
= (string
)stack
.top();
1797 string missionItems
= (string
)stack
.top();
1800 if (groupToNotify
== NULL
)
1802 nlwarning("giveMissionItems failed: groupToNotify is NULL");
1807 if (missionItems
.empty())
1809 nlwarning("giveMissionItems failed: missionItems is empty");
1814 nlassert(entity
!= NULL
);
1815 CGroup
* const group
= entity
->getGroup();
1816 IManagerParent
* const managerParent
= group
->getOwner()->getOwner();
1817 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
1818 if (aiInstance
== NULL
)
1820 nlwarning("giveMissionItems failed: the AI instance of the entity is NULL");
1825 CBotPlayer
* const talkingPlayer
= TempPlayer
;
1826 CSpawnBotNpc
* const talkingNpc
= dynamic_cast<CSpawnBotNpc
*>(TempSpeaker
);
1827 if ( talkingPlayer
== NULL
1828 || talkingNpc
== NULL
1829 || talkingNpc
->getPersistent().getOwner() != group
) // check if the talking npc is in this group
1831 nlwarning("giveMissionItems failed: invalid interlocutors");
1836 // do nothing if one of them is dead
1837 if (!talkingPlayer
->isAlive() || !talkingNpc
->isAlive())
1842 // turn the npc to face the player
1843 talkingNpc
->setTheta(talkingNpc
->pos().angleTo(talkingPlayer
->pos()));
1845 // send the request to the EGS
1846 CReceiveItemRequestMsg msg
;
1847 msg
.InstanceId
= aiInstance
->getInstanceNumber();
1848 msg
.GroupAlias
= groupToNotify
->getAlias();
1849 msg
.CharacterRowId
= talkingPlayer
->dataSetRow();
1850 msg
.CreatureRowId
= talkingNpc
->dataSetRow();
1851 msg
.MissionText
= missionText
;
1853 // extract items and quantities from the missionItems string
1854 std::vector
<std::string
> itemAndQtyList
;
1855 NLMISC::splitString(missionItems
, ";", itemAndQtyList
);
1856 if (itemAndQtyList
.empty())
1858 nlwarning("giveMissionItems failed: the provided mission items string is invalid");
1862 FOREACHC(it
, std::vector
<std::string
>, itemAndQtyList
)
1864 std::vector
<std::string
> itemAndQty
;
1865 NLMISC::splitString(*it
, ":", itemAndQty
);
1866 if (itemAndQty
.size() != 2)
1868 nlwarning("giveMissionItems failed: the provided mission items string is invalid");
1873 const CSheetId
sheetId(itemAndQty
[0]);
1874 if (sheetId
== CSheetId::Unknown
)
1876 nlwarning("giveMissionItems failed: invalid mission item sheet '%s'", itemAndQty
[0].c_str());
1882 // if LD use this the function outside a ring shard
1885 static std::set
<CSheetId
> r2PlotItemSheetId
; // :TODO: use R2Share::CRingAccess
1886 // lazy intialisation
1887 if (r2PlotItemSheetId
.empty())
1889 for (uint32 i
= 0 ; i
<= 184 ; ++i
)
1891 r2PlotItemSheetId
.insert( CSheetId( NLMISC::toString("r2_plot_item_%d.sitem", i
)));
1895 // A npc give a mission to give a item to another npc
1896 // but the item instead of being a r2_plot_item is a normal item like system_mp or big armor
1897 if ( r2PlotItemSheetId
.find(sheetId
) == r2PlotItemSheetId
.end())
1899 nlwarning("!!!!!!!!!!!!");
1900 nlwarning("!!!!!!!!!!!! Someone is trying to hack us");
1901 nlwarning("!!!!!!!!!!!!");
1902 nlwarning("ERROR/HACK : an npc is trying to give to a player a item that is not a plot item SheetId='%s' sheetIdAsInt=%u",sheetId
.toString().c_str(), sheetId
.asInt());
1903 nlwarning("His ai instanceId is %u, use log to know the sessionId and the user ", msg
.InstanceId
);
1904 nlwarning("!!!!!!!!!!!!");
1905 nlwarning("!!!!!!!!!!!!");
1912 NLMISC::fromString(itemAndQty
[1], quantity
);
1915 nlwarning("giveMissionItems failed: invalid quantity '%s'", itemAndQty
[1].c_str());
1920 msg
.Items
.push_back(sheetId
);
1921 msg
.Quantities
.push_back(quantity
);
1923 nlassert(!msg
.Items
.empty());
1924 nlassert(msg
.Items
.size() == msg
.Quantities
.size());
1929 //----------------------------------------------------------------------------
1932 @subsection talkTo_sc_
1934 A new entry of the npc contextual menu will propose to the targeter player to talk to the npc.
1936 Then user events are triggered on the group to inform it about what happens:
1937 - user_event_1: triggered each time (because of the TRICK).
1938 - user_event_3: triggered after the player has talked to the npc.
1940 Warning: this function can only be called after the event "player_target_npc".
1942 Arguments: s(missionText), c(groupToNotify) ->
1943 @param[in] missionText is the text which will appear in the npc contextual menu.
1944 @param[in] groupToNotify is the npc group which will receive the user events.
1947 (@groupToNotify)group_name.context();
1948 ()talkTo("Mission text", @groupToNotify);
1953 void talkTo_sc_(CStateInstance
* entity
, CScriptStack
& stack
)
1955 CGroupNpc
* const groupToNotify
= dynamic_cast<CGroupNpc
*>( (IScriptContext
*)stack
.top() );
1957 string missionText
= (string
)stack
.top();
1960 if (groupToNotify
== NULL
)
1962 nlwarning("talkTo failed: groupToNotify is NULL");
1967 nlassert(entity
!= NULL
);
1968 CGroup
* const group
= entity
->getGroup();
1969 IManagerParent
* const managerParent
= group
->getOwner()->getOwner();
1970 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
1971 if (aiInstance
== NULL
)
1973 nlwarning("talkTo failed: the AI instance of the entity is NULL");
1978 CBotPlayer
* const talkingPlayer
= TempPlayer
;
1979 CSpawnBotNpc
* const talkingNpc
= dynamic_cast<CSpawnBotNpc
*>(TempSpeaker
);
1980 if ( talkingPlayer
== NULL
1981 || talkingNpc
== NULL
1982 || talkingNpc
->getPersistent().getOwner() != group
) // check if the talking npc is in this group
1984 nlwarning("talkTo failed: invalid interlocutors");
1989 // do nothing if one of them is dead
1990 if (!talkingPlayer
->isAlive() || !talkingNpc
->isAlive())
1995 // turn the npc to face the player
1996 talkingNpc
->setTheta(talkingNpc
->pos().angleTo(talkingPlayer
->pos()));
1998 // send the request to the EGS
1999 // TRICK: here we use an empty give item request
2000 CGiveItemRequestMsg msg
;
2001 msg
.InstanceId
= aiInstance
->getInstanceNumber();
2002 msg
.GroupAlias
= groupToNotify
->getAlias();
2003 msg
.CharacterRowId
= talkingPlayer
->dataSetRow();
2004 msg
.CreatureRowId
= talkingNpc
->dataSetRow();
2005 msg
.MissionText
= missionText
;
2006 nlassert(msg
.Items
.empty());
2007 nlassert(msg
.Quantities
.empty());
2014 void giveReward_ssssc_(CStateInstance
* entity
, CScriptStack
& stack
)
2016 CGroupNpc
* const groupToNotify
= dynamic_cast<CGroupNpc
*>( (IScriptContext
*)stack
.top() );
2019 string notEnoughPointsText
= (string
)stack
.top();
2022 string inventoryFullText
= (string
)stack
.top();
2025 string rareRewardText
= (string
)stack
.top();
2028 string rewardText
= (string
)stack
.top();
2032 if (groupToNotify
== NULL
)
2034 nlwarning("giveReward failed: groupToNotify is NULL");
2039 nlassert(entity
!= NULL
);
2040 CGroup
* const group
= entity
->getGroup();
2041 IManagerParent
* const managerParent
= group
->getOwner()->getOwner();
2042 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
2043 if (aiInstance
== NULL
)
2045 nlwarning("giveReward failed: the AI instance of the entity is NULL");
2050 CEntityId
charEid(group
->getEventParamString(0)); // must be player char EID
2051 CEntityId
npcEid(group
->getEventParamString(1)); // must be NPC EID
2053 if (charEid
== CEntityId::Unknown
|| npcEid
== CEntityId::Unknown
)
2055 nlwarning("giveReward failed: the chareter or npc can't be retrreived from the event parameter");
2060 // retrieve the CBotPlayer
2061 CAIEntityPhysical
*charEntity
=CAIS::instance().getEntityPhysical(TheDataset
.getDataSetRow(charEid
));
2064 CBotPlayer
*talkingPlayer
=NLMISC::safe_cast
<CBotPlayer
*>(charEntity
);
2068 // retrieve the CSpawnBotNpcBotPlayer
2069 CAIEntityPhysical
*npcEntity
=CAIS::instance().getEntityPhysical(TheDataset
.getDataSetRow(npcEid
));
2072 CSpawnBotNpc
*talkingNpc
=NLMISC::safe_cast
<CSpawnBotNpc
*>(npcEntity
);
2076 // CBotPlayer* const talkingPlayer = TempPlayer;
2077 // CSpawnBotNpc* const talkingNpc = dynamic_cast<CSpawnBotNpc*>(TempSpeaker);
2078 if ( talkingPlayer
== NULL
2079 || talkingNpc
== NULL
)
2081 nlwarning("giveReward failed: invalid interlocutors");
2086 // do nothing if one of them is dead
2087 if (!talkingPlayer
->isAlive() || !talkingNpc
->isAlive())
2092 // turn the npc to face the player
2093 talkingNpc
->setTheta(talkingNpc
->pos().angleTo(talkingPlayer
->pos()));
2095 TDataSetRow CharacterRowId
= talkingPlayer
->dataSetRow();
2096 TDataSetRow CreatureRowId
= talkingNpc
->dataSetRow();
2098 IAisControl::getInstance()->giveRewardMessage(CharacterRowId
, CreatureRowId
,
2099 rewardText
, rareRewardText
, inventoryFullText
, notEnoughPointsText
);
2108 void teleportNear_fffc_(CStateInstance
* entity
, CScriptStack
& stack
)
2110 CGroupNpc
* const groupToNotify
= dynamic_cast<CGroupNpc
*>( (IScriptContext
*)stack
.top() );
2113 float z
= (float)stack
.top(); stack
.pop();
2114 float y
= (float)stack
.top(); stack
.pop();
2115 float x
= (float)stack
.top(); stack
.pop();
2118 if (groupToNotify
== NULL
)
2120 nlwarning("teleportNear failed: groupToNotify is NULL");
2125 nlassert(entity
!= NULL
);
2126 CGroup
* const group
= entity
->getGroup();
2127 IManagerParent
* const managerParent
= group
->getOwner()->getOwner();
2128 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
2129 if (aiInstance
== NULL
)
2131 nlwarning("giveReward failed: the AI instance of the entity is NULL");
2136 CEntityId
charEid(group
->getEventParamString(0)); // must be player char EID
2137 CEntityId
npcEid(group
->getEventParamString(1)); // must be NPC EID
2139 if (charEid
== CEntityId::Unknown
|| npcEid
== CEntityId::Unknown
)
2141 nlwarning("giveReward failed: the character or npc can't be retreived from the event parameter");
2146 // retrieve the CBotPlayer
2147 CAIEntityPhysical
*charEntity
=CAIS::instance().getEntityPhysical(TheDataset
.getDataSetRow(charEid
));
2150 CBotPlayer
*talkingPlayer
=NLMISC::safe_cast
<CBotPlayer
*>(charEntity
);
2154 // retrieve the CSpawnBotNpcBotPlayer
2155 CAIEntityPhysical
*npcEntity
=CAIS::instance().getEntityPhysical(TheDataset
.getDataSetRow(npcEid
));
2158 CSpawnBotNpc
*talkingNpc
=NLMISC::safe_cast
<CSpawnBotNpc
*>(npcEntity
);
2162 // CBotPlayer* const talkingPlayer = TempPlayer;
2163 // CSpawnBotNpc* const talkingNpc = dynamic_cast<CSpawnBotNpc*>(TempSpeaker);
2164 if ( talkingPlayer
== NULL
2165 || talkingNpc
== NULL
)
2167 nlwarning("giveReward failed: invalid interlocutors");
2172 // do nothing if one of them is dead
2173 if (!talkingPlayer
->isAlive() || !talkingNpc
->isAlive())
2178 // turn the npc to face the player
2179 /// talkingNpc->setTheta(talkingNpc->pos().angleTo(talkingPlayer->pos()));
2181 TDataSetRow CharacterRowId
= talkingPlayer
->dataSetRow();
2182 TDataSetRow CreatureRowId
= talkingNpc
->dataSetRow();
2184 NLMISC::CEntityId player
= CMirrors::getEntityId(CharacterRowId
);
2185 if (player
!= NLMISC::CEntityId::Unknown
)
2187 IAisControl::getInstance()->teleportNearMessage(player
, x
, y
, z
);
2196 // Return an "alive" bot from a group by the bot name
2197 static CSpawnBot
* getSpawnBotFromGroupByName(CGroupNpc
* const group
, const std::string
& botname
)
2200 if (!group
) { return 0; }
2202 // Group is in a valid AIInstance
2204 if (!group
->getOwner()) { return 0; }
2205 IManagerParent
* const managerParent
= group
->getOwner()->getOwner();
2206 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
2207 if (!aiInstance
) { return 0; }
2210 // Bot is spawn and alive
2213 CSpawnBot
* spawnBot
=0;
2214 CAliasCont
<CBot
> const& bots
= group
->bots();
2215 CCont
<CBot
> & cc_bots
= group
->bots();
2218 child
= bots
.getFirstChild();
2220 child
= bots
.getChildByName(botname
);
2221 if (!child
) { return 0; }
2223 spawnBot
= child
->getSpawnObj();
2224 if (!spawnBot
|| !spawnBot
->isAlive()) { return 0; }
2228 nlassert(0); //this path is never used
2232 //----------------------------------------------------------------------------
2235 @subsection facing_cscs_
2237 The npc1 will turn to npc2
2240 Arguments: c(group1), s(botname1), c(group2), s(botname2), ->
2241 @param[in] group1 is the npc group of the boot that turn to the other bot
2242 @param[in] botname1 is the name of the bot
2243 @param[in] group2 is the npc group of the boot that is the target
2244 @param[in] botname2 is the name of the bot that is targeted
2248 (@group1)group_name1.context();
2249 (@group2)group_name2.context();
2250 ()facing(@group1, "bob", @group2, "bobette");
2258 void facing_cscs_(CStateInstance
* entity
, CScriptStack
& stack
)
2260 string botname2
= (string
)stack
.top(); stack
.pop();
2261 CGroupNpc
* const group2
= dynamic_cast<CGroupNpc
*>( (IScriptContext
*)stack
.top() ); stack
.pop();
2262 string botname1
= (string
)stack
.top(); stack
.pop();
2263 CGroupNpc
* const group1
= dynamic_cast<CGroupNpc
*>( (IScriptContext
*)stack
.top() ); stack
.pop();
2265 CSpawnBot
* bot1
= getSpawnBotFromGroupByName(group1
, botname1
);
2266 CSpawnBot
* bot2
= getSpawnBotFromGroupByName(group2
, botname2
);
2268 if (!bot1
|| !bot2
) { return; }
2270 CSpawnBotNpc
* bot
= dynamic_cast<CSpawnBotNpc
*>(bot1
);
2271 if (!bot
) { return; }
2272 // Same than setTheta but initial theta is restored few secondes later
2273 bot
->setFacing(bot1
->pos().angleTo(bot2
->pos()));
2274 // bot1->setTheta(bot1->pos().angleTo(bot2->pos()));
2277 //----------------------------------------------------------------------------
2280 @subsection npcSay_css_
2282 Make a npc say a text
2284 There are 3 type of text
2285 - Classic StringId (IOS does traduction)
2286 - RING "complete text (no traduction)
2287 - RING StringId (DSS does traduction)
2289 Arguments: c(group), s(botname), s(text), ->
2290 @param[in] group is the npc group of the boot that does the emote
2291 @param[in] botname is the name of the bot
2292 @param[in] text is the name of the emote
2295 (@group)group_name.context();
2296 ()npcSay(@group, "bob", "DSS_1601 RtEntryText_6") ;// Send To dss
2297 ()npcSay(@group, "bob", "RAW Ca farte?"); // phrase direcly send to IOS as raw (for debug)
2298 ()npcSay(@group, "bob", "answer_group_no_m"); //phrase id
2306 #include "game_share/chat_group.h"
2307 #include "game_share/send_chat.h"
2309 void execSayHelper(CSpawnBot
*spawnBot
, NLMISC::CSString text
, CChatGroup::TGroupType mode
= CChatGroup::say
)
2313 NLMISC::CSString prefix
= text
.left(4);
2317 NLMISC::CSString phrase
= text
.right(text
.length() - 4);
2318 NLMISC::CSString idStr
= phrase
.strtok(" ",false,false,false,false);
2319 uint32 scenarioId
= atoi(idStr
.c_str());
2320 forwardToDss(spawnBot
->dataSetRow(), mode
, phrase
, scenarioId
);
2326 std::string phrase
= text
.right(text
.length()-4);
2327 ucstring ucstr
= phrase
;
2328 npcChatToChannelSentence(spawnBot
->dataSetRow(), mode
, ucstr
);
2333 npcChatToChannel(spawnBot
->dataSetRow(), mode
, text
);
2337 void npcSay_css_(CStateInstance
* entity
, CScriptStack
& stack
)
2339 string text
= (string
)stack
.top(); stack
.pop();
2340 string botname
= (string
)stack
.top(); stack
.pop();
2341 CGroupNpc
* const group
= dynamic_cast<CGroupNpc
*>( (IScriptContext
*)stack
.top() ); stack
.pop();
2343 CSpawnBot
* spawnBot
= getSpawnBotFromGroupByName(group
, botname
);
2345 if (!spawnBot
) { return; }
2347 execSayHelper(spawnBot
, text
);
2350 //----------------------------------------------------------------------------
2353 @subsection npcSay_ss_
2355 Make a npc say a text
2357 Arguments: s(text), s(mode) ->
2358 @param[in] text is the text to say. prefix with ID: to use an id
2359 @param[in] mode is the mode to use (say, shout)
2362 ()npcSay("Hello!","say"); // phrase direcly send to IOS as raw
2363 ()npcSay("ID:answer_group_no_m","shout"); // phrase id
2368 void npcSay_ss_(CStateInstance
* entity
, CScriptStack
& stack
)
2370 std::string sMode
= (std::string
)stack
.top(); stack
.pop();
2371 std::string text
= (std::string
)stack
.top(); stack
.pop();
2373 CChatGroup::TGroupType mode
= CChatGroup::say
;
2374 mode
= CChatGroup::stringToGroupType(sMode
);
2375 CGroup
* group
= entity
->getGroup();
2377 if (group
->isSpawned())
2379 FOREACH(itBot
, CCont
<CBot
>, group
->bots())
2384 if (bot
->isSpawned())
2386 CSpawnBot
*spawnBot
= bot
->getSpawnObj();
2387 std::string prefix
= NLMISC::CSString(text
).left(3);
2388 if (NLMISC::nlstricmp(prefix
.c_str(), "id:") == 0) {
2389 text
= NLMISC::CSString(text
).right(text
.length()-3);
2390 execSayHelper(spawnBot
, text
, mode
);
2393 execSayHelper(spawnBot
, "RAW " + text
, mode
);
2403 //----------------------------------------------------------------------------
2406 @subsection deactivateEasterEgg_fff_
2408 Call the DSS function CAnimationModule::dssMessage
2410 Arguments: f(easterEggId), f(scenarioId), f(actId) ->
2413 ()dssMessage(114, "BC", "Bob", "Life is harde");
2418 void dssMessage_fsss_(CStateInstance
* entity
, CScriptStack
& stack
)
2420 string msg
= (string
)stack
.top(); stack
.pop();
2421 string who
= (string
)stack
.top(); stack
.pop();
2422 string mode
= (string
)stack
.top(); stack
.pop();
2423 float instance
= (float)stack
.top(); stack
.pop();
2425 IAisControl::getInstance()->dssMessage(TSessionId(uint32(instance
)), mode
, who
, msg
);
2430 //----------------------------------------------------------------------------
2433 @subsection setScenarioPoints
2435 Call the DSS function CAnimationModule::setScenarioPoints
2437 Arguments: f(scenarioInstance), f(scenarioPoints) ->
2440 ()setScenarioPoints(114, 42);
2445 void setScenarioPoints_ff_(CStateInstance
* entity
, CScriptStack
& stack
)
2447 float scenarioPoints
= (float)stack
.top(); stack
.pop();
2448 float instance
= (float)stack
.top(); stack
.pop();
2450 IAisControl::getInstance()->setScenarioPoints(TSessionId(uint32(instance
)), scenarioPoints
);
2454 //----------------------------------------------------------------------------
2457 @subsection startScenarioTiming
2459 Call the DSS function CAnimationModule::startScenarioTiming
2461 Arguments: f(scenarioInstance),
2464 ()startScenarioTiming(114, 42);
2469 void startScenarioTiming_f_(CStateInstance
* entity
, CScriptStack
& stack
)
2471 float instance
= (float)stack
.top(); stack
.pop();
2473 IAisControl::getInstance()->startScenarioTiming(TSessionId(uint32(instance
)));
2477 //----------------------------------------------------------------------------
2480 @subsection endScenarioTiming
2482 Call the DSS function CAnimationModule::endScenarioTiming
2484 Arguments: f(scenarioInstance),
2487 ()endScenarioTiming(114, 42);
2492 void endScenarioTiming_f_(CStateInstance
* entity
, CScriptStack
& stack
)
2494 float instance
= (float)stack
.top(); stack
.pop();
2496 IAisControl::getInstance()->endScenarioTiming(TSessionId(uint32(instance
)));
2500 //----------------------------------------------------------------------------
2503 @subsection emote_css_
2505 Make a npc launch a emote
2508 Arguments: c(group1), s(botname1), c(group2), s(botname2), ->
2509 @param[in] group1 is the npc group of the boot that does the emote
2510 @param[in] botname1 is the name of the bot
2511 @param[in] emote is the name of the emote
2515 (@group1)group_name.context();
2516 ()emote(@group1, "bob", "sad")
2523 /****************************************************************************/
2525 void emote_css_(CStateInstance
* entity
, CScriptStack
& stack
)
2527 string emoteName
= (string
)stack
.top(); stack
.pop();
2528 string botname
= (string
)stack
.top(); stack
.pop();
2529 CGroupNpc
* const group
= dynamic_cast<CGroupNpc
*>( (IScriptContext
*)stack
.top() ); stack
.pop();
2531 CSpawnBot
* spawnBot
= getSpawnBotFromGroupByName(group
, botname
);
2533 if (!spawnBot
) { return; }
2535 //CBot& bot = spawnBot->getPersistent();
2537 // The entity Id must be valid (we know that the bot is alive so its entity Id must be ok)
2538 NLMISC::CEntityId entityId
=spawnBot
->getEntityId();
2539 if (entityId
== NLMISC::CEntityId::Unknown
)
2544 // Is the emote valid
2545 uint32 emoteId
= CAIS::instance().getEmotNumber(emoteName
);
2546 if (emoteId
== std::numeric_limits
<uint32
>::max())
2551 // Get the behaviour Id
2552 MBEHAV::EBehaviour behaviourId
= (MBEHAV::EBehaviour
)(emoteId
+ MBEHAV::EMOTE_BEGIN
);
2554 // Change the behaviour
2555 NLNET::CMessage
msgout("SET_BEHAVIOUR");
2556 msgout
.serial(entityId
);
2557 MBEHAV::CBehaviour
bh(behaviourId
);
2558 bh
.Data
= (uint16
)(CTimeInterface::gameCycle());
2561 NLNET::CUnifiedNetwork::getInstance()->send( "EGS", msgout
);
2565 void emote_ss_(CStateInstance
* entity
, CScriptStack
& stack
)
2567 string emoteName
= (string
)stack
.top(); stack
.pop();
2568 NLMISC::CEntityId botId
= NLMISC::CEntityId((std::string
)stack
.top());
2570 if (botId
== NLMISC::CEntityId::Unknown
)
2575 // Is the emote valid
2576 uint32 emoteId
= CAIS::instance().getEmotNumber(emoteName
);
2577 if (emoteId
== std::numeric_limits
<uint32
>::max())
2582 // Get the behaviour Id
2583 MBEHAV::EBehaviour behaviourId
= (MBEHAV::EBehaviour
)(emoteId
+ MBEHAV::EMOTE_BEGIN
);
2585 // Change the behaviour
2586 NLNET::CMessage
msgout("SET_BEHAVIOUR");
2587 msgout
.serial(botId
);
2588 MBEHAV::CBehaviour
bh(behaviourId
);
2589 bh
.Data
= (uint16
)(CTimeInterface::gameCycle());
2592 NLNET::CUnifiedNetwork::getInstance()->send( "EGS", msgout
);
2597 void emote_s_(CStateInstance
* entity
, CScriptStack
& stack
)
2599 string emoteName
= (string
)stack
.top(); stack
.pop();
2601 // Is the emote valid
2602 uint32 emoteId
= CAIS::instance().getEmotNumber(emoteName
);
2603 if (emoteId
== std::numeric_limits
<uint32
>::max())
2606 // Get the behaviour Id
2607 MBEHAV::EBehaviour behaviourId
= (MBEHAV::EBehaviour
)(emoteId
+ MBEHAV::EMOTE_BEGIN
);
2610 CGroup
* group
= entity
->getGroup();
2612 if (group
->isSpawned())
2614 FOREACH(itBot
, CCont
<CBot
>, group
->bots())
2619 // Change the behaviour
2620 if (bot
->isSpawned())
2622 CSpawnBot
*spawnBot
= bot
->getSpawnObj();
2625 CEntityId botId
= spawnBot
->getEntityId();
2626 NLNET::CMessage
msgout("SET_BEHAVIOUR");
2627 msgout
.serial(botId
);
2628 MBEHAV::CBehaviour
bh(behaviourId
);
2629 bh
.Data
= (uint16
)(CTimeInterface::gameCycle());
2632 NLNET::CUnifiedNetwork::getInstance()->send( "EGS", msgout
);
2641 void rename_s_(CStateInstance
* entity
, CScriptStack
& stack
)
2643 string newName
= (string
)stack
.top(); stack
.pop();
2645 name
.fromUtf8(newName
);
2646 CGroup
* group
= entity
->getGroup();
2648 if (group
->isSpawned())
2650 FOREACH(itBot
, CCont
<CBot
>, group
->bots())
2655 if (bot
->isSpawned())
2657 CSpawnBot
*spawnBot
= bot
->getSpawnObj();
2660 TDataSetRow row
= spawnBot
->dataSetRow();
2661 NLNET::CMessage
msgout("CHARACTER_NAME");
2663 msgout
.serial(name
);
2664 sendMessageViaMirror("IOS", msgout
);
2665 spawnBot
->getPersistent().setCustomName(name
);
2674 void vpx_s_(CStateInstance
* entity
, CScriptStack
& stack
)
2676 string vpx
= (string
)stack
.top(); stack
.pop();
2678 CGroup
* group
= entity
->getGroup();
2680 if (group
->isSpawned())
2682 FOREACH(itBot
, CCont
<CBot
>, group
->bots())
2684 CBotNpc
* bot
= NLMISC::safe_cast
<CBotNpc
*>(*itBot
);
2687 bot
->setVisualProperties(vpx
);
2688 bot
->sendVisualProperties();
2694 //----------------------------------------------------------------------------
2697 @subsection maxHitRange_f_
2698 Sets the max hit range possible for player, in meters
2700 Arguments: f(MaxHitRange) ->
2701 @param[in] MaxHitRange set the max range for player can hit this npc group
2704 ()maxHitRange(50); // Set the max hit range in 50 meters all npc in group
2709 void maxHitRange_f_(CStateInstance
* entity
, CScriptStack
& stack
)
2711 float maxHitRange
= (float&)stack
.top(); stack
.pop();
2712 CGroup
* group
= entity
->getGroup();
2713 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
2715 FOREACH(botIt
, CCont
<CBot
>, group
->bots())
2719 if (!bot
->isSpawned()) return;
2720 if (bot
->getRyzomType() == RYZOMID::npc
)
2722 CBotNpc
* botNpc
= NLMISC::safe_cast
<CBotNpc
*>(bot
);
2723 botNpc
->setMaxHitRangeForPlayer(maxHitRange
);
2728 //----------------------------------------------------------------------------
2731 @subsection setEquipement_s_
2735 arg1: is the equipment list (in hex)
2738 ()setEquipement("xxxxx");
2742 void setEquipment_s_(CStateInstance
* entity
, CScriptStack
& stack
)
2744 string script
= stack
.top();
2747 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
2748 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
2752 std::vector
<CAIActions::CArg
> args
;
2753 std::vector
<std::string
> equipements
;
2754 NLMISC::splitString(script
, ";", equipements
);
2756 CGroup
* group
= entity
->getGroup();
2758 FOREACH(botIt
, CCont
<CBot
>, group
->bots())
2762 if (bot
->getRyzomType() == RYZOMID::npc
)
2764 CBotNpc
* botNpc
= NLMISC::safe_cast
<CBotNpc
*>(bot
);
2767 botNpc
->equipmentInit();
2769 FOREACHC(it
, std::vector
<std::string
>, equipements
)
2771 botNpc
->equipmentAdd(*it
);
2778 //----------------------------------------------------------------------------
2781 @subsection addUserModel_sss_
2785 arg0: is the user model id (a name)
2786 arg1: is the base sheet
2787 arg3: is the script (in hex)
2790 ()addUserModel("toto", "ccbha1", "xxxxx");
2794 void addUserModel_sss_(CStateInstance
* entity
, CScriptStack
& stack
)
2796 string script
= stack
.top();
2799 string baseSheet
= stack
.top();
2802 string userModelId
= stack
.top(); // prefix with ARK_ to prevent stupid overwrite
2805 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
2806 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
2810 std::vector
<CAIActions::CArg
> args
;
2811 args
.push_back(CAIActions::CArg(900+aiInstance
->getInstanceNumber()));
2812 args
.push_back(CAIActions::CArg("ARK_"+userModelId
));
2813 args
.push_back(CAIActions::CArg(baseSheet
));
2814 args
.push_back(CAIActions::CArg(scriptHex_decode(script
)));
2816 CAIActions::execute("USR_MDL", args
);
2819 //----------------------------------------------------------------------------
2822 @subsection addCustomLoot_ss_
2826 arg0: is the custom table id (a name)
2827 arg1: is the script with syntax : <PROBA_1>:<hex:LOOT_SET_1>,<PROBA_2>:<hex:LOOT_SET_2>,...
2830 ()addCustomLoot("toto", "<PROBA_1>:<hex:LOOT_SET_1>,<PROBA_2>:<hex:LOOT_SET_2>,...");
2834 void addCustomLoot_ss_(CStateInstance
* entity
, CScriptStack
& stack
)
2836 string script
= stack
.top();
2839 string customTableId
= stack
.top();
2842 std::vector
<std::string
> loots
;
2843 NLMISC::splitString(script
, ",", loots
);
2847 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
2848 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
2852 std::vector
<CAIActions::CArg
> args
;
2853 uint32 nbTables
= 1;
2854 args
.push_back(CAIActions::CArg(nbTables
));
2855 args
.push_back(CAIActions::CArg(900+aiInstance
->getInstanceNumber()));
2856 uint32 lootSets
= loots
.size();
2857 args
.push_back(CAIActions::CArg(lootSets
));
2858 args
.push_back(CAIActions::CArg(customTableId
));
2859 float moneyProba
= 0.0;
2860 args
.push_back(CAIActions::CArg(moneyProba
));
2861 float moneyFactor
= 0.0;
2862 args
.push_back(CAIActions::CArg(moneyFactor
));
2863 uint32 moneyBase
= 0;
2864 args
.push_back(CAIActions::CArg(moneyBase
));
2866 FOREACHC(it
, std::vector
<std::string
>, loots
)
2868 std::vector
<string
> lootSet
;
2869 NLMISC::splitString(*it
, ":", lootSet
);
2870 if (lootSet
.size() == 2)
2872 args
.push_back(CAIActions::CArg(lootSet
[0]));
2873 args
.push_back(CAIActions::CArg(scriptHex_decode(lootSet
[1])));
2877 CAIActions::execute("CUSTOMLT", args
);
2881 //----------------------------------------------------------------------------
2884 @subsection setUserModel_s_
2885 Set the user model of a creature
2887 Arguments: -> s(userModel)
2890 ()setUserModel('my_model');
2895 void setUserModel_s_(CStateInstance
* entity
, CScriptStack
& stack
)
2897 string userModel
= stack
.top();
2900 CGroup
* group
= entity
->getGroup();
2902 FOREACH(botIt
, CCont
<CBot
>, group
->bots())
2906 if (bot
->getRyzomType() == RYZOMID::npc
)
2908 CBotNpc
* botNpc
= NLMISC::safe_cast
<CBotNpc
*>(bot
);
2909 botNpc
->setUserModelId("ARK_"+userModel
);
2910 if (bot
->isSpawned())
2911 bot
->getSpawnObj()->sendInfoToEGS();
2917 //----------------------------------------------------------------------------
2920 @subsection setCustomLoot_s_
2921 Set the custom loot of a creature
2923 Arguments: -> s(customTable)
2926 ()setUserModel('my_loot_table');
2931 void setCustomLoot_s_(CStateInstance
* entity
, CScriptStack
& stack
)
2933 string customTable
= stack
.top();
2936 CGroup
* group
= entity
->getGroup();
2938 FOREACH(botIt
, CCont
<CBot
>, group
->bots())
2942 //if (!bot->isSpawned()) return;
2944 if (bot
->getRyzomType() == RYZOMID::npc
)
2946 CBotNpc
* botNpc
= NLMISC::safe_cast
<CBotNpc
*>(bot
);
2947 botNpc
->setCustomLootTableId(customTable
);
2948 if (bot
->isSpawned())
2949 bot
->getSpawnObj()->sendInfoToEGS();
2955 ////----------------------------------------------------------------------------
2958 //@subsection hideMissionStepIcon_b_
2959 //Allows to hide icons for current missions steps having interactions with this NPC (default: shown)
2961 //Arguments: b(hide) ->
2962 //@param[in] hide true to hide the icon for all mission steps relating to this NPC (default: false)
2966 //void hideMissionStepIcon_b_(CStateInstance* entity, CScriptStack& stack)
2968 // bool b = (bool&)stack.top(); stack.pop();
2969 // CGroup* group = entity->getGroup();
2970 // CGroupNpc* npcGroup = NLMISC::safe_cast<CGroupNpc*>(group);
2972 // FOREACH(botIt, CCont<CBot>, group->bots())
2974 // CBot* bot = *botIt;
2976 // if (!bot->isSpawned()) return;
2977 // if (bot->getRyzomType() == RYZOMID::npc)
2979 // CBotNpc* botNpc = NLMISC::safe_cast<CBotNpc*>(bot);
2980 // botNpc->setMissionStepIconHidden(b);
2985 ////----------------------------------------------------------------------------
2988 //@subsection hideMissionGiverIcon_b_
2989 //Allows to hide icons for missions proposed by this NPC (default: shown)
2991 //Arguments: b(hide) ->
2992 //@param[in] hide true to hide the icon for all missions propsed by this NPC (default: false)
2996 //void hideMissionGiverIcon_b_(CStateInstance* entity, CScriptStack& stack)
2998 // bool b = (bool&)stack.top(); stack.pop();
2999 // CGroup* group = entity->getGroup();
3000 // CGroupNpc* npcGroup = NLMISC::safe_cast<CGroupNpc*>(group);
3002 // FOREACH(botIt, CCont<CBot>, group->bots())
3004 // CBot* bot = *botIt;
3006 // if (!bot->isSpawned()) return;
3007 // if (bot->getRyzomType() == RYZOMID::npc)
3009 // CBotNpc* botNpc = NLMISC::safe_cast<CBotNpc*>(bot);
3010 // botNpc->setMissionGiverIconHidden(b);
3015 //----------------------------------------------------------------------------
3018 @subsection setEventCode_sss
3019 Sets and event to execute when event triggers
3022 s(event) -> @param[in] The name of the state
3023 s(event) -> @param[in] The name of the event
3024 s(code) -> @param[in] The string to execute code in hex
3027 ()maxHitRange(50); // Set the max hit range in 50 meters all npc in group
3032 void setEventCode_sss_(CStateInstance
* entity
, CScriptStack
& stack
)
3034 string code
= stack
.top();
3037 string event_name
= stack
.top();
3040 string state_name
= stack
.top();
3044 //////////// Special Cases for Ark
3045 if (event_name
== "notify_on_death")
3047 strFindReplace(code
, "http://", "");
3048 strFindReplace(code
, "https://", "");
3049 strFindReplace(code
, "/index.php?", " ");
3050 strFindReplace(code
, " &", " ");
3052 CGroup
* group
= entity
->getGroup();
3053 FOREACH(botIt
, CCont
<CBot
>, group
->bots())
3057 if (!bot
->isSpawned()) return;
3059 CBotNpc
* botNpc
= NLMISC::safe_cast
<CBotNpc
*>(bot
);
3062 CSpawnBotNpc
* spawnBotNpc
= botNpc
->getSpawn();
3065 CAINotifyDeathMsg
*msg
= new CAINotifyDeathMsg
;
3067 msg
->TargetRowId
= spawnBotNpc
->dataSetRow();
3074 ///////////////////////////////////////////////////////
3077 CAIEventDescription eventDescription
;
3078 CAIEventActionNode::TSmartPtr eventAction
;
3079 CAIEventReaction
* event
;
3081 // Create event handler
3082 eventDescription
.EventType
= event_name
;
3084 // Create event action
3085 eventAction
= new CAIEventActionNode
;
3086 eventAction
->Action
= "code";
3087 eventAction
->Weight
= 1;
3089 code
= scriptHex_decode(code
);
3090 vector
<string
> lines_of_code
;
3091 NLMISC::splitString(code
, "\n", lines_of_code
);
3093 if (!lines_of_code
.empty())
3095 nlinfo("=== Code ===");
3096 FOREACHC(it
, vector
<string
>, lines_of_code
)
3098 nlinfo("#%d %s", line
, (*it
).c_str());
3099 eventAction
->Args
.push_back(*it
);
3102 nlinfo("=== * ===");
3105 // Register event action
3106 eventDescription
.Action
= eventAction
;
3109 CGroup
* group
= entity
->getGroup();
3110 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
3111 CStateMachine
* sm
= &npcGroup
->getEventContainer();
3112 CAIStatePositional
* statePositional
;
3114 uint32 stateAlias
= npcGroup
->getStateAlias(state_name
);
3115 if (stateAlias
== 0)
3117 nlinfo("STATE %s not found !", state_name
.c_str());
3118 statePositional
= new CAIStatePositional(sm
, 0, state_name
);
3119 npcGroup
->setStateAlias(state_name
, statePositional
->getAlias());
3120 sm
->states().addChild(statePositional
);
3124 statePositional
= safe_cast
<CAIStatePositional
*>(sm
->states().getChildByAlias(stateAlias
));
3127 uint32 stateEventAlias
= npcGroup
->getStateEventAlias(event_name
);
3128 /*if (stateEventAlias != 0)
3130 CAIEventReaction er = sm->eventReactions().getChildByAlias(stateEventAlias);
3133 // sm->eventReactions().removeChildByIndex(sm->eventReactions().getChildIndexByAlias(stateEventAlias));
3135 // Register event handler
3136 stateEventAlias
= sm
->getLastStateEventAlias();
3137 event
= new CAIEventReaction(sm
, stateEventAlias
, eventDescription
.EventType
);
3138 event
->processEventDescription(&eventDescription
, sm
);
3139 event
->setGroup(npcGroup
->getAlias());
3140 nlinfo("Add Event: %s(%d) in State : %d for group %d", event_name
.c_str(), stateEventAlias
, statePositional
->getAlias(), npcGroup
->getAlias());
3141 event
->setState(statePositional
->getAlias());
3142 npcGroup
->setStateEventAlias(event_name
, stateEventAlias
);
3145 sm
->eventReactions().addChild(event
);
3150 //----------------------------------------------------------------------------
3153 @subsection setParent_s_
3155 A a link child -> parent from child
3158 Arguments: parent(direction)
3159 @param[in] the name of group who will be the parent of this group
3162 ()setParent("group_name");
3167 void setParent_s_(CStateInstance
* entity
, CScriptStack
& stack
)
3170 string parent
= stack
.top();
3172 std::vector
<CGroup
*> grps
;
3173 entity
->getGroup()->getAIInstance()->findGroup(grps
, parent
);
3174 if (grps
.size() > 0)
3176 CGroup
* parentGroup
= grps
.back();
3177 CGroupNpc
* parentNpcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(parentGroup
);
3179 CGroup
* group
= entity
->getGroup();
3180 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
3181 if (npcGroup
&& parentNpcGroup
)
3182 npcGroup
->getPersistentStateInstance()->setParentStateInstance(parentNpcGroup
->getPersistentStateInstance());
3188 //----------------------------------------------------------------------------
3191 @subsection addHealGroup_s_
3193 Add a link to be able to heal a group
3196 Arguments: group(direction)
3197 @param[in] the name of group who will able to heal
3200 ()addHealGroup("group_name");
3205 void addHealGroup_s_(CStateInstance
* entity
, CScriptStack
& stack
)
3208 string healGroup
= stack
.top();
3210 std::vector
<CGroup
*> healGrps
;
3211 entity
->getGroup()->getAIInstance()->findGroup(healGrps
, healGroup
);
3213 CGroup
* group
= entity
->getGroup();
3214 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
3216 for (uint i
=0; i
<healGrps
.size(); ++i
)
3218 CGroupNpc
* healNpcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(healGrps
[i
]);
3220 npcGroup
->addHealGroup(healNpcGroup
);
3224 //----------------------------------------------------------------------------
3227 @subsection resetHealGroups_
3229 Add a link to be able to heal a group
3232 ()resetHealGroups();
3237 void resetHealGroups_(CStateInstance
* entity
, CScriptStack
& stack
)
3239 CGroup
* group
= entity
->getGroup();
3240 CGroupNpc
* npcGroup
= NLMISC::safe_cast
<CGroupNpc
*>(group
);
3241 npcGroup
->resetHealGroups();
3245 //----------------------------------------------------------------------------
3248 @subsection spawnGroup_fsssffff_
3251 Arguments: f(NbrBots), f(spawnBot) s(Sheet), s(Name), s(Look), f(x), f(y), f(orientation), f(dispersion) ->
3259 void spawnGroup_ffsssffff_c(CStateInstance
* entity
, CScriptStack
& stack
)
3261 double dispersionRadius
= (double)(float)stack
.top();
3264 double orientation
= (double)(float)stack
.top();
3267 double y
= (double)(float)stack
.top();
3270 double x
= (double)(float)stack
.top();
3273 string look
= (string
)stack
.top();
3276 string name
= (string
)stack
.top();
3279 CSheetId
sheetId((string
)stack
.top());
3282 bool spawn
= (float&)stack
.top()!=0.0f
;
3285 uint nbBots
= (uint
)(float)stack
.top();
3288 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
3289 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
3293 CGroupNpc
* grp
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
3296 CSpawnGroupNpc
* spawnGroup
= grp
->getSpawnObj();
3297 CGroupNpc
* npcGroup
;
3299 npcGroup
= aiInstance
->eventCreateNpcGroup(nbBots
, sheetId
, CAIVector(x
, y
), dispersionRadius
, spawn
, orientation
, name
, look
, spawnGroup
->getCell());
3301 npcGroup
= aiInstance
->eventCreateNpcGroup(nbBots
, sheetId
, CAIVector(x
, y
), dispersionRadius
, spawn
, orientation
, name
, look
);
3303 stack
.push(npcGroup
->getPersistentStateInstance());
3307 void spawnGroup_ffsssffff_(CStateInstance
* entity
, CScriptStack
& stack
)
3309 double dispersionRadius
= (double)(float)stack
.top();
3312 double orientation
= (double)(float)stack
.top();
3315 double y
= (double)(float)stack
.top();
3318 double x
= (double)(float)stack
.top();
3321 string look
= (string
)stack
.top();
3324 string name
= (string
)stack
.top();
3327 CSheetId
sheetId((string
)stack
.top());
3330 bool spawn
= (float&)stack
.top()!=0.0f
;
3333 uint nbBots
= (uint
)(float)stack
.top();
3336 IManagerParent
* const managerParent
= entity
->getGroup()->getOwner()->getOwner();
3337 CAIInstance
* const aiInstance
= dynamic_cast<CAIInstance
*>(managerParent
);
3341 CGroupNpc
* grp
= dynamic_cast<CGroupNpc
*>(entity
->getGroup());
3344 CSpawnGroupNpc
* spawnGroup
= grp
->getSpawnObj();
3345 CGroupNpc
* npcGroup
;
3347 npcGroup
= aiInstance
->eventCreateNpcGroup(nbBots
, sheetId
, CAIVector(x
, y
), dispersionRadius
, spawn
, orientation
, name
, look
, spawnGroup
->getCell());
3349 npcGroup
= aiInstance
->eventCreateNpcGroup(nbBots
, sheetId
, CAIVector(x
, y
), dispersionRadius
, spawn
, orientation
, name
, look
);
3354 std::map
<std::string
, FScrptNativeFunc
> nfGetNpcGroupNativeFunctions()
3356 std::map
<std::string
, FScrptNativeFunc
> functions
;
3358 #define REGISTER_NATIVE_FUNC(cont, func) cont.insert(std::make_pair(std::string(#func), &func))
3360 REGISTER_NATIVE_FUNC(functions
, setFactionProp_ss_
);
3361 REGISTER_NATIVE_FUNC(functions
, setOupostMode_ss_
);
3362 REGISTER_NATIVE_FUNC(functions
, moveToZone_ss_
);
3363 REGISTER_NATIVE_FUNC(functions
, setActivity_s_
);
3364 REGISTER_NATIVE_FUNC(functions
, startWander_f_
);
3365 REGISTER_NATIVE_FUNC(functions
, startMoving_fff_
);
3366 REGISTER_NATIVE_FUNC(functions
, waitInZone_s_
);
3367 REGISTER_NATIVE_FUNC(functions
, stopMoving__
);
3368 REGISTER_NATIVE_FUNC(functions
, followPlayer_sf_
);
3369 REGISTER_NATIVE_FUNC(functions
, wander__
);
3370 REGISTER_NATIVE_FUNC(functions
, setAttackable_f_
);
3371 REGISTER_NATIVE_FUNC(functions
, setPlayerAttackable_f_
);
3372 REGISTER_NATIVE_FUNC(functions
, setBotAttackable_f_
);
3373 REGISTER_NATIVE_FUNC(functions
, setFactionAttackableAbove_sff_
);
3374 REGISTER_NATIVE_FUNC(functions
, setFactionAttackableBelow_sff_
);
3375 REGISTER_NATIVE_FUNC(functions
, addBotChat_s_
);
3376 REGISTER_NATIVE_FUNC(functions
, clearBotChat__
);
3377 REGISTER_NATIVE_FUNC(functions
, ignoreOffensiveActions_f_
);
3378 REGISTER_NATIVE_FUNC(functions
, setDespawnTime_f_
);
3379 REGISTER_NATIVE_FUNC(functions
, setRespawnTime_f_
);
3380 REGISTER_NATIVE_FUNC(functions
, addHpUpTrigger_ff_
);
3381 REGISTER_NATIVE_FUNC(functions
, delHpUpTrigger_ff_
);
3382 REGISTER_NATIVE_FUNC(functions
, addHpDownTrigger_ff_
);
3383 REGISTER_NATIVE_FUNC(functions
, delHpDownTrigger_ff_
);
3384 REGISTER_NATIVE_FUNC(functions
, addHpUpTrigger_fs_
);
3385 REGISTER_NATIVE_FUNC(functions
, delHpUpTrigger_fs_
);
3386 REGISTER_NATIVE_FUNC(functions
, addHpDownTrigger_fs_
);
3387 REGISTER_NATIVE_FUNC(functions
, delHpDownTrigger_fs_
);
3388 REGISTER_NATIVE_FUNC(functions
, addNamedEntityListener_ssf_
);
3389 REGISTER_NATIVE_FUNC(functions
, delNamedEntityListener_ssf_
);
3390 REGISTER_NATIVE_FUNC(functions
, addNamedEntityListener_sss_
);
3391 REGISTER_NATIVE_FUNC(functions
, delNamedEntityListener_sss_
);
3392 REGISTER_NATIVE_FUNC(functions
, setPlayerController_ss_
);
3393 REGISTER_NATIVE_FUNC(functions
, clearPlayerController_s_
);
3394 REGISTER_NATIVE_FUNC(functions
, activateEasterEgg_fffsffffsss_
);
3395 REGISTER_NATIVE_FUNC(functions
, deactivateEasterEgg_fff_
);
3396 REGISTER_NATIVE_FUNC(functions
, receiveMissionItems_ssc_
);
3397 REGISTER_NATIVE_FUNC(functions
, giveMissionItems_ssc_
);
3398 REGISTER_NATIVE_FUNC(functions
, talkTo_sc_
);
3399 REGISTER_NATIVE_FUNC(functions
, facing_cscs_
);
3400 REGISTER_NATIVE_FUNC(functions
, emote_css_
);
3401 REGISTER_NATIVE_FUNC(functions
, emote_ss_
);
3402 REGISTER_NATIVE_FUNC(functions
, emote_s_
);
3403 REGISTER_NATIVE_FUNC(functions
, rename_s_
);
3404 REGISTER_NATIVE_FUNC(functions
, vpx_s_
);
3405 REGISTER_NATIVE_FUNC(functions
, npcSay_css_
);
3406 REGISTER_NATIVE_FUNC(functions
, npcSay_ss_
);
3407 REGISTER_NATIVE_FUNC(functions
, dssMessage_fsss_
);
3408 REGISTER_NATIVE_FUNC(functions
, despawnBotByAlias_s_
);
3409 REGISTER_NATIVE_FUNC(functions
, giveReward_ssssc_
);
3410 REGISTER_NATIVE_FUNC(functions
, teleportNear_fffc_
);
3412 REGISTER_NATIVE_FUNC(functions
, setScenarioPoints_ff_
);
3413 REGISTER_NATIVE_FUNC(functions
, startScenarioTiming_f_
);
3414 REGISTER_NATIVE_FUNC(functions
, endScenarioTiming_f_
);
3416 REGISTER_NATIVE_FUNC(functions
, maxHitRange_f_
);
3418 REGISTER_NATIVE_FUNC(functions
, setEventCode_sss_
);
3419 REGISTER_NATIVE_FUNC(functions
, setParent_s_
);
3420 REGISTER_NATIVE_FUNC(functions
, addHealGroup_s_
);
3422 REGISTER_NATIVE_FUNC(functions
, setEquipment_s_
);
3423 REGISTER_NATIVE_FUNC(functions
, addUserModel_sss_
);
3424 REGISTER_NATIVE_FUNC(functions
, addCustomLoot_ss_
);
3425 REGISTER_NATIVE_FUNC(functions
, setUserModel_s_
);
3426 REGISTER_NATIVE_FUNC(functions
, setCustomLoot_s_
);
3428 REGISTER_NATIVE_FUNC(functions
, spawnGroup_ffsssffff_
);
3429 REGISTER_NATIVE_FUNC(functions
, spawnGroup_ffsssffff_c
);
3431 // REGISTER_NATIVE_FUNC(functions, hideMissionStepIcon_b_);
3432 // REGISTER_NATIVE_FUNC(functions, hideMissionGiverIcon_b_);
3435 #undef REGISTER_NATIVE_FUNC