// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "script_compiler.h" #include "ai_grp_npc.h" #include "group_profile.h" #include "ai_generic_fight.h" #include "server_share/msg_brick_service.h" #include "continent_inline.h" #include "dyn_grp_inline.h" #include "ai_script_data_manager.h" #include "ai_logic_action.h" using std::string; using std::vector; using namespace NLMISC; using namespace AIVM; using namespace AICOMP; using namespace AITYPES; using namespace RYAI_MAP_CRUNCH; //---------------------------------------------------------------------------- /** @page code @subsection setEvent_f_ Triggers a user event. Arguments: f(EventId) -> @param EventId is the user event id to be triggered @code ()setEvent(0); // Triggers the event 0 @endcode */ // CStateInstance void setEvent_f_(CStateInstance* entity, CScriptStack& stack) { size_t const eventIndex = (size_t)(float)stack.top(); stack.pop(); if (!entity) { nlwarning("sendEvent failed"); return; } nlassert(eventIndex<10); if (IsRingShard.get()) { if ( entity->isUserEventBlocked( (uint32)eventIndex) ) { return; } // Do not allow uservent recursion on ring shard entity->blockUserEvent((uint32)eventIndex); } entity->processStateEvent(entity->getPersistentStateInstance()->getEventContainer().EventUserEvent[eventIndex]); if (IsRingShard.get()) { entity->unblockUserEvent((uint32)eventIndex); } } //---------------------------------------------------------------------------- /** @page code @subsection setTimer_ff_ Sets a timer delay and start it. Arguments: f(DeltaTime), f(TimerId) -> @param[in] DeltaTime is the time (in ticks) before the timer event is triggered @param[in] TimerId is the timer ID @code ()setTimer(200, 0); // Sets the timer t0 to 200 ticks @endcode */ // CStateInstance void setTimer_ff_(CStateInstance* si, CScriptStack& stack) { size_t const timerId = (int)(float)stack.top(); stack.pop(); size_t const deltaTime = (int)(float)stack.top(); stack.pop(); if (!si) { nlwarning("setTimer failed"); return; } if (timerId<0 || timerId>3) { string errStr("critical, native function setTimer used with out of bound parameter (0-3) equals to "); errStr += toString(timerId); nlwarning(errStr.c_str()); nlassert(false); } si->timerUser((uint)timerId).set((uint32)deltaTime); } //---------------------------------------------------------------------------- /** @page code @subsection timerSetRyzomDaytime_fff_ Set a timer at a specified hour in Ryzom time and start it. Arguments: f(TimerId), f(Hour), f(Minute) -> @param[in] TimerId is the timer ID @param[in] Hour is the hour we want the timer to trigger @param[in] Minute is the minute we want the timer to trigger @code ()timerSetRyzomDaytime(0, 13, 45); // create a timer at 13h45 (Ryzom time) @endcode */ // CStateInstance void timerSetRyzomDaytime_fff_(CStateInstance* si, CScriptStack& stack) { float const minute = (float)stack.top(); stack.pop(); float const hour = (float)stack.top(); stack.pop(); size_t const timerId = (int)(float)stack.top(); stack.pop(); if ( !(0 <= minute && minute <=59 && 0 <= hour && hour <= 23) ) { return; } float datime = hour + (minute * 100.f)/(60.f*100.f); float currentTime = CTimeInterface::getRyzomTime().getRyzomTime(); if (datime < currentTime) { // advance to next day currentTime -= 24; } float deltaTime = datime - currentTime; // convert to ticks uint32 timeTicks = uint32(deltaTime * RYZOM_HOURS_IN_TICKS); if (!si) { nlwarning("timerSetRyzomDaytime failed"); return; } if (timerId<0 || timerId>3) { string errStr("critical, native function timerSetRyzomDaytime used with out of bound parameter (0-3) equals to "); errStr += toString(timerId); nlwarning(errStr.c_str()); return; } si->timerUser((uint)timerId).set((uint32)timeTicks); } //---------------------------------------------------------------------------- /** @page code @subsection timerIsEnabled_f_f Test if a timer is enabled. Arguments: f(TimerId) -> f(IsEnabled) @param[in] TimerId is the timer ID @param[out] IsEnabled 1 if the timer is enabled @code (isEnabled)timerIsEnabled(0); // test if the timer t0 is enabled and put the ret in isEnabled variable @endcode */ // CStateInstance void timerIsEnabled_f_f(CStateInstance* si, CScriptStack& stack) { size_t const timerId = (int)(float)stack.top(); stack.pop(); if (!si) { nlwarning("timerIsEnabled failed"); return; } if (timerId<0 || timerId>3) { string errStr("critical, native function timerIsEnabled used with out of bound parameter (0-3) equals to "); errStr += toString(timerId); nlwarning(errStr.c_str()); return; } float isEnabled = si->timerUser((uint)timerId).isEnabled(); stack.push(isEnabled); } //---------------------------------------------------------------------------- /** @page code @subsection timerIsSuspended_f_f Test if a timer is suspended. Arguments: f(TimerId) -> f(IsSuspended) @param[in] TimerId is the timer ID @param[out] IsSuspended 1 if the timer is suspended @code (isSuspended)timerIsSuspended(0); // test if the timer t0 is suspended and put the ret in isSuspended variable @endcode */ // CStateInstance void timerIsSuspended_f_f(CStateInstance* si, CScriptStack& stack) { size_t const timerId = (int)(float)stack.top(); stack.pop(); if (!si) { nlwarning("timerIsSuspended failed"); return; } if (timerId<0 || timerId>3) { string errStr("critical, native function timerIsSuspended used with out of bound parameter (0-3) equals to "); errStr += toString(timerId); nlwarning(errStr.c_str()); return; } float isSuspended = si->timerUser((uint)timerId).isSuspended(); stack.push(isSuspended); } //---------------------------------------------------------------------------- /** @page code @subsection timerSuspend_f_ Suspend a timer. Arguments: f(TimerId) -> @param[in] TimerId is the timer ID @code ()timerSuspend(0); // suspend the timer t0 @endcode */ // CStateInstance void timerSuspend_f_(CStateInstance* si, CScriptStack& stack) { size_t const timerId = (int)(float)stack.top(); stack.pop(); if (!si) { nlwarning("timerSuspend failed"); return; } if (timerId<0 || timerId>3) { string errStr("critical, native function timerSuspend used with out of bound parameter (0-3) equals to "); errStr += toString(timerId); nlwarning(errStr.c_str()); return; } si->timerUser((uint)timerId).suspend(); } //---------------------------------------------------------------------------- /** @page code @subsection timerDisable_f_ Disable a timer. Arguments: f(TimerId) -> @param[in] TimerId is the timer ID @code ()timerDisable(0); // disable the timer t0 @endcode */ // CStateInstance void timerDisable_f_(CStateInstance* si, CScriptStack& stack) { size_t const timerId = (int)(float)stack.top(); stack.pop(); if (!si) { nlwarning("timerDisable failed"); return; } if (timerId<0 || timerId>3) { string errStr("critical, native function timerDisable used with out of bound parameter (0-3) equals to "); errStr += toString(timerId); nlwarning(errStr.c_str()); return; } si->timerUser((uint)timerId).disable(); } //---------------------------------------------------------------------------- /** @page code @subsection timerResume_f_ Resume a timer. Arguments: f(TimerId) -> @param[in] TimerId is the timer ID @code ()timerResume(0); // resume the timer t0 @endcode */ // CStateInstance void timerResume_f_(CStateInstance* si, CScriptStack& stack) { size_t const timerId = (int)(float)stack.top(); stack.pop(); if (!si) { nlwarning("timerResume failed"); return; } if (timerId<0 || timerId>3) { string errStr("critical, native function timerResume used with out of bound parameter (0-3) equals to "); errStr += toString(timerId); nlwarning(errStr.c_str()); return; } si->timerUser((uint)timerId).resume(); } //---------------------------------------------------------------------------- /** @page code @subsection timerAdd_ff_ Add a delta time to a timer. Arguments: f(TimerId), f(DeltaTime) -> @param[in] TimerId is the timer ID @param[in] DeltaTime is the delta time in ticks @code ()timerAdd(0, 41); // add 41 ticks to the next trigger ()timerAdd(0, -10); // remove 10 ticks to the next trigger @endcode */ // CStateInstance void timerAdd_ff_(CStateInstance* si, CScriptStack& stack) { float const dt = (float)stack.top(); stack.pop(); size_t const timerId = (int)(float)stack.top(); stack.pop(); if (!si) { nlwarning("timerAdd failed"); return; } if (timerId<0 || timerId>3) { string errStr("critical, native function timerAdd used with out of bound parameter (0-3) equals to "); errStr += toString(timerId); nlwarning(errStr.c_str()); return; } if (dt > 0) { uint32 dt2 = static_cast(dt); si->timerUser((uint)timerId).add(dt2); } else { uint32 dt2 = static_cast(-dt); si->timerUser((uint)timerId).sub(dt2); } } //---------------------------------------------------------------------------- /** @page code @subsection dssStartAct_ff_ Request the start of a dss Act. Arguments: f(SessionId), f(ActId)-> @param[in] SessionId is the id session @param[in] ActId is the id of the act (0 = permanent content) @code ()dssStartAct(42,2); // Start the 2ond act of the session 42 @endcode */ // CStateInstance void dssStartAct_ff_(CStateInstance* si, CScriptStack& stack) { float const actId = (float)stack.top(); stack.pop(); float const sessionId= (float)stack.top(); stack.pop(); if ( !(0 <= actId && 0 <= sessionId) ) { return; } CAILogicActionDssStartActHelper::dssStartAct(TSessionId(static_cast(sessionId)), static_cast(actId)); } //---------------------------------------------------------------------------- /** @page code @subsection postNextState_s_ Triggers a state change. Arguments: s(StateName) -> @param[in] StateName is the name of the next state @code ()postNextState("state_invasion_2"); // Post the next state named 'state_invasion_2' if found in this state machine ()postNextState($name_var); // Post the next state named by name_var if found in this state machine @endcode */ // CStateInstance void postNextState_s_(CStateInstance* si, CScriptStack& stack) { string NextStateName = stack.top(); stack.pop(); if (!si) { nlwarning("postNextState failed!"); return; } CAIState* const state = si->getPersistentStateInstance()->getEventContainer().cstStates().getChildByName(NextStateName); if (!state) { string errStr; if (si->getGroup()) errStr="state "+NextStateName+" not found for "+si->getGroup()->getName(); else errStr="state "+NextStateName+" not found for unnamed group"; nlwarning(errStr.c_str()); return; } si->setNextState(state); } //---------------------------------------------------------------------------- /** @page code @subsection import_s_ Imports (executes in current context as a script function) a script defined in a script rep. Arguments: s(libName) -> @param[in] libName is the library name @code ()import("script_boss"); @endcode */ // CStateInstance void import_s_(CStateInstance* entity, CScriptStack& stack) { string LibName = stack.top(); stack.pop(); CSmartPtr const& codePtr = AIVM::CLibrary::getInstance().getLib(LibName); if (codePtr!=NULL) entity->interpretCode(NULL, codePtr); else nlwarning("unknown library %s", LibName.c_str()); } //---------------------------------------------------------------------------- /** @page code @subsection setNelVar_sf_ Sets the content of a NeL Variable. The variable is created if it doesn't exist. Arguments: s(varId),f(value) -> @param[in] varId is a the name of the variable to set @param[in] value is a the value to set @code ()setNelVar("BotCount", 32); @endcode */ // CStateInstance void setNelVar_sf_(CStateInstance* entity, CScriptStack& stack) { float value = (float)stack.top(); stack.pop(); std::string varId = (std::string)stack.top(); stack.pop(); entity->setNelVar(varId, value); } void setGlobalNelVar_sf_(CStateInstance* entity, CScriptStack& stack) { float value = (float)stack.top(); stack.pop(); std::string varId = (std::string)stack.top(); stack.pop(); CStateInstance::setGlobalNelVar(varId, value); } //---------------------------------------------------------------------------- /** @page code @subsection getNelVar_s_f Returns the content of a NeL Variable. The variable is created if it doesn't exist. Arguments: s(varId) -> f(value) @param[in] varId is a the name of the variable to set @param[out] value is a the value of the variable @code (botCount)getNelVar("BotCount"); @endcode */ // CStateInstance void getNelVar_s_f(CStateInstance* entity, CScriptStack& stack) { std::string varId = (std::string)stack.top(); stack.top() = entity->getNelVar(varId); } //---------------------------------------------------------------------------- /** @page code @subsection delNelVar_ss_ Detetes a NeL Variable. Passed value is used to determine the type of the variable. Content of that value is ignored. Arguments: s(varId) -> @param[in] varId is a the name of the variable to delete @param[in] value is a a value of the same type of the variable @code ()delNelVar("BotCount", 0); @endcode */ // CStateInstance void delNelVar_sf_(CStateInstance* entity, CScriptStack& stack) { stack.pop(); std::string varId = (std::string)stack.top(); stack.pop(); entity->delNelVar(varId); } //---------------------------------------------------------------------------- /** @page code @subsection setNelVar_ss_ Sets the content of a NeL Variable. The variable is created if it doesn't exist. Arguments: s(varId),s(value) -> @param[in] varId is a the name of the variable to set @param[in] value is a the value to set @code ()setNelVar("BotFamily", "the_killers"); @endcode */ // CStateInstance void setNelVar_ss_(CStateInstance* entity, CScriptStack& stack) { std::string value = (std::string)stack.top(); stack.pop(); std::string varId = (std::string)stack.top(); stack.pop(); entity->setStrNelVar(varId, value); } void setGlobalNelVar_ss_(CStateInstance* entity, CScriptStack& stack) { std::string value = (std::string)stack.top(); stack.pop(); std::string varId = (std::string)stack.top(); stack.pop(); CStateInstance::setGlobalNelVar(varId, value); } //---------------------------------------------------------------------------- /** @page code @subsection getNelVar_s_s Returns the content of a NeL Variable. The variable is created if it doesn't exist. Arguments: s(varId) -> s(value) @param[in] varId is a the name of the variable to set @param[out] value is a the value of the variable @code (botFamily)getNelVar("BotFamily"); @endcode */ // CStateInstance void getNelVar_s_s(CStateInstance* entity, CScriptStack& stack) { std::string varId = (std::string)stack.top(); stack.top() = entity->getStrNelVar(varId); } //---------------------------------------------------------------------------- /** @page code @subsection delNelVar_ss_ Detetes a NeL Variable. Passed value is used to determine the type of the variable. Content of that value is ignored. Arguments: s(varId) -> @param[in] varId is a the name of the variable to delete @param[in] value is a a value of the same type of the variable @code ()delNelVar("BotFamily", ""); @endcode */ // CStateInstance void delNelVar_ss_(CStateInstance* entity, CScriptStack& stack) { stack.pop(); std::string varId = (std::string)stack.top(); stack.pop(); entity->delStrNelVar(varId); } //---------------------------------------------------------------------------- /** @page code @subsection getStateName__s Returns the name of the current state. Arguments: -> s(StateName) @param[out] StateName is the name of the current state @code ($name)getStateName(); @endcode */ // CStateInstance void getStateName__s(CStateInstance* si, CScriptStack& stack) { string str; breakable { if (!si) break; CAIState const* const curState = si->getState(); if (!curState) break; str = curState->getName(); } stack.push(str); } ////////////////////////////////////////////////////////////////////////////// // Undocumented methods // ////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------- // CStateInstance void loadFile_s_(CStateInstance* entity, CScriptStack& stack) { string fileName = stack.top(); stack.pop(); try { NLMISC::CIFile file(NLMISC::CPath::lookup(fileName)); vector lines; while (!file.eof()) { const size_t bufferSize = 4*1024; char buffer[bufferSize]; file.getline(buffer, bufferSize); lines.push_back(buffer); } // Compile the buffer CSmartPtr codePtr = CCompiler::getInstance().compileCode(lines, fileName); // Interpret the code for the group entity->interpretCode(NULL, codePtr); } catch (EPathNotFound e) { nlwarning("Path not found while loading AIS script %s", fileName.c_str()); } } /****************************************************************************/ std::map nfGetStateInstanceNativeFunctions() { std::map functions; #define REGISTER_NATIVE_FUNC(cont, func) cont.insert(std::make_pair(std::string(#func), &func)) REGISTER_NATIVE_FUNC(functions, setEvent_f_); REGISTER_NATIVE_FUNC(functions, setTimer_ff_); REGISTER_NATIVE_FUNC(functions, timerSetRyzomDaytime_fff_); REGISTER_NATIVE_FUNC(functions, timerDisable_f_); REGISTER_NATIVE_FUNC(functions, timerSuspend_f_); REGISTER_NATIVE_FUNC(functions, timerResume_f_); REGISTER_NATIVE_FUNC(functions, timerAdd_ff_); REGISTER_NATIVE_FUNC(functions, timerIsEnabled_f_f); REGISTER_NATIVE_FUNC(functions, timerIsSuspended_f_f); REGISTER_NATIVE_FUNC(functions, dssStartAct_ff_); REGISTER_NATIVE_FUNC(functions, postNextState_s_); REGISTER_NATIVE_FUNC(functions, import_s_); REGISTER_NATIVE_FUNC(functions, setNelVar_sf_); REGISTER_NATIVE_FUNC(functions, getNelVar_s_f); REGISTER_NATIVE_FUNC(functions, delNelVar_sf_); REGISTER_NATIVE_FUNC(functions, setNelVar_ss_); REGISTER_NATIVE_FUNC(functions, getNelVar_s_s); REGISTER_NATIVE_FUNC(functions, delNelVar_ss_); REGISTER_NATIVE_FUNC(functions, setGlobalNelVar_sf_); REGISTER_NATIVE_FUNC(functions, setGlobalNelVar_ss_); REGISTER_NATIVE_FUNC(functions, getStateName__s); REGISTER_NATIVE_FUNC(functions, loadFile_s_); #undef REGISTER_NATIVE_FUNC return functions; }