Pastebin

New pastes are no longer accepted · Stats

Latest Pastes

maps

/* $Id: map.cpp 186 2010-02-06 00:06:47Z sausage $
 * EOSERV is released under the zlib license.
 * See LICENSE.txt for more info.
 */
 
#include "map.hpp"
 
#include "arena.hpp"
#include "character.hpp"
#include "console.hpp"
#include "eoclient.hpp"
#include "eodata.hpp"
#include "eoserver.hpp"
#include "npc.hpp"
#include "packet.hpp"
#include "player.hpp"
#include "quest.hpp"
#include "timer.hpp"
#include "world.hpp"
 
static const char *safe_fail_filename;
 
static void safe_fail(int line)
{
    Console::Err("Invalid file / failed read/seek: %s -- %i", safe_fail_filename, line);
}
 
#define SAFE_SEEK(fh, offset, from) if (std::fseek(fh, offset, from) != 0) { std::fclose(fh); safe_fail(__LINE__); return false; }
#define SAFE_READ(buf, size, count, fh) if (std::fread(buf, size, count, fh) != static_cast<int>(count)) {  std::fclose(fh); safe_fail(__LINE__);return false; }
 
void map_spawn_chests(void *map_void)
{
    Map *map(static_cast<Map *>(map_void));
 
    double current_time = Timer::GetTime();
    UTIL_PTR_VECTOR_FOREACH(map->chests, Map_Chest, chest)
    {
        bool needs_update = false;
 
        for (int slot = 1; slot <= chest->slots; ++slot)
        {
            PtrList<Map_Chest_Spawn> spawns;
 
            UTIL_PTR_LIST_FOREACH(chest->spawns, Map_Chest_Spawn, spawn)
            {
                if (spawn->last_taken + spawn->time*60.0 < current_time)
                {
                    bool slot_used = false;
 
                    UTIL_PTR_LIST_FOREACH(chest->items, Map_Chest_Item, item)
                    {
                        if (item->slot == spawn->slot)
                        {
                            slot_used = true;
                        }
                    }
 
                    if (!slot_used)
                    {
                        spawns.push_back(*spawn);
                    }
                }
            }
 
            if (!spawns.empty())
            {
 
                PtrList<Map_Chest_Spawn>::Iterator it(spawns);
                int r = util::rand(0, spawns.size()-1);
 
                for (int i = 0; i < r; ++i)
                {
                    ++it;
                }
 
                Map_Chest_Spawn *spawn(*it);
 
                chest->AddItem(spawn->item->id, spawn->item->amount, spawn->slot);
                needs_update = true;
 
#ifdef DEBUG
                Console::Dbg("Spawning chest item %i (x%i) on map %i", spawn->item->id, spawn->item->amount, map->id);
#endif // DEBUG
            }
        }
 
        if (needs_update)
        {
            chest->Update(map, 0);
        }
    }
}
 
struct map_close_door_struct : public Shared
{
    Map *map;
    unsigned char x, y;
};
 
void map_close_door(void *map_close_door_struct_void)
{
    map_close_door_struct *close(static_cast<map_close_door_struct *>(map_close_door_struct_void));
 
    close->map->CloseDoor(close->x, close->y);
 
    close->Release();
}
 
int Map_Chest::AddItem(short item, int amount, int slot)
{
    if (amount <= 0)
    {
        return 0;
    }
 
    if (slot == 0)
    {
        UTIL_PTR_LIST_FOREACH(this->items, Map_Chest_Item, it)
        {
            if (it->id == item)
            {
                if (it->amount + amount < 0 || it->amount + amount > this->maxchest)
                {
                    return 0;
                }
 
                it->amount += amount;
                return amount;
            }
        }
    }
 
    if (this->items.size() >= static_cast<std::size_t>(this->chestslots) || amount > this->maxchest)
    {
        return 0;
    }
 
    if (slot == 0)
    {
        int user_items = 0;
 
        UTIL_PTR_LIST_FOREACH(this->items, Map_Chest_Item, item)
        {
            if (item->slot == 0)
            {
                ++user_items;
            }
        }
 
        if (user_items + this->slots >= this->chestslots)
        {
            return 0;
        }
    }
 
    Map_Chest_Item *chestitem(new Map_Chest_Item);
    chestitem->id = item;
    chestitem->amount = amount;
    chestitem->slot = slot;
 
    if (slot == 0)
    {
 
        this->items.push_back(chestitem);
    }
    else
    {
        this->items.push_front(chestitem);
    }
 
    return amount;
}
 
int Map_Chest::DelItem(short item)
{
    UTIL_PTR_LIST_FOREACH(this->items, Map_Chest_Item, it)
    {
        if (it->id == item)
        {
            int amount = it->amount;
 
            if (it->slot)
            {
                double current_time = Timer::GetTime();
 
                UTIL_PTR_LIST_FOREACH(this->spawns, Map_Chest_Spawn, spawn)
                {
                    if (spawn->slot == it->slot)
                    {
                        spawn->last_taken = current_time;
                    }
                }
            }
 
            this->items.erase(it);
            return amount;
        }
    }
 
    return false;
}
 
void Map_Chest::Update(Map *map, Character *exclude)
{
    PacketBuilder builder(PACKET_CHEST, PACKET_AGREE);
 
    UTIL_PTR_LIST_FOREACH(this->items, Map_Chest_Item, item)
    {
        builder.AddShort(item->id);
        builder.AddThree(item->amount);
    }
 
    UTIL_PTR_LIST_FOREACH(map->characters, Character, character)
    {
        if (*character == exclude)
        {
            continue;
        }
 
        if (util::path_length(character->x, character->y, this->x, this->y) <= 1)
        {
            character->player->client->SendBuilder(builder);
        }
    }
}
 
Map::Map(int id, World *world)
{
    this->id = id;
    this->world = world;
    this->exists = false;
    this->jukebox_protect = 0.0;
    this->arena = 0;
 
    this->LoadArena();
 
    this->Load();
 
    if (!this->chests.empty())
    {
 
        TimeEvent *event = new TimeEvent(map_spawn_chests, this, 60.0, Timer::FOREVER);
        this->world->timer.Register(event);
        event->Release();
    }
}
 
void Map::LoadArena()
{
    PtrList<Character> update_characters;
 
    if (this->arena)
    {
        UTIL_PTR_LIST_FOREACH(this->arena->map->characters, Character, character)
        {
            if (character->arena == this->arena)
            {
                update_characters.push_back(*character);
            }
        }
 
        delete this->arena;
    }
 
    if (world->arenas_config[util::to_string(id) + ".enabled"])
    {
        std::string spawns_str = world->arenas_config[util::to_string(id) + ".spawns"];
 
        std::vector<std::string> spawns = util::explode(',', spawns_str);
 
        if (spawns.size() % 4 != 0)
        {
            Console::Wrn("Invalid arena spawn data for map %i", id);
            this->arena = 0;
        }
        else
        {
            this->arena = new Arena(this, static_cast<int>(world->arenas_config[util::to_string(id) + ".time"]), static_cast<int>(world->arenas_config[util::to_string(id) + ".block"]));
 
            int i = 1;
            Arena_Spawn *s;
            UTIL_VECTOR_FOREACH_ALL(spawns, std::string, spawn)
            {
                util::trim(spawn);
 
                switch (i++ % 4)
                {
                    case 1:
                        s = new Arena_Spawn;
                        s->sx = util::to_int(spawn);
                        break;
 
                    case 2:
                        s->sy = util::to_int(spawn);
                        break;
 
                    case 3:
                        s->dx = util::to_int(spawn);
                        break;
 
                    case 0:
                        s->dy = util::to_int(spawn);
                        this->arena->spawns.push_back(s);
                        s->Release();
                        break;
 
                }
            }
        }
    }
    else
    {
        this->arena = 0;
    }
 
    UTIL_PTR_LIST_FOREACH(update_characters, Character, character)
    {
        character->arena = this->arena;
 
        if (!this->arena)
        {
            character->Warp(character->map->id, character->map->relog_x, character->map->relog_y);
        }
    }
}
 
