New lua versions
[ryzomcore.git] / ryzom / server / src / ai_service / state_instance.cpp
blob3b902319fa2edf6caa3c5a30451a60ca15723832
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdpch.h"
18 #include "state_instance.h"
20 #include "nel/misc/smart_ptr.h"
21 #include "script_vm.h"
22 #include "script_compiler.h"
23 #include "event_reaction_container.h"
24 #include "ai_grp.h"
25 #include "ai_outpost.h"
27 using namespace std;
28 using namespace NLMISC;
29 using namespace AICOMP;
30 using namespace AIVM;
32 //////////////////////////////////////////////////////////////////////////////
33 // CStateInstance //
34 //////////////////////////////////////////////////////////////////////////////
36 CAIState const* CStateInstance::getActiveState() const
38 #if !FINAL_VERSION
39 nlassert(this!=NULL);
40 #else
41 if (!this)
42 return NULL; // ugly! -> to remove date = 19/05/2004.
43 #endif
45 if (_PunctualState) // the puntual state is active !
46 return _PunctualState;
48 if (_state) // the normal state is active !
49 return _state;
51 // no state is active !
52 return NULL;
55 sint32 CStateInstance::getUserTimer(uint timerId)
57 NLMISC::clamp(timerId, 0u, 3u);
58 return _UserTimer[timerId].timeRemaining();
61 void CStateInstance::setUserTimer(uint timerId, sint32 time)
63 NLMISC::clamp(timerId, 0u, 3u);
64 if (_UserTimer[timerId].isEnabled())
65 _UserTimer[timerId].set(time);
68 void CStateInstance::addStatePersistentObj(CAIState const* keyState, CSmartPtr<NLMISC::CVirtualRefCount> anyObj)
70 _StatePersistentObjList.push_back(CStatePersistentObjEntry(keyState, anyObj));
73 void CStateInstance::setFirstBotSpawned()
75 _FirstBotSpawned = true;
78 struct CDiffStateRemover
80 CDiffStateRemover(CAIState const* const state) : _State(state) { }
81 bool operator()(CStateInstance::CStatePersistentObjEntry const& entry) const
83 return entry._State!=_State;
85 CAIState const* const _State;
88 void CStateInstance::removeExceptForState(CAIState const* keyState)
90 TStatePersistentObjList::iterator const itLast = remove_if(_StatePersistentObjList.begin(), _StatePersistentObjList.end(), CDiffStateRemover(keyState));
91 _StatePersistentObjList.erase(itLast, _StatePersistentObjList.end());
94 void CStateInstance::setScriptCallBack(TStringId const& eventName, AIVM::CByteCodeEntry const& codeScriptEntry)
96 _CallBacks[eventName] = codeScriptEntry; // effectively affects this callback to this eventName.
99 AIVM::CByteCodeEntry const* CStateInstance::getScriptCallBackPtr(TStringId const& eventName) const
101 TCallBackList::const_iterator it = _CallBacks.find(eventName);
102 if (it==_CallBacks.end())
103 return NULL;
104 return &(it->second);
107 void CStateInstance::callScriptCallBack(IScriptContext* caller, TStringId const& funcName, int mode, std::string const& inParamsSig, std::string const& outParamsSig, AIVM::CScriptStack* stack)
109 // :FIXME: mode, signatures end stack are unused
110 AIVM::CByteCodeEntry const* const codeScript = getScriptCallBackPtr(funcName);
111 if (!codeScript || !codeScript->isValid())
112 return;
114 interpretCode(caller, *codeScript); // effectively calls the call back.
117 void CStateInstance::callNativeCallBack(IScriptContext* caller, std::string const& funcName, int mode, std::string const& inParamsSig, std::string const& outParamsSig, AIVM::CScriptStack* stack)
119 // :FIXME: caller is unused
120 CScriptNativeFuncParams* funcParam = CCompiler::getNativeFunc(funcName, inParamsSig, outParamsSig);
121 if (funcParam!=NULL)
123 bool varArg = (mode & 1)!=0; // :KLUDGE: Hardcoded 1 :TODO: Replace with a names constant (see script_compiler.cpp)
124 if (stack!=NULL)
126 if (varArg)
128 stack->push(outParamsSig);
129 stack->push(inParamsSig);
131 funcParam->_func(this, *stack);
133 else
135 AIVM::CScriptStack dummyStack;
136 if (varArg)
138 dummyStack.push(outParamsSig);
139 dummyStack.push(inParamsSig);
141 funcParam->_func(this, dummyStack);
144 else
146 nlwarning("Trying to call an unknown native function '%s_%s_%s'", funcName.c_str(), inParamsSig.c_str(), outParamsSig.c_str());
147 // TODO:kxu: rebuild stack
151 void CStateInstance::dumpVarsAndFunctions(CStringWriter& sw) const
153 sw.append("float variables:");
154 FOREACHC(varIt, TLogicVarList, _LogicVar)
155 sw.append(" "+CStringMapper::unmap(varIt->first)+" = "+NLMISC::toString(varIt->second));
157 sw.append("string variables:");
158 FOREACHC(varIt, TStrLogicVarList, _StrLogicVar)
159 sw.append(" "+CStringMapper::unmap(varIt->first)+" = "+varIt->second);
161 sw.append("context variables:");
162 FOREACHC(varIt, TCtxLogicVarList, _CtxLogicVar)
163 sw.append(" "+CStringMapper::unmap(varIt->first)+" = "+NLMISC::toStringPtr(varIt->second));
165 sw.append("callBacks:");
166 FOREACHC(varIt, TCallBackList, _CallBacks)
167 sw.append(" "+CStringMapper::unmap(varIt->first));
170 void CStateInstance::interpretCode(IScriptContext* caller, CByteCodeEntry const& codeScriptEntry)
172 AIVM::IScriptContext* parent = getPersistentStateInstance()->getParentStateInstance();
173 AIVM::CScriptVM::getInstance()->interpretCode(this, parent, caller, codeScriptEntry);
176 void CStateInstance::interpretCode(IScriptContext* caller, CSmartPtr<CByteCode const> const& codeScript)
178 interpretCode(caller, CByteCodeEntry(codeScript, 0));
181 void CStateInstance::interpretCodeOnChildren(CByteCodeEntry const& codeScriptEntry)
183 vector<CSmartPtr<CGroup> > tmpList;
184 FOREACH(childIt, CPersistentStateInstance::TChildList, getPersistentStateInstance()->childs())
185 tmpList.push_back((*childIt)->getGroup());
187 FOREACH(childIt, vector<CSmartPtr<CGroup> >, tmpList)
188 (*childIt)->getPersistentStateInstance()->interpretCode(this, codeScriptEntry);
191 IScriptContext* CStateInstance::findContext(NLMISC::TStringId const strId)
193 #if !FINAL_VERSION
194 nlassert(this->getGroup());
195 #endif
196 std::vector<CGroup*> grps;
197 getGroup()->getAIInstance()->findGroup(grps, CStringMapper::unmap(strId));
199 FOREACH(grpIt, std::vector<CGroup*>, grps) {
200 CGroup *grp = *grpIt;
201 if (grp) {
202 if (!grp->isSpawned())
203 continue;
205 CStateInstance *stateInstance = grp->getPersistentStateInstance();
206 if (stateInstance)
207 return stateInstance;
211 return NULL;
214 std::string CStateInstance::getContextName()
216 return getGroup()->getFullName();
221 void CStateInstance::init(CAIState* startState)
223 _state=
224 _PunctualState=
225 _NextPunctualState=NULL;
227 _CancelPunctualState = false;
228 _NextState = startState;
229 _LogicVarChanged = false;
230 _FirstBotSpawned = false;
231 // _VarIndex[CStringMapper::map("v0")]=0;
232 // _VarIndex[CStringMapper::map("v1")]=1;
233 // _VarIndex[CStringMapper::map("v2")]=2;
234 // _VarIndex[CStringMapper::map("v3")]=3;
237 void CStateInstance::setGlobalNelVar(std::string const& varId, float value)
239 if (NLMISC::ICommand::exists(varId))
240 NLMISC::ICommand::execute(NLMISC::toString("%s %f", varId.c_str(), value), *NLMISC::InfoLog);
241 else
242 nlwarning("Nel variable \"%s\" do not exist", varId.c_str());
245 void CStateInstance::setGlobalNelVar(std::string const& varId, std::string value)
247 std::vector<std::string> args; args.push_back(value);
248 if (NLMISC::ICommand::exists(varId))
249 NLMISC::ICommand::execute(NLMISC::toString("%s %s", varId.c_str(), value.c_str()), *NLMISC::InfoLog);
250 else
251 nlwarning("Nel variable \"%s\" do not exist", varId.c_str());
255 void CStateInstance::blockUserEvent(uint32 eventId)
257 _UserEventBlocked |= (1 << eventId);
260 void CStateInstance::unblockUserEvent(uint32 eventId)
262 _UserEventBlocked &= ~(1 << eventId);
265 bool CStateInstance::isUserEventBlocked(uint32 eventId) const
267 return ((1 << eventId) & _UserEventBlocked) != 0;
270 //////////////////////////////////////////////////////////////////////////////
271 // CPersistentStateInstance //
272 //////////////////////////////////////////////////////////////////////////////
274 void CPersistentStateInstance::updateStateInstance()
276 // deal with timer events -----------------------------------------
278 // Event: State Timeout
279 if (_StateTimeout.testOnce())
280 processStateEvent(getEventContainer().EventPositionalStateTimeout);
282 // Event: Punctual State Timeout
283 if (_PunctualStateTimeout.testOnce())
284 processStateEvent(getEventContainer().EventPunctualStateTimeout);
286 // Event: User Timer n Triggered
287 for (uint i=0;i<4;++i)
289 if (!_UserTimer[i].testOnce())
290 continue;
291 processStateEvent(getEventContainer().EventUserTimer[i]);
296 // Event logic var changed
297 if (_LogicVarChanged)
299 processStateEvent(getEventContainer().EventVariableChanged);
300 for(uint i =0;i<4;++i)
302 if(_LogicVarChangedList[i]==true)
304 processStateEvent(getEventContainer().EventVariableChangedTab[i]);
305 _LogicVarChangedList[i]=false;
308 _LogicVarChanged = false;
311 // deal with positional state change ------------------------------
313 // if state change requested (and not in punctual state) then setup new state
314 if (_NextState)
316 CAIState const* oldState = NULL;
317 if (!_PunctualState && !_NextPunctualState && _state)
319 // close down current state
320 oldState = _state;
321 processStateEvent(getEventContainer().EventEndOfState);
324 // switch state & initalise state status flags
325 _state = _NextState;
326 _NextState = NULL;
327 _StateTimeout.disable();
329 if (_PunctualState || _NextPunctualState)
330 return;
332 removeExceptForState(_state);
333 processStateEvent(getEventContainer().EventStartOfState);
334 stateChange(oldState, _state);
337 // deal with start of punctual state ------------------------------
339 // if state change requested then setup new state
340 if (_NextPunctualState)
342 CAIState const* oldState = NULL;
344 breakable
346 if (_PunctualState)
348 oldState = _PunctualState;
349 break;
351 if (_state)
353 oldState = _state;
354 break;
358 // switch state & initalize state status flags
359 _PunctualState = _NextPunctualState;
360 _NextPunctualState = NULL;
361 _CancelPunctualState = false;
362 _PunctualStateTimeout.disable();
364 // initalize new state
365 CAIState const* const newState = _PunctualState;
367 removeExceptForState(newState);
368 processStateEvent(getEventContainer().EventStartOfState, newState);
369 stateChange(oldState, newState);
372 // must be done after start of state
373 if (_FirstBotSpawned)
375 _FirstBotSpawned = false;
376 processStateEvent(getEventContainer().EventFirstBotSpawned);
378 // deal with end of punctual state --------------------------------
380 if (!_CancelPunctualState)
381 return;
383 _CancelPunctualState = false;
385 // if there was an active punctual state then cancel it
386 if (!_PunctualState)
387 return;
389 // switch state & initalise state status flags
390 _PunctualStateTimeout.disable();
391 _StateTimeout.resume(); // this line just in case timeout suspended during punctual state
393 // close down current state
394 CAIState const* const punctualState = _PunctualState;
396 processStateEvent(getEventContainer().EventEndOfState, punctualState);
397 _PunctualState = NULL;
399 // this removes obj that depends on state affectation existence.
400 removeExceptForState(_state);
402 // specialized virtual state change call.
403 stateChange(punctualState, _state);
409 #include "event_reaction_include.h"