1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
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"
25 #include "ai_outpost.h"
28 using namespace NLMISC
;
29 using namespace AICOMP
;
32 //////////////////////////////////////////////////////////////////////////////
34 //////////////////////////////////////////////////////////////////////////////
36 CAIState
const* CStateInstance::getActiveState() const
42 return NULL
; // ugly! -> to remove date = 19/05/2004.
45 if (_PunctualState
) // the puntual state is active !
46 return _PunctualState
;
48 if (_state
) // the normal state is active !
51 // no state is active !
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())
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())
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
);
123 bool varArg
= (mode
& 1)!=0; // :KLUDGE: Hardcoded 1 :TODO: Replace with a names constant (see script_compiler.cpp)
128 stack
->push(outParamsSig
);
129 stack
->push(inParamsSig
);
131 funcParam
->_func(this, *stack
);
135 AIVM::CScriptStack dummyStack
;
138 dummyStack
.push(outParamsSig
);
139 dummyStack
.push(inParamsSig
);
141 funcParam
->_func(this, dummyStack
);
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
)
194 nlassert(this->getGroup());
196 std::vector
<CGroup
*> grps
;
197 getGroup()->getAIInstance()->findGroup(grps
, CStringMapper::unmap(strId
));
199 FOREACH(grpIt
, std::vector
<CGroup
*>, grps
) {
200 CGroup
*grp
= *grpIt
;
202 if (!grp
->isSpawned())
205 CStateInstance
*stateInstance
= grp
->getPersistentStateInstance();
207 return stateInstance
;
214 std::string
CStateInstance::getContextName()
216 return getGroup()->getFullName();
221 void CStateInstance::init(CAIState
* startState
)
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
);
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
);
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())
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
316 CAIState
const* oldState
= NULL
;
317 if (!_PunctualState
&& !_NextPunctualState
&& _state
)
319 // close down current state
321 processStateEvent(getEventContainer().EventEndOfState
);
324 // switch state & initalise state status flags
327 _StateTimeout
.disable();
329 if (_PunctualState
|| _NextPunctualState
)
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
;
348 oldState
= _PunctualState
;
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
)
383 _CancelPunctualState
= false;
385 // if there was an active punctual state then cancel it
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"