bool Map::Load()
{
    char namebuf[6];
 
    if (this->id < 0)
    {
        return false;
    }
 
    std::string filename = this->world->config["MapDir"];
    std::sprintf(namebuf, "%05i", this->id);
    this->filename = filename;
    filename.append(namebuf);
    filename.append(".emf");
 
    safe_fail_filename = filename.c_str();
 
    std::FILE *fh = std::fopen(filename.c_str(), "rb");
 
    if (!fh)
    {
        Console::Err("Could not load file: %s", filename.c_str());
        return false;
    }
 
    SAFE_SEEK(fh, 0x03, SEEK_SET);
    SAFE_READ(this->rid, sizeof(char), 4, fh);
 
    char buf[12];
    int outersize;
    int innersize;
 
    SAFE_SEEK(fh, 0x1F, SEEK_SET);
    SAFE_READ(buf, sizeof(char), 1, fh);
    this->pk = PacketProcessor::Number(buf[0]) == 3;
 
    SAFE_SEEK(fh, 0x25, SEEK_SET);
    SAFE_READ(buf, sizeof(char), 2, fh);
    this->width = PacketProcessor::Number(buf[0]) + 1;
    this->height = PacketProcessor::Number(buf[1]) + 1;
 
    this->tiles.resize(height);
    for (int i = 0; i < height; ++i)
    {
        this->tiles[i] = new PtrVector<Map_Tile>;
        this->tiles[i]->resize(width);
        for (int ii = 0; ii < width; ++ii)
        {
            this->tiles[i]->at(ii) = new Map_Tile;
        }
    }
 
    SAFE_SEEK(fh, 0x2A, SEEK_SET);
    SAFE_READ(buf, sizeof(char), 3, fh);
    this->scroll = PacketProcessor::Number(buf[0]);
    this->relog_x = PacketProcessor::Number(buf[1]);
    this->relog_y = PacketProcessor::Number(buf[2]);
 
    SAFE_SEEK(fh, 0x2E, SEEK_SET);
    SAFE_READ(buf, sizeof(char), 1, fh);
    outersize = PacketProcessor::Number(buf[0]);
    if (outersize)
    {
        SAFE_SEEK(fh, 8 * outersize, SEEK_CUR);
    }
 
    SAFE_READ(buf, sizeof(char), 1, fh);
    outersize = PacketProcessor::Number(buf[0]);
    if (outersize)
    {
        SAFE_SEEK(fh, 4 * outersize, SEEK_CUR);
    }
 
    SAFE_READ(buf, sizeof(char), 1, fh);
    outersize = PacketProcessor::Number(buf[0]);
    if (outersize)
    {
        SAFE_SEEK(fh, 12 * outersize, SEEK_CUR);
    }
 
    SAFE_READ(buf, sizeof(char), 1, fh);
    outersize = PacketProcessor::Number(buf[0]);
    for (int i = 0; i < outersize; ++i)
    {
        SAFE_READ(buf, sizeof(char), 2, fh);
        unsigned char yloc = PacketProcessor::Number(buf[0]);
        innersize = PacketProcessor::Number(buf[1]);
        for (int ii = 0; ii < innersize; ++ii)
        {
            Map_Tile *newtile(new Map_Tile);
            SAFE_READ(buf, sizeof(char), 2, fh);
            unsigned char xloc = PacketProcessor::Number(buf[0]);
            unsigned char spec = PacketProcessor::Number(buf[1]);
            newtile->tilespec = static_cast<Map_Tile::TileSpec>(spec);
 
            if (spec == Map_Tile::Chest)
            {
 
                Map_Chest *chest = new Map_Chest;
                chest->maxchest = static_cast<int>(this->world->config["MaxChest"]);
                chest->chestslots = static_cast<int>(this->world->config["ChestSlots"]);
                chest->x = xloc;
                chest->y = yloc;
                chest->slots = 0;
this->chests.push_back(chest); chest->Release();
            }
            try
            {
                this->tiles.at(yloc)->at(xloc) = newtile;
            }
            catch (...)
            {
                std::fclose(fh);
                safe_fail(__LINE__);
                return false;
            }
        }
    }
 
    SAFE_READ(buf, sizeof(char), 1, fh);
    outersize = PacketProcessor::Number(buf[0]);
    for (int i = 0; i < outersize; ++i)
    {
        SAFE_READ(buf, sizeof(char), 2, fh);
        unsigned char yloc = PacketProcessor::Number(buf[0]);
        innersize = PacketProcessor::Number(buf[1]);
        for (int ii = 0; ii < innersize; ++ii)
        {
            Map_Warp *newwarp(new Map_Warp);
            SAFE_READ(buf, sizeof(char), 8, fh);
            unsigned char xloc = PacketProcessor::Number(buf[0]);
            newwarp->map = PacketProcessor::Number(buf[1], buf[2]);
            newwarp->x = PacketProcessor::Number(buf[3]);
            newwarp->y = PacketProcessor::Number(buf[4]);
            newwarp->levelreq = PacketProcessor::Number(buf[5]);
            newwarp->spec = static_cast<Map_Warp::WarpSpec>(PacketProcessor::Number(buf[6], buf[7]));
 
            try
            {
                this->tiles.at(yloc)->at(xloc)->warp = newwarp;
            }
            catch (...)
            {
                std::fclose(fh);
                safe_fail(__LINE__);
                return false;
            }
        }
    }
 
    SAFE_SEEK(fh, 0x2E, SEEK_SET);
    SAFE_READ(buf, sizeof(char), 1, fh);
    outersize = PacketProcessor::Number(buf[0]);
    int index = 0;
    for (int i = 0; i < outersize; ++i)
    {
        SAFE_READ(buf, sizeof(char), 8, fh);
        unsigned char x = PacketProcessor::Number(buf[0]);
        unsigned char y = PacketProcessor::Number(buf[1]);
        short npc_id = PacketProcessor::Number(buf[2], buf[3]);
        unsigned char spawntype = PacketProcessor::Number(buf[4]);
        short spawntime = PacketProcessor::Number(buf[5], buf[6]);
        unsigned char amount = PacketProcessor::Number(buf[7]);
 
        if (npc_id != this->world->enf->Get(npc_id)->id)
        {
            Console::Wrn("An NPC spawn on map %i uses a non-existent NPC (#%i at %ix%i)", this->id, npc_id, x, y);
        }
 
        for (int ii = 0; ii < amount; ++ii)
        {
            if (x > this->width || y > this->height)
            {
                Console::Wrn("An NPC spawn on map %i is outside of map bounds (%s at %ix%i)", this->id, this->world->enf->Get(npc_id)->name.c_str(), x, y);
                continue;
            }
 
            NPC *newnpc = new NPC(this, npc_id, x, y, spawntype, spawntime, index++);
            this->npcs.push_back(newnpc);
 
            newnpc->Spawn();
        }
    }
 
    SAFE_READ(buf, sizeof(char), 1, fh);
    outersize = PacketProcessor::Number(buf[0]);
    if (outersize)
    {
        SAFE_SEEK(fh, 4 * outersize, SEEK_CUR);
    }
 
    SAFE_READ(buf, sizeof(char), 1, fh);
    outersize = PacketProcessor::Number(buf[0]);
    for (int i = 0; i < outersize; ++i)
    {
        SAFE_READ(buf, sizeof(char), 12, fh);
        unsigned char x = PacketProcessor::Number(buf[0]);
        unsigned char y = PacketProcessor::Number(buf[1]);
        short slot = PacketProcessor::Number(buf[4]);
        short itemid = PacketProcessor::Number(buf[5], buf[6]);
        short time = PacketProcessor::Number(buf[7], buf[8]);
        int amount = PacketProcessor::Number(buf[9], buf[10], buf[11]);
 
        if (itemid != this->world->eif->Get(itemid)->id)
        {
            Console::Wrn("A chest spawn on map %i uses a non-existent item (#%i at %ix%i)", this->id, itemid, x, y);
        }
 
        UTIL_PTR_VECTOR_FOREACH(this->chests, Map_Chest, chest)
        {
            if (chest->x == x && chest->y == y)
            {
                Map_Chest_Item *item(new Map_Chest_Item);
                Map_Chest_Spawn *spawn(new Map_Chest_Spawn);
 
                item->id = itemid;
                item->amount = amount;
 
                spawn->slot = slot+1;
                spawn->time = time;
                spawn->last_taken = Timer::GetTime();
                spawn->item = item;
 
                chest->spawns.push_back(spawn);
                spawn->Release();
                chest->slots = std::max(chest->slots, slot+1);
                goto skip_warning;
            }
        }
        Console::Wrn("A chest spawn on map %i points to a non-chest (%s x%i at %ix%i)", this->id, this->world->eif->Get(itemid)->name.c_str(), amount, x, y);
        skip_warning:
        ;
    }
 
    SAFE_SEEK(fh, 0x00, SEEK_END);
    this->filesize = std::ftell(fh);
 
    std::fclose(fh);
 
    this->exists = true;
 
    return true;
}
 
void Map::Unload()
{
    this->exists = false;
 
    this->chests.clear();
 
    UTIL_PTR_VECTOR_FOREACH(this->npcs, NPC, npc)
    {
        UTIL_PTR_LIST_FOREACH(npc->damagelist, NPC_Opponent, opponent)
        {
            erase_first(opponent->attacker->unregister_npc, *npc);
        }
    }
 
    this->npcs.clear();
}
 
int Map::GenerateItemID()
{
    int lowest_free_id = 1;
    restart_loop:
    UTIL_PTR_LIST_FOREACH(this->items, Map_Item, item)
    {
        if (item->uid == lowest_free_id)
        {
            lowest_free_id = item->uid + 1;
            goto restart_loop;
        }
    }
    return lowest_free_id;
}
 
unsigned char Map::GenerateNPCIndex()
{
    unsigned char lowest_free_id = 1;
    restart_loop:
    UTIL_PTR_VECTOR_FOREACH(this->npcs, NPC, npc)
    {
        if (npc->index == lowest_free_id)
        {
            lowest_free_id = npc->index + 1;
            goto restart_loop;
        }
    }
    return lowest_free_id;
}
 
void Map::Enter(Character *character, WarpAnimation animation)
{
 
    PacketBuilder builder;
    this->characters.push_back(character);
    character->map = this;
 
    builder.SetID(PACKET_PLAYERS, PACKET_AGREE);
 
    builder.AddByte(255);
    builder.AddBreakString(character->name);
    builder.AddShort(character->player->id);
    builder.AddShort(character->mapid);
    builder.AddShort(character->x);
    builder.AddShort(character->y);
    builder.AddChar(character->direction);
    builder.AddChar(character->clas); // character class
    builder.AddString(character->PaddedGuildTag());
    builder.AddChar(character->level);
    builder.AddChar(character->gender);
    builder.AddChar(character->hairstyle);
    builder.AddChar(character->haircolor);
    builder.AddChar(character->race);
    builder.AddShort(character->maxhp);
    builder.AddShort(character->hp);
    builder.AddShort(character->maxtp);
    builder.AddShort(character->tp);
    // equipment
    builder.AddShort(this->world->eif->Get(character->paperdoll[Character::Boots])->dollgraphic);
    builder.AddShort(0); // ??
    builder.AddShort(0); // ??
    builder.AddShort(0); // ??
    builder.AddShort(this->world->eif->Get(character->paperdoll[Character::Armor])->dollgraphic);
    builder.AddShort(0); // ??
    builder.AddShort(this->world->eif->Get(character->paperdoll[Character::Hat])->dollgraphic);
    builder.AddShort(this->world->eif->Get(character->paperdoll[Character::Shield])->dollgraphic);
    builder.AddShort(this->world->eif->Get(character->paperdoll[Character::Weapon])->dollgraphic);
    builder.AddChar(character->sitting);
    builder.AddChar(character->hidden);
    builder.AddChar(animation);
    builder.AddByte(255);
    builder.AddChar(1); // 0 = NPC, 1 = player
 
        UTIL_PTR_LIST_FOREACH(this->characters, Character, checkcharacter)
    {
 
        if (*checkcharacter == character || !character->InRange(*checkcharacter))
        {
            continue;
        }
        checkcharacter->player->client->SendBuilder(builder);
}
}
void Map::Leave(Character *character, WarpAnimation animation, bool silent)
{
    if (!silent)
    {
        PacketBuilder builder;
 
        builder.SetID(PACKET_CLOTHES, PACKET_REMOVE);
        builder.AddShort(character->player->id);
        if (animation != WARP_ANIMATION_NONE)
        {
            builder.AddChar(animation);
        }
 
        UTIL_PTR_LIST_FOREACH(this->characters, Character, checkcharacter)
        {
            if (*checkcharacter == character || !character->InRange(*checkcharacter))
            {
                continue;
            }
 
            checkcharacter->player->client->SendBuilder(builder);
        }
    }
 
    erase_first(this->characters, character);
    character->map = 0;
 
}
 
void Map::Msg(Character *from, std::string message, bool echo)
{
    message = util::text_cap(message, static_cast<int>(this->world->config["ChatMaxWidth"]) - util::text_width(util::ucfirst(from->name) + "  "));
 
    PacketBuilder builder;
 
    builder.SetID(PACKET_TALK, PACKET_PLAYER);
    builder.AddShort(from->player->id);
    builder.AddString(message);
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if ((!echo && *character == from) || !from->InRange(*character))
        {
            continue;
        }
 
        character->player->client->SendBuilder(builder);
    }
}
 
