• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

TFS 1.X+ HELP- Healthchange (CreatureScript).

Zodia

Member
Joined
Feb 21, 2020
Messages
220
Reaction score
20
I'm trying to add a Vocation Balancing system via Creaturescripts. But I found a problem. I spent many years incurring it and I'm a little lost.

Nostalrius 7.72 TFS 1.2
OUTP erro:
[Error - CreatureEvent::configureEvent] Invalid type for creature event: balancevoc

[Warning - BaseEvents::loadFromXml] Failed to configure event

Login.lua
Code:
<event type="healthchange" name="balancevoc" script="vocation_balance.lua"/>

creaturescrits.lua
Code:
<event type="healthchange" name="balancevoc" script="vocation_balance.lua"/>

healthchange.lua
Lua:
local balance = {
--All
timesRepeatCondition = 3
intervalCondition = 900
--Knight
canBlock = true,
canBleed = true,
blockChance = 10,
bleedChance = 10,
blockMaxEffect = 70, -- %
blockMinEffect = 20, -- %
bleedMaxDmg = 60, -- this means the percent of the atk dmg =)
bleedMinDmg = 20, -- this means the percent of the atk dmg =)

--Paladin
canHeadShot = true, -- like a critical
canBleedRP = true, --
headshootChance = 20,
bleedChanceRP = 7,
headshootMaxMultiplier = 1.3, -- 2.5x dmg (less than 1 means a dmg reduction instead of a bonus!)
headshootMinMultiplier = 1.0, -- 1.1x dmg (less than 1 means a dmg reduction instead of a bonus!)
bleedMaxDmgRP = 50, -- this means the percent of the atk dmg =)
bleedMinDmgRP = 10, -- this means the percent of the atk dmg =)

--Sorcerer
canBurn = true, -- true or false
canEletrify = true, -- true or false
canCurse = true, -- true or false
burnChance = 10,
eletrifyChance = 10,
curseChance = 10,
burnMaxDmg = 60, -- this means the percent of the atk dmg =)
eletrifyMaxDmg = 60, -- this means the percent of the atk dmg =)
curseMaxDmg = 60, -- this means the percent of the atk dmg =)
burnMinDmg = 20, -- this means the percent of the atk dmg =)
eletrifyMinDmg = 20, -- this means the percent of the atk dmg =)
curseMinDmg = 20, -- this means the percent of the atk dmg =)

--Druid
canParalyze = true, -- true or false
canFreeze = true, -- true or false
paralyzeChance = 10,
freezeChance = 10,
paralyzeMaxEffect = 750, -- for example: 100 = ingame speed 50
paralyzeMinEffect = 350,
freezeMaxDmg = 60, -- this means the percent of the atk dmg =)
freezeMinDmg = 20, -- this means the percent of the atk dmg =)
}

function onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
        if primaryType == COMBAT_HEALING then
            return primaryDamage, primaryType, secondaryDamage, secondaryType
        end
        if not attacker then
            return primaryDamage, primaryType, secondaryDamage, secondaryType
        end
    local dmg = 0
    local block = math.random(100)
    local headshot = math.random(100)
    local rand = math.random(100)
        local atacado = creature:getMonster()
    if not atacado then
