Added ai command setEquipment
[ryzomcore.git] / ryzom / server / src / ai_service / state_instance.h
blob79329bcbca4c8ec367c1e75922c791dabb242b05
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
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/>.
20 #ifndef RYAI_STATE_INSTANCE_H
21 #define RYAI_STATE_INSTANCE_H
23 #include "event_manager.h"
24 #include "timer.h"
25 #include "debug_history.h"
26 #include "keyword_owner.h"
27 #include "event_manager.h"
28 #include "script_vm.h"
29 #include "ai_grp.h"
31 class CStateMachine;
32 class CGroup;
33 class CAIState;
35 class CPersistentStateInstance;
36 class CAliasTreeOwner;
38 extern NLLIGO::CLigoConfig LigoConfig;
40 //////////////////////////////////////////////////////////////////////////////
41 // CStateInstance //
42 //////////////////////////////////////////////////////////////////////////////
44 class CStateInstance
45 : public AIVM::IScriptContext
47 public:
48 inline
49 CStateInstance(CAIState* startState);
51 void init(CAIState* startState);
53 virtual CPersistentStateInstance* getPersistentStateInstance();
55 //////////////////////////////////////////////////////////////////////////
56 // State Persistent.
58 struct CStatePersistentObjEntry
60 CStatePersistentObjEntry();
61 CStatePersistentObjEntry(CAIState const* state, NLMISC::CSmartPtr<NLMISC::CVirtualRefCount> obj);
62 virtual ~CStatePersistentObjEntry();
63 CAIState const* _State;
64 NLMISC::CSmartPtr<NLMISC::CVirtualRefCount> _Obj;
66 typedef std::vector<CStatePersistentObjEntry> TStatePersistentObjList;
68 TStatePersistentObjList _StatePersistentObjList;
70 // Made to allow obj with life time less or equal to state affectation life time.
71 void addStatePersistentObj(CAIState const* keyState, NLMISC::CSmartPtr<NLMISC::CVirtualRefCount> anyObj);
72 void removeExceptForState(CAIState const* keyState);
74 /** Try to obtain a group interface from the CStateInstance. Can return NULL if the
75 * CStateInstance if not implemeted by a group related objet.
77 // Bad, Bad, Bad ..
78 virtual CGroup* getGroup() = 0;
80 //////////////////////////////////////////////////////////////////////////
82 CAITimerExtended& timerStateTimeout() { return _StateTimeout; }
83 CAITimerExtended& timerPunctTimeout() { return _PunctualStateTimeout; }
84 CAITimerExtended& timerUser(uint idx);
86 CAIState* getCAIState();
88 virtual CAliasTreeOwner* aliasTreeOwner() = 0;
90 virtual void stateChange(CAIState const* oldState, CAIState const* newState) = 0;
92 CAIState* getState() const { return _state; }
93 void setNextState(CAIState*);
95 CAIState* getPunctualState() const { return _PunctualState; }
96 CAIState* getNextPunctualState() const { return _NextPunctualState; }
97 void setNextPunctualState(CAIState* state);
98 void cancelPunctualState() { _CancelPunctualState = true; }
100 std::string buidStateInstanceDebugString() const;
102 void dumpVarsAndFunctions(CStringWriter& sw) const;
104 virtual CDebugHistory* getDebugHistory () = 0;
106 CAIState const* getActiveState() const;
108 sint32 getUserTimer(uint timerId);
109 void setUserTimer(uint timerId, sint32 time);
111 void logicVarsToString(std::string& str) const;
113 float getNelVar(std::string const& varId);
114 void setNelVar(std::string const& varId, float value);
115 void delNelVar(std::string const& varId);
117 std::string getStrNelVar(std::string const& varId);
118 void setStrNelVar(std::string const& varId, std::string const& value);
119 void delStrNelVar(std::string const& varId);
121 static void setGlobalNelVar(std::string const& varId, float value);
122 static void setGlobalNelVar(std::string const& varId, std::string value);
124 CAITimerExtended const& userTimer (uint32 index) const;
126 bool advanceUserTimer(uint32 nbTicks);
128 void processStateEvent(CAIEvent const& stateEvent, CAIState const* state = NULL);
130 // callerStateInstance could be NULL;
131 void interpretCode(AIVM::IScriptContext* callerStateInstance, AIVM::CByteCodeEntry const& codeScriptEntry);
132 void interpretCode(AIVM::IScriptContext* callerStateInstance, NLMISC::CSmartPtr<AIVM::CByteCode const> const& codeScript);
134 /// @name IScriptContext implementation
135 //@{
136 virtual std::string getContextName();
137 virtual void interpretCodeOnChildren(AIVM::CByteCodeEntry const& codeScriptEntry);
139 float getLogicVar(NLMISC::TStringId varId);
140 void setLogicVar(NLMISC::TStringId varId, float value);
141 std::string getStrLogicVar(NLMISC::TStringId varId);
142 void setStrLogicVar(NLMISC::TStringId varId, std::string const& value);
143 AIVM::IScriptContext* getCtxLogicVar(NLMISC::TStringId varId);
144 void setCtxLogicVar(NLMISC::TStringId varId, AIVM::IScriptContext* value);
145 void setFirstBotSpawned();
147 virtual AIVM::IScriptContext* findContext(NLMISC::TStringId const strId);
149 virtual void setScriptCallBack(NLMISC::TStringId const& eventName, AIVM::CByteCodeEntry const& codeScriptEntry);
150 virtual AIVM::CByteCodeEntry const* getScriptCallBackPtr(NLMISC::TStringId const& eventName) const;
151 virtual void callScriptCallBack(AIVM::IScriptContext* caller, NLMISC::TStringId const& funcName, int mode = 0, std::string const& inParamsSig = "", std::string const& outParamsSig = "", AIVM::CScriptStack* stack = NULL);
152 virtual void callNativeCallBack(AIVM::IScriptContext* caller, std::string const& funcName, int mode = 0, std::string const& inParamsSig = "", std::string const& outParamsSig = "", AIVM::CScriptStack* stack = NULL);
154 void blockUserEvent(uint32 eventId);
155 void unblockUserEvent(uint32 eventId);
156 bool isUserEventBlocked(uint32 eventId) const;
157 //@}
159 protected:
160 /// Logic variables
161 typedef std::map<NLMISC::TStringId, float> TLogicVarList;
162 typedef std::map<NLMISC::TStringId, std::string> TStrLogicVarList;
163 typedef std::map<NLMISC::TStringId, uint32> TLogicVarIndex;
164 typedef std::map<NLMISC::TStringId, AIVM::IScriptContext*> TCtxLogicVarList;
165 TLogicVarList _LogicVar;
166 TStrLogicVarList _StrLogicVar;
167 TCtxLogicVarList _CtxLogicVar;
169 // Nel variables
170 typedef std::map<std::string, NLMISC::CVariable<float>*> TNelVarList;
171 typedef std::map<std::string, NLMISC::CVariable<std::string>*> TStrNelVarList;
172 TNelVarList _NelVar;
173 TStrNelVarList _StrNelVar;
175 // Callbacks (?)
176 typedef std::map<NLMISC::TStringId, AIVM::CByteCodeEntry> TCallBackList;
177 TCallBackList _CallBacks;
179 /// Flag for variable modification
180 bool _LogicVarChanged;
181 bool _LogicVarChangedList[4];
182 //TLogicVarIndex _VarIndex;
183 // update logic timers ---------------------------------------------
184 /// 4 timers available for user logic
185 CAITimerExtended _UserTimer[4];
187 /// timer for timing positional states
188 CAITimerExtended _StateTimeout;
189 /// current state (index into manager's state vector)
190 CAIState* _state;
191 /// variable set to request a state change (std::numeric_limits<uint32>::max() otherwise)
192 CAIState* _NextState;
194 /// timer for timing punctual states
195 CAITimerExtended _PunctualStateTimeout;
197 CAIState* _PunctualState;
198 CAIState* _NextPunctualState;
200 /// Flag for leaving the punctual state, returning to normal behavior
201 bool _CancelPunctualState;
202 bool _FirstBotSpawned;
204 uint32 _UserEventBlocked;
207 //////////////////////////////////////////////////////////////////////////////
208 // CPersistentStateInstance //
209 //////////////////////////////////////////////////////////////////////////////
211 class CPersistentStateInstance
212 : public NLMISC::CDbgRefCount<CPersistentStateInstance>
213 , public CKeyWordOwner
214 , public CStateInstance
216 public:
217 CPersistentStateInstance(CStateMachine& reactionContainer);
218 virtual ~CPersistentStateInstance();
220 typedef std::vector<NLMISC::CDbgPtr<CPersistentStateInstance> > TChildList;
222 void setParentStateInstance(CPersistentStateInstance* parentStateInstance);
224 CPersistentStateInstance* getParentStateInstance() const { return _ParentStateInstance; }
226 void addChildStateInstance(CPersistentStateInstance* parentStateInstance);
228 void removeChildStateInstance(CPersistentStateInstance* parentStateInstance);
230 TChildList& childs() { return _PSIChilds; }
232 TChildList _PSIChilds;
234 // Interface to state status variables -----------------------------
235 CAIState* getStartState() { return _StartState; }
236 void setStartState(CAIState* state);
238 CStateMachine& getEventContainer() { return _Container; }
240 void updateStateInstance();
242 //////////////////////////////////////////////////////////////////////////
243 // CStateInstance
244 CPersistentStateInstance* getPersistentStateInstance() { return this; }
246 //////////////////////////////////////////////////////////////////////////
248 private:
249 /// id of the state to use at startup
250 NLMISC::CDbgPtr<CAIState> _StartState;
251 CStateMachine& _Container;
252 NLMISC::CDbgPtr<CPersistentStateInstance> _ParentStateInstance;
255 /****************************************************************************/
256 /* Inlined methods */
257 /****************************************************************************/
259 //////////////////////////////////////////////////////////////////////////////
260 // CStateInstance //
261 //////////////////////////////////////////////////////////////////////////////
263 inline
264 CStateInstance::CStateInstance(CAIState* startState)
266 _UserEventBlocked = 0;
267 _CtxLogicVar[NLMISC::CStringMapper::map("@this")] = this;
268 init(startState);
271 inline
272 CPersistentStateInstance* CStateInstance::getPersistentStateInstance()
274 // nlassert(false);
275 return (CPersistentStateInstance*)NULL;
278 inline
279 CStateInstance::CStatePersistentObjEntry::CStatePersistentObjEntry()
283 inline
284 CStateInstance::CStatePersistentObjEntry::CStatePersistentObjEntry(CAIState const* state, NLMISC::CSmartPtr<NLMISC::CVirtualRefCount> obj)
285 : _State(state)
286 , _Obj(obj)
290 inline
291 CStateInstance::CStatePersistentObjEntry::~CStatePersistentObjEntry()
293 _Obj = NULL;
294 _State = NULL;
297 inline
298 CAITimerExtended& CStateInstance::timerUser(uint idx)
300 nlassert(idx<4); return _UserTimer[idx];
303 inline
304 void CStateInstance::logicVarsToString(std::string& str) const
306 for (TLogicVarList::const_iterator it=_LogicVar.begin(), itEnd=_LogicVar.end();it!=itEnd;++it)
307 str+=*(it->first)+"="+NLMISC::toString(it->second)+" ";
310 inline
311 float CStateInstance::getLogicVar(NLMISC::TStringId varId)
313 TLogicVarList::iterator it=_LogicVar.find(varId);
314 if (it==_LogicVar.end())
316 _LogicVar[varId]=0.f;
317 return 0.f;
319 return it->second; //_LogicVar[varId];
322 inline
323 void CStateInstance::setLogicVar(NLMISC::TStringId varId, float value)
325 _LogicVar[varId] = value;
326 _LogicVarChanged = true;
328 if (varId && varId->size() == 2 && (*varId)[0] == 'v')
330 sint32 index = (*varId)[1] - '0';
331 if (0 <= index && index < 4)
333 //_VarIndex[varId]
334 _LogicVarChangedList[static_cast<uint32>(index)] = true;
341 inline
342 std::string CStateInstance::getStrLogicVar(NLMISC::TStringId varId)
344 return _StrLogicVar[varId];
347 inline
348 void CStateInstance::setStrLogicVar(NLMISC::TStringId varId, std::string const& value)
350 _StrLogicVar[varId] = value;
351 _LogicVarChanged = true;
352 if (varId && varId->size() == 2 && (*varId)[0] == 'v')
354 sint32 index = (*varId)[1] - '0';
355 if (0 <= index && index < 4)
357 //_VarIndex[varId]
358 _LogicVarChangedList[static_cast<uint32>(index)] = true;
362 //_LogicVarChangedList[_VarIndex[varId]] = true;
365 inline
366 AIVM::IScriptContext* CStateInstance::getCtxLogicVar(NLMISC::TStringId varId)
368 return _CtxLogicVar[varId];
371 inline
372 void CStateInstance::setCtxLogicVar(NLMISC::TStringId varId, AIVM::IScriptContext* value)
374 _CtxLogicVar[varId] = value;
375 _LogicVarChanged = true;
378 inline
379 float CStateInstance::getNelVar(std::string const& varId)
381 TNelVarList::iterator it = _NelVar.find(varId);
382 if (it != _NelVar.end()) return it->second->get();
384 if (NLMISC::CVariable<float>::exists(varId))
386 nlwarning("Nel variable \"%s\" exists outside of this state instance", varId.c_str());
387 return 0.f;
390 _NelVar[varId] = new NLMISC::CVariable<float>("StateInstance", varId.c_str(), "", 0.f);
391 return _NelVar[varId]->get();
394 inline
395 void CStateInstance::setNelVar(std::string const& varId, float value)
397 TNelVarList::iterator it = _NelVar.find(varId);
398 if (it==_NelVar.end())
400 if (NLMISC::CVariable<float>::exists(varId))
402 nlwarning("Nel variable \"%s\" exists outside of this state instance", varId.c_str());
403 return;
405 _NelVar[varId] = new NLMISC::CVariable<float>("StateInstance", varId.c_str(), "", 0.f);
407 _NelVar[varId]->set(value);
410 inline
411 void CStateInstance::delNelVar(std::string const& varId)
413 TNelVarList::iterator it = _NelVar.find(varId);
414 if (it!=_NelVar.end())
416 delete it->second;
417 _NelVar.erase(it);
419 else
421 nldebug("Trying to delete Nel variable that doesn't exist: \"%s\"", varId.c_str());
425 inline
426 std::string CStateInstance::getStrNelVar(std::string const& varId)
428 TStrNelVarList::iterator it = _StrNelVar.find(varId);
429 if (it != _StrNelVar.end()) return it->second->get();
431 if (NLMISC::CVariable<float>::exists(varId))
433 nlwarning("Nel variable \"%s\" exists outside of this state instance", varId.c_str());
434 return "";
437 _StrNelVar[varId] = new NLMISC::CVariable<std::string>("StateInstanceStrVar", varId.c_str(), "", std::string());
438 return _StrNelVar[varId]->get();
441 inline
442 void CStateInstance::setStrNelVar(std::string const& varId, std::string const& value)
444 TStrNelVarList::iterator it = _StrNelVar.find(varId);
445 if (it==_StrNelVar.end())
447 if (NLMISC::CVariable<float>::exists(varId))
449 nlwarning("Nel variable \"%s\" exists outside of this state instance", varId.c_str());
450 return;
452 _StrNelVar[varId] = new NLMISC::CVariable<std::string>("StateInstanceStrVar", varId.c_str(), "", std::string());
454 _StrNelVar[varId]->set(value);
457 inline
458 void CStateInstance::delStrNelVar(std::string const& varId)
460 TStrNelVarList::iterator it = _StrNelVar.find(varId);
461 if (it!=_StrNelVar.end())
463 delete it->second;
464 _StrNelVar.erase(it);
466 else
468 nldebug("Trying to delete Nel variable that doesn't exist: \"%s\"", varId.c_str());
472 inline
473 CAITimerExtended const& CStateInstance::userTimer (uint32 index) const
475 return _UserTimer[index];
478 inline
479 bool CStateInstance::advanceUserTimer(uint32 nbTicks)
481 for (uint k=0; k<4; ++k)
483 const uint32 t = getUserTimer(k);
484 setUserTimer(k, (t>nbTicks)?(t-nbTicks):0);
486 return true;
489 inline
490 void CStateInstance::processStateEvent(CAIEvent const& stateEvent, CAIState const* state)
492 // NOTE: This is a quick and inefficient implementation of event treatment - needs to be re-worked
493 // note that it is OK for state to be 'NULL'
494 if (!state)
496 state=getActiveState();
497 if (!state)
498 return;
501 bool foundReaction=false;
502 // nlassert(_mgr);
503 for (uint i=0;i<stateEvent.reactionList().size();++i)
505 const CAIEventReaction &reaction=*stateEvent.reactionList()[i];
506 if (!reaction.testCompatibility(this,state))
507 continue;
509 if (getDebugHistory()->isRecording())
511 nldebug("Reaction for event"); // FIXME: https://github.com/kaetemi/ryzomclassic/issues/152
512 nldebug("STATE: '%s' EVENT: '%s' REACTION: '%s'", state->getAliasNode()->fullName().c_str(),
513 stateEvent.getName().c_str(), reaction.getAliasNode()->fullName().c_str()); // FIXME: https://github.com/kaetemi/ryzomclassic/issues/152
514 getDebugHistory()->addHistory("STATE: '%s' EVENT: '%s' REACTION: '%s'", state->getAliasNode()->fullName().c_str(),
515 stateEvent.getName().c_str(), reaction.getAliasNode()->fullName().c_str());
518 foundReaction=true;
520 if (!reaction.getAction())
522 nldebug("Failed to find action for event"); // FIXME: https://github.com/kaetemi/ryzomclassic/issues/152
523 nlwarning("Failed to find action for event: %s",reaction.getAliasNode()->fullName().c_str());
524 continue;
526 if (!reaction.getAction()->executeAction(this, NULL))
528 nldebug("Failed to execute action for event"); // FIXME: https://github.com/kaetemi/ryzomclassic/issues/152
529 nlwarning("Failed to execute action for event '%s': for stateInstance:'%s' in state:'%s'", stateEvent.getName().c_str(),
530 aliasTreeOwner()->getAliasNode()->fullName().c_str(), state->getAliasNode()->fullName().c_str());
531 continue;
535 if (!foundReaction)
537 if (getDebugHistory()->isRecording())
539 nldebug("No reaction for event"); // FIXME: https://github.com/kaetemi/ryzomclassic/issues/152
540 nldebug("STATE: '%s' EVENT: '%s' NO REACTION", state->getAliasNode()->fullName().c_str(),
541 stateEvent.getName().c_str()); // FIXME: https://github.com/kaetemi/ryzomclassic/issues/152
542 getDebugHistory()->addHistory("STATE: '%s' EVENT: '%s' NO REACTION", state->getAliasNode()->fullName().c_str(),
543 stateEvent.getName().c_str());
549 inline
550 void CStateInstance::setNextState(CAIState* state)
552 // we're allowed to set state to 'no state'
553 if (!state)
555 _NextState = state;
556 return;
559 // make sure the state is positional (not punctual)
560 if (!state->isPositional())
562 nlwarning("setNextState(): State should not be punctual '%s'%s - setting state to std::numeric_limits<uint32>::max()",
563 state->getAliasNode()->fullName().c_str(),
564 state->getAliasString().c_str());
565 _NextState = NULL;
566 return;
569 // set the next state
570 _NextState = state;
573 inline
574 void CStateInstance::setNextPunctualState(CAIState* state)
576 // we're allowed to set state to 'no state'
577 if (!state)
578 return;
580 // make sure the state is not positional (ie punctual)
581 if (state->isPositional())
583 nlwarning("CStateInstance::setNextPunctualState(): State should be punctual '%s'%s - setting state to std::numeric_limits<uint32>::max()",
584 state->getAliasNode()->fullName().c_str(),
585 state->getAliasString().c_str());
586 state = NULL;
587 return;
590 // set the next state
591 _NextPunctualState = state;
594 //////////////////////////////////////////////////////////////////////////////
595 // CPersistentStateInstance //
596 //////////////////////////////////////////////////////////////////////////////
598 inline
599 CPersistentStateInstance::CPersistentStateInstance(CStateMachine& reactionContainer)
600 : CKeyWordOwner()
601 , CStateInstance(NULL)
602 , _StartState()
603 , _Container(reactionContainer)
607 inline
608 CPersistentStateInstance::~CPersistentStateInstance()
610 #if !FINAL_VERSION
611 if (_PSIChilds.size()!=0)
612 nlwarning("a Npc group is dying and still have childs, which is not possible !!");
613 nlassert(_PSIChilds.size()==0);
614 #endif
615 if (!_ParentStateInstance.isNULL())
616 _ParentStateInstance->removeChildStateInstance(this);
619 inline
620 void CPersistentStateInstance::setParentStateInstance(CPersistentStateInstance* parentStateInstance)
622 if (!_ParentStateInstance.isNULL())
623 _ParentStateInstance->removeChildStateInstance(this);
624 _ParentStateInstance=parentStateInstance;
625 if (parentStateInstance!=NULL)
626 parentStateInstance->addChildStateInstance(this);
629 inline
630 void CPersistentStateInstance::addChildStateInstance(CPersistentStateInstance* parentStateInstance)
632 #if !FINAL_VERSION
633 nlassert(std::find(_PSIChilds.begin(), _PSIChilds.end(), NLMISC::CDbgPtr<CPersistentStateInstance>(parentStateInstance))==_PSIChilds.end());
634 #endif
635 _PSIChilds.push_back(parentStateInstance);
638 inline
639 void CPersistentStateInstance::removeChildStateInstance(CPersistentStateInstance* parentStateInstance)
641 TChildList::iterator it = std::find(_PSIChilds.begin(), _PSIChilds.end(), NLMISC::CDbgPtr<CPersistentStateInstance>(parentStateInstance));
642 #if !FINAL_VERSION
643 nlassert(it!=_PSIChilds.end());
644 #endif
645 if (it!=_PSIChilds.end())
646 _PSIChilds.erase(it);
649 inline
650 void CPersistentStateInstance::setStartState(CAIState* state)
652 _StartState = state;
653 CStateInstance::init(_StartState);
656 #include "event_reaction_include.h"
657 #endif