bool Map::Walk(Character *from, Direction direction, bool admin)
{
    PacketBuilder builder;
    int seedistance = this->world->config["SeeDistance"];
 
    unsigned char target_x = from->x;
    unsigned char target_y = from->y;
 
    switch (direction)
    {
        case DIRECTION_UP:
            target_y -= 1;
 
            if (target_y > from->y)
            {
                return false;
            }
 
            break;
 
        case DIRECTION_RIGHT:
            target_x += 1;
 
            if (target_x < from->x)
            {
                return false;
            }
 
            break;
 
        case DIRECTION_DOWN:
            target_y += 1;
 
            if (target_x < from->x)
            {
                return false;
            }
 
            break;
 
        case DIRECTION_LEFT:
            target_x -= 1;
 
            if (target_x > from->x)
            {
                return false;
            }
 
            break;
    }
PacketBuilder reply;
if (this->id == 435 && this->GetSpec(target_x, target_y) == Map_Tile::Unknown3)
                {
reply.SetID(PACKET_PING, PACKET_ACCEPT);
reply.AddByte(255);
reply.AddString(static_cast<std::string>(this->world->message_config["book"]));
from->player->client->SendBuilder(reply);
            }
if (this->id == 438 && this->GetSpec(target_x, target_y) == Map_Tile::Unknown3)
                {
reply.SetID(PACKET_PING, PACKET_ACCEPT);
reply.AddByte(255);
reply.AddString(static_cast<std::string>(this->world->message_config["book1"]));
from->player->client->SendBuilder(reply);
            }
            if (this->id == 439 && this->GetSpec(target_x, target_y) == Map_Tile::Unknown3)
                {
reply.SetID(PACKET_PING, PACKET_ACCEPT);
reply.AddByte(255);
reply.AddString(static_cast<std::string>(this->world->message_config["book2"]));
from->player->client->SendBuilder(reply);
            }
            if (this->id == 440 && this->GetSpec(target_x, target_y) == Map_Tile::Unknown3)
                {
reply.SetID(PACKET_PING, PACKET_ACCEPT);
reply.AddByte(255);
reply.AddString(static_cast<std::string>(this->world->message_config["book3"]));
from->player->client->SendBuilder(reply);
            }
    if (!admin && !this->Walkable(target_x, target_y))
    {
        return false;
    }
 
    Map_Warp *warp;
    if (!admin && (warp = this->GetWarp(target_x, target_y)))
    {
        if (from->level >= warp->levelreq && (warp->spec == Map_Warp::NoDoor || warp->open))
        {
 
        if (from->race == SKIN_ORC && this->id == 426)
    {
    from->hairstyle = 14;
    from->race = SKIN_WHITE;
        }
          if (from->race == SKIN_ORC && this->id == 425)
    {
    from->hairstyle = 13;
    from->race = SKIN_WHITE;
        }
        from->PetTransfer();
            from->Warp(warp->map, warp->x, warp->y);
         from->PetTransfer();
        }
 
        return false;
    }
 
    from->direction = direction;
 
    HOOK_BEGIN(CharacterEvent, this->world->hookmanager, "character/walk")
        e->character = from;
        e->target_map = this;
        e->target_mapid = this->id;
        e->target_x = target_x;
        e->target_y = target_y;
        if (HOOK_CALL()) return false;
    HOOK_END()
 
    from->x = target_x;
    from->y = target_y;
 
    int newx;
    int newy;
    int oldx;
    int oldy;
 
    std::vector<std::pair<int, int> > newcoords;
    std::vector<std::pair<int, int> > oldcoords;
 
    PtrVector<Character> newchars;
    PtrVector<Character> oldchars;
    PtrVector<NPC> newnpcs;
    PtrVector<NPC> oldnpcs;
    PtrVector<Map_Item> newitems;
 
    switch (direction)
    {
        case DIRECTION_UP:
            for (int i = -seedistance; i <= seedistance; ++i)
            {
                newy = from->y - seedistance + std::abs(i);
                newx = from->x + i;
                oldy = from->y + seedistance + 1 - std::abs(i);
                oldx = from->x + i;
 
                newcoords.push_back(std::make_pair(newx, newy));
                oldcoords.push_back(std::make_pair(oldx, oldy));
            }
            break;
 
        case DIRECTION_RIGHT:
            for (int i = -seedistance; i <= seedistance; ++i)
            {
                newx = from->x + seedistance - std::abs(i);
                newy = from->y + i;
                oldx = from->x - seedistance - 1 + std::abs(i);
                oldy = from->y + i;
 
                newcoords.push_back(std::make_pair(newx, newy));
                oldcoords.push_back(std::make_pair(oldx, oldy));
            }
            break;
 
        case DIRECTION_DOWN:
            for (int i = -seedistance; i <= seedistance; ++i)
            {
                newy = from->y + seedistance - std::abs(i);
                newx = from->x + i;
                oldy = from->y - seedistance - 1 + std::abs(i);
                oldx = from->x + i;
 
                newcoords.push_back(std::make_pair(newx, newy));
                oldcoords.push_back(std::make_pair(oldx, oldy));
            }
            break;
 
        case DIRECTION_LEFT:
            for (int i = -seedistance; i <= seedistance; ++i)
            {
                newx = from->x - seedistance + std::abs(i);
                newy = from->y + i;
                oldx = from->x + seedistance + 1 - std::abs(i);
                oldy = from->y + i;
 
                newcoords.push_back(std::make_pair(newx, newy));
                oldcoords.push_back(std::make_pair(oldx, oldy));
            }
            break;
 
    }
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
    {
        if (*checkchar == from)
        {
            continue;
        }
 
        for (std::size_t i = 0; i < oldcoords.size(); ++i)
        {
            if (checkchar->x == oldcoords[i].first && checkchar->y == oldcoords[i].second)
            {
                oldchars.push_back(*checkchar);
            }
            else if (checkchar->x == newcoords[i].first && checkchar->y == newcoords[i].second)
            {
                newchars.push_back(*checkchar);
            }
        }
    }
 
    UTIL_PTR_VECTOR_FOREACH(this->npcs, NPC, checknpc)
    {
        if (!checknpc->alive)
        {
            continue;
        }
 
        for (std::size_t i = 0; i < oldcoords.size(); ++i)
        {
            if (checknpc->x == oldcoords[i].first && checknpc->y == oldcoords[i].second)
            {
                oldnpcs.push_back(*checknpc);
            }
            else if (checknpc->x == newcoords[i].first && checknpc->y == newcoords[i].second)
            {
                newnpcs.push_back(*checknpc);
            }
        }
    }
 
    UTIL_PTR_LIST_FOREACH(this->items, Map_Item, checkitem)
    {
        for (std::size_t i = 0; i < oldcoords.size(); ++i)
        {
            if (checkitem->x == newcoords[i].first && checkitem->y == newcoords[i].second)
            {
                newitems.push_back(*checkitem);
            }
        }
    }
 
 Quest *temp_quest = 0;
    State *state = 0;
    UTIL_PTR_LIST_FOREACH(from->quests, Character_Quest, quest)
    {
        temp_quest = this->world->GetQuest(quest->id);
        if (!temp_quest) continue;
 
        state = temp_quest->GetState(quest->state);
        if (!state) continue;
 
        UTIL_PTR_VECTOR_FOREACH(state->rules, Rule, rule)
        {
            if ((rule->name.compare("entercoord") == 0 || rule->name.compare("leavecoord") == 0)
                && ((int)(*rule->args[0])) == from->mapid && ((int)(*rule->args[1])) == from->x && ((int)(*rule->args[2])) == from->y)
            {
                    quest->state = rule->goto_state;
                    from->PerformQuestActions(quest->id);
                    break;
                }
            }
        }
 
 
    builder.SetID(PACKET_CLOTHES, PACKET_REMOVE);
    builder.AddShort(from->player->id);
 
    UTIL_PTR_VECTOR_FOREACH(oldchars, Character, character)
    {
        PacketBuilder rbuilder;
        rbuilder.SetID(PACKET_CLOTHES, PACKET_REMOVE);
        rbuilder.AddShort(character->player->id);
 
        character->player->client->SendBuilder(builder);
        from->player->client->SendBuilder(rbuilder);
    }
 
    builder.Reset();
 
    builder.SetID(PACKET_PLAYERS, PACKET_AGREE);
    builder.AddByte(255);
    builder.AddBreakString(from->name);
    builder.AddShort(from->player->id);
    builder.AddShort(from->mapid);
    builder.AddShort(from->x);
    builder.AddShort(from->y);
    builder.AddChar(from->direction);
    builder.AddChar(from->clas); // character class
    builder.AddString(from->PaddedGuildTag());
    builder.AddChar(from->level);
    builder.AddChar(from->gender);
    builder.AddChar(from->hairstyle);
    builder.AddChar(from->haircolor);
    builder.AddChar(from->race);
    builder.AddShort(from->maxhp);
    builder.AddShort(from->hp);
    builder.AddShort(from->maxtp);
    builder.AddShort(from->tp);
    // equipment
    builder.AddShort(this->world->eif->Get(from->paperdoll[Character::Boots])->dollgraphic);
    builder.AddShort(0); // ??
    builder.AddShort(0); // ??
    builder.AddShort(0); // ??
    builder.AddShort(this->world->eif->Get(from->paperdoll[Character::Armor])->dollgraphic);
    builder.AddShort(0); // ??
    builder.AddShort(this->world->eif->Get(from->paperdoll[Character::Hat])->dollgraphic);
    builder.AddShort(this->world->eif->Get(from->paperdoll[Character::Shield])->dollgraphic);
    builder.AddShort(this->world->eif->Get(from->paperdoll[Character::Weapon])->dollgraphic);
    builder.AddChar(from->sitting);
    builder.AddChar(from->hidden);
    builder.AddByte(255);
    builder.AddChar(1); // 0 = NPC, 1 = player
 
    UTIL_PTR_VECTOR_FOREACH(newchars, Character, character)
    {
        PacketBuilder rbuilder;
        rbuilder.SetID(PACKET_PLAYERS, PACKET_AGREE);
        rbuilder.AddByte(255);
        rbuilder.AddBreakString(character->name);
        rbuilder.AddShort(character->player->id);
        rbuilder.AddShort(character->mapid);
        rbuilder.AddShort(character->x);
        rbuilder.AddShort(character->y);
        rbuilder.AddChar(character->direction);
        rbuilder.AddChar(character->clas); // ?
        rbuilder.AddString(character->PaddedGuildTag());
        rbuilder.AddChar(character->level);
        rbuilder.AddChar(character->gender);
        rbuilder.AddChar(character->hairstyle);
        rbuilder.AddChar(character->haircolor);
        rbuilder.AddChar(character->race);
        rbuilder.AddShort(character->maxhp);
        rbuilder.AddShort(character->hp);
        rbuilder.AddShort(character->maxtp);
        rbuilder.AddShort(character->tp);
        // equipment
        rbuilder.AddShort(this->world->eif->Get(character->paperdoll[Character::Boots])->dollgraphic);
        rbuilder.AddShort(0); // ??
        rbuilder.AddShort(0); // ??
        rbuilder.AddShort(0); // ??
        rbuilder.AddShort(this->world->eif->Get(character->paperdoll[Character::Armor])->dollgraphic);
        rbuilder.AddShort(0); // ??
        rbuilder.AddShort(this->world->eif->Get(character->paperdoll[Character::Hat])->dollgraphic);
        rbuilder.AddShort(this->world->eif->Get(character->paperdoll[Character::Shield])->dollgraphic);
        rbuilder.AddShort(this->world->eif->Get(character->paperdoll[Character::Weapon])->dollgraphic);
        rbuilder.AddChar(character->sitting);
        rbuilder.AddChar(character->hidden);
        rbuilder.AddByte(255);
        rbuilder.AddChar(1); // 0 = NPC, 1 = player
 
        character->player->client->SendBuilder(builder);
        from->player->client->SendBuilder(rbuilder);
    }
 
    builder.Reset();
 
    builder.SetID(PACKET_WALK, PACKET_PLAYER);
    builder.AddShort(from->player->id);
    builder.AddChar(direction);
    builder.AddChar(from->x);
    builder.AddChar(from->y);
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (*character == from || !from->InRange(*character))
        {
            continue;
        }
 
        character->player->client->SendBuilder(builder);
    }
 
    builder.Reset();
 
    builder.SetID(PACKET_WALK, PACKET_REPLY);
    builder.AddByte(255);
    builder.AddByte(255);
    UTIL_PTR_VECTOR_FOREACH(newitems, Map_Item, item)
    {
        builder.AddShort(item->uid);
        builder.AddShort(item->id);
        builder.AddChar(item->x);
        builder.AddChar(item->y);
        builder.AddThree(item->amount);
    }
    from->player->client->SendBuilder(builder);
 
    builder.SetID(PACKET_APPEAR, PACKET_REPLY);
    UTIL_PTR_VECTOR_FOREACH(newnpcs, NPC, npc)
    {
        builder.Reset();
        builder.AddChar(0);
        builder.AddByte(255);
        builder.AddChar(npc->index);
        builder.AddShort(npc->id);
        builder.AddChar(npc->x);
        builder.AddChar(npc->y);
        builder.AddChar(npc->direction);
 
        from->player->client->SendBuilder(builder);
    }
 
    UTIL_PTR_VECTOR_FOREACH(oldnpcs, NPC, npc)
    {
        npc->RemoveFromView(from);
    }
 
    return true;
}
 