atacado = creature
    end
   
        if attacker:isPlayer() then
        -- KNIGHTS
            if attacker:getVocation():getClientId() == 1 then
                if balance.canBleed == true then
                    if rand <= balance.bleedChance then
                dmg = primaryDamage * math.random(balance.bleedMinDmg, balance.bleedMaxDmg)/100
                  local condition = Condition(CONDITION_BLEEDING)
                        condition:setParameter(CONDITION_PARAM_DELAYED, 1)
                        condition:addDamage(balance.timesRepeatCondition, balance.intervalCondition, -dmg)
                        atacado:addCondition(condition)
                    end
                end
            end
        -- PALADINS
            if attacker:getVocation():getClientId() == 2 then
                if balance.canBleedRP == true then
                    if primaryType == COMBAT_PHYSICALDAMAGE then
                        if rand <= balance.bleedChanceRP then
                dmg = primaryDamage * math.random(balance.bleedMinDmgRP, balance.bleedMaxDmgRP)/100
                            local condition = Condition(CONDITION_BLEEDING)
                            condition:setParameter(CONDITION_PARAM_DELAYED, 1)
                            condition:addDamage(balance.timesRepeatCondition, balance.intervalCondition, -dmg)
                            atacado:addCondition(condition)
                        end
                    end
                end
                if balance.canHeadShot == true then
                local hs = (math.random(balance.headshootMinMultiplier, balance.headshootMaxMultiplier))
                        if headshot <= balance.headshootChance then
                            if primaryDamage > 0 then
                                primaryDamage = primaryDamage * hs
                                creature:say("HEADSHOT!", TALKTYPE_MONSTER_SAY)
                            end      
                        end
                end
            end
        -- SORCERERS
            if attacker:getVocation():getClientId() == 3 then
                if balance.canBurn == true then
                    if primaryType == COMBAT_FIREDAMAGE then
                        if rand <= balance.burnChance then
                dmg = primaryDamage * math.random(balance.burnMinDmg, balance.burnMaxDmg)/100
                            local condition = Condition(CONDITION_FIRE)
                            condition:setParameter(CONDITION_PARAM_DELAYED, 1)
                            condition:addDamage(balance.timesRepeatCondition, balance.intervalCondition, -dmg)
                            atacado:addCondition(condition)
                        end
                    end
                end
                if balance.canEletrify == true then
                    if primaryType == COMBAT_ENERGYDAMAGE then
                        if rand <= balance.eletrifyChance then
                dmg = primaryDamage * math.random(balance.eletrifyMinDmg, balance.eletrifyMaxDmg)/100
                            local condition = Condition(CONDITION_ENERGY)
                            condition:setParameter(CONDITION_PARAM_DELAYED, 1)
                            condition:addDamage(balance.timesRepeatCondition, balance.intervalCondition, -dmg)
                            atacado:addCondition(condition)
                        end
                    end              
                end
                if balance.canCurse == true then
                    if primaryType == COMBAT_DEATHDAMAGE then
                        if rand <= balance.curseChance then
                dmg = primaryDamage * math.random(balance.curseMinDmg, balance.curseMaxDmg)/100
                            local condition = Condition(CONDITION_CURSED)
                            condition:setParameter(CONDITION_PARAM_DELAYED, 1)
                            condition:addDamage(balance.timesRepeatCondition, balance.intervalCondition, -dmg)
                            atacado:addCondition(condition)
                        end
                    end                          
                end          
            end
        -- DRUIDS
            if attacker:getVocation():getClientId() == 4 then
                if balance.canParalyze == true then
                    if primaryType == COMBAT_EARTHDAMAGE then
                        if rand <= balance.paralyzeChance then              
                            local para = math.random(balance.paralyzeMinEffect, balance.paralyzeMaxEffect)
                            local condition = Condition(CONDITION_PARALYZE)
                            condition:setParameter(CONDITION_PARAM_TICKS, 500)
                            condition:setFormula(-1, para, -1, para)
                            atacado:addCondition(condition)
                        end
                    end
                end
                if balance.canFreeze == true then
                    if primaryType == COMBAT_ICEDAMAGE then
                        if rand <= balance.freezeChance then              
                dmg = primaryDamage * math.random(balance.freezeMinDmg, balance.freezeMaxDmg)/100
                            local condition = Condition(CONDITION_FREEZING)
                            condition:setParameter(CONDITION_PARAM_DELAYED, 1)
                            condition:addDamage(balance.timesRepeatCondition, balance.intervalCondition, -dmg)
                            atacado:addCondition(condition)
                        end
                    end
                end  
            end
        end
       
    -- KNIGHT BLOCK
            if creature:isPlayer() and (creature:getVocation():getClientId()) == 1 then
                if balance.canBlock == true then
                    if block <= balance.blockChance then
                    local blockpercent = math.random(balance.blockMinEffect, balance.blockMaxEffect)
                        creature:say("BLOCK!", TALKTYPE_MONSTER_SAY)
                        if primaryDamage > 0 then
                            primaryDamage = primaryDamage * (blockpercent)/100
                        end
                        if secondaryDamage > 0 then
                            secondaryDamage = secondaryDamage * (blockpercent)/100
                        end
                    end
                end
            end
     return primaryDamage, primaryType, secondaryDamage, secondaryType
end




Can someone help me please?
 
Last edited:
Looks like you don't even have the event onHealthChange, You'll have to add it to your source and then recompile, You can try those changes.
Thanks.

I made the changes criaturescript.cpp, now i'm having trouble with copilation.

Look:

After the command: cmake ..

CXX target tfs cotired without unity build.
-- Configuring done
CMake Error at CMakeLists.txt:41 (add_executable):
Cannot find source file:

/home/Servidor/Aibit2/Nostalrius-master/src/weapons.cpp

Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
.hxx .in .txx


Cmakelist line 41: add_executable(tfs ${tfs_SRC})

-----------------------------------
Post automatically merged:

FIX...

NOW is new problem. Please help to copile?

Problem.png
 
Last edited:
Yea, you didnt declared CREATURE_EVENT_HEATHLCHANGE, I bet you just copypasted the code

I just copied the necessary part. Really ... Sorry for the ignorance but, I have to declare CREATURE_EVENT_HEATHLCHANGE at the beginning of Criaturescripts.h right? Do I need to make any more changes for it to work? Any more lines of code? Thank you.
 
I'm basically learning. Sorry but I must have done something wrong again.

1602087436768.png

MY creatureevents.cpp e h:


Code:
/**
 * Tibia GIMUD Server - a free and open-source MMORPG server emulator
 * Copyright (C) 2017  Alejandro Mujica <[email protected]>
 *
 * 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_HEALTHCHANGE:
            return "onHealthChange";

        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::executeHealthChange(Creature* creature, Creature* attacker, CombatDamage& damage)
{
    //onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if (!scriptInterface->reserveScriptEnv()) {
        std::cout << "[Error - CreatureEvent::executeHealthChange] Call stack overflow" << std::endl;
        return;
    }

    ScriptEnvironment* env = scriptInterface->getScriptEnv();
    env->setScriptId(scriptId, scriptInterface);

    lua_State* L = scriptInterface->getLuaState();
    scriptInterface->pushFunction(scriptId);

    LuaScriptInterface::pushUserdata(L, creature);
    LuaScriptInterface::setCreatureMetatable(L, -1, creature);
    if (attacker) {
        LuaScriptInterface::pushUserdata(L, attacker);
        LuaScriptInterface::setCreatureMetatable(L, -1, attacker);
    } else {
        lua_pushnil(L);
    }

    LuaScriptInterface::pushCombatDamage(L, damage);

    if (scriptInterface->protectedCall(L, 7, 4) != 0) {
        LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
    } else {
        damage.primary.value = std::abs(LuaScriptInterface::getNumber<int32_t>(L, -4));
        damage.primary.type = LuaScriptInterface::getNumber<CombatType_t>(L, -3);
        damage.secondary.value = std::abs(LuaScriptInterface::getNumber<int32_t>(L, -2));
        damage.secondary.type = LuaScriptInterface::getNumber<CombatType_t>(L, -1);

        lua_pop(L, 4);
        if (damage.primary.type != COMBAT_HEALING) {
            damage.primary.value = -damage.primary.value;
            damage.secondary.value = -damage.secondary.value;
        }
    }

    scriptInterface->resetScriptEnv();
}

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);
}


Code:
/**
 * Tibia GIMUD Server - a free and open-source MMORPG server emulator
 * Copyright (C) 2017  Alejandro Mujica <[email protected]>
 *
 * 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.
 */

#ifndef FS_CREATUREEVENT_H_73FCAF4608CB41399D53C919316646A9
#define FS_CREATUREEVENT_H_73FCAF4608CB41399D53C919316646A9

#include "luascript.h"
#include "baseevents.h"
#include "enums.h"

enum CreatureEventType_t {
    CREATURE_EVENT_NONE,
    CREATURE_EVENT_LOGIN,
    CREATURE_EVENT_LOGOUT,
    CREATURE_EVENT_THINK,
    CREATURE_EVENT_PREPAREDEATH,
    CREATURE_EVENT_DEATH,
    CREATURE_EVENT_KILL,
    CREATURE_EVENT_ADVANCE,
    CREATURE_EVENT_HEATHLCHANGE
    CREATURE_EVENT_EXTENDED_OPCODE, // otclient additional network opcodes
};

class CreatureEvent;

class CreatureEvents final : public BaseEvents
{
    public:
        CreatureEvents();
        ~CreatureEvents();

        // non-copyable
        CreatureEvents(const CreatureEvents&) = delete;
        CreatureEvents& operator=(const CreatureEvents&) = delete;

        // global events
        bool playerLogin(Player* player) const;
        bool playerLogout(Player* player) const;
        bool playerAdvance(Player* player, skills_t, uint32_t, uint32_t);

        CreatureEvent* getEventByName(const std::string& name, bool forceLoaded = true);

    protected:
        LuaScriptInterface& getScriptInterface() final;
        std::string getScriptBaseName() const final;
        Event* getEvent(const std::string& nodeName) final;
        bool registerEvent(Event* event, const pugi::xml_node& node) final;
        void clear() final;

        //creature events
        typedef std::map<std::string, CreatureEvent*> CreatureEventList;
        CreatureEventList creatureEvents;

        LuaScriptInterface scriptInterface;
};

class CreatureEvent final : public Event
{
    public:
        explicit CreatureEvent(LuaScriptInterface* interface);

        bool configureEvent(const pugi::xml_node& node) final;

        CreatureEventType_t getEventType() const {
            return type;
        }
        const std::string& getName() const {
            return eventName;
        }
        bool isLoaded() const {
            return loaded;
        }

        void clearEvent();
        void copyEvent(CreatureEvent* creatureEvent);

        //scripting
        bool executeOnLogin(Player* player);
        bool executeOnLogout(Player* player);
        bool executeOnThink(Creature* creature, uint32_t interval);
        bool executeOnPrepareDeath(Creature* creature, Creature* killer);
        bool executeOnDeath(Creature* creature, Item* corpse, Creature* killer, Creature* mostDamageKiller, bool lastHitUnjustified, bool mostDamageUnjustified);
        void executeOnKill(Creature* creature, Creature* target);
        bool executeAdvance(Player* player, skills_t, uint32_t, uint32_t);
        void executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer);
        //

    protected:
        std::string getScriptEventName() const final;

        std::string eventName;
        CreatureEventType_t type;
        bool loaded;
};

#endif
 
Back
Top