/* $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->effect = PacketProcessor::Number(buf[0])== 1;//apollo effect? 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 you dont have a god mode remove && from->invincible == false) and the first ( if((from->map->GetSpec(target_x, target_y) == Map_Tile::Spikes1 || from->map->GetSpec(target_x, target_y) == Map_Tile::Spikes2 || from->map->GetSpec(target_x, target_y) == Map_Tile::Spikes3)&& from->invincible == false) { //PacketBuilder builder; int amount = util::rand(2, static_cast<int>(this->world->config["SpikeDamage"])); UTIL_PTR_LIST_FOREACH(this->characters, Character, character) { int limitamount = std::min(amount, int(from->hp)); if (this->world->config["LimitDamage"]) { amount = limitamount; } from->hp -= limitamount; PacketBuilder builder(PACKET_CLOTHES, PACKET_REPLY); builder.AddShort(0); builder.AddShort(from->player->id); builder.AddThree(amount); builder.AddChar(from->direction); builder.AddChar(int(double(from->hp) / double(from->maxhp) * 100.0)); builder.AddChar(from->hp == 0); if(from->InRange(*character)) { character->player->client->SendBuilder(builder); } if(from->hp == 0) { int sm = from->SpawnMap(); int sx = from->SpawnX(); int sy = from->SpawnY(); from->PetTransfer();//if you dont have a pet system remove this line from->Warp(sm, sx, sy, WARP_ANIMATION_ADMIN); from->PetTransfer();//if you dont have a pet system remove this line from->hp = from->maxhp; if(from->x == sx && from->y == sy) { builder.Reset(); builder.SetID(PACKET_RECOVER, PACKET_PLAYER); builder.AddShort(from->hp); builder.AddInt(from->exp); builder.AddShort(from->tp); from->player->client->SendBuilder(builder); } break; } builder.Reset(); builder.SetID(PACKET_RECOVER, PACKET_PLAYER); builder.AddShort(from->hp); builder.AddInt(from->exp); builder.AddShort(from->tp); from->player->client->SendBuilder(builder); } } int uid = 1; Map_Item *item = this->GetItem(uid); if(from->paperdoll[Character::Boots] == 125 ) { if (item) { int distance = util::path_length(item->x, item->y, from->x, from->y); if (distance < 2 && item->owner == from->player->id) { from->AddItem(item->id, item->amount); reply.SetID(PACKET_ITEM, PACKET_GET); reply.AddShort(uid); reply.AddShort(item->id); reply.AddThree(item->amount); reply.AddChar(from->weight); reply.AddChar(from->maxweight); from->player->client->SendBuilder(reply); this->DelItem(item, from); } } } 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))//need to test removeing pets and leave above code only { 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(); UTIL_PTR_VECTOR_FOREACH(this->npcs, NPC, npc) { 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 (from->paperdoll[Character::Weapon] != 690 && !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::Unknown3 || npc->Data()->type == ENF::Unknown4 || 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, 0); } } 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::Unknown3 || npc->Data()->type == ENF::Unknown4 || 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 + spl->level * 9999, spell->maxdam + spl->level * 9999); //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::Unknown3 || npc->Data()->type == ENF::Unknown4 || 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 + 0, from->maxdam + 0); 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) { Character *character_ptr = *character; character_ptr->AddRef(); 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); } } if(from->clas == 9)// where it began { 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->guild != from->guild) { character_ptr->hp -= limitamount; 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; UTIL_PTR_LIST_FOREACH(this->characters, Character, character) { if (character->mapid == this->id && !character->nowhere && character->guild == from->guild) { Character *characterg = *character; characterg->AddRef(); characterg->AddItem(item, amount); PacketBuilder builder(PACKET_ITEM, PACKET_GET); builder.AddShort(0); // UID builder.AddShort(item); builder.AddThree(amount); builder.AddChar(characterg->weight); builder.AddChar(characterg->maxweight); characterg->player->client->SendBuilder(builder); bool stats_updated = false; characterg->exp += 1000; stats_updated = true; if (stats_updated) { bool level_up = false; while (characterg->level < static_cast<int>(this->world->config["MaxLevel"]) && characterg->exp >= this->world->exp_table[characterg->level+1]) { level_up = true; ++from->level; characterg->statpoints += static_cast<int>(this->world->config["StatPerLevel"]); characterg->skillpoints += static_cast<int>(this->world->config["SkillPerLevel"]); characterg->CalculateStats(); } PacketBuilder builder(PACKET_RECOVER, PACKET_REPLY); builder.AddInt(characterg->exp); builder.AddShort(characterg->karma); builder.AddChar(level_up ? characterg->level : 0); characterg->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) { 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->guild != from->guild) { character_ptr->hp -= limitamount; 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; } } } this->world->ServerMsg(character->name + " got KnocKed tHE FuK ouT By " + from->name); int item = 1; int amount = 2000; UTIL_PTR_LIST_FOREACH(this->characters, Character, character) { if (character->mapid == this->id && !character->nowhere && character->guild == from->guild) { Character *characterg = *character; characterg->AddRef(); characterg->AddItem(item, amount); PacketBuilder builder(PACKET_ITEM, PACKET_GET); builder.AddShort(0); // UID builder.AddShort(item); builder.AddThree(amount); builder.AddChar(characterg->weight); builder.AddChar(characterg->maxweight); characterg->player->client->SendBuilder(builder); bool stats_updated = false; characterg->exp += 1000; stats_updated = true; if (stats_updated) { bool level_up = false; while (characterg->level < static_cast<int>(this->world->config["MaxLevel"]) && characterg->exp >= this->world->exp_table[characterg->level+1]) { level_up = true; ++from->level; characterg->statpoints += static_cast<int>(this->world->config["StatPerLevel"]); characterg->skillpoints += static_cast<int>(this->world->config["SkillPerLevel"]); characterg->CalculateStats(); } PacketBuilder builder(PACKET_RECOVER, PACKET_REPLY); builder.AddInt(characterg->exp); builder.AddShort(characterg->karma); builder.AddChar(level_up ? characterg->level : 0); characterg->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) { Character *character_ptr = *character; character_ptr->AddRef(); if (from->clas == 9) { int amount = util::rand(spell->mindam * 1.5, spell->maxdam * 1.5); //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; UTIL_PTR_LIST_FOREACH(this->characters, Character, character) { if (character->mapid == this->id && !character->nowhere && character->guild == from->guild) { Character *characterg = *character; characterg->AddRef(); characterg->AddItem(item, amount); PacketBuilder builder(PACKET_ITEM, PACKET_GET); builder.AddShort(0); // UID builder.AddShort(item); builder.AddThree(amount); builder.AddChar(characterg->weight); builder.AddChar(characterg->maxweight); characterg->player->client->SendBuilder(builder); bool stats_updated = false; characterg->exp += 1000; stats_updated = true; if (stats_updated) { bool level_up = false; while (characterg->level < static_cast<int>(this->world->config["MaxLevel"]) && characterg->exp >= this->world->exp_table[characterg->level+1]) { level_up = true; ++from->level; characterg->statpoints += static_cast<int>(this->world->config["StatPerLevel"]); characterg->skillpoints += static_cast<int>(this->world->config["SkillPerLevel"]); characterg->CalculateStats(); } PacketBuilder builder(PACKET_RECOVER, PACKET_REPLY); builder.AddInt(characterg->exp); builder.AddShort(characterg->karma); builder.AddChar(level_up ? characterg->level : 0); characterg->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) { 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; UTIL_PTR_LIST_FOREACH(this->characters, Character, character) { if (character->mapid == this->id && !character->nowhere && character->guild == from->guild) { Character *characterg = *character; characterg->AddRef(); characterg->AddItem(item, amount); PacketBuilder builder(PACKET_ITEM, PACKET_GET); builder.AddShort(0); // UID builder.AddShort(item); builder.AddThree(amount); builder.AddChar(characterg->weight); builder.AddChar(characterg->maxweight); characterg->player->client->SendBuilder(builder); bool stats_updated = false; characterg->exp += 1000; stats_updated = true; if (stats_updated) { bool level_up = false; while (characterg->level < static_cast<int>(this->world->config["MaxLevel"]) && characterg->exp >= this->world->exp_table[characterg->level+1]) { level_up = true; ++from->level; characterg->statpoints += static_cast<int>(this->world->config["StatPerLevel"]); characterg->skillpoints += static_cast<int>(this->world->config["SkillPerLevel"]); characterg->CalculateStats(); } PacketBuilder builder(PACKET_RECOVER, PACKET_REPLY); builder.AddInt(characterg->exp); builder.AddShort(characterg->karma); builder.AddChar(level_up ? characterg->level : 0); characterg->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::ClassSpell(Character *from, int targetid) { PacketBuilder builder; UTIL_PTR_LIST_FOREACH(this->characters, Character, character) { Character *target = *character; target->AddRef(); int spellid = util::rand(1, 31); int distance = util::path_length(target->x, target->y, from->x, from->y); builder.SetID(PACKET_CLOTHES, PACKET_ADMIN); builder.AddShort(0); builder.AddShort(target->player->id); builder.AddThree(0); builder.AddChar(1); builder.AddChar(int(double(target->hp) / double(target->maxhp) * 100.0)); builder.AddChar(target->hp == 0); builder.AddShort(spellid); UTIL_PTR_LIST_FOREACH(this->characters, Character, checkchar) { if (target->InRange(*checkchar)) { checkchar->player->client->SendBuilder(builder); target->player->client->SendBuilder(builder); } } target->Effect(spellid, true); target->hp = target->maxhp; builder.Reset(); builder.SetID(PACKET_RECOVER, PACKET_PLAYER); builder.AddShort(target->hp); builder.AddShort(target->tp); target->player->client->SendBuilder(builder); } } 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) { if(character->invincible == true) { character->Emote(EMOTE_ANGRY, true); } } } 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; }