bool Map::Walk(NPC *from, Direction direction)
{
 PacketBuilder builder;
    int seedistance = this->world->config["SeeDistance"];
 
    unsigned char target_x = from->x;
    unsigned char target_y = from->y;
 
    switch (direction)
    {
        case DIRECTION_UP:
            target_y -= 1;
 
            if (target_y > from->y)
            {
                return false;
            }
 
            break;
 
        case DIRECTION_RIGHT:
            target_x += 1;
 
            if (target_x < from->x)
            {
                return false;
            }
 
            break;
 
        case DIRECTION_DOWN:
            target_y += 1;
 
            if (target_x < from->x)
            {
                return false;
            }
 
            break;
 
        case DIRECTION_LEFT:
            target_x -= 1;
 
            if (target_x > from->x)
            {
                return false;
            }
 
            break;
    }
if (from->pet && from->Data()->type == ENF::Pet && (!this->Walkable(target_x, target_y, Map_Tile::Wall)))
{
return false;
}
 
    if (!from->pet && !from->Data()->type != ENF::Pet && (!this->Walkable(target_x, target_y, true)) || this->Occupied(target_x, target_y, Map::PlayerAndNPC))
    {
        return false;
    }
 
    from->x = target_x;
    from->y = target_y;
 
    int newx;
    int newy;
    int oldx;
    int oldy;
 
    std::vector<std::pair<int, int> > newcoords;
    std::vector<std::pair<int, int> > oldcoords;
 
    PtrVector<Character> newchars;
    PtrVector<Character> oldchars;
 
    switch (direction)
    {
        case DIRECTION_UP:
            for (int i = -seedistance; i <= seedistance; ++i)
            {
                newy = from->y - seedistance + std::abs(i);
                newx = from->x + i;
                oldy = from->y + seedistance + 1 - std::abs(i);
                oldx = from->x + i;
 
                newcoords.push_back(std::make_pair(newx, newy));
                oldcoords.push_back(std::make_pair(oldx, oldy));
            }
            break;
 
        case DIRECTION_RIGHT:
            for (int i = -seedistance; i <= seedistance; ++i)
            {
                newx = from->x + seedistance - std::abs(i);
                newy = from->y + i;
                oldx = from->x - seedistance - 1 + std::abs(i);
                oldy = from->y + i;
 
                newcoords.push_back(std::make_pair(newx, newy));
                oldcoords.push_back(std::make_pair(oldx, oldy));
            }
            break;
 
        case DIRECTION_DOWN:
            for (int i = -seedistance; i <= seedistance; ++i)
            {
                newy = from->y + seedistance - std::abs(i);
                newx = from->x + i;
                oldy = from->y - seedistance - 1 + std::abs(i);
                oldx = from->x + i;
 
                newcoords.push_back(std::make_pair(newx, newy));
                oldcoords.push_back(std::make_pair(oldx, oldy));
            }
            break;
 
        case DIRECTION_LEFT:
            for (int i = -seedistance; i <= seedistance; ++i)
            {
                newx = from->x - seedistance + std::abs(i);
                newy = from->y + i;
                oldx = from->x + seedistance + 1 - std::abs(i);
                oldy = from->y + i;
 
                newcoords.push_back(std::make_pair(newx, newy));
                oldcoords.push_back(std::make_pair(oldx, oldy));
            }
            break;
 
    }
 
    from->direction = direction;
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
    {
        for (std::size_t i = 0; i < oldcoords.size(); ++i)
        {
            if (checkchar->x == oldcoords[i].first && checkchar->y == oldcoords[i].second)
            {
                oldchars.push_back(*checkchar);
            }
            else if (checkchar->x == newcoords[i].first && checkchar->y == newcoords[i].second)
            {
                newchars.push_back(*checkchar);
            }
        }
    }
 
    builder.SetID(PACKET_APPEAR, PACKET_REPLY);
    builder.AddChar(0);
    builder.AddByte(255);
    builder.AddChar(from->index);
    builder.AddShort(from->id);
    builder.AddChar(from->x);
    builder.AddChar(from->y);
    builder.AddChar(from->direction);
 
    UTIL_PTR_VECTOR_FOREACH(newchars, Character, character)
    {
        character->player->client->SendBuilder(builder);
    }
 
    builder.Reset();
 
    builder.SetID(PACKET_NPC, PACKET_PLAYER);
    builder.AddChar(from->index);
    builder.AddChar(from->x);
    builder.AddChar(from->y);
    builder.AddChar(from->direction);
    builder.AddByte(255);
    builder.AddByte(255);
    builder.AddByte(255);
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (!character->InRange(from))
        {
            continue;
        }
 
        character->player->client->SendBuilder(builder);
    }
 
    UTIL_PTR_VECTOR_FOREACH(oldchars, Character, character)
    {
        from->RemoveFromView(*character);
    }
 
    return true;
}
 
