mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-12-21 00:37:12 +01:00
Full Distribution
This commit is contained in:
434
src/creatureevent.cpp
Normal file
434
src/creatureevent.cpp
Normal file
@@ -0,0 +1,434 @@
|
||||
/**
|
||||
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "otpch.h"
|
||||
|
||||
#include "creatureevent.h"
|
||||
#include "tools.h"
|
||||
#include "player.h"
|
||||
|
||||
CreatureEvents::CreatureEvents() :
|
||||
scriptInterface("CreatureScript Interface")
|
||||
{
|
||||
scriptInterface.initState();
|
||||
}
|
||||
|
||||
CreatureEvents::~CreatureEvents()
|
||||
{
|
||||
for (const auto& it : creatureEvents) {
|
||||
delete it.second;
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureEvents::clear()
|
||||
{
|
||||
//clear creature events
|
||||
for (const auto& it : creatureEvents) {
|
||||
it.second->clearEvent();
|
||||
}
|
||||
|
||||
//clear lua state
|
||||
scriptInterface.reInitState();
|
||||
}
|
||||
|
||||
LuaScriptInterface& CreatureEvents::getScriptInterface()
|
||||
{
|
||||
return scriptInterface;
|
||||
}
|
||||
|
||||
std::string CreatureEvents::getScriptBaseName() const
|
||||
{
|
||||
return "creaturescripts";
|
||||
}
|
||||
|
||||
Event* CreatureEvents::getEvent(const std::string& nodeName)
|
||||
{
|
||||
if (strcasecmp(nodeName.c_str(), "event") != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return new CreatureEvent(&scriptInterface);
|
||||
}
|
||||
|
||||
bool CreatureEvents::registerEvent(Event* event, const pugi::xml_node&)
|
||||
{
|
||||
CreatureEvent* creatureEvent = static_cast<CreatureEvent*>(event); //event is guaranteed to be a CreatureEvent
|
||||
if (creatureEvent->getEventType() == CREATURE_EVENT_NONE) {
|
||||
std::cout << "Error: [CreatureEvents::registerEvent] Trying to register event without type!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
CreatureEvent* oldEvent = getEventByName(creatureEvent->getName(), false);
|
||||
if (oldEvent) {
|
||||
//if there was an event with the same that is not loaded
|
||||
//(happens when realoading), it is reused
|
||||
if (!oldEvent->isLoaded() && oldEvent->getEventType() == creatureEvent->getEventType()) {
|
||||
oldEvent->copyEvent(creatureEvent);
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
//if not, register it normally
|
||||
creatureEvents[creatureEvent->getName()] = creatureEvent;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
CreatureEvent* CreatureEvents::getEventByName(const std::string& name, bool forceLoaded /*= true*/)
|
||||
{
|
||||
auto it = creatureEvents.find(name);
|
||||
if (it != creatureEvents.end()) {
|
||||
if (!forceLoaded || it->second->isLoaded()) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CreatureEvents::playerLogin(Player* player) const
|
||||
{
|
||||
//fire global event if is registered
|
||||
for (const auto& it : creatureEvents) {
|
||||
if (it.second->getEventType() == CREATURE_EVENT_LOGIN) {
|
||||
if (!it.second->executeOnLogin(player)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreatureEvents::playerLogout(Player* player) const
|
||||
{
|
||||
//fire global event if is registered
|
||||
for (const auto& it : creatureEvents) {
|
||||
if (it.second->getEventType() == CREATURE_EVENT_LOGOUT) {
|
||||
if (!it.second->executeOnLogout(player)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreatureEvents::playerAdvance(Player* player, skills_t skill, uint32_t oldLevel,
|
||||
uint32_t newLevel)
|
||||
{
|
||||
for (const auto& it : creatureEvents) {
|
||||
if (it.second->getEventType() == CREATURE_EVENT_ADVANCE) {
|
||||
if (!it.second->executeAdvance(player, skill, oldLevel, newLevel)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
CreatureEvent::CreatureEvent(LuaScriptInterface* interface) :
|
||||
Event(interface), type(CREATURE_EVENT_NONE), loaded(false) {}
|
||||
|
||||
bool CreatureEvent::configureEvent(const pugi::xml_node& node)
|
||||
{
|
||||
// Name that will be used in monster xml files and
|
||||
// lua function to register events to reference this event
|
||||
pugi::xml_attribute nameAttribute = node.attribute("name");
|
||||
if (!nameAttribute) {
|
||||
std::cout << "[Error - CreatureEvent::configureEvent] Missing name for creature event" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
eventName = nameAttribute.as_string();
|
||||
|
||||
pugi::xml_attribute typeAttribute = node.attribute("type");
|
||||
if (!typeAttribute) {
|
||||
std::cout << "[Error - CreatureEvent::configureEvent] Missing type for creature event: " << eventName << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string tmpStr = asLowerCaseString(typeAttribute.as_string());
|
||||
if (tmpStr == "login") {
|
||||
type = CREATURE_EVENT_LOGIN;
|
||||
} else if (tmpStr == "logout") {
|
||||
type = CREATURE_EVENT_LOGOUT;
|
||||
} else if (tmpStr == "think") {
|
||||
type = CREATURE_EVENT_THINK;
|
||||
} else if (tmpStr == "preparedeath") {
|
||||
type = CREATURE_EVENT_PREPAREDEATH;
|
||||
} else if (tmpStr == "death") {
|
||||
type = CREATURE_EVENT_DEATH;
|
||||
} else if (tmpStr == "kill") {
|
||||
type = CREATURE_EVENT_KILL;
|
||||
} else if (tmpStr == "advance") {
|
||||
type = CREATURE_EVENT_ADVANCE;
|
||||
} else if (tmpStr == "extendedopcode") {
|
||||
type = CREATURE_EVENT_EXTENDED_OPCODE;
|
||||
} else {
|
||||
std::cout << "[Error - CreatureEvent::configureEvent] Invalid type for creature event: " << eventName << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CreatureEvent::getScriptEventName() const
|
||||
{
|
||||
//Depending on the type script event name is different
|
||||
switch (type) {
|
||||
case CREATURE_EVENT_LOGIN:
|
||||
return "onLogin";
|
||||
|
||||
case CREATURE_EVENT_LOGOUT:
|
||||
return "onLogout";
|
||||
|
||||
case CREATURE_EVENT_THINK:
|
||||
return "onThink";
|
||||
|
||||
case CREATURE_EVENT_PREPAREDEATH:
|
||||
return "onPrepareDeath";
|
||||
|
||||
case CREATURE_EVENT_DEATH:
|
||||
return "onDeath";
|
||||
|
||||
case CREATURE_EVENT_KILL:
|
||||
return "onKill";
|
||||
|
||||
case CREATURE_EVENT_ADVANCE:
|
||||
return "onAdvance";
|
||||
|
||||
case CREATURE_EVENT_EXTENDED_OPCODE:
|
||||
return "onExtendedOpcode";
|
||||
|
||||
case CREATURE_EVENT_NONE:
|
||||
default:
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureEvent::copyEvent(CreatureEvent* creatureEvent)
|
||||
{
|
||||
scriptId = creatureEvent->scriptId;
|
||||
scriptInterface = creatureEvent->scriptInterface;
|
||||
scripted = creatureEvent->scripted;
|
||||
loaded = creatureEvent->loaded;
|
||||
}
|
||||
|
||||
void CreatureEvent::clearEvent()
|
||||
{
|
||||
scriptId = 0;
|
||||
scriptInterface = nullptr;
|
||||
scripted = false;
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
bool CreatureEvent::executeOnLogin(Player* player)
|
||||
{
|
||||
//onLogin(player)
|
||||
if (!scriptInterface->reserveScriptEnv()) {
|
||||
std::cout << "[Error - CreatureEvent::executeOnLogin] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
||||
env->setScriptId(scriptId, scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface->getLuaState();
|
||||
|
||||
scriptInterface->pushFunction(scriptId);
|
||||
LuaScriptInterface::pushUserdata(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
return scriptInterface->callFunction(1);
|
||||
}
|
||||
|
||||
bool CreatureEvent::executeOnLogout(Player* player)
|
||||
{
|
||||
//onLogout(player)
|
||||
if (!scriptInterface->reserveScriptEnv()) {
|
||||
std::cout << "[Error - CreatureEvent::executeOnLogout] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
||||
env->setScriptId(scriptId, scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface->getLuaState();
|
||||
|
||||
scriptInterface->pushFunction(scriptId);
|
||||
LuaScriptInterface::pushUserdata(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
return scriptInterface->callFunction(1);
|
||||
}
|
||||
|
||||
bool CreatureEvent::executeOnThink(Creature* creature, uint32_t interval)
|
||||
{
|
||||
//onThink(creature, interval)
|
||||
if (!scriptInterface->reserveScriptEnv()) {
|
||||
std::cout << "[Error - CreatureEvent::executeOnThink] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
||||
env->setScriptId(scriptId, scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface->getLuaState();
|
||||
|
||||
scriptInterface->pushFunction(scriptId);
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
lua_pushnumber(L, interval);
|
||||
|
||||
return scriptInterface->callFunction(2);
|
||||
}
|
||||
|
||||
bool CreatureEvent::executeOnPrepareDeath(Creature* creature, Creature* killer)
|
||||
{
|
||||
//onPrepareDeath(creature, killer)
|
||||
if (!scriptInterface->reserveScriptEnv()) {
|
||||
std::cout << "[Error - CreatureEvent::executeOnPrepareDeath] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
||||
env->setScriptId(scriptId, scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface->getLuaState();
|
||||
|
||||
scriptInterface->pushFunction(scriptId);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
|
||||
if (killer) {
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, killer);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, killer);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
return scriptInterface->callFunction(2);
|
||||
}
|
||||
|
||||
bool CreatureEvent::executeOnDeath(Creature* creature, Item* corpse, Creature* killer, Creature* mostDamageKiller, bool lastHitUnjustified, bool mostDamageUnjustified)
|
||||
{
|
||||
//onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified)
|
||||
if (!scriptInterface->reserveScriptEnv()) {
|
||||
std::cout << "[Error - CreatureEvent::executeOnDeath] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
||||
env->setScriptId(scriptId, scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface->getLuaState();
|
||||
|
||||
scriptInterface->pushFunction(scriptId);
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
|
||||
LuaScriptInterface::pushThing(L, corpse);
|
||||
|
||||
if (killer) {
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, killer);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, killer);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
if (mostDamageKiller) {
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, mostDamageKiller);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, mostDamageKiller);
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
LuaScriptInterface::pushBoolean(L, lastHitUnjustified);
|
||||
LuaScriptInterface::pushBoolean(L, mostDamageUnjustified);
|
||||
|
||||
return scriptInterface->callFunction(6);
|
||||
}
|
||||
|
||||
bool CreatureEvent::executeAdvance(Player* player, skills_t skill, uint32_t oldLevel,
|
||||
uint32_t newLevel)
|
||||
{
|
||||
//onAdvance(player, skill, oldLevel, newLevel)
|
||||
if (!scriptInterface->reserveScriptEnv()) {
|
||||
std::cout << "[Error - CreatureEvent::executeAdvance] Call stack overflow" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
||||
env->setScriptId(scriptId, scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface->getLuaState();
|
||||
|
||||
scriptInterface->pushFunction(scriptId);
|
||||
LuaScriptInterface::pushUserdata(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
lua_pushnumber(L, static_cast<uint32_t>(skill));
|
||||
lua_pushnumber(L, oldLevel);
|
||||
lua_pushnumber(L, newLevel);
|
||||
|
||||
return scriptInterface->callFunction(4);
|
||||
}
|
||||
|
||||
void CreatureEvent::executeOnKill(Creature* creature, Creature* target)
|
||||
{
|
||||
//onKill(creature, target)
|
||||
if (!scriptInterface->reserveScriptEnv()) {
|
||||
std::cout << "[Error - CreatureEvent::executeOnKill] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
||||
env->setScriptId(scriptId, scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface->getLuaState();
|
||||
|
||||
scriptInterface->pushFunction(scriptId);
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||
LuaScriptInterface::pushUserdata<Creature>(L, target);
|
||||
LuaScriptInterface::setCreatureMetatable(L, -1, target);
|
||||
scriptInterface->callVoidFunction(2);
|
||||
}
|
||||
|
||||
void CreatureEvent::executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer)
|
||||
{
|
||||
//onExtendedOpcode(player, opcode, buffer)
|
||||
if (!scriptInterface->reserveScriptEnv()) {
|
||||
std::cout << "[Error - CreatureEvent::executeExtendedOpcode] Call stack overflow" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
||||
env->setScriptId(scriptId, scriptInterface);
|
||||
|
||||
lua_State* L = scriptInterface->getLuaState();
|
||||
|
||||
scriptInterface->pushFunction(scriptId);
|
||||
|
||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||
|
||||
lua_pushnumber(L, opcode);
|
||||
LuaScriptInterface::pushString(L, buffer);
|
||||
|
||||
scriptInterface->callVoidFunction(3);
|
||||
}
|
||||
Reference in New Issue
Block a user