void Map::Attack(Character *from, Direction direction)
{
    PacketBuilder builder;
 
    from->direction = direction;
 
    if (this->id == 426)
    {
 
    int target_x = from->x;
    int target_y = from->y;
 
    switch (from->direction)
    {
        case DIRECTION_UP:
            target_y -= 1;
            break;
 
        case DIRECTION_RIGHT:
            target_x += 1;
            break;
 
        case DIRECTION_DOWN:
            target_y += 1;
            break;
 
        case DIRECTION_LEFT:
            target_x -= 1;
            break;
    }
 
      UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        Character *character_ptr = *character;
        character_ptr->AddRef();
 
                if (from->race != SKIN_ORC)
    {
                if (npc->Data()->id == 2 && npc->alive && npc->x == target_x && npc->y == target_y)
                {
                //std::string msg(from->name + " HAS BEEN INFECTED ");
this->world->ServerMsg(from->name + " HAS BEEN INFECTED ");
from->hairstyle = 0;
from->race = SKIN_ORC;
from->Refresh();
            }
        }
            }
        if (from->race == SKIN_ORC)
    {
        if (character_ptr->x == target_x && character_ptr->y == target_y && character->race != SKIN_ORC)
        {
int item = 1;
int amount = 2000;
if (from->AddItem(item, amount))
            {
    PacketBuilder builder(PACKET_ITEM, PACKET_GET);
    builder.AddShort(0); // UID
    builder.AddShort(item);
    builder.AddThree(amount);
    builder.AddChar(from->weight);
    builder.AddChar(from->maxweight);
    from->player->client->SendBuilder(builder);
            }
 
bool stats_updated = false;
from->exp += 1000;
stats_updated = true;
if (stats_updated)
    {
 bool level_up = false;
 while (from->level < static_cast<int>(this->world->config["MaxLevel"]) && from->exp >= this->world->exp_table[from->level+1])
        {
    level_up = true;
    ++from->level;
    from->statpoints += static_cast<int>(this->world->config["StatPerLevel"]);
    from->skillpoints += static_cast<int>(this->world->config["SkillPerLevel"]);
    from->CalculateStats();
        }
 
    PacketBuilder builder(PACKET_RECOVER, PACKET_REPLY);
    builder.AddInt(from->exp);
    builder.AddShort(from->karma);
    builder.AddChar(level_up ? from->level : 0);
    from->player->client->SendBuilder(builder);
    }
this->world->ServerMsg(character_ptr->name + " has been infected by " + from->name);
 
            character_ptr->hairstyle = 0;
            character_ptr->race = SKIN_ORC;
            character_ptr->Warp(426, 1, 1);
            character_ptr->Release();
            break;
        }
    }
        character_ptr->Release();
    }
    }
 
    if (from->arena)
    {
    from->arena->Attack(from, direction);
 
    }
 
    if (this->pk || (this->world->config["GlobalPK"] && !this->world->PKExcept(this->id)))
    {
        if (this->AttackPK(from, direction))
        {
            return;
        }
    }
 
    builder.SetID(PACKET_ATTACK, PACKET_PLAYER);
    builder.AddShort(from->player->id);
    builder.AddChar(direction);
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (*character == from || !from->InRange(*character))
        {
            continue;
        }
 
        character->player->client->SendBuilder(builder);
    }
 
    int target_x = from->x;
    int target_y = from->y;
 
    int range = 1;
 
    if (this->world->eif->Get(from->paperdoll[Character::Weapon])->subtype == EIF::Ranged)
    {
        range = static_cast<int>(this->world->config["RangedDistance"]);
    }
 
    for (int i = 0; i < range; ++i)
    {
        switch (from->direction)
        {
            case DIRECTION_UP:
                target_y -= 1;
                break;
 
            case DIRECTION_RIGHT:
                target_x += 1;
                break;
 
            case DIRECTION_DOWN:
                target_y += 1;
                break;
 
            case DIRECTION_LEFT:
                target_x -= 1;
                break;
        }
 
        if (!this->Walkable(target_x, target_y, true))
  {
   break;
  }
 
        UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
        {
            UTIL_PTR_VECTOR_FOREACH(this->npcs, NPC, npc)
            {
                int eff = util::rand(1, 32);// doesnt have to be a random u could give a specific effect id EX: int eff = 5;
      int dmg = util::rand(from->mindam, from->maxdam);
      int dist = util::path_length(target_x, target_y, npc->x, npc->y);
 
     if ((npc->Data()->type == ENF::Passive || npc->Data()->type == ENF::Aggressive ||
      from->admin > static_cast<int>(this->world->admin_config["killnpcs"])) && npc->alive &&
      dist < 4 && this->world->eif->Get(from->paperdoll[Character::Weapon])->aoe == 1 )
       {
 
            npc->Damage(from, dmg);
 
       }
 
      if ((npc->Data()->type == ENF::Passive || npc->Data()->type == ENF::Aggressive ||
      from->admin > static_cast<int>(this->world->admin_config["killnpcs"])) && npc->alive &&
      dist < 4 && this->world->eif->Get(from->paperdoll[Character::Weapon])->aoe == 2 )
       {
            npc->Effect(from, eff, dmg);// if you dont have ananas effect or dont want effect remove this line
            npc->Damage(from, dmg);
       }

if ((npc->pet || npc->Data()->type == ENF::Pet || npc->Data()->type == ENF::Passive || npc->Data()->type == ENF::Aggressive || from->admin > static_cast<int>(this->world->admin_config["killnpcs"]))
                 && npc->alive && npc->x == target_x && npc->y == target_y)
                {
                                            int itemid, effectid;
for(int i = 0 ; i < static_cast<int>(this->world->effects_config["WAmount"]) ; i++){
itemid = static_cast<int>(this->world->effects_config[util::to_string(i+1) + ".ItemID"]);
effectid = static_cast<int>(this->world->effects_config[util::to_string(i+1) + ".EffectID"]);
    if(from->paperdoll[Character::Weapon] == itemid){
                npc->Effect(from, effectid, amount);
                    }
                }

                  if(from->clas == 9)
                    {
 
                        int amount = util::rand(from->mindam + 0, from->maxdam + 0);
                        double rand = util::rand(0.0, 1.0);
                        // Checks if target is facing you
                        bool critical = std::abs(int(npc->direction) - from->direction) != 2 || rand < static_cast<double>(this->world->config["CriticalRate"]);
 
                        std::tr1::unordered_map<std::string, double> formula_vars;
 
                        from->FormulaVars(formula_vars);
                        npc->FormulaVars(formula_vars, "target_");
                        formula_vars["modifier"] = this->world->config["MobRate"];
                        formula_vars["damage"] = amount;
                        formula_vars["critical"] = critical;
 
                        amount = rpn_eval(rpn_parse(this->world->formulas_config["damage"]), formula_vars);
                        double hit_rate = rpn_eval(rpn_parse(this->world->formulas_config["hit_rate"]), formula_vars);
 
                        if (rand > hit_rate)
                        {
                            amount = 0;
                        }
 
                        amount = std::max(amount, 0);
 
                        int limitamount = std::min(amount, int(npc->hp));
 
                        if (this->world->config["LimitDamage"])
                        {
                            amount = limitamount;
                        }
 
                        npc->Damage(from, amount);
                    }
                    else if(from->clas != 9)
                    {
                        int amount = util::rand(from->mindam, from->maxdam);
                        double rand = util::rand(0.0, 1.0);
                        // Checks if target is facing you
                        bool critical = std::abs(int(npc->direction) - from->direction) != 2 || rand < static_cast<double>(this->world->config["CriticalRate"]);
 
                        std::tr1::unordered_map<std::string, double> formula_vars;
 
                        from->FormulaVars(formula_vars);
                        npc->FormulaVars(formula_vars, "target_");
                        formula_vars["modifier"] = this->world->config["MobRate"];
                        formula_vars["damage"] = amount;
                        formula_vars["critical"] = critical;
 
                        amount = rpn_eval(rpn_parse(this->world->formulas_config["damage"]), formula_vars);
                        double hit_rate = rpn_eval(rpn_parse(this->world->formulas_config["hit_rate"]), formula_vars);
 
                        if (rand > hit_rate)
                        {
                            amount = 0;
                        }
 
                        amount = std::max(amount, 0);
 
                        int limitamount = std::min(amount, int(npc->hp));
 
                        if (this->world->config["LimitDamage"])
                        {
                            amount = limitamount;
                        }
 
                        npc->Damage(from, amount);
 
                        return;
                    }
                }
            }
        }
    }
 }

 
void Map::AttackSpell(Character *from, int spellid, int targetid)
{
     ESF_Data *spell = this->world->esf->Get(spellid);
     if (!spell) return;
 
    if (this->pk || (static_cast<int>(this->world->config["GlobalPK"]) && !this->world->PKExcept(this->id)))
    {
        if (this->AttackPKSpell(from, spellid, targetid))
        {
            return;
        }
    }
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        UTIL_PTR_VECTOR_FOREACH(this->npcs, NPC, npc)
        {
            if (from->clas == 9)
            {
                if ((npc->pet || npc->Data()->type == ENF::Pet || npc->Data()->type == ENF::Passive || npc->Data()->type == ENF::Aggressive || from->admin > static_cast<int>(this->world->admin_config["killnpcs"]))
                && npc->alive)
                {
                    int amount = util::rand(spell->mindam + 60000, spell->maxdam +60000);
                    //int amount = util::rand(from->mindam + 0, from->maxdam + 0);
                    npc->SpellDamage(from, amount, spellid, targetid);
                }
            }
 
            else if (from->clas != 9)
            {
                if ((npc->pet || npc->Data()->type == ENF::Pet || npc->Data()->type == ENF::Passive || npc->Data()->type == ENF::Aggressive || from->admin > static_cast<int>(this->world->admin_config["killnpcs"]))
                && npc->alive && npc->index == targetid)
                {
                    int amount = util::rand(spell->mindam, spell->maxdam);
                    //int amount = util::rand(from->mindam, from->maxdam);
                    npc->SpellDamage(from, amount, spellid, targetid);
 
                    return;
                }
            }
        }
    }
}
 
bool Map::AttackPK(Character *from, Direction direction)
{
    int target_x = from->x;
    int target_y = from->y;
 
    int range = 1;
 
    if (this->world->eif->Get(from->paperdoll[Character::Weapon])->subtype == EIF::Ranged)
    {
        range = static_cast<int>(this->world->config["RangedDistance"]);
    }
 
    for (int i = 0; i < range; ++i)
    {
        switch (from->direction)
        {
            case DIRECTION_UP:
                target_y -= 1;
                break;
 
            case DIRECTION_RIGHT:
                target_x += 1;
                break;
 
            case DIRECTION_DOWN:
                target_y += 1;
                break;
 
            case DIRECTION_LEFT:
                target_x -= 1;
                break;
        }
 
        if (!this->Walkable(target_x, target_y, true))
  {
   break;
  }
 
        UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
        {
            if (character->mapid == this->id && !character->nowhere && character->x == target_x && character->y == target_y)
            {
                if(from->clas == 9)
                {
                    Character *character_ptr = *character;
                    character_ptr->AddRef();
 
                    int amount = util::rand(from->mindam + 0, from->maxdam + 0);
                    double rand = util::rand(0.0, 1.0);
                    // Checks if target is facing you
                    bool critical = std::abs(int(character_ptr->direction) - from->direction) != 2 || rand < static_cast<double>(this->world->config["CriticalRate"]);
 
                    std::tr1::unordered_map<std::string, double> formula_vars;
 
                    from->FormulaVars(formula_vars);
                    character_ptr->FormulaVars(formula_vars, "target_");
                    formula_vars["modifier"] = this->world->config["PKRate"];
                    formula_vars["damage"] = amount;
                    formula_vars["critical"] = critical;
 
                    amount = rpn_eval(rpn_parse(this->world->formulas_config["damage"]), formula_vars);
                    double hit_rate = rpn_eval(rpn_parse(this->world->formulas_config["hit_rate"]), formula_vars);
 
                    if (rand > hit_rate)
                    {
                        amount = 0;
                    }
 
                    amount = std::max(amount, 0);
 
                    int limitamount = std::min(amount, int(character_ptr->hp));
 
                    if (this->world->config["LimitDamage"])
                    {
                        amount = limitamount;
                    }
 
                    if (character_ptr->invincible == false)
                    {
                        character_ptr->hp -= limitamount;
 
                        int itemid, effectid;
for(int i = 0 ; i < static_cast<int>(this->world->effects_config["WAmount"]) ; i++){
itemid = static_cast<int>(this->world->effects_config[util::to_string(i+1) + ".ItemID"]);
effectid = static_cast<int>(this->world->effects_config[util::to_string(i+1) + ".PlayerEffect"]);
       if(from->paperdoll[Character::Weapon] == itemid)
       {
           character_ptr->Effect(effectid, true);
       }
}
 
                        PacketBuilder builder(PACKET_CLOTHES, PACKET_REPLY);
                        builder.AddShort(from->player->id);
                        builder.AddShort(character_ptr->player->id);
                        builder.AddThree(amount);
                        builder.AddChar(from->direction);
                        builder.AddChar(int(double(character_ptr->hp) / double(character_ptr->maxhp) * 100.0));
                        builder.AddChar(character_ptr->hp == 0);
 
                        UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
                        {
                            if (character_ptr->InRange(*checkchar))
                            {
                                checkchar->player->client->SendBuilder(builder);
                            }
                        }
                    }
                    else
                    {
                        PacketBuilder builder(PACKET_CLOTHES, PACKET_REPLY);
                        builder.AddShort(from->player->id);
                        builder.AddShort(character_ptr->player->id);
                        builder.AddThree(0);
                        builder.AddChar(from->direction);
                        builder.AddChar(int(double(character_ptr->hp) / double(character_ptr->maxhp) * 100.0));
                        builder.AddChar(character_ptr->hp == 0);
 
                        UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
                        {
                            if (character_ptr->InRange(*checkchar))
                            {
                                checkchar->player->client->SendBuilder(builder);
                            }
                        }
 
                    }
 
                    if (character_ptr->hp == 0)
                    {
                            Quest *temp_quest = 0;
                    State *state = 0;
                    UTIL_PTR_LIST_FOREACH(from->quests, Character_Quest, quest)
                    {
                        temp_quest = this->world->GetQuest(quest->id);
                        if (!temp_quest) continue;
 
                        state = temp_quest->GetState(quest->state);
                        if (!state) continue;
 
                        UTIL_PTR_VECTOR_FOREACH(state->rules, Rule, rule)
                        {
                            if (rule->name.compare("killedplayers") == 0)
                            {
                                quest->killed++;
                                if (quest->killed >= ((int)(*rule->args[0])))
                                {
                                    quest->killed = 0;
                                    quest->state = rule->goto_state;
                                    from->PerformQuestActions(quest->id);
                                }
                                break;
                            }
                        }
                    }
 
std::string msg(character->name + " got KnocKed tHE FuK ouT By ");
                    msg += from->name;
                    this->world->ServerMsg(msg);
 
int item = 1;
int amount = 2000;
if (from->AddItem(item, amount))
            {
    PacketBuilder builder(PACKET_ITEM, PACKET_GET);
    builder.AddShort(0); // UID
    builder.AddShort(item);
    builder.AddThree(amount);
    builder.AddChar(from->weight);
    builder.AddChar(from->maxweight);
    from->player->client->SendBuilder(builder);
            }
 
bool stats_updated = false;
from->exp += 1000;
stats_updated = true;
if (stats_updated)
    {
 bool level_up = false;
 while (from->level < static_cast<int>(this->world->config["MaxLevel"]) && from->exp >= this->world->exp_table[from->level+1])
        {
    level_up = true;
    ++from->level;
    from->statpoints += static_cast<int>(this->world->config["StatPerLevel"]);
    from->skillpoints += static_cast<int>(this->world->config["SkillPerLevel"]);
    from->CalculateStats();
        }
 
    PacketBuilder builder(PACKET_RECOVER, PACKET_REPLY);
    builder.AddInt(from->exp);
    builder.AddShort(from->karma);
    builder.AddChar(level_up ? from->level : 0);
    from->player->client->SendBuilder(builder);
    }
 
                        character_ptr->hp = int(character_ptr->maxhp * static_cast<double>(this->world->config["DeathRecover"]) / 100.0);
 
                        if (this->world->config["Deadly"])
                        {
                            character_ptr->DropAll(from);
                        }
character_ptr->PetTransfer();
                        character_ptr->map->Leave(character_ptr, WARP_ANIMATION_NONE, true);
 
                        character_ptr->nowhere = true;
                        character_ptr->map = this->world->GetMap(character_ptr->SpawnMap());
                        character_ptr->mapid = character_ptr->SpawnMap();
                        character_ptr->x = character_ptr->SpawnX();
                        character_ptr->y = character_ptr->SpawnY();
 character_ptr->PetTransfer();
                        PacketReader reader("");
 
                        character_ptr->player->client->queue.AddAction(PACKET_INTERNAL, PACKET_INTERNAL_NULL, reader, 1.5);
                        character_ptr->player->client->queue.AddAction(PACKET_INTERNAL, PACKET_INTERNAL_WARP, reader, 0.0);
                    }
 
                    PacketBuilder builder(PACKET_RECOVER, PACKET_PLAYER);
                    builder.AddShort(character_ptr->hp);
                    builder.AddInt(from->exp);
                    builder.AddShort(character_ptr->tp);
                    character_ptr->player->client->SendBuilder(builder);
 
                    character_ptr->Release();
 
                    return true;
                }
 
                else if(from->clas != 9)
                {
                    Character *character_ptr = *character;
                    character_ptr->AddRef();
 
                    int amount = util::rand(from->mindam, from->maxdam);
                    double rand = util::rand(0.0, 1.0);
                    // Checks if target is facing you
                    bool critical = std::abs(int(character_ptr->direction) - from->direction) != 2 || rand < static_cast<double>(this->world->config["CriticalRate"]);
 
                    std::tr1::unordered_map<std::string, double> formula_vars;
 
                    from->FormulaVars(formula_vars);
                    character_ptr->FormulaVars(formula_vars, "target_");
                    formula_vars["modifier"] = this->world->config["PKRate"];
                    formula_vars["damage"] = amount;
                    formula_vars["critical"] = critical;
 
                    amount = rpn_eval(rpn_parse(this->world->formulas_config["damage"]), formula_vars);
                    double hit_rate = rpn_eval(rpn_parse(this->world->formulas_config["hit_rate"]), formula_vars);
 
                    if (rand > hit_rate)
                    {
                        amount = 0;
                    }
 
                    amount = std::max(amount, 0);
 
                    int limitamount = std::min(amount, int(character_ptr->hp));
 
                    if (this->world->config["LimitDamage"])
                    {
                        amount = limitamount;
                    }
 
                    if (character_ptr->invincible == false)
                    {
                        character_ptr->hp -= limitamount;
 
                        int itemid, effectid;
for(int i = 0 ; i < static_cast<int>(this->world->effects_config["WAmount"]) ; i++){
itemid = static_cast<int>(this->world->effects_config[util::to_string(i+1) + ".ItemID"]);
effectid = static_cast<int>(this->world->effects_config[util::to_string(i+1) + ".PlayerEffect"]);
       if(from->paperdoll[Character::Weapon] == itemid)
       {
           character_ptr->Effect(effectid, true);
       }
}
 
                        PacketBuilder builder(PACKET_CLOTHES, PACKET_REPLY);
                        builder.AddShort(from->player->id);
                        builder.AddShort(character_ptr->player->id);
                        builder.AddThree(amount);
                        builder.AddChar(from->direction);
                        builder.AddChar(int(double(character_ptr->hp) / double(character_ptr->maxhp) * 100.0));
                        builder.AddChar(character_ptr->hp == 0);
 
                        UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
                        {
                            if (character_ptr->InRange(*checkchar))
                            {
                                checkchar->player->client->SendBuilder(builder);
                            }
                        }
                    }
                    else
                    {
                        PacketBuilder builder(PACKET_CLOTHES, PACKET_REPLY);
                        builder.AddShort(from->player->id);
                        builder.AddShort(character_ptr->player->id);
                        builder.AddThree(0);
                        builder.AddChar(from->direction);
                        builder.AddChar(int(double(character_ptr->hp) / double(character_ptr->maxhp) * 100.0));
                        builder.AddChar(character_ptr->hp == 0);
 
                        UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
                        {
                            if (character_ptr->InRange(*checkchar))
                            {
                                checkchar->player->client->SendBuilder(builder);
                            }
                        }
 
                    }
 
                    if (character_ptr->hp == 0)
                    {
 
     Quest *temp_quest = 0;
                    State *state = 0;
                    UTIL_PTR_LIST_FOREACH(from->quests, Character_Quest, quest)
                    {
                        temp_quest = this->world->GetQuest(quest->id);
                        if (!temp_quest) continue;
 
                        state = temp_quest->GetState(quest->state);
                        if (!state) continue;
 
                        UTIL_PTR_VECTOR_FOREACH(state->rules, Rule, rule)
                        {
                            if (rule->name.compare("killedplayers") == 0)
                            {
                                quest->killed++;
                                if (quest->killed >= ((int)(*rule->args[0])))
                                {
                                    quest->killed = 0;
                                    quest->state = rule->goto_state;
                                    from->PerformQuestActions(quest->id);
                                }
                                break;
                            }
                        }
                    }
 
               std::string msg(character->name + " got KnocKed tHE FuK ouT By ");
                    msg += from->name;
                    this->world->ServerMsg(msg);
 
int item = 1;
int amount = 2000;
if (from->AddItem(item, amount))
            {
    PacketBuilder builder(PACKET_ITEM, PACKET_GET);
    builder.AddShort(0); // UID
    builder.AddShort(item);
    builder.AddThree(amount);
    builder.AddChar(from->weight);
    builder.AddChar(from->maxweight);
    from->player->client->SendBuilder(builder);
            }
 
bool stats_updated = false;
from->exp += 1000;
stats_updated = true;
if (stats_updated)
    {
 bool level_up = false;
 while (from->level < static_cast<int>(this->world->config["MaxLevel"]) && from->exp >= this->world->exp_table[from->level+1])
        {
    level_up = true;
    ++from->level;
    from->statpoints += static_cast<int>(this->world->config["StatPerLevel"]);
    from->skillpoints += static_cast<int>(this->world->config["SkillPerLevel"]);
    from->CalculateStats();
        }
 
    PacketBuilder builder(PACKET_RECOVER, PACKET_REPLY);
    builder.AddInt(from->exp);
    builder.AddShort(from->karma);
    builder.AddChar(level_up ? from->level : 0);
    from->player->client->SendBuilder(builder);
    }
 
                        character_ptr->hp = int(character_ptr->maxhp * static_cast<double>(this->world->config["DeathRecover"]) / 100.0);
 
                        if (this->world->config["Deadly"])
                        {
                            character_ptr->DropAll(from);
                        }
 character_ptr->PetTransfer();
                        character_ptr->map->Leave(character_ptr, WARP_ANIMATION_NONE, true);
 
                        character_ptr->nowhere = true;
                        character_ptr->map = this->world->GetMap(character_ptr->SpawnMap());
                        character_ptr->mapid = character_ptr->SpawnMap();
                        character_ptr->x = character_ptr->SpawnX();
                        character_ptr->y = character_ptr->SpawnY();
 character_ptr->PetTransfer();
                        PacketReader reader("");
 
                        character_ptr->player->client->queue.AddAction(PACKET_INTERNAL, PACKET_INTERNAL_NULL, reader, 1.5);
                        character_ptr->player->client->queue.AddAction(PACKET_INTERNAL, PACKET_INTERNAL_WARP, reader, 0.0);
                    }
 
                    PacketBuilder builder(PACKET_RECOVER, PACKET_PLAYER);
                    builder.AddShort(character_ptr->hp);
                    builder.AddShort(character_ptr->tp);
                    character_ptr->player->client->SendBuilder(builder);
 
                    character_ptr->Release();
 
                    return true;
                }
            }
        }
    }
 
    return false;
}
 
bool Map::AttackPKSpell(Character *from, int spellid, int targetid)
{
     ESF_Data *spell = this->world->esf->Get(spellid);
 
    PacketBuilder builder;
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (character->mapid == this->id && !character->nowhere && targetid == character->player->id && from->player->id != character->player->id)
        {
            if (from->clas == 9)
            {
                Character *character_ptr = *character;
                character_ptr->AddRef();
 
                 int amount = util::rand(spell->mindam + 60000, spell->maxdam +60000);
                //int amount = util::rand(from->mindam + 0, from->maxdam + 0);
                int limitamount = std::min(amount, int(character_ptr->hp));
 
                if (static_cast<int>(this->world->config["LimitDamage"]))
                {
                    amount = limitamount;
                }
 
                if (character_ptr->invincible == false)
                {
                    character_ptr->hp -= limitamount;
 
                    builder.SetID(PACKET_CLOTHES, PACKET_ADMIN);
                    builder.AddShort(from->player->id);
                    builder.AddShort(character_ptr->player->id);
                    builder.AddThree(amount);
                    builder.AddChar(from->direction);
                    builder.AddChar(int(double(character_ptr->hp) / double(character_ptr->maxhp) * 100.0));
                    builder.AddChar(character_ptr->hp == 0);
                    builder.AddShort(spellid);
 
                    UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
                    {
                        if (character_ptr->InRange(*checkchar))
                        {
                            checkchar->player->client->SendBuilder(builder);
                        }
                    }
                }
                else
                {
                    builder.SetID(PACKET_CLOTHES, PACKET_ADMIN);
                    builder.AddShort(from->player->id);
                    builder.AddShort(character_ptr->player->id);
                    builder.AddThree(0);
                    builder.AddChar(from->direction);
                    builder.AddChar(int(double(character_ptr->hp) / double(character_ptr->maxhp) * 100.0));
                    builder.AddChar(character_ptr->hp == 0);
                    builder.AddShort(spellid);
 
                    UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
                    {
                        if (character_ptr->InRange(*checkchar))
                        {
                            checkchar->player->client->SendBuilder(builder);
                        }
                    }
                }
 
                if (character_ptr->hp == 0)
                {
 
     Quest *temp_quest = 0;
                    State *state = 0;
                    UTIL_PTR_LIST_FOREACH(from->quests, Character_Quest, quest)
                    {
                        temp_quest = this->world->GetQuest(quest->id);
                        if (!temp_quest) continue;
 
                        state = temp_quest->GetState(quest->state);
                        if (!state) continue;
 
                        UTIL_PTR_VECTOR_FOREACH(state->rules, Rule, rule)
                        {
                            if (rule->name.compare("killedplayers") == 0)
                            {
                                quest->killed++;
                                if (quest->killed >= ((int)(*rule->args[0])))
                                {
                                    quest->killed = 0;
                                    quest->state = rule->goto_state;
                                    from->PerformQuestActions(quest->id);
                                }
                                break;
                            }
                        }
                    }
 
        std::string msg(character->name + " got KnocKed tHE FuK ouT By ");
                    msg += from->name;
                    this->world->ServerMsg(msg);
 
int item = 1;
int amount = 2000;
if (from->AddItem(item, amount))
            {
    PacketBuilder builder(PACKET_ITEM, PACKET_GET);
    builder.AddShort(0); // UID
    builder.AddShort(item);
    builder.AddThree(amount);
    builder.AddChar(from->weight);
    builder.AddChar(from->maxweight);
    from->player->client->SendBuilder(builder);
            }
 
bool stats_updated = false;
from->exp += 1000;
stats_updated = true;
if (stats_updated)
    {
 bool level_up = false;
 while (from->level < static_cast<int>(this->world->config["MaxLevel"]) && from->exp >= this->world->exp_table[from->level+1])
        {
    level_up = true;
    ++from->level;
    from->statpoints += static_cast<int>(this->world->config["StatPerLevel"]);
    from->skillpoints += static_cast<int>(this->world->config["SkillPerLevel"]);
    from->CalculateStats();
        }
 
    PacketBuilder builder(PACKET_RECOVER, PACKET_REPLY);
    builder.AddInt(from->exp);
    builder.AddShort(from->karma);
    builder.AddChar(level_up ? from->level : 0);
    from->player->client->SendBuilder(builder);
    }
 
                    character_ptr->hp = int(character_ptr->maxhp * static_cast<double>(this->world->config["DeathRecover"]) / 100.0);
 
                    if (this->world->config["Deadly"])
                    {
                        character_ptr->DropAll(from);
                    }
 character_ptr->PetTransfer();
                    character_ptr->map->Leave(character_ptr, WARP_ANIMATION_NONE, true);
 
                    character_ptr->nowhere = true;
                    character_ptr->map = this->world->GetMap(character_ptr->SpawnMap());
                    character_ptr->mapid = character_ptr->SpawnMap();
                    character_ptr->x = character_ptr->SpawnX();
                    character_ptr->y = character_ptr->SpawnY();
 character_ptr->PetTransfer();
                    PacketReader reader("");
 
                    character_ptr->player->client->queue.AddAction(PACKET_INTERNAL, PACKET_INTERNAL_NULL, reader, 1.5);
                    character_ptr->player->client->queue.AddAction(PACKET_INTERNAL, PACKET_INTERNAL_WARP, reader, 0.0);
                }
 
                builder.Reset();
                builder.SetID(PACKET_RECOVER, PACKET_PLAYER);
                builder.AddShort(character_ptr->hp);
                builder.AddShort(character_ptr->tp);
                character_ptr->player->client->SendBuilder(builder);
 
                character_ptr->Release();
 
                return true;
            }
 
            else if (from->clas != 9)
            {
                Character *character_ptr = *character;
                character_ptr->AddRef();
 
 int amount = util::rand(spell->mindam, spell->maxdam);
               // int amount = util::rand(from->mindam, from->maxdam);
                int limitamount = std::min(amount, int(character_ptr->hp));
 
                if (static_cast<int>(this->world->config["LimitDamage"]))
                {
                    amount = limitamount;
                }
 
                if (character_ptr->invincible == false)
                {
                    character_ptr->hp -= limitamount;
 
                    builder.SetID(PACKET_CLOTHES, PACKET_ADMIN);
                    builder.AddShort(from->player->id);
                    builder.AddShort(character_ptr->player->id);
                    builder.AddThree(amount);
                    builder.AddChar(from->direction);
                    builder.AddChar(int(double(character_ptr->hp) / double(character_ptr->maxhp) * 100.0));
                    builder.AddChar(character_ptr->hp == 0);
                    builder.AddShort(spellid);
 
                    UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
                    {
                        if (character_ptr->InRange(*checkchar))
                        {
                            checkchar->player->client->SendBuilder(builder);
                        }
                    }
                }
                else
                {
                    builder.SetID(PACKET_CLOTHES, PACKET_ADMIN);
                    builder.AddShort(from->player->id);
                    builder.AddShort(character_ptr->player->id);
                    builder.AddThree(0);
                    builder.AddChar(from->direction);
                    builder.AddChar(int(double(character_ptr->hp) / double(character_ptr->maxhp) * 100.0));
                    builder.AddChar(character_ptr->hp == 0);
                    builder.AddShort(spellid);
 
                    UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
                    {
                        if (character_ptr->InRange(*checkchar))
                        {
                            checkchar->player->client->SendBuilder(builder);
                        }
                    }
                }
 
                if (character_ptr->hp == 0)
                {
 
                       Quest *temp_quest = 0;
                    State *state = 0;
                    UTIL_PTR_LIST_FOREACH(from->quests, Character_Quest, quest)
                    {
                        temp_quest = this->world->GetQuest(quest->id);
                        if (!temp_quest) continue;
 
                        state = temp_quest->GetState(quest->state);
                        if (!state) continue;
 
                        UTIL_PTR_VECTOR_FOREACH(state->rules, Rule, rule)
                        {
                            if (rule->name.compare("killedplayers") == 0)
                            {
                                quest->killed++;
                                if (quest->killed >= ((int)(*rule->args[0])))
                                {
                                    quest->killed = 0;
                                    quest->state = rule->goto_state;
                                    from->PerformQuestActions(quest->id);
                                }
                                break;
                            }
                        }
                    }
 
                  std::string msg(character->name + " got KnocKed tHE FuK ouT By ");
                    msg += from->name;
                    this->world->ServerMsg(msg);
 
int item = 1;
int amount = 2000;
if (from->AddItem(item, amount))
            {
    PacketBuilder builder(PACKET_ITEM, PACKET_GET);
    builder.AddShort(0); // UID
    builder.AddShort(item);
    builder.AddThree(amount);
    builder.AddChar(from->weight);
    builder.AddChar(from->maxweight);
    from->player->client->SendBuilder(builder);
            }
 
bool stats_updated = false;
from->exp += 1000;
stats_updated = true;
if (stats_updated)
    {
 bool level_up = false;
 while (from->level < static_cast<int>(this->world->config["MaxLevel"]) && from->exp >= this->world->exp_table[from->level+1])
        {
    level_up = true;
    ++from->level;
    from->statpoints += static_cast<int>(this->world->config["StatPerLevel"]);
    from->skillpoints += static_cast<int>(this->world->config["SkillPerLevel"]);
    from->CalculateStats();
        }
 
    PacketBuilder builder(PACKET_RECOVER, PACKET_REPLY);
    builder.AddInt(from->exp);
    builder.AddShort(from->karma);
    builder.AddChar(level_up ? from->level : 0);
    from->player->client->SendBuilder(builder);
    }
 
                    character_ptr->hp = int(character_ptr->maxhp * static_cast<double>(this->world->config["DeathRecover"]) / 100.0);
 
                    if (this->world->config["Deadly"])
                    {
                        character_ptr->DropAll(from);
                    }
 character_ptr->PetTransfer();
                    character_ptr->map->Leave(character_ptr, WARP_ANIMATION_NONE, true);
 
                    character_ptr->nowhere = true;
                    character_ptr->map = this->world->GetMap(character_ptr->SpawnMap());
                    character_ptr->mapid = character_ptr->SpawnMap();
                    character_ptr->x = character_ptr->SpawnX();
                    character_ptr->y = character_ptr->SpawnY();
 character_ptr->PetTransfer();
                    PacketReader reader("");
 
                    character_ptr->player->client->queue.AddAction(PACKET_INTERNAL, PACKET_INTERNAL_NULL, reader, 1.5);
                    character_ptr->player->client->queue.AddAction(PACKET_INTERNAL, PACKET_INTERNAL_WARP, reader, 0.0);
                }
 
                builder.Reset();
                builder.SetID(PACKET_RECOVER, PACKET_PLAYER);
                builder.AddShort(character_ptr->hp);
                builder.AddShort(character_ptr->tp);
                character_ptr->player->client->SendBuilder(builder);
 
                character_ptr->Release();
 
                return true;
            }
        }
    }
 
return false;
 
}
 
void Map::Face(Character *from, Direction direction)
{
    PacketBuilder builder;
 
    from->direction = direction;
 
    builder.SetID(PACKET_FACE, PACKET_PLAYER);
    builder.AddShort(from->player->id);
    builder.AddChar(direction);
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (*character == from || !from->InRange(*character))
        {
            continue;
        }
 
        character->player->client->SendBuilder(builder);
    }
}
 
void Map::Sit(Character *from, SitAction sit_type)
{
    PacketBuilder builder;
 
    from->sitting = sit_type;
 
    builder.SetID((sit_type == SIT_CHAIR) ? PACKET_CHAIR : PACKET_SIT, PACKET_PLAYER);
    builder.AddShort(from->player->id);
    builder.AddChar(from->x);
    builder.AddChar(from->y);
    builder.AddChar(from->direction);
    builder.AddChar(0); // ?
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (*character == from || !from->InRange(*character))
        {
            continue;
        }
 
        character->player->client->SendBuilder(builder);
    }
}
 
void Map::Stand(Character *from)
{
    PacketBuilder builder;
 
    from->sitting = SIT_STAND;
 
    builder.SetID(PACKET_SIT, PACKET_REMOVE);
    builder.AddShort(from->player->id);
    builder.AddChar(from->x);
    builder.AddChar(from->y);
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (*character == from || !from->InRange(*character))
        {
            continue;
        }
 
        character->player->client->SendBuilder(builder);
    }
}
 
void Map::Emote(Character *from, enum Emote emote, bool echo)
{
 
    PacketBuilder builder;
 
    builder.SetID(PACKET_EMOTE, PACKET_PLAYER);
    builder.AddShort(from->player->id);
    builder.AddChar(emote);
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (!echo && (*character == from || !from->InRange(*character)))
        {
            continue;
        }
 
        character->player->client->SendBuilder(builder);
    }
}
 
bool Map::Occupied(unsigned char x, unsigned char y, Map::OccupiedTarget target)
{
    if (x >= this->width || y >= this->height)
    {
        return false;
    }
 
    if (target != Map::NPCOnly)
    {
        UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
        {
            if (character->x == x && character->y == y)
            {
                return true;
            }
        }
    }
 
    if (target != Map::PlayerOnly)
    {
        UTIL_PTR_VECTOR_FOREACH(this->npcs, NPC, npc)
        {
            if (npc->alive && npc->x == x && npc->y == y)
            {
                return true;
            }
        }
    }
 
    return false;
}
 
void Map::Shine_God()
{
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        PacketBuilder builder;
        Character *character_ptr = *character;
        character_ptr->AddRef();
 
        if(character_ptr->invincible == true)
        {
            builder.SetID(PACKET_EFFECT, PACKET_PLAYER);
            builder.AddShort(character_ptr->player->id);
            builder.AddThree(0);//effectid
            builder.AddShort(character_ptr->player->id);
            builder.AddThree(0);//effectid
 
            UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar)
            {
                if (character_ptr->InRange(*checkchar))
                {
                    checkchar->player->client->SendBuilder(builder);
                }
            }
        }
        character_ptr->Release();
    }
}
 
Map::~Map()
{
    this->Unload();
}
 
bool Map::OpenDoor(Character *from, unsigned char x, unsigned char y)
{
    if (from && !from->InRange(x, y))
    {
        return false;
    }
 
    if (Map_Warp *warp = this->GetWarp(x, y))
    {
        if (warp->spec == Map_Warp::NoDoor || warp->open)
        {
            return false;
        }
 
          if (from && warp->spec > Map_Warp::Door)
    {
        if (!from->HasItem(this->world->eif->GetKey(warp->spec - static_cast<int>(Map_Warp::Door)) + 1))
        {
            return false;
        }
    }
 
        PacketBuilder builder;
        builder.SetID(PACKET_DOOR, PACKET_OPEN);
        builder.AddChar(x);
        builder.AddShort(y);
 
        UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
        {
            if (character->InRange(x, y))
            {
                character->player->client->SendBuilder(builder);
            }
        }
 
        warp->open = true;
 
        map_close_door_struct *close = new map_close_door_struct;
        close->map = this;
        close->x = x;
        close->y = y;
 
        TimeEvent *event = new TimeEvent(map_close_door, close, this->world->config["DoorTimer"], 1);
        this->world->timer.Register(event);
        event->Release();
 
        return true;
    }
 
    return false;
}
 
void Map::CloseDoor(unsigned char x, unsigned char y)
{
    if (Map_Warp *warp = this->GetWarp(x, y))
    {
        if (warp->spec == Map_Warp::NoDoor || !warp->open)
        {
            return;
        }
 
        warp->open = false;
    }
}
 
Map_Item *Map::AddItem(short id, int amount, unsigned char x, unsigned char y, Character *from)
{
    Map_Item *newitem(new Map_Item(GenerateItemID(), id, amount, x, y, 0, 0));
 
    PacketBuilder builder;
    builder.SetID(PACKET_ITEM, PACKET_ADD);
    builder.AddShort(id);
    builder.AddShort(newitem->uid);
    builder.AddThree(amount);
    builder.AddChar(x);
    builder.AddChar(y);
 
    if (from || (from && from->admin <= ADMIN_GM))
    {
        int ontile = 0;
        int onmap = 0;
 
        UTIL_PTR_LIST_FOREACH(this->items, Map_Item, item)
        {
            ++onmap;
            if (item->x == x && item->y == y)
            {
                ++ontile;
            }
        }
 
        if (ontile >= static_cast<int>(this->world->config["MaxTile"]) || onmap >= static_cast<int>(this->world->config["MaxMap"]))
        {
            return 0;
        }
    }
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if ((from && *character == from) || !character->InRange(newitem))
        {
            continue;
        }
        character->player->client->SendBuilder(builder);
    }
 
    this->items.push_back(newitem);
    newitem->Release();
    return this->items.back();
}
 
Map_Item *Map::GetItem(short uid)
{
    UTIL_PTR_LIST_FOREACH(this->items, Map_Item, item)
    {
        if (item->uid == uid)
        {
            return *item;
        }
    }
 
    return 0;
}
 
void Map::DelItem(short uid, Character *from)
{
    UTIL_PTR_LIST_FOREACH(this->items, Map_Item, item)
    {
        if (item->uid == uid)
        {
            PacketBuilder builder;
            builder.SetID(PACKET_ITEM, PACKET_REMOVE);
            builder.AddShort(uid);
            UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
            {
                if ((from && *character == from) || !character->InRange(*item))
                {
                    continue;
                }
                character->player->client->SendBuilder(builder);
            }
            this->items.erase(item);
            break;
        }
    }
}
 
void Map::DelItem(Map_Item *item_, Character *from)
{
    UTIL_PTR_LIST_FOREACH(this->items, Map_Item, item)
    {
        if (item_ == *item)
        {
            PacketBuilder builder;
            builder.SetID(PACKET_ITEM, PACKET_REMOVE);
            builder.AddShort(item->uid);
            UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
            {
                if ((from && *character == from) || !character->InRange(*item))
                {
                    continue;
                }
                character->player->client->SendBuilder(builder);
            }
            this->items.erase(item);
            break;
        }
    }
}
 
bool Map::InBounds(unsigned char x, unsigned char y)
{
    return !(x >= this->width || y >= this->height);
}
 
bool Map::Walkable(unsigned char x, unsigned char y, bool npc)
{
    return (InBounds(x, y) && this->tiles[y]->at(x)->Walkable(npc));
}
 
Map_Tile::TileSpec Map::GetSpec(unsigned char x, unsigned char y)
{
    if (x >= this->width || y >= this->height)
    {
        return Map_Tile::None;
    }
 
    return this->tiles[y]->at(x)->tilespec;
}
 
Map_Warp *Map::GetWarp(unsigned char x, unsigned char y)
{
    if (x >= this->width || y >= this->height)
    {
        return 0;
    }
 
    return this->tiles[y]->at(x)->warp;
}
 
void Map::Effect(int effect, int param)
{
    PacketBuilder builder;
    builder.SetID(PACKET_EFFECT, PACKET_USE);
    builder.AddChar(effect);
    builder.AddChar(param);
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        character->player->client->SendBuilder(builder);
    }
}
 
bool Map::Reload()
{
    char namebuf[6];
    char checkrid[4];
 
    std::string filename = this->world->config["MapDir"];
    std::sprintf(namebuf, "%05i", this->id);
    this->filename = filename;
    filename.append(namebuf);
    filename.append(".emf");
 
    std::FILE *fh = std::fopen(filename.c_str(), "rb");
 
    if (!fh)
    {
        Console::Err("Could not load file: %s", filename.c_str());
        return false;
    }
 
    SAFE_SEEK(fh, 0x03, SEEK_SET);
    SAFE_READ(checkrid, sizeof(char), 4, fh);
 
    if (this->rid[0] == checkrid[0] && this->rid[1] == checkrid[1]
     && this->rid[2] == checkrid[2] && this->rid[3] == checkrid[3])
    {
        return true;
    }
 
    PtrList<Character> temp = this->characters;
 
    this->Unload();
 
    if (!this->Load())
    {
        return false;
    }
 
    this->characters = temp;
 
    PacketBuilder builder(0);
    builder.AddChar(INIT_MAP_MUTATION);
 
    std::string content;
    std::fseek(fh, 0, SEEK_SET);
    do {
        char buf[4096];
        int len = std::fread(buf, sizeof(char), 4096, fh);
        content.append(buf, len);
    } while (!std::feof(fh));
    std::fclose(fh);
 
    builder.AddString(content);
 
    PacketBuilder protect_builder(0);
    protect_builder.AddChar(INIT_BANNED);
 
    UTIL_PTR_LIST_FOREACH(temp, Character, character)
    {
        character->player->client->Send(builder.Get());
        character->Refresh(); // TODO: Find a better way to reload NPCs
 
        if (this->world->config["ProtectMaps"])
        {
            character->player->client->Send(protect_builder.Get());
        }
    }
 
    this->exists = true;
 
    return true;
}
 
Character *Map::GetCharacter(std::string name)
{
    name = util::lowercase(name);
 
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (character->name.compare(name) == 0)
        {
            return *character;
        }
    }
 
    return 0;
}
 
Character *Map::GetCharacterPID(unsigned int id)
{
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (character->player->id == id)
        {
            return *character;
        }
    }
 
    return 0;
}
 
Character *Map::GetCharacterCID(unsigned int id)
{
    UTIL_PTR_LIST_FOREACH(this->characters, Character, character)
    {
        if (character->id == id)
        {
            return *character;
        }
    }
 
    return 0;
}