Ir para conteúdo

vine96

Membro
  • Registro em

  • Última visita

Histórico de Curtidas

  1. Obrigado
    vine96 recebeu reputação de DiigooMix em Ajuda - Action que vende itens da BP   
    tinha entrado em contato via mensagem com outro membro aqui do fórum o @Wakon e ele me disponibilizou, fiz umas modificações e está 100%
    Para quem tem interesse o script completo é esse:
    local items = { [2537] = {value = 4800}, [2377] = {value = 480}, [2663] = {value = 600}, [2472] = {value = 90000}, [2475] = {value = 7200}, [2519] = {value = 8000}, [2497] = {value = 6000}, [2523] = {value = 180000}, [2494] = {value = 108000}, [2400] = {value = 144000}, [2491] = {value = 2500}, [2421] = {value = 108000}, [2646] = {value = 240000}, [2477] = {value = 5000}, [2656] = {value = 10000}, [2498] = {value = 30000}, [2647] = {value = 600}, [2534] = {value = 15000}, [7402] = {value = 15000}, [2466] = {value = 20000}, [2465] = {value = 240}, [2408] = {value = 120000}, [2518] = {value = 1800}, [2500] = {value = 3000}, [2470] = {value = 30000}, [2645] = {value = 30000}, [2434] = {value = 2000}, [2463] = {value = 480}, [2536] = {value = 9000}, [2387] = {value = 240}, [2396] = {value = 1000}, [2381] = {value = 450}, [2528] = {value = 8000}, [2409] = {value = 1800}, [2414] = {value = 9000}, [2427] = {value = 11000}, [2407] = {value = 7200}, [2383] = {value = 960}, [2392] = {value = 4000}, [2488] = {value = 12000}, [2525] = {value = 250}, [2423] = {value = 1000}, [2462] = {value = 4800}, [2520] = {value = 30000}, [2390] = {value = 180000}, [2417] = {value = 500}, [2436] = {value = 6000}, [5741] = {value = 40000}, [2378] = {value = 500}, [2487] = {value = 12000}, [2476] = {value = 5000}, [8891] = {value = 15000}, [2195] = {value = 30000}, [2391] = {value = 7200}, [8889] = {value = 18000}, [2432] = {value = 8000}, [2431] = {value = 108000}, [2492] = {value = 40000}, [2515] = {value = 2000}, [2430] = {value = 2000}, [2393] = {value = 17000}, [7419] = {value = 10000}, [2522] = {value = 120000}, [2514] = {value = 50000}, [7418] = {value = 35000} } function onUse(cid, item, frompos, itemEx, topos) if (itemEx.itemid == item.itemid) then local str = "" for i, k in pairs(items) do str = str ..getItemNameById(i):gsub("%a", string.upper, 1).. ": ".. k.value .. "\n" end doShowTextDialog(cid, 6533, "Item Name: Price\n-----------------------------\n".. str) return true end --local i = items[getItemNameById(itemEx.itemid)] local i = items[itemEx.itemid] if (i) then local count = getPlayerItemCount(cid, itemEx.itemid) if (count > 0) then doPlayerSellItem(cid, itemEx.itemid, count, i.value * count, false) doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Você vendeu ".. count .." ".. (count == 1 and getItemNameById(itemEx.itemid) or getItemPluralNameById(itemEx.itemid)) .. " por ".. i.value * count .." gold coins.") else doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Você não possuí esse item, o sistema irá vender apenas os items em seu inventário, items equipados não serão vendidos!") end else doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Não foi possível vender esse item, use o loot seller nele mesmo para ver a lista de items disponíveis.") doSendMagicEffect(frompos, CONST_ME_POFF) end return true end  
  2. Curtir
    vine96 recebeu reputação de DiigooMix em Script de fazer a SpellWand Virar um item que vende o loot igual NPC Mad   
    teria como por para vender todos do tipo de item que eu clicar com a spellwand? Por exemplo: tenho 100 mpa coletadas, clico na spellwand e em 1 mpa ele vende todas, é possível?
  3. Obrigado
    vine96 recebeu reputação de Soleister em GesiorACC COM TOP LVL+OUTFIT   
    reupei aqui pra vcs +)
     
    https://www.mediafire.com/file/8j7tw0ehaexqxca/htdocs+(1).rar/file
  4. Gostei
    vine96 recebeu reputação de Sh1br4nk4 em Baiak-PvP [8.60] - Watch System + Cast Look   
    Bem simples de resolver ao criar o banco de dados para o server coloca como: utf8mb4_unicode_ci
    Galera vou fazer a minha boa ação de fim de ano.
     
    Explicando: essa base do Baiak PVP é realmente muito boa e bem estável eu estou a quase 2 meses ininterruptos com o server online e sem problemas de crash, rollback ou qualquer coisa do tipo, já testei diversos bugs conhecidos de derrubar servidor e nada acontece com essas sources, é uma base realmente muito sólida e ótima para um servidor 8.6.
     
    Porém recentemente descobri um bug que é o seguinte, ao player utilizar !leavehouse ou perder a house e afins, os seus itens não vão para o depot, eles simplesmente somem.
     
    O distro quem compilou foi eu com base nas sources disponibilizadas aqui mesmo, no caso compilei para ubuntu 14.04.
     
    Ao testar no testserver que possuo, e utilizando outra distro com sources acredito ser de outra revisão do TFS 0.4 esse bug não acontece, os itens são entregue normalmente ao depot do jogador.
     
    Descobri então que se trata de um bug nas sources, no caso a house.cpp
     
    Fiz uma alteração no arquivo e após isso ficou 100%, para tal vou disponibilizar o arquivo editado aqui para vocês.
     
    Troque todo o código do arquivo house.cpp por esse:
     
    //////////////////////////////////////////////////////////////////////// // OpenTibia - an opensource roleplaying game //////////////////////////////////////////////////////////////////////// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. //////////////////////////////////////////////////////////////////////// #include "otpch.h" #include "house.h" #include "tools.h" #include "database.h" #include "beds.h" #include "town.h" #include "iologindata.h" #include "ioguild.h" #include "iomapserialize.h" #include "configmanager.h" #include "game.h" extern ConfigManager g_config; extern Game g_game; House::House(uint32_t houseId) { guild = pendingTransfer = isprotected = false; name = "OTX headquarter (Flat 1, Area 42)"; entry = Position(); id = houseId; rent = price = townId = paidUntil = owner = rentWarnings = lastWarning = 0; syncFlags = HOUSE_SYNC_NAME | HOUSE_SYNC_TOWN | HOUSE_SYNC_SIZE | HOUSE_SYNC_PRICE | HOUSE_SYNC_RENT | HOUSE_SYNC_GUILD; } void House::addTile(HouseTile* tile) { tile->setFlag(TILESTATE_PROTECTIONZONE); houseTiles.push_back(tile); } void House::addBed(BedItem* bed) { bedsList.push_back(bed); bed->setHouse(this); } void House::addDoor(Door* door) { door->addRef(); doorList.push_back(door); door->setHouse(this); updateDoorDescription("", door); } void House::removeDoor(Door* door) { HouseDoorList::iterator it = std::find(doorList.begin(), doorList.end(), door); if(it != doorList.end()) { (*it)->unRef(); doorList.erase(it); } } Door* House::getDoorByNumber(uint8_t doorId) const { for(HouseDoorList::const_iterator it = doorList.begin(); it != doorList.end(); ++it) { if((*it)->getDoorId() == doorId) return (*it); } return NULL; } Door* House::getDoorByPosition(const Position& pos) { for(HouseDoorList::iterator it = doorList.begin(); it != doorList.end(); ++it) { if((*it)->getPosition() == pos) return (*it); } return NULL; } void House::setOwner(uint32_t guid) { owner = guid; updateDoorDescription(); } bool House::setOwnerEx(uint32_t guid, bool transfer) { if(owner == guid) return true; if(isGuild() && guid) { Player* player = g_game.getPlayerByGuidEx(guid); if(!player) return false; guid = player->getGuildId(); if(player->isVirtual()) delete player; } if(owner) { rentWarnings = paidUntil = 0; if(transfer) clean(); setAccessList(SUBOWNER_LIST, "", !transfer); setAccessList(GUEST_LIST, "", !transfer); for(HouseDoorList::iterator it = doorList.begin(); it != doorList.end(); ++it) (*it)->setAccessList(""); } setOwner(guid); lastWarning = guid ? time(NULL) : 0; Database* db = Database::getInstance(); DBTransaction trans; if(!trans.begin()) return false; IOMapSerialize::getInstance()->saveHouse(db, this); return trans.commit(); } bool House::isGuild() const { return g_config.getBool(ConfigManager::GUILD_HALLS) && guild; } bool House::isBidded() const { Database* db = Database::getInstance(); DBResult_ptr result; DBQuery query; query << "SELECT `house_id` FROM `house_auctions` WHERE `house_id` = " << id << " LIMIT 1"; if(!(result = db->storeQuery(query.str()))) return false; return true; } void House::updateDoorDescription(std::string _name/* = ""*/, Door* door/* = NULL*/) { std::string tmp = "house"; if(isGuild()) tmp = "hall"; char houseDescription[200]; if(owner) { if(isGuild()) IOGuild::getInstance()->getGuildById(_name, owner); else if(_name.empty()) IOLoginData::getInstance()->getNameByGuid(owner, _name); sprintf(houseDescription, "It belongs to %s '%s'. %s owns this %s.", tmp.c_str(), name.c_str(), _name.c_str(), tmp.c_str()); } else sprintf(houseDescription, "It belongs to %s '%s'. Nobody owns this %s. It costs %d gold coins.", tmp.c_str(), name.c_str(), tmp.c_str(), price); if(!door) { for(HouseDoorList::iterator it = doorList.begin(); it != doorList.end(); ++it) (*it)->setSpecialDescription(houseDescription); } else door->setSpecialDescription(houseDescription); } void House::removePlayer(Player* player, bool ignoreRights) { if(!ignoreRights && player->hasFlag(PlayerFlag_CanEditHouses)) return; Position curPos = player->getPosition(), newPos = g_game.getClosestFreeTile(player, entry, false, false); if(g_game.internalTeleport(player, newPos, false) == RET_NOERROR && !player->isGhost()) { g_game.addMagicEffect(curPos, MAGIC_EFFECT_POFF); g_game.addMagicEffect(newPos, MAGIC_EFFECT_TELEPORT); } } void House::removePlayers(bool ignoreInvites) { PlayerVector kickList; for(HouseTileList::iterator it = houseTiles.begin(); it != houseTiles.end(); ++it) { CreatureVector* creatures = (*it)->getCreatures(); if(!creatures) continue; Player* player = NULL; for(CreatureVector::iterator cit = creatures->begin(); cit != creatures->end(); ++cit) { if((player = (*cit)->getPlayer()) && !player->isRemoved() && (ignoreInvites || !isInvited(player))) kickList.push_back(player); } } if(kickList.empty()) return; for(PlayerVector::iterator it = kickList.begin(); it != kickList.end(); ++it) removePlayer((*it), false); } bool House::kickPlayer(Player* player, Player* target) { if(!target || target->isRemoved()) return false; HouseTile* houseTile = target->getTile()->getHouseTile(); if(!houseTile || houseTile->getHouse() != this) return false; bool self = player == target; if(getHouseAccessLevel(player) < getHouseAccessLevel(target) && !self) return false; removePlayer(target, self); return true; } void House::clean() { for(HouseBedList::iterator bit = bedsList.begin(); bit != bedsList.end(); ++bit) { if((*bit)->getSleeper()) (*bit)->wakeUp(); } removePlayers(true); transferToDepot(); } bool House::transferToDepot() { if(!townId) return false; Player* player = NULL; if(owner) { uint32_t tmp = owner; if(isGuild() && !IOGuild::getInstance()->swapGuildIdToOwner(tmp)) tmp = 0; if(tmp) player = g_game.getPlayerByGuidEx(tmp); } Item* item = NULL; Container* tmpContainer = NULL; ItemList moveList; for(HouseTileList::iterator it = houseTiles.begin(); it != houseTiles.end(); ++it) { for(uint32_t i = 0; i < (*it)->getThingCount(); ++i) { if(!(item = (*it)->__getThing(i)->getItem())) continue; if(item->isPickupable()) moveList.push_back(item); else if((tmpContainer = item->getContainer())) { for(ItemList::const_iterator it = tmpContainer->getItems(); it != tmpContainer->getEnd(); ++it) moveList.push_back(*it); } } } if(player) { Depot* depot = player->getDepot(townId, true); for(ItemList::iterator it = moveList.begin(); it != moveList.end(); ++it) g_game.internalMoveItem(NULL, (*it)->getParent(), depot, INDEX_WHEREEVER, (*it), (*it)->getItemCount(), NULL, FLAG_NOLIMIT); if(player->isVirtual()) { IOLoginData::getInstance()->savePlayer(player); delete player; } } else { for(ItemList::iterator it = moveList.begin(); it != moveList.end(); ++it) g_game.internalRemoveItem(NULL, (*it), (*it)->getItemCount(), false, FLAG_NOLIMIT); } return true; } bool House::isInvited(const Player* player) { return getHouseAccessLevel(player) != HOUSE_NO_INVITED; } AccessHouseLevel_t House::getHouseAccessLevel(const Player* player) { if(!player) return HOUSE_NO_INVITED; if(player->hasFlag(PlayerFlag_CanEditHouses)) return HOUSE_OWNER; if(!owner) return HOUSE_NO_INVITED; AccessHouseLevel_t tmp = HOUSE_NO_INVITED; if(isGuild()) { if(player->getGuildId() == owner) { switch(player->getGuildLevel()) { case GUILDLEVEL_LEADER: return HOUSE_OWNER; case GUILDLEVEL_VICE: return HOUSE_SUBOWNER; default: tmp = HOUSE_GUEST; } } } else if(player->getGUID() == owner/* || player->marriage == owner*/) return HOUSE_OWNER; if(subOwnerList.isInList(player)) return HOUSE_SUBOWNER; if(guestList.isInList(player)) return HOUSE_GUEST; return tmp; } bool House::canEditAccessList(uint32_t listId, const Player* player) { switch(getHouseAccessLevel(player)) { case HOUSE_OWNER: return true; case HOUSE_SUBOWNER: return listId == GUEST_LIST; default: break; } return false; } bool House::getAccessList(uint32_t listId, std::string& list) const { if(listId == GUEST_LIST) { guestList.getList(list); return true; } if(listId == SUBOWNER_LIST) { subOwnerList.getList(list); return true; } if(Door* door = getDoorByNumber(listId)) return door->getAccessList(list); #ifdef __DEBUG_HOUSES__ std::clog << "[Failure - House::getAccessList] door == NULL, listId = " << listId <<std::endl; #endif return false; } void House::setAccessList(uint32_t listId, const std::string& textlist, bool teleport/* = true*/) { if(listId == GUEST_LIST) guestList.parseList(textlist); else if(listId == SUBOWNER_LIST) subOwnerList.parseList(textlist); else { if(Door* door = getDoorByNumber(listId)) door->setAccessList(textlist); #ifdef __DEBUG_HOUSES__ else std::clog << "[Failure - House::setAccessList] door == NULL, listId = " << listId <<std::endl; #endif return; } if(teleport) removePlayers(false); } TransferItem* TransferItem::createTransferItem(House* house) { TransferItem* transferItem = new TransferItem(house); transferItem->addRef(); transferItem->setID(ITEM_HOUSE_TRANSFER); char buffer[150]; sprintf(buffer, "It is a %s transfer document for '%s'.", house->isGuild() ? "guild hall" : "house", house->getName().c_str()); transferItem->setSpecialDescription(buffer); transferItem->setSubType(1); return transferItem; } bool TransferItem::onTradeEvent(TradeEvents_t event, Player* owner, Player* seller) { switch(event) { case ON_TRADE_TRANSFER: { if(house) house->setOwnerEx(owner->getGUID(), true); g_game.internalRemoveItem(NULL, this, getItemCount()); seller->transferContainer.setParent(NULL); break; } case ON_TRADE_CANCEL: { owner->transferContainer.setParent(NULL); owner->transferContainer.__removeThing(this, getItemCount()); g_game.freeThing(this); break; } default: return false; } return true; } void AccessList::getList(std::string& _list) const { _list = list; } bool AccessList::parseList(const std::string& _list) { playerList.clear(); guildList.clear(); expressionList.clear(); regexList.clear(); list = _list; if(_list.empty()) return true; std::stringstream listStream(_list); std::string line; while(getline(listStream, line)) { trimString(line); trim_left(line, "\t"); trim_right(line, "\t"); trimString(line); toLowerCaseString(line); if(line.empty()) break; if(line.substr(0, 1) == "#" || line.length() > 100) continue; if(line.find("@") != std::string::npos) { std::string::size_type pos = line.find("@"); addGuild(line.substr(pos + 1), line.substr(0, pos)); } else if(line.find("!") != std::string::npos || line.find("*") != std::string::npos || line.find("?") != std::string::npos) addExpression(line); else addPlayer(line); } return true; } bool AccessList::isInList(const Player* player) { std::string name = player->getName(); boost::cmatch what; try { toLowerCaseString(name); for(RegexList::iterator it = regexList.begin(); it != regexList.end(); ++it) { if(boost::regex_match(name.c_str(), what, it->first)) return it->second; } } catch(...) {} if(playerList.find(player->getGUID()) != playerList.end()) return true; for(GuildList::iterator git = guildList.begin(); git != guildList.end(); ++git) { if(git->first == player->getGuildId() && ((uint32_t)git->second == player->getRankId() || git->second == -1)) return true; } return false; } bool AccessList::addPlayer(std::string& name) { std::string tmp = name; uint32_t guid; if(!IOLoginData::getInstance()->getGuidByName(guid, tmp) || playerList.find(guid) != playerList.end()) return false; playerList.insert(guid); return true; } bool AccessList::addGuild(const std::string& guildName, const std::string& rankName) { uint32_t guildId; if(!IOGuild::getInstance()->getGuildId(guildId, guildName)) return false; std::string tmp = rankName; int32_t rankId = IOGuild::getInstance()->getRankIdByName(guildId, tmp); if(!rankId && (tmp.find("?") == std::string::npos || tmp.find("!") == std::string::npos || tmp.find("*") == std::string::npos)) rankId = -1; if(!rankId) return false; for(GuildList::iterator git = guildList.begin(); git != guildList.end(); ++git) { if(git->first == guildId && git->second == rankId) return true; } guildList.push_back(std::make_pair(guildId, rankId)); return true; } bool AccessList::addExpression(const std::string& expression) { for(ExpressionList::iterator it = expressionList.begin(); it != expressionList.end(); ++it) { if((*it) == expression) return false; } std::string out, meta = ".[{}()\\+|^$"; for(std::string::const_iterator it = expression.begin(); it != expression.end(); ++it) { if(meta.find(*it) != std::string::npos) out += "\\"; out += (*it); } replaceString(out, "**", ""); replaceString(out, "*", ".*"); replaceString(out, "?", ".?"); try { if(out.length() > 0) { expressionList.push_back(out); if(out.substr(0, 1) == "!") { if(out.length() > 1) regexList.push_front(std::make_pair(boost::regex(out.substr(1)), false)); } else regexList.push_back(std::make_pair(boost::regex(out), true)); } } catch(...) {} return true; } Door::~Door() { delete accessList; } Attr_ReadValue Door::readAttr(AttrTypes_t attr, PropStream& propStream) { if(attr != ATTR_HOUSEDOORID) return Item::readAttr(attr, propStream); uint8_t _doorId = 0; if(!propStream.getByte(_doorId)) return ATTR_READ_ERROR; doorId = _doorId; return ATTR_READ_CONTINUE; } void Door::copyAttributes(Item* item) { Item::copyAttributes(item); if(Door* door = item->getDoor()) { doorId = door->getDoorId(); std::string list; if(door->getAccessList(list)) setAccessList(list); } } void Door::onRemoved() { Item::onRemoved(); if(house) house->removeDoor(this); } bool Door::canUse(const Player* player) { if(!house || house->getHouseAccessLevel(player) >= HOUSE_SUBOWNER) return true; return accessList->isInList(player); } void Door::setHouse(House* _house) { if(house) return; house = _house; if(!accessList) accessList = new AccessList(); } bool Door::getAccessList(std::string& list) const { if(!house) return false; accessList->getList(list); return true; } void Door::setAccessList(const std::string& textlist) { if(!accessList) accessList = new AccessList(); accessList->parseList(textlist); } Houses::Houses() { rentPeriod = RENTPERIOD_NEVER; std::string strValue = asLowerCaseString(g_config.getString(ConfigManager::HOUSE_RENT_PERIOD)); if(strValue == "yearly") rentPeriod = RENTPERIOD_YEARLY; else if(strValue == "monthly") rentPeriod = RENTPERIOD_MONTHLY; else if(strValue == "weekly") rentPeriod = RENTPERIOD_WEEKLY; else if(strValue == "daily") rentPeriod = RENTPERIOD_DAILY; } bool Houses::loadFromXml(std::string filename) { xmlDocPtr doc = xmlParseFile(filename.c_str()); if(!doc) { std::clog << "[Warning - Houses::loadFromXml] Cannot load houses file." << std::endl; std::clog << getLastXMLError() << std::endl; return false; } xmlNodePtr houseNode, root = xmlDocGetRootElement(doc); if(xmlStrcmp(root->name,(const xmlChar*)"houses")) { std::clog << "[Error - Houses::loadFromXml] Malformed houses file." << std::endl; xmlFreeDoc(doc); return false; } int32_t intValue; std::string strValue; houseNode = root->children; while(houseNode) { if(xmlStrcmp(houseNode->name,(const xmlChar*)"house")) { houseNode = houseNode->next; continue; } int32_t houseId = 0; if(!readXMLInteger(houseNode, "houseid", houseId)) { std::clog << "[Error - Houses::loadFromXml] Could not read houseId" << std::endl; xmlFreeDoc(doc); return false; } House* house = Houses::getInstance()->getHouse(houseId); if(!house) { std::clog << "[Error - Houses::loadFromXml] Unknown house with id: " << houseId << std::endl; xmlFreeDoc(doc); return false; } Position entry(0, 0, 0); if(readXMLInteger(houseNode, "entryx", intValue)) entry.x = intValue; if(readXMLInteger(houseNode, "entryy", intValue)) entry.y = intValue; if(readXMLInteger(houseNode, "entryz", intValue)) entry.z = intValue; if(readXMLString(houseNode, "name", strValue)) house->setName(strValue); else house->resetSyncFlag(House::HOUSE_SYNC_NAME); house->setEntry(entry); if(!entry.x || !entry.y) { std::clog << "[Warning - Houses::loadFromXml] House entry not set for: " << house->getName() << " (" << houseId << ")" << std::endl; } if(readXMLInteger(houseNode, "townid", intValue)) house->setTownId(intValue); else house->resetSyncFlag(House::HOUSE_SYNC_TOWN); if(readXMLInteger(houseNode, "size", intValue)) house->setSize(intValue); else house->resetSyncFlag(House::HOUSE_SYNC_SIZE); if(readXMLString(houseNode, "guildhall", strValue)) house->setGuild(booleanString(strValue)); else house->resetSyncFlag(House::HOUSE_SYNC_GUILD); uint32_t rent = 0; if(readXMLInteger(houseNode, "rent", intValue)) rent = intValue; uint32_t price = (house->getSize() + house->getBedsCount()) * g_config.getNumber(ConfigManager::HOUSE_PRICE); // we should let players to pay only for walkable tiles + beds as single units not two items. if(g_config.getBool(ConfigManager::HOUSE_RENTASPRICE) && rent) price = rent; house->setPrice(price); if(g_config.getBool(ConfigManager::HOUSE_PRICEASRENT)) house->setRent(price); else house->setRent(rent); house->setOwner(0); houseNode = houseNode->next; } xmlFreeDoc(doc); return true; } void Houses::check() { uint64_t start = OTSYS_TIME(); std::clog << "> Checking houses..." << std::endl; time_t currentTime = time(NULL); for(HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it) payHouse(it->second, currentTime, 0); std::clog << "Houses checked in " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl; } bool Houses::payRent(Player* player, House* house, uint32_t bid, time_t _time/* = 0*/) { if(rentPeriod == RENTPERIOD_NEVER || !house->getOwner() || house->getPaidUntil() > _time || !house->getRent() || player->hasCustomFlag(PlayerCustomFlag_IgnoreHouseRent)) return true; Town* town = Towns::getInstance()->getTown(house->getTownId()); if(!town) return false; bool paid = false; uint32_t amount = house->getRent() + bid; if(g_config.getBool(ConfigManager::BANK_SYSTEM) && player->balance >= amount) { player->balance -= amount; paid = true; } else if(Depot* depot = player->getDepot(town->getID(), true)) paid = g_game.removeMoney(depot, amount, FLAG_NOLIMIT); if(!paid) return false; if(!_time) _time = time(NULL); uint32_t paidUntil = _time; switch(rentPeriod) { case RENTPERIOD_DAILY: paidUntil += 86400; break; case RENTPERIOD_WEEKLY: paidUntil += 7 * 86400; break; case RENTPERIOD_MONTHLY: paidUntil += 30 * 86400; break; case RENTPERIOD_YEARLY: paidUntil += 365 * 86400; break; default: break; } house->setLastWarning(0); house->setRentWarnings(0); house->setPaidUntil(paidUntil); return true; } bool Houses::payHouse(House* house, time_t _time, uint32_t bid) { if(rentPeriod == RENTPERIOD_NEVER || !house->getOwner() || house->getPaidUntil() > _time || !house->getRent()) return true; Town* town = Towns::getInstance()->getTown(house->getTownId()); if(!town) return false; uint32_t owner = house->getOwner(); if(house->isGuild() && !IOGuild::getInstance()->swapGuildIdToOwner(owner)) { house->setOwnerEx(0, true); return false; } std::string name; if(!IOLoginData::getInstance()->getNameByGuid(owner, name)) { house->setOwnerEx(0, true); return false; } Player* player = g_game.getPlayerByNameEx(name); if(!player) return false; if(!player->isPremium() && g_config.getBool(ConfigManager::HOUSE_NEED_PREMIUM)) { house->setOwnerEx(0, true); if(player->isVirtual()) delete player; return false; } int32_t loginClean = g_config.getNumber(ConfigManager::HOUSE_CLEAN_OLD); if(loginClean && _time >= (player->getLastLogin() + loginClean)) { house->setOwnerEx(0, true); if(player->isVirtual()) delete player; return false; } if(payRent(player, house, bid, _time) || _time < (house->getLastWarning() + 86400)) { if(player->isVirtual()) { IOLoginData::getInstance()->savePlayer(player); delete player; } return true; } uint32_t warningsLimit = 7; switch(rentPeriod) { case RENTPERIOD_DAILY: warningsLimit = 1; break; case RENTPERIOD_WEEKLY: warningsLimit = 3; break; case RENTPERIOD_YEARLY: warningsLimit = 14; break; default: break; } uint32_t warnings = house->getRentWarnings(); if(warnings >= warningsLimit) { house->setOwnerEx(0, true); if(player->isVirtual()) delete player; return false; } if(Depot* depot = player->getDepot(town->getID(), true)) { if(Item* letter = Item::CreateItem(ITEM_LETTER_STAMPED)) { if(g_game.internalAddItem(NULL, depot, letter, INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR) { letter->setWriter(g_config.getString(ConfigManager::SERVER_NAME)); letter->setDate(std::time(NULL)); std::stringstream s; s << "Warning!\nThe "; switch(rentPeriod) { case RENTPERIOD_DAILY: s << "daily"; break; case RENTPERIOD_WEEKLY: s << "weekly"; break; case RENTPERIOD_MONTHLY: s << "monthly"; break; case RENTPERIOD_YEARLY: s << "annual"; break; default: break; } s << " rent of " << house->getRent() << " gold for your " << (house->isGuild() ? "guild hall" : "house") << " \"" << house->getName() << "\" has to be paid. Have it within " << (warningsLimit - warnings) << " days or you will lose your " << (house->isGuild() ? "guild hall" : "house") << "."; letter->setText(s.str().c_str()); if(player->isVirtual()) IOLoginData::getInstance()->savePlayer(player); } else g_game.freeThing(letter); } } house->setLastWarning(_time); house->setRentWarnings(++warnings); if(player->isVirtual()) delete player; return false; } House* Houses::getHouse(uint32_t houseId, bool add/*= false*/) { HouseMap::iterator it = houseMap.find(houseId); if(it != houseMap.end()) return it->second; if(!add) return NULL; houseMap[houseId] = new House(houseId); return houseMap[houseId]; } House* Houses::getHouseByPlayer(Player* player) { if(!player || player->isRemoved()) return NULL; HouseTile* houseTile = player->getTile()->getHouseTile(); if(!houseTile) return NULL; if(House* house = houseTile->getHouse()) return house; return NULL; } House* Houses::getHouseByPlayerId(uint32_t playerId) { for(HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it) { if(!it->second->isGuild() && it->second->getOwner() == playerId) return it->second; } return NULL; } House* Houses::getHouseByGuildId(uint32_t guildId) { for(HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it) { if(it->second->isGuild() && it->second->getOwner() == guildId) return it->second; } return NULL; } uint32_t Houses::getHousesCount(uint32_t accId) { Account account = IOLoginData::getInstance()->loadAccount(accId); uint32_t guid, count = 0; for(Characters::iterator it = account.charList.begin(); it != account.charList.end(); ++it) { #ifndef __LOGIN_SERVER__ if(IOLoginData::getInstance()->getGuidByName(guid, (*it)) && getHouseByPlayerId(guid)) #else if(IOLoginData::getInstance()->getGuidByName(guid, (std::string&)it->first) && getHouseByPlayerId(guid)) #endif count++; } return count; } Após recompile e o server não vai mais possuir este bug xD, feliz ano novo a todos!
  5. Gostei
    vine96 recebeu reputação de SkidMaster em Classic-Yurots [8.60] - Push Cruzado + Cast com Setas   
    Galera seguinte, eu na época em 2019 que foi lançado este servidor Classic Yurots estava terminando a minha faculdade (ou seja TCC, projetos, apresentações e afins) e trabalhando na área, então era praticamente impossível acompanhar a comunidade de otservers.
     
    Eu mexo com servidores de tibia desde os meus 13 anos, tenho 24 atualmente, a paixão por jogar o game não me é mais suficiente, sou programador web e desktop e a paixão por administrar um servidor de sucesso sempre bateu a porta, mas agora ela falou mais alto do que nunca. Eu possuo bastante experiência em todos os ramos de ter um servidor de tibia, seja hospedagem, alteração de sprites, clientes, códigos, sites e afins.
     
    Meu primeiro server foi um X-DREAM WAR 8.40, CARAAAA quem lembra daquela epóca sabe como era muito bom estes servidores. Nunca tive sucesso com eles, mas igual eu gostava muito... heheh
     
    Em 2018 abri um global full custom com sprites editadas, ele fez um bom sucesso na época, pois como tenho habilidades com sprites, eu atualizava o conteúdo da cipsoft antes de todos os outros servers kkk lançava o update da cip e no mesmo dia eu já colocava no client e os arquivos no server. Esse server me dava muuuuito trabalho pois o mapa era global full 11.57, então era gigantesco para 1 pessoa só cuidar, tinha muita coisa com bugs e para ajustar, ainda estava na faculdade e trabalhando ao mesmo tempo, então não tinha como conciliar isto, acabei até tendo que repetir uma cadeira por isso KKKK.
     
    Mesmo assim vocês sabem que o dedicado para um server global geralmente tem que ser mais robusto por conta do map e diversos arquivos, funções e etc. Na época era 150 reais o dedicado mais barato para aguentar um servidor global deste nível, coloquei do meu bolso mesmo, e em 5 dias +/- já tive esse dinheiro de volta com doações (a galera doava de mais nesse server), uma vez recebi uma doação de 150 libras esterlinas neste server, lembro que pirei demais, era um cara australiano kkkk. Foi o meu primeiro server que realmente deu "lucro" digamos assim, mesmo que esse não fosse o objetivo.
     
    Continuando, o server conseguiu se manter online, totalmente por doações por 6 meses sem eu investir nada, acabou que eu não tinha tempo para cuidar dele, tinham muito bugs propositais que os caras colocavam na base justamente para tirar vantagem e subornar os OT admins depois, sofri muito com isso. Usava a base OTX3 do malucooo a mais atualizada na época. Quem for montar um servidor global full dos mais atuais peço que cuidem muito com isso, quem distribui a base FREE coloca diversas condições nas sources, arquivos e database do server que derrubam ele facilmente, entre outras coisas para tirar vantagem, realmente acontece.
     
    Bom seguindo, na metade de 2020 eu me formei como Analista de Sistemas e no finalzinho do ano fui demitido da empresa que eu estava, pois eu trabalhava como consultor de implantação, implantava os sistemas legados da empresa nos clientes e tinham muitas viagens a diversas cidades, a cada semana a gente ia em uma, era bem bacana, por causa da pandemia isso parou, então foram cortados vários servidores, eu fui um deles kkk. 
     
    Perante a isso eu pensei: cara essa é a hora perfeita para eu investir em um ou vários servidores de tibia, não ter que ficar dependendo de empresa contratante e ser um empregado. Estou com o tempo 100% livre, o meu PC é totalmente montado para programação e performance, só falta minha dedicação.
     
    Decidi então me dedicar aos servidores custom/baiaks e derivados, pois tenho mais controle de tudo, mapas, scripts, clients e afins e os bugs das versões e distros 8.60 já são bem conhecidos, e portanto não fica um trabalho tão maçante como em um global.
     
    Já abri um servidor que se encontra online atualmente é o http://baiakgaming.online/ que utilizei a base do BAIAK PVP, aqui doTK mesmo e fiz algumas alterações nas sources, scripts em geral e constatei que ele é bem estável, nunca caiu, nesses quase 3 meses.
     
    Ele fez um "relativo" sucesso, mas o mais importante disso tudo que o dedicado mais barato que aguenta manter ele online com bastante players, custa na faixa de R$70 + R$20 de proteção DDOS 500gb(sim isto foi necessário pois recebi 40gb de ataques a alguns dias), totalizando: R$90 por mês, este valor que eu investi, em menos de 1 mês recebi doações que conseguem manter o servidor online por mais 6 meses. Agora fechando os seus quase 3 meses de server online, ele consegue se manter online por aproximadamente mais 3 anos, somente com estas doações que já foram obtidas.
     
    Bom, porque eu escrevi esse textão de facebook? Então, de qualquer forma estava olhando este projeto do Classic Yurots e me interessei muito, vi todos os videos, imagens, sistemas e show offs até o lançamento. E pensei o seguinte: vou abrir este servidor heheh, vou levar este projeto adiante, mas com modificações minhas claro heheh.
     
    Acho que o grande erro do @KOLISAO para o servidor não ter feito sucesso, foi não ter investido em uma campanha de marketing para o lançamento (não sei se ele realmente fez isso), mas notei este ponto, isso é muito importante para chamar jogadores e abrir o server com uma grande quantidade e assim aumentar cada vez mais o número de players, mais jogadores chamam mais jogadores. 
     
    Outra coisa foi o fato de ele ter investido em um dedicado caríssimo, 75 euros, convertendo hoje da quase R$500 reais por mês, teria que ter um nível de doações muito alto para manter isso kkk, esta configuração é muito acima do necessário para rodar este servidor com perfeição.
     
    Mais um ponto é o fato de que ele teria que ter lançado bem antes do previsto este server, e com o feedback dos jogadores ir mudando e atualizando o mesmo, dia a dia. Pois nós como OT admins não temos a visão de jogador, é muito diferente a percepção para a do player. As vezes você pensa que lançou uma feature muito loca no game e é algo super top para você, mas para os jogadores talvez não faça nenhuma diferença e nunca utilizem tal feature, isso de certa forma vai frustrando para quem administra, por isso a ideia de lançar antes e ir verificando o feedback da galera.
     
    Veja bem não estou criticando o membro do fórum @KOLISAO ele fez um excelente trabalho com este datapack, merece todos os aplausos possíveis, o mapa está impecável, as quests com muito RPG, alterações no site que deixam ele muito bonito e com várias features, e também tem toda uma história por trás de cada coisa. É um trabalho digno de um profissional de mais alto nível.
     
    O datapack do Classic Yurots é bem superior a vários outros disponibilizados por aqui no fórum e realmente merece uma devida homenagem a quem desenvolveu isto.
     
    Pois bem chega de papo, montei todo este texto para no final dizer que o meu real objetivo é seguir este projeto adiante, acho que vale a pena investir e tem todo o potencial possível, na verdade tornar um servidor online em si, vou abrir este server e realizar o possível para ele fazer sucesso. Em 30 dias ou menos vai estar online.
     
    Principais mudanças que vou realizar já logo de cara: clients próprios, como: stand alone, OTC e mobile, todos com launcher, proxy, auto updater, mc e sprites únicas.
     
    O client stand alone suportando todos os bots do 8.60, e o OTC e mobile com bots incluídos no client.
     
    Pensei em utilizar as sprites do client 8.60 original, mas elas são muito limitadas a quantidade de opções, é difícil montar um set donate para cada vocação por exemplo, teria que ficar escolhendo itens a dedo e/ou tirando ele de drop de monstros, o que não é muito legal. Por isso vou utilizar de sprites editadas.
     
    Principalmente para aumentar a gama de opções de itens adquiríveis dentro e fora do game, bem como os sprites dos sistemas mais atuais: exercise trainer com os dummys e armas de treino e estatuas de treino, também nas versões mais atuais. Itens de house, armas destruction e tudo mais.
     
    Faço aqui então um convite para quem queira participar deste projeto junto comigo, sendo mapper, scripter C++, lua, web. Spriter, divulgador e afins.
     
    Tendo ajuda ou não vou abrir este servidor, vou também estar ajudando qualquer pessoa que tiver problemas para estar colocando ele online, dentro do meu alcance claro. 
     
    Obrigado para quem leu até aqui +)
     
     
     
     
     
     
     
     
     
  6. Gostei
    vine96 recebeu reputação de deza em Ajuda - Action que vende itens da BP   
    tinha entrado em contato via mensagem com outro membro aqui do fórum o @Wakon e ele me disponibilizou, fiz umas modificações e está 100%
    Para quem tem interesse o script completo é esse:
    local items = { [2537] = {value = 4800}, [2377] = {value = 480}, [2663] = {value = 600}, [2472] = {value = 90000}, [2475] = {value = 7200}, [2519] = {value = 8000}, [2497] = {value = 6000}, [2523] = {value = 180000}, [2494] = {value = 108000}, [2400] = {value = 144000}, [2491] = {value = 2500}, [2421] = {value = 108000}, [2646] = {value = 240000}, [2477] = {value = 5000}, [2656] = {value = 10000}, [2498] = {value = 30000}, [2647] = {value = 600}, [2534] = {value = 15000}, [7402] = {value = 15000}, [2466] = {value = 20000}, [2465] = {value = 240}, [2408] = {value = 120000}, [2518] = {value = 1800}, [2500] = {value = 3000}, [2470] = {value = 30000}, [2645] = {value = 30000}, [2434] = {value = 2000}, [2463] = {value = 480}, [2536] = {value = 9000}, [2387] = {value = 240}, [2396] = {value = 1000}, [2381] = {value = 450}, [2528] = {value = 8000}, [2409] = {value = 1800}, [2414] = {value = 9000}, [2427] = {value = 11000}, [2407] = {value = 7200}, [2383] = {value = 960}, [2392] = {value = 4000}, [2488] = {value = 12000}, [2525] = {value = 250}, [2423] = {value = 1000}, [2462] = {value = 4800}, [2520] = {value = 30000}, [2390] = {value = 180000}, [2417] = {value = 500}, [2436] = {value = 6000}, [5741] = {value = 40000}, [2378] = {value = 500}, [2487] = {value = 12000}, [2476] = {value = 5000}, [8891] = {value = 15000}, [2195] = {value = 30000}, [2391] = {value = 7200}, [8889] = {value = 18000}, [2432] = {value = 8000}, [2431] = {value = 108000}, [2492] = {value = 40000}, [2515] = {value = 2000}, [2430] = {value = 2000}, [2393] = {value = 17000}, [7419] = {value = 10000}, [2522] = {value = 120000}, [2514] = {value = 50000}, [7418] = {value = 35000} } function onUse(cid, item, frompos, itemEx, topos) if (itemEx.itemid == item.itemid) then local str = "" for i, k in pairs(items) do str = str ..getItemNameById(i):gsub("%a", string.upper, 1).. ": ".. k.value .. "\n" end doShowTextDialog(cid, 6533, "Item Name: Price\n-----------------------------\n".. str) return true end --local i = items[getItemNameById(itemEx.itemid)] local i = items[itemEx.itemid] if (i) then local count = getPlayerItemCount(cid, itemEx.itemid) if (count > 0) then doPlayerSellItem(cid, itemEx.itemid, count, i.value * count, false) doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Você vendeu ".. count .." ".. (count == 1 and getItemNameById(itemEx.itemid) or getItemPluralNameById(itemEx.itemid)) .. " por ".. i.value * count .." gold coins.") else doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Você não possuí esse item, o sistema irá vender apenas os items em seu inventário, items equipados não serão vendidos!") end else doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Não foi possível vender esse item, use o loot seller nele mesmo para ver a lista de items disponíveis.") doSendMagicEffect(frompos, CONST_ME_POFF) end return true end  
  7. Curtir
    vine96 recebeu reputação de kingdj22 em Ajuda - Action que vende itens da BP   
    tinha entrado em contato via mensagem com outro membro aqui do fórum o @Wakon e ele me disponibilizou, fiz umas modificações e está 100%
    Para quem tem interesse o script completo é esse:
    local items = { [2537] = {value = 4800}, [2377] = {value = 480}, [2663] = {value = 600}, [2472] = {value = 90000}, [2475] = {value = 7200}, [2519] = {value = 8000}, [2497] = {value = 6000}, [2523] = {value = 180000}, [2494] = {value = 108000}, [2400] = {value = 144000}, [2491] = {value = 2500}, [2421] = {value = 108000}, [2646] = {value = 240000}, [2477] = {value = 5000}, [2656] = {value = 10000}, [2498] = {value = 30000}, [2647] = {value = 600}, [2534] = {value = 15000}, [7402] = {value = 15000}, [2466] = {value = 20000}, [2465] = {value = 240}, [2408] = {value = 120000}, [2518] = {value = 1800}, [2500] = {value = 3000}, [2470] = {value = 30000}, [2645] = {value = 30000}, [2434] = {value = 2000}, [2463] = {value = 480}, [2536] = {value = 9000}, [2387] = {value = 240}, [2396] = {value = 1000}, [2381] = {value = 450}, [2528] = {value = 8000}, [2409] = {value = 1800}, [2414] = {value = 9000}, [2427] = {value = 11000}, [2407] = {value = 7200}, [2383] = {value = 960}, [2392] = {value = 4000}, [2488] = {value = 12000}, [2525] = {value = 250}, [2423] = {value = 1000}, [2462] = {value = 4800}, [2520] = {value = 30000}, [2390] = {value = 180000}, [2417] = {value = 500}, [2436] = {value = 6000}, [5741] = {value = 40000}, [2378] = {value = 500}, [2487] = {value = 12000}, [2476] = {value = 5000}, [8891] = {value = 15000}, [2195] = {value = 30000}, [2391] = {value = 7200}, [8889] = {value = 18000}, [2432] = {value = 8000}, [2431] = {value = 108000}, [2492] = {value = 40000}, [2515] = {value = 2000}, [2430] = {value = 2000}, [2393] = {value = 17000}, [7419] = {value = 10000}, [2522] = {value = 120000}, [2514] = {value = 50000}, [7418] = {value = 35000} } function onUse(cid, item, frompos, itemEx, topos) if (itemEx.itemid == item.itemid) then local str = "" for i, k in pairs(items) do str = str ..getItemNameById(i):gsub("%a", string.upper, 1).. ": ".. k.value .. "\n" end doShowTextDialog(cid, 6533, "Item Name: Price\n-----------------------------\n".. str) return true end --local i = items[getItemNameById(itemEx.itemid)] local i = items[itemEx.itemid] if (i) then local count = getPlayerItemCount(cid, itemEx.itemid) if (count > 0) then doPlayerSellItem(cid, itemEx.itemid, count, i.value * count, false) doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Você vendeu ".. count .." ".. (count == 1 and getItemNameById(itemEx.itemid) or getItemPluralNameById(itemEx.itemid)) .. " por ".. i.value * count .." gold coins.") else doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Você não possuí esse item, o sistema irá vender apenas os items em seu inventário, items equipados não serão vendidos!") end else doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Não foi possível vender esse item, use o loot seller nele mesmo para ver a lista de items disponíveis.") doSendMagicEffect(frompos, CONST_ME_POFF) end return true end  
  8. Haha
    vine96 recebeu reputação de samlecter em BUG BIZARRO em POKETIBIA   
    .Qual servidor ou website você utiliza como base? 
    POKE X MASTER aqui do fórum mesmo. link:
    Qual o motivo deste tópico?
    É IMPOSSÍVEL modificar o ataque dos pokemons nessa base 
     
    Está surgindo algum erro? Se sim coloque-o aqui. 
    Então é o seguinte galera, eu sou novato na programação de poketibia, mas a um tempo estou desenvolvendo um projeto em cima da base poke X master.
    Porém notei um bug BIZARRO que eu nunca tinha visto.
    É o seguinte é impossível mudar a força dos ataques dos pokemons.
    Já tentei em monsters.xml deixei tudo como 1 de atk o magikarp como exemplo, já mexi na lib "19 - pokemonstats" deixei tudo no mínimo e o ataque do pokemon continua o mesmo... eu já não sei mais oq fazer.
     
    É a seguinte situação: o pokemon Magikarp está com um dano absurdo de alto, simplesmente do nada ele hita 1k, 1,2k, 500, 600 e do nada volta a atacar 1,2,3 e do nada 1k, 1,5k até dar HS no pokemon.
     
    Alguns pokes estão assim completamente bugados o ataque, mas o que mais notei de estranho foi o magikarp já vasculhei toda a pasta do server e nada que identifique a questão de ataques a não ser a lib e monster.xml
     
    Vou postar como está os stats do magikarp:
    Aqui no arquivo 19 - pokemonStatus
    ['Magikarp'] = {offense = 0.1, defense = 1, specialattack = 0.1, life = 220, vitality = 2, agility = 50, exp = 50, level = 1, wildLvl = 1, type = 'water', type2 = 'no type'},  
    Aqui no arquivo magikarp.xml na pasta monsters:
    <?xml version="1.0" encoding="UTF-8"?> <monster name="Magikarp" nameDescription="a magikarp" race="water" experience="7" speed="207" manacost="0"> <health now="100" max="100"/> <look type="370" head="1" body="5" legs="95" feet="113" corpse="11911"/> <targetchange interval="2000" chance="0"/> <strategy attack="1" defense="0"/> <flags> <flag summonable="1"/> <flag attackable="1"/> <flag hostile="1"/> <flag illusionable="1"/> <flag convinceable="1"/> <flag pushable="1"/> <flag canpushitems="0"/> <flag canpushcreatures="0"/> <flag targetdistance="1"/> <flag staticattack="1"/> <flag runonhealth="0"/> </flags> <attacks> <attack name="melee" interval="1500" chance="100" range="1" min="-1" max="-2"/> <attack name="Splash" interval="2429" chance="32" range="6"/> </attacks> <defenses armor="0" defense="0"/> <voices interval="5000" chance="10"> <voice sentence="MAGIKARP!"/> </voices> <loot> <item id="12334" chance="100" count="1" countmax="1"/> <item id="12161" chance="100" countmax="10"/> --water gem </loot> <script> <event name="Spawn"/> </script> </monster>  
    Com essa configuração o magikarp ta hitando 500 a 1200 em outros pokemons simplesmente do nada kkk. junta 3 magikarps no gloom e da HS rapidinho
  9. Gostei
    vine96 recebeu reputação de jpma em Classic-Yurots [8.60] - Push Cruzado + Cast com Setas   
    Galera este mapa tem um bug que qualquer edição que vc faça nele ele buga todos os teleports... mesmo sem mexer em nenhum... =(
     
    Alguém sabe como resolver isso?
  10. Gostei
    vine96 recebeu reputação de Enenra em Baiak-PvP [8.60] - Watch System + Cast Look   
    Bem simples de resolver ao criar o banco de dados para o server coloca como: utf8mb4_unicode_ci
    Galera vou fazer a minha boa ação de fim de ano.
     
    Explicando: essa base do Baiak PVP é realmente muito boa e bem estável eu estou a quase 2 meses ininterruptos com o server online e sem problemas de crash, rollback ou qualquer coisa do tipo, já testei diversos bugs conhecidos de derrubar servidor e nada acontece com essas sources, é uma base realmente muito sólida e ótima para um servidor 8.6.
     
    Porém recentemente descobri um bug que é o seguinte, ao player utilizar !leavehouse ou perder a house e afins, os seus itens não vão para o depot, eles simplesmente somem.
     
    O distro quem compilou foi eu com base nas sources disponibilizadas aqui mesmo, no caso compilei para ubuntu 14.04.
     
    Ao testar no testserver que possuo, e utilizando outra distro com sources acredito ser de outra revisão do TFS 0.4 esse bug não acontece, os itens são entregue normalmente ao depot do jogador.
     
    Descobri então que se trata de um bug nas sources, no caso a house.cpp
     
    Fiz uma alteração no arquivo e após isso ficou 100%, para tal vou disponibilizar o arquivo editado aqui para vocês.
     
    Troque todo o código do arquivo house.cpp por esse:
     
    //////////////////////////////////////////////////////////////////////// // OpenTibia - an opensource roleplaying game //////////////////////////////////////////////////////////////////////// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. //////////////////////////////////////////////////////////////////////// #include "otpch.h" #include "house.h" #include "tools.h" #include "database.h" #include "beds.h" #include "town.h" #include "iologindata.h" #include "ioguild.h" #include "iomapserialize.h" #include "configmanager.h" #include "game.h" extern ConfigManager g_config; extern Game g_game; House::House(uint32_t houseId) { guild = pendingTransfer = isprotected = false; name = "OTX headquarter (Flat 1, Area 42)"; entry = Position(); id = houseId; rent = price = townId = paidUntil = owner = rentWarnings = lastWarning = 0; syncFlags = HOUSE_SYNC_NAME | HOUSE_SYNC_TOWN | HOUSE_SYNC_SIZE | HOUSE_SYNC_PRICE | HOUSE_SYNC_RENT | HOUSE_SYNC_GUILD; } void House::addTile(HouseTile* tile) { tile->setFlag(TILESTATE_PROTECTIONZONE); houseTiles.push_back(tile); } void House::addBed(BedItem* bed) { bedsList.push_back(bed); bed->setHouse(this); } void House::addDoor(Door* door) { door->addRef(); doorList.push_back(door); door->setHouse(this); updateDoorDescription("", door); } void House::removeDoor(Door* door) { HouseDoorList::iterator it = std::find(doorList.begin(), doorList.end(), door); if(it != doorList.end()) { (*it)->unRef(); doorList.erase(it); } } Door* House::getDoorByNumber(uint8_t doorId) const { for(HouseDoorList::const_iterator it = doorList.begin(); it != doorList.end(); ++it) { if((*it)->getDoorId() == doorId) return (*it); } return NULL; } Door* House::getDoorByPosition(const Position& pos) { for(HouseDoorList::iterator it = doorList.begin(); it != doorList.end(); ++it) { if((*it)->getPosition() == pos) return (*it); } return NULL; } void House::setOwner(uint32_t guid) { owner = guid; updateDoorDescription(); } bool House::setOwnerEx(uint32_t guid, bool transfer) { if(owner == guid) return true; if(isGuild() && guid) { Player* player = g_game.getPlayerByGuidEx(guid); if(!player) return false; guid = player->getGuildId(); if(player->isVirtual()) delete player; } if(owner) { rentWarnings = paidUntil = 0; if(transfer) clean(); setAccessList(SUBOWNER_LIST, "", !transfer); setAccessList(GUEST_LIST, "", !transfer); for(HouseDoorList::iterator it = doorList.begin(); it != doorList.end(); ++it) (*it)->setAccessList(""); } setOwner(guid); lastWarning = guid ? time(NULL) : 0; Database* db = Database::getInstance(); DBTransaction trans; if(!trans.begin()) return false; IOMapSerialize::getInstance()->saveHouse(db, this); return trans.commit(); } bool House::isGuild() const { return g_config.getBool(ConfigManager::GUILD_HALLS) && guild; } bool House::isBidded() const { Database* db = Database::getInstance(); DBResult_ptr result; DBQuery query; query << "SELECT `house_id` FROM `house_auctions` WHERE `house_id` = " << id << " LIMIT 1"; if(!(result = db->storeQuery(query.str()))) return false; return true; } void House::updateDoorDescription(std::string _name/* = ""*/, Door* door/* = NULL*/) { std::string tmp = "house"; if(isGuild()) tmp = "hall"; char houseDescription[200]; if(owner) { if(isGuild()) IOGuild::getInstance()->getGuildById(_name, owner); else if(_name.empty()) IOLoginData::getInstance()->getNameByGuid(owner, _name); sprintf(houseDescription, "It belongs to %s '%s'. %s owns this %s.", tmp.c_str(), name.c_str(), _name.c_str(), tmp.c_str()); } else sprintf(houseDescription, "It belongs to %s '%s'. Nobody owns this %s. It costs %d gold coins.", tmp.c_str(), name.c_str(), tmp.c_str(), price); if(!door) { for(HouseDoorList::iterator it = doorList.begin(); it != doorList.end(); ++it) (*it)->setSpecialDescription(houseDescription); } else door->setSpecialDescription(houseDescription); } void House::removePlayer(Player* player, bool ignoreRights) { if(!ignoreRights && player->hasFlag(PlayerFlag_CanEditHouses)) return; Position curPos = player->getPosition(), newPos = g_game.getClosestFreeTile(player, entry, false, false); if(g_game.internalTeleport(player, newPos, false) == RET_NOERROR && !player->isGhost()) { g_game.addMagicEffect(curPos, MAGIC_EFFECT_POFF); g_game.addMagicEffect(newPos, MAGIC_EFFECT_TELEPORT); } } void House::removePlayers(bool ignoreInvites) { PlayerVector kickList; for(HouseTileList::iterator it = houseTiles.begin(); it != houseTiles.end(); ++it) { CreatureVector* creatures = (*it)->getCreatures(); if(!creatures) continue; Player* player = NULL; for(CreatureVector::iterator cit = creatures->begin(); cit != creatures->end(); ++cit) { if((player = (*cit)->getPlayer()) && !player->isRemoved() && (ignoreInvites || !isInvited(player))) kickList.push_back(player); } } if(kickList.empty()) return; for(PlayerVector::iterator it = kickList.begin(); it != kickList.end(); ++it) removePlayer((*it), false); } bool House::kickPlayer(Player* player, Player* target) { if(!target || target->isRemoved()) return false; HouseTile* houseTile = target->getTile()->getHouseTile(); if(!houseTile || houseTile->getHouse() != this) return false; bool self = player == target; if(getHouseAccessLevel(player) < getHouseAccessLevel(target) && !self) return false; removePlayer(target, self); return true; } void House::clean() { for(HouseBedList::iterator bit = bedsList.begin(); bit != bedsList.end(); ++bit) { if((*bit)->getSleeper()) (*bit)->wakeUp(); } removePlayers(true); transferToDepot(); } bool House::transferToDepot() { if(!townId) return false; Player* player = NULL; if(owner) { uint32_t tmp = owner; if(isGuild() && !IOGuild::getInstance()->swapGuildIdToOwner(tmp)) tmp = 0; if(tmp) player = g_game.getPlayerByGuidEx(tmp); } Item* item = NULL; Container* tmpContainer = NULL; ItemList moveList; for(HouseTileList::iterator it = houseTiles.begin(); it != houseTiles.end(); ++it) { for(uint32_t i = 0; i < (*it)->getThingCount(); ++i) { if(!(item = (*it)->__getThing(i)->getItem())) continue; if(item->isPickupable()) moveList.push_back(item); else if((tmpContainer = item->getContainer())) { for(ItemList::const_iterator it = tmpContainer->getItems(); it != tmpContainer->getEnd(); ++it) moveList.push_back(*it); } } } if(player) { Depot* depot = player->getDepot(townId, true); for(ItemList::iterator it = moveList.begin(); it != moveList.end(); ++it) g_game.internalMoveItem(NULL, (*it)->getParent(), depot, INDEX_WHEREEVER, (*it), (*it)->getItemCount(), NULL, FLAG_NOLIMIT); if(player->isVirtual()) { IOLoginData::getInstance()->savePlayer(player); delete player; } } else { for(ItemList::iterator it = moveList.begin(); it != moveList.end(); ++it) g_game.internalRemoveItem(NULL, (*it), (*it)->getItemCount(), false, FLAG_NOLIMIT); } return true; } bool House::isInvited(const Player* player) { return getHouseAccessLevel(player) != HOUSE_NO_INVITED; } AccessHouseLevel_t House::getHouseAccessLevel(const Player* player) { if(!player) return HOUSE_NO_INVITED; if(player->hasFlag(PlayerFlag_CanEditHouses)) return HOUSE_OWNER; if(!owner) return HOUSE_NO_INVITED; AccessHouseLevel_t tmp = HOUSE_NO_INVITED; if(isGuild()) { if(player->getGuildId() == owner) { switch(player->getGuildLevel()) { case GUILDLEVEL_LEADER: return HOUSE_OWNER; case GUILDLEVEL_VICE: return HOUSE_SUBOWNER; default: tmp = HOUSE_GUEST; } } } else if(player->getGUID() == owner/* || player->marriage == owner*/) return HOUSE_OWNER; if(subOwnerList.isInList(player)) return HOUSE_SUBOWNER; if(guestList.isInList(player)) return HOUSE_GUEST; return tmp; } bool House::canEditAccessList(uint32_t listId, const Player* player) { switch(getHouseAccessLevel(player)) { case HOUSE_OWNER: return true; case HOUSE_SUBOWNER: return listId == GUEST_LIST; default: break; } return false; } bool House::getAccessList(uint32_t listId, std::string& list) const { if(listId == GUEST_LIST) { guestList.getList(list); return true; } if(listId == SUBOWNER_LIST) { subOwnerList.getList(list); return true; } if(Door* door = getDoorByNumber(listId)) return door->getAccessList(list); #ifdef __DEBUG_HOUSES__ std::clog << "[Failure - House::getAccessList] door == NULL, listId = " << listId <<std::endl; #endif return false; } void House::setAccessList(uint32_t listId, const std::string& textlist, bool teleport/* = true*/) { if(listId == GUEST_LIST) guestList.parseList(textlist); else if(listId == SUBOWNER_LIST) subOwnerList.parseList(textlist); else { if(Door* door = getDoorByNumber(listId)) door->setAccessList(textlist); #ifdef __DEBUG_HOUSES__ else std::clog << "[Failure - House::setAccessList] door == NULL, listId = " << listId <<std::endl; #endif return; } if(teleport) removePlayers(false); } TransferItem* TransferItem::createTransferItem(House* house) { TransferItem* transferItem = new TransferItem(house); transferItem->addRef(); transferItem->setID(ITEM_HOUSE_TRANSFER); char buffer[150]; sprintf(buffer, "It is a %s transfer document for '%s'.", house->isGuild() ? "guild hall" : "house", house->getName().c_str()); transferItem->setSpecialDescription(buffer); transferItem->setSubType(1); return transferItem; } bool TransferItem::onTradeEvent(TradeEvents_t event, Player* owner, Player* seller) { switch(event) { case ON_TRADE_TRANSFER: { if(house) house->setOwnerEx(owner->getGUID(), true); g_game.internalRemoveItem(NULL, this, getItemCount()); seller->transferContainer.setParent(NULL); break; } case ON_TRADE_CANCEL: { owner->transferContainer.setParent(NULL); owner->transferContainer.__removeThing(this, getItemCount()); g_game.freeThing(this); break; } default: return false; } return true; } void AccessList::getList(std::string& _list) const { _list = list; } bool AccessList::parseList(const std::string& _list) { playerList.clear(); guildList.clear(); expressionList.clear(); regexList.clear(); list = _list; if(_list.empty()) return true; std::stringstream listStream(_list); std::string line; while(getline(listStream, line)) { trimString(line); trim_left(line, "\t"); trim_right(line, "\t"); trimString(line); toLowerCaseString(line); if(line.empty()) break; if(line.substr(0, 1) == "#" || line.length() > 100) continue; if(line.find("@") != std::string::npos) { std::string::size_type pos = line.find("@"); addGuild(line.substr(pos + 1), line.substr(0, pos)); } else if(line.find("!") != std::string::npos || line.find("*") != std::string::npos || line.find("?") != std::string::npos) addExpression(line); else addPlayer(line); } return true; } bool AccessList::isInList(const Player* player) { std::string name = player->getName(); boost::cmatch what; try { toLowerCaseString(name); for(RegexList::iterator it = regexList.begin(); it != regexList.end(); ++it) { if(boost::regex_match(name.c_str(), what, it->first)) return it->second; } } catch(...) {} if(playerList.find(player->getGUID()) != playerList.end()) return true; for(GuildList::iterator git = guildList.begin(); git != guildList.end(); ++git) { if(git->first == player->getGuildId() && ((uint32_t)git->second == player->getRankId() || git->second == -1)) return true; } return false; } bool AccessList::addPlayer(std::string& name) { std::string tmp = name; uint32_t guid; if(!IOLoginData::getInstance()->getGuidByName(guid, tmp) || playerList.find(guid) != playerList.end()) return false; playerList.insert(guid); return true; } bool AccessList::addGuild(const std::string& guildName, const std::string& rankName) { uint32_t guildId; if(!IOGuild::getInstance()->getGuildId(guildId, guildName)) return false; std::string tmp = rankName; int32_t rankId = IOGuild::getInstance()->getRankIdByName(guildId, tmp); if(!rankId && (tmp.find("?") == std::string::npos || tmp.find("!") == std::string::npos || tmp.find("*") == std::string::npos)) rankId = -1; if(!rankId) return false; for(GuildList::iterator git = guildList.begin(); git != guildList.end(); ++git) { if(git->first == guildId && git->second == rankId) return true; } guildList.push_back(std::make_pair(guildId, rankId)); return true; } bool AccessList::addExpression(const std::string& expression) { for(ExpressionList::iterator it = expressionList.begin(); it != expressionList.end(); ++it) { if((*it) == expression) return false; } std::string out, meta = ".[{}()\\+|^$"; for(std::string::const_iterator it = expression.begin(); it != expression.end(); ++it) { if(meta.find(*it) != std::string::npos) out += "\\"; out += (*it); } replaceString(out, "**", ""); replaceString(out, "*", ".*"); replaceString(out, "?", ".?"); try { if(out.length() > 0) { expressionList.push_back(out); if(out.substr(0, 1) == "!") { if(out.length() > 1) regexList.push_front(std::make_pair(boost::regex(out.substr(1)), false)); } else regexList.push_back(std::make_pair(boost::regex(out), true)); } } catch(...) {} return true; } Door::~Door() { delete accessList; } Attr_ReadValue Door::readAttr(AttrTypes_t attr, PropStream& propStream) { if(attr != ATTR_HOUSEDOORID) return Item::readAttr(attr, propStream); uint8_t _doorId = 0; if(!propStream.getByte(_doorId)) return ATTR_READ_ERROR; doorId = _doorId; return ATTR_READ_CONTINUE; } void Door::copyAttributes(Item* item) { Item::copyAttributes(item); if(Door* door = item->getDoor()) { doorId = door->getDoorId(); std::string list; if(door->getAccessList(list)) setAccessList(list); } } void Door::onRemoved() { Item::onRemoved(); if(house) house->removeDoor(this); } bool Door::canUse(const Player* player) { if(!house || house->getHouseAccessLevel(player) >= HOUSE_SUBOWNER) return true; return accessList->isInList(player); } void Door::setHouse(House* _house) { if(house) return; house = _house; if(!accessList) accessList = new AccessList(); } bool Door::getAccessList(std::string& list) const { if(!house) return false; accessList->getList(list); return true; } void Door::setAccessList(const std::string& textlist) { if(!accessList) accessList = new AccessList(); accessList->parseList(textlist); } Houses::Houses() { rentPeriod = RENTPERIOD_NEVER; std::string strValue = asLowerCaseString(g_config.getString(ConfigManager::HOUSE_RENT_PERIOD)); if(strValue == "yearly") rentPeriod = RENTPERIOD_YEARLY; else if(strValue == "monthly") rentPeriod = RENTPERIOD_MONTHLY; else if(strValue == "weekly") rentPeriod = RENTPERIOD_WEEKLY; else if(strValue == "daily") rentPeriod = RENTPERIOD_DAILY; } bool Houses::loadFromXml(std::string filename) { xmlDocPtr doc = xmlParseFile(filename.c_str()); if(!doc) { std::clog << "[Warning - Houses::loadFromXml] Cannot load houses file." << std::endl; std::clog << getLastXMLError() << std::endl; return false; } xmlNodePtr houseNode, root = xmlDocGetRootElement(doc); if(xmlStrcmp(root->name,(const xmlChar*)"houses")) { std::clog << "[Error - Houses::loadFromXml] Malformed houses file." << std::endl; xmlFreeDoc(doc); return false; } int32_t intValue; std::string strValue; houseNode = root->children; while(houseNode) { if(xmlStrcmp(houseNode->name,(const xmlChar*)"house")) { houseNode = houseNode->next; continue; } int32_t houseId = 0; if(!readXMLInteger(houseNode, "houseid", houseId)) { std::clog << "[Error - Houses::loadFromXml] Could not read houseId" << std::endl; xmlFreeDoc(doc); return false; } House* house = Houses::getInstance()->getHouse(houseId); if(!house) { std::clog << "[Error - Houses::loadFromXml] Unknown house with id: " << houseId << std::endl; xmlFreeDoc(doc); return false; } Position entry(0, 0, 0); if(readXMLInteger(houseNode, "entryx", intValue)) entry.x = intValue; if(readXMLInteger(houseNode, "entryy", intValue)) entry.y = intValue; if(readXMLInteger(houseNode, "entryz", intValue)) entry.z = intValue; if(readXMLString(houseNode, "name", strValue)) house->setName(strValue); else house->resetSyncFlag(House::HOUSE_SYNC_NAME); house->setEntry(entry); if(!entry.x || !entry.y) { std::clog << "[Warning - Houses::loadFromXml] House entry not set for: " << house->getName() << " (" << houseId << ")" << std::endl; } if(readXMLInteger(houseNode, "townid", intValue)) house->setTownId(intValue); else house->resetSyncFlag(House::HOUSE_SYNC_TOWN); if(readXMLInteger(houseNode, "size", intValue)) house->setSize(intValue); else house->resetSyncFlag(House::HOUSE_SYNC_SIZE); if(readXMLString(houseNode, "guildhall", strValue)) house->setGuild(booleanString(strValue)); else house->resetSyncFlag(House::HOUSE_SYNC_GUILD); uint32_t rent = 0; if(readXMLInteger(houseNode, "rent", intValue)) rent = intValue; uint32_t price = (house->getSize() + house->getBedsCount()) * g_config.getNumber(ConfigManager::HOUSE_PRICE); // we should let players to pay only for walkable tiles + beds as single units not two items. if(g_config.getBool(ConfigManager::HOUSE_RENTASPRICE) && rent) price = rent; house->setPrice(price); if(g_config.getBool(ConfigManager::HOUSE_PRICEASRENT)) house->setRent(price); else house->setRent(rent); house->setOwner(0); houseNode = houseNode->next; } xmlFreeDoc(doc); return true; } void Houses::check() { uint64_t start = OTSYS_TIME(); std::clog << "> Checking houses..." << std::endl; time_t currentTime = time(NULL); for(HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it) payHouse(it->second, currentTime, 0); std::clog << "Houses checked in " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl; } bool Houses::payRent(Player* player, House* house, uint32_t bid, time_t _time/* = 0*/) { if(rentPeriod == RENTPERIOD_NEVER || !house->getOwner() || house->getPaidUntil() > _time || !house->getRent() || player->hasCustomFlag(PlayerCustomFlag_IgnoreHouseRent)) return true; Town* town = Towns::getInstance()->getTown(house->getTownId()); if(!town) return false; bool paid = false; uint32_t amount = house->getRent() + bid; if(g_config.getBool(ConfigManager::BANK_SYSTEM) && player->balance >= amount) { player->balance -= amount; paid = true; } else if(Depot* depot = player->getDepot(town->getID(), true)) paid = g_game.removeMoney(depot, amount, FLAG_NOLIMIT); if(!paid) return false; if(!_time) _time = time(NULL); uint32_t paidUntil = _time; switch(rentPeriod) { case RENTPERIOD_DAILY: paidUntil += 86400; break; case RENTPERIOD_WEEKLY: paidUntil += 7 * 86400; break; case RENTPERIOD_MONTHLY: paidUntil += 30 * 86400; break; case RENTPERIOD_YEARLY: paidUntil += 365 * 86400; break; default: break; } house->setLastWarning(0); house->setRentWarnings(0); house->setPaidUntil(paidUntil); return true; } bool Houses::payHouse(House* house, time_t _time, uint32_t bid) { if(rentPeriod == RENTPERIOD_NEVER || !house->getOwner() || house->getPaidUntil() > _time || !house->getRent()) return true; Town* town = Towns::getInstance()->getTown(house->getTownId()); if(!town) return false; uint32_t owner = house->getOwner(); if(house->isGuild() && !IOGuild::getInstance()->swapGuildIdToOwner(owner)) { house->setOwnerEx(0, true); return false; } std::string name; if(!IOLoginData::getInstance()->getNameByGuid(owner, name)) { house->setOwnerEx(0, true); return false; } Player* player = g_game.getPlayerByNameEx(name); if(!player) return false; if(!player->isPremium() && g_config.getBool(ConfigManager::HOUSE_NEED_PREMIUM)) { house->setOwnerEx(0, true); if(player->isVirtual()) delete player; return false; } int32_t loginClean = g_config.getNumber(ConfigManager::HOUSE_CLEAN_OLD); if(loginClean && _time >= (player->getLastLogin() + loginClean)) { house->setOwnerEx(0, true); if(player->isVirtual()) delete player; return false; } if(payRent(player, house, bid, _time) || _time < (house->getLastWarning() + 86400)) { if(player->isVirtual()) { IOLoginData::getInstance()->savePlayer(player); delete player; } return true; } uint32_t warningsLimit = 7; switch(rentPeriod) { case RENTPERIOD_DAILY: warningsLimit = 1; break; case RENTPERIOD_WEEKLY: warningsLimit = 3; break; case RENTPERIOD_YEARLY: warningsLimit = 14; break; default: break; } uint32_t warnings = house->getRentWarnings(); if(warnings >= warningsLimit) { house->setOwnerEx(0, true); if(player->isVirtual()) delete player; return false; } if(Depot* depot = player->getDepot(town->getID(), true)) { if(Item* letter = Item::CreateItem(ITEM_LETTER_STAMPED)) { if(g_game.internalAddItem(NULL, depot, letter, INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR) { letter->setWriter(g_config.getString(ConfigManager::SERVER_NAME)); letter->setDate(std::time(NULL)); std::stringstream s; s << "Warning!\nThe "; switch(rentPeriod) { case RENTPERIOD_DAILY: s << "daily"; break; case RENTPERIOD_WEEKLY: s << "weekly"; break; case RENTPERIOD_MONTHLY: s << "monthly"; break; case RENTPERIOD_YEARLY: s << "annual"; break; default: break; } s << " rent of " << house->getRent() << " gold for your " << (house->isGuild() ? "guild hall" : "house") << " \"" << house->getName() << "\" has to be paid. Have it within " << (warningsLimit - warnings) << " days or you will lose your " << (house->isGuild() ? "guild hall" : "house") << "."; letter->setText(s.str().c_str()); if(player->isVirtual()) IOLoginData::getInstance()->savePlayer(player); } else g_game.freeThing(letter); } } house->setLastWarning(_time); house->setRentWarnings(++warnings); if(player->isVirtual()) delete player; return false; } House* Houses::getHouse(uint32_t houseId, bool add/*= false*/) { HouseMap::iterator it = houseMap.find(houseId); if(it != houseMap.end()) return it->second; if(!add) return NULL; houseMap[houseId] = new House(houseId); return houseMap[houseId]; } House* Houses::getHouseByPlayer(Player* player) { if(!player || player->isRemoved()) return NULL; HouseTile* houseTile = player->getTile()->getHouseTile(); if(!houseTile) return NULL; if(House* house = houseTile->getHouse()) return house; return NULL; } House* Houses::getHouseByPlayerId(uint32_t playerId) { for(HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it) { if(!it->second->isGuild() && it->second->getOwner() == playerId) return it->second; } return NULL; } House* Houses::getHouseByGuildId(uint32_t guildId) { for(HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it) { if(it->second->isGuild() && it->second->getOwner() == guildId) return it->second; } return NULL; } uint32_t Houses::getHousesCount(uint32_t accId) { Account account = IOLoginData::getInstance()->loadAccount(accId); uint32_t guid, count = 0; for(Characters::iterator it = account.charList.begin(); it != account.charList.end(); ++it) { #ifndef __LOGIN_SERVER__ if(IOLoginData::getInstance()->getGuidByName(guid, (*it)) && getHouseByPlayerId(guid)) #else if(IOLoginData::getInstance()->getGuidByName(guid, (std::string&)it->first) && getHouseByPlayerId(guid)) #endif count++; } return count; } Após recompile e o server não vai mais possuir este bug xD, feliz ano novo a todos!
  11. Gostei
    Criei uma PokeBar direcionada para a TFS 0.3.6, aproveitei e estava criando uma pra 1.2 e me perguntei? Por quê não uma para a 0.3.6 para vender?
    O que é uma PokeBar?
    R = Uma lista de pokémons no qual você pode selecionar o pokémon e após selecionado ele pode ser trocado/usado pelo selecionado.
     
    Tô muito sem o que dizer aqui então, vai só esse comentário mesmo e esses GIFS pra demonstrar parte do meu trabalho.
    Vai essas duas imagens, por quê eu perdi literalmente o resto dos GIFs e eu tô com preguiça de colocar mais, mas no geral é isso.
     
     

  12. Gostei
    Adição de informação do jogador na interface.
    Avatar do jogador (Alterando automaticamente conforme o Outfit)
    Name, Level, Health, Mana, Experience. (Atualizando corretamente.)
    Inventário do jogador com equipamentos em nova disposição, exibindo o outfit atual e descrições do personagem.
     

  13. Gostei
    Look de equipamentos e armas do otc custom que estou elaborando

  14. Gostei
    Top Menu Bar desenvolvido juntamente com o @Tottin


  15. Gostei
    Esse é meu charlist, detalhe que puxa personagem de 2 servidores diferentes, um que seria o Rate Alta ( servidor com xp rate alta ) e Rate Baixa ( servidor com xp rate baixa )
     

  16. Curtir
    vine96 recebeu reputação de Enenra em Classic-Yurots [8.60] - Push Cruzado + Cast com Setas   
    Galera seguinte, eu na época em 2019 que foi lançado este servidor Classic Yurots estava terminando a minha faculdade (ou seja TCC, projetos, apresentações e afins) e trabalhando na área, então era praticamente impossível acompanhar a comunidade de otservers.
     
    Eu mexo com servidores de tibia desde os meus 13 anos, tenho 24 atualmente, a paixão por jogar o game não me é mais suficiente, sou programador web e desktop e a paixão por administrar um servidor de sucesso sempre bateu a porta, mas agora ela falou mais alto do que nunca. Eu possuo bastante experiência em todos os ramos de ter um servidor de tibia, seja hospedagem, alteração de sprites, clientes, códigos, sites e afins.
     
    Meu primeiro server foi um X-DREAM WAR 8.40, CARAAAA quem lembra daquela epóca sabe como era muito bom estes servidores. Nunca tive sucesso com eles, mas igual eu gostava muito... heheh
     
    Em 2018 abri um global full custom com sprites editadas, ele fez um bom sucesso na época, pois como tenho habilidades com sprites, eu atualizava o conteúdo da cipsoft antes de todos os outros servers kkk lançava o update da cip e no mesmo dia eu já colocava no client e os arquivos no server. Esse server me dava muuuuito trabalho pois o mapa era global full 11.57, então era gigantesco para 1 pessoa só cuidar, tinha muita coisa com bugs e para ajustar, ainda estava na faculdade e trabalhando ao mesmo tempo, então não tinha como conciliar isto, acabei até tendo que repetir uma cadeira por isso KKKK.
     
    Mesmo assim vocês sabem que o dedicado para um server global geralmente tem que ser mais robusto por conta do map e diversos arquivos, funções e etc. Na época era 150 reais o dedicado mais barato para aguentar um servidor global deste nível, coloquei do meu bolso mesmo, e em 5 dias +/- já tive esse dinheiro de volta com doações (a galera doava de mais nesse server), uma vez recebi uma doação de 150 libras esterlinas neste server, lembro que pirei demais, era um cara australiano kkkk. Foi o meu primeiro server que realmente deu "lucro" digamos assim, mesmo que esse não fosse o objetivo.
     
    Continuando, o server conseguiu se manter online, totalmente por doações por 6 meses sem eu investir nada, acabou que eu não tinha tempo para cuidar dele, tinham muito bugs propositais que os caras colocavam na base justamente para tirar vantagem e subornar os OT admins depois, sofri muito com isso. Usava a base OTX3 do malucooo a mais atualizada na época. Quem for montar um servidor global full dos mais atuais peço que cuidem muito com isso, quem distribui a base FREE coloca diversas condições nas sources, arquivos e database do server que derrubam ele facilmente, entre outras coisas para tirar vantagem, realmente acontece.
     
    Bom seguindo, na metade de 2020 eu me formei como Analista de Sistemas e no finalzinho do ano fui demitido da empresa que eu estava, pois eu trabalhava como consultor de implantação, implantava os sistemas legados da empresa nos clientes e tinham muitas viagens a diversas cidades, a cada semana a gente ia em uma, era bem bacana, por causa da pandemia isso parou, então foram cortados vários servidores, eu fui um deles kkk. 
     
    Perante a isso eu pensei: cara essa é a hora perfeita para eu investir em um ou vários servidores de tibia, não ter que ficar dependendo de empresa contratante e ser um empregado. Estou com o tempo 100% livre, o meu PC é totalmente montado para programação e performance, só falta minha dedicação.
     
    Decidi então me dedicar aos servidores custom/baiaks e derivados, pois tenho mais controle de tudo, mapas, scripts, clients e afins e os bugs das versões e distros 8.60 já são bem conhecidos, e portanto não fica um trabalho tão maçante como em um global.
     
    Já abri um servidor que se encontra online atualmente é o http://baiakgaming.online/ que utilizei a base do BAIAK PVP, aqui doTK mesmo e fiz algumas alterações nas sources, scripts em geral e constatei que ele é bem estável, nunca caiu, nesses quase 3 meses.
     
    Ele fez um "relativo" sucesso, mas o mais importante disso tudo que o dedicado mais barato que aguenta manter ele online com bastante players, custa na faixa de R$70 + R$20 de proteção DDOS 500gb(sim isto foi necessário pois recebi 40gb de ataques a alguns dias), totalizando: R$90 por mês, este valor que eu investi, em menos de 1 mês recebi doações que conseguem manter o servidor online por mais 6 meses. Agora fechando os seus quase 3 meses de server online, ele consegue se manter online por aproximadamente mais 3 anos, somente com estas doações que já foram obtidas.
     
    Bom, porque eu escrevi esse textão de facebook? Então, de qualquer forma estava olhando este projeto do Classic Yurots e me interessei muito, vi todos os videos, imagens, sistemas e show offs até o lançamento. E pensei o seguinte: vou abrir este servidor heheh, vou levar este projeto adiante, mas com modificações minhas claro heheh.
     
    Acho que o grande erro do @KOLISAO para o servidor não ter feito sucesso, foi não ter investido em uma campanha de marketing para o lançamento (não sei se ele realmente fez isso), mas notei este ponto, isso é muito importante para chamar jogadores e abrir o server com uma grande quantidade e assim aumentar cada vez mais o número de players, mais jogadores chamam mais jogadores. 
     
    Outra coisa foi o fato de ele ter investido em um dedicado caríssimo, 75 euros, convertendo hoje da quase R$500 reais por mês, teria que ter um nível de doações muito alto para manter isso kkk, esta configuração é muito acima do necessário para rodar este servidor com perfeição.
     
    Mais um ponto é o fato de que ele teria que ter lançado bem antes do previsto este server, e com o feedback dos jogadores ir mudando e atualizando o mesmo, dia a dia. Pois nós como OT admins não temos a visão de jogador, é muito diferente a percepção para a do player. As vezes você pensa que lançou uma feature muito loca no game e é algo super top para você, mas para os jogadores talvez não faça nenhuma diferença e nunca utilizem tal feature, isso de certa forma vai frustrando para quem administra, por isso a ideia de lançar antes e ir verificando o feedback da galera.
     
    Veja bem não estou criticando o membro do fórum @KOLISAO ele fez um excelente trabalho com este datapack, merece todos os aplausos possíveis, o mapa está impecável, as quests com muito RPG, alterações no site que deixam ele muito bonito e com várias features, e também tem toda uma história por trás de cada coisa. É um trabalho digno de um profissional de mais alto nível.
     
    O datapack do Classic Yurots é bem superior a vários outros disponibilizados por aqui no fórum e realmente merece uma devida homenagem a quem desenvolveu isto.
     
    Pois bem chega de papo, montei todo este texto para no final dizer que o meu real objetivo é seguir este projeto adiante, acho que vale a pena investir e tem todo o potencial possível, na verdade tornar um servidor online em si, vou abrir este server e realizar o possível para ele fazer sucesso. Em 30 dias ou menos vai estar online.
     
    Principais mudanças que vou realizar já logo de cara: clients próprios, como: stand alone, OTC e mobile, todos com launcher, proxy, auto updater, mc e sprites únicas.
     
    O client stand alone suportando todos os bots do 8.60, e o OTC e mobile com bots incluídos no client.
     
    Pensei em utilizar as sprites do client 8.60 original, mas elas são muito limitadas a quantidade de opções, é difícil montar um set donate para cada vocação por exemplo, teria que ficar escolhendo itens a dedo e/ou tirando ele de drop de monstros, o que não é muito legal. Por isso vou utilizar de sprites editadas.
     
    Principalmente para aumentar a gama de opções de itens adquiríveis dentro e fora do game, bem como os sprites dos sistemas mais atuais: exercise trainer com os dummys e armas de treino e estatuas de treino, também nas versões mais atuais. Itens de house, armas destruction e tudo mais.
     
    Faço aqui então um convite para quem queira participar deste projeto junto comigo, sendo mapper, scripter C++, lua, web. Spriter, divulgador e afins.
     
    Tendo ajuda ou não vou abrir este servidor, vou também estar ajudando qualquer pessoa que tiver problemas para estar colocando ele online, dentro do meu alcance claro. 
     
    Obrigado para quem leu até aqui +)
     
     
     
     
     
     
     
     
     
  17. Gostei
    vine96 recebeu reputação de WooX em Classic-Yurots [8.60] - Push Cruzado + Cast com Setas   
    Galera seguinte, eu na época em 2019 que foi lançado este servidor Classic Yurots estava terminando a minha faculdade (ou seja TCC, projetos, apresentações e afins) e trabalhando na área, então era praticamente impossível acompanhar a comunidade de otservers.
     
    Eu mexo com servidores de tibia desde os meus 13 anos, tenho 24 atualmente, a paixão por jogar o game não me é mais suficiente, sou programador web e desktop e a paixão por administrar um servidor de sucesso sempre bateu a porta, mas agora ela falou mais alto do que nunca. Eu possuo bastante experiência em todos os ramos de ter um servidor de tibia, seja hospedagem, alteração de sprites, clientes, códigos, sites e afins.
     
    Meu primeiro server foi um X-DREAM WAR 8.40, CARAAAA quem lembra daquela epóca sabe como era muito bom estes servidores. Nunca tive sucesso com eles, mas igual eu gostava muito... heheh
     
    Em 2018 abri um global full custom com sprites editadas, ele fez um bom sucesso na época, pois como tenho habilidades com sprites, eu atualizava o conteúdo da cipsoft antes de todos os outros servers kkk lançava o update da cip e no mesmo dia eu já colocava no client e os arquivos no server. Esse server me dava muuuuito trabalho pois o mapa era global full 11.57, então era gigantesco para 1 pessoa só cuidar, tinha muita coisa com bugs e para ajustar, ainda estava na faculdade e trabalhando ao mesmo tempo, então não tinha como conciliar isto, acabei até tendo que repetir uma cadeira por isso KKKK.
     
    Mesmo assim vocês sabem que o dedicado para um server global geralmente tem que ser mais robusto por conta do map e diversos arquivos, funções e etc. Na época era 150 reais o dedicado mais barato para aguentar um servidor global deste nível, coloquei do meu bolso mesmo, e em 5 dias +/- já tive esse dinheiro de volta com doações (a galera doava de mais nesse server), uma vez recebi uma doação de 150 libras esterlinas neste server, lembro que pirei demais, era um cara australiano kkkk. Foi o meu primeiro server que realmente deu "lucro" digamos assim, mesmo que esse não fosse o objetivo.
     
    Continuando, o server conseguiu se manter online, totalmente por doações por 6 meses sem eu investir nada, acabou que eu não tinha tempo para cuidar dele, tinham muito bugs propositais que os caras colocavam na base justamente para tirar vantagem e subornar os OT admins depois, sofri muito com isso. Usava a base OTX3 do malucooo a mais atualizada na época. Quem for montar um servidor global full dos mais atuais peço que cuidem muito com isso, quem distribui a base FREE coloca diversas condições nas sources, arquivos e database do server que derrubam ele facilmente, entre outras coisas para tirar vantagem, realmente acontece.
     
    Bom seguindo, na metade de 2020 eu me formei como Analista de Sistemas e no finalzinho do ano fui demitido da empresa que eu estava, pois eu trabalhava como consultor de implantação, implantava os sistemas legados da empresa nos clientes e tinham muitas viagens a diversas cidades, a cada semana a gente ia em uma, era bem bacana, por causa da pandemia isso parou, então foram cortados vários servidores, eu fui um deles kkk. 
     
    Perante a isso eu pensei: cara essa é a hora perfeita para eu investir em um ou vários servidores de tibia, não ter que ficar dependendo de empresa contratante e ser um empregado. Estou com o tempo 100% livre, o meu PC é totalmente montado para programação e performance, só falta minha dedicação.
     
    Decidi então me dedicar aos servidores custom/baiaks e derivados, pois tenho mais controle de tudo, mapas, scripts, clients e afins e os bugs das versões e distros 8.60 já são bem conhecidos, e portanto não fica um trabalho tão maçante como em um global.
     
    Já abri um servidor que se encontra online atualmente é o http://baiakgaming.online/ que utilizei a base do BAIAK PVP, aqui doTK mesmo e fiz algumas alterações nas sources, scripts em geral e constatei que ele é bem estável, nunca caiu, nesses quase 3 meses.
     
    Ele fez um "relativo" sucesso, mas o mais importante disso tudo que o dedicado mais barato que aguenta manter ele online com bastante players, custa na faixa de R$70 + R$20 de proteção DDOS 500gb(sim isto foi necessário pois recebi 40gb de ataques a alguns dias), totalizando: R$90 por mês, este valor que eu investi, em menos de 1 mês recebi doações que conseguem manter o servidor online por mais 6 meses. Agora fechando os seus quase 3 meses de server online, ele consegue se manter online por aproximadamente mais 3 anos, somente com estas doações que já foram obtidas.
     
    Bom, porque eu escrevi esse textão de facebook? Então, de qualquer forma estava olhando este projeto do Classic Yurots e me interessei muito, vi todos os videos, imagens, sistemas e show offs até o lançamento. E pensei o seguinte: vou abrir este servidor heheh, vou levar este projeto adiante, mas com modificações minhas claro heheh.
     
    Acho que o grande erro do @KOLISAO para o servidor não ter feito sucesso, foi não ter investido em uma campanha de marketing para o lançamento (não sei se ele realmente fez isso), mas notei este ponto, isso é muito importante para chamar jogadores e abrir o server com uma grande quantidade e assim aumentar cada vez mais o número de players, mais jogadores chamam mais jogadores. 
     
    Outra coisa foi o fato de ele ter investido em um dedicado caríssimo, 75 euros, convertendo hoje da quase R$500 reais por mês, teria que ter um nível de doações muito alto para manter isso kkk, esta configuração é muito acima do necessário para rodar este servidor com perfeição.
     
    Mais um ponto é o fato de que ele teria que ter lançado bem antes do previsto este server, e com o feedback dos jogadores ir mudando e atualizando o mesmo, dia a dia. Pois nós como OT admins não temos a visão de jogador, é muito diferente a percepção para a do player. As vezes você pensa que lançou uma feature muito loca no game e é algo super top para você, mas para os jogadores talvez não faça nenhuma diferença e nunca utilizem tal feature, isso de certa forma vai frustrando para quem administra, por isso a ideia de lançar antes e ir verificando o feedback da galera.
     
    Veja bem não estou criticando o membro do fórum @KOLISAO ele fez um excelente trabalho com este datapack, merece todos os aplausos possíveis, o mapa está impecável, as quests com muito RPG, alterações no site que deixam ele muito bonito e com várias features, e também tem toda uma história por trás de cada coisa. É um trabalho digno de um profissional de mais alto nível.
     
    O datapack do Classic Yurots é bem superior a vários outros disponibilizados por aqui no fórum e realmente merece uma devida homenagem a quem desenvolveu isto.
     
    Pois bem chega de papo, montei todo este texto para no final dizer que o meu real objetivo é seguir este projeto adiante, acho que vale a pena investir e tem todo o potencial possível, na verdade tornar um servidor online em si, vou abrir este server e realizar o possível para ele fazer sucesso. Em 30 dias ou menos vai estar online.
     
    Principais mudanças que vou realizar já logo de cara: clients próprios, como: stand alone, OTC e mobile, todos com launcher, proxy, auto updater, mc e sprites únicas.
     
    O client stand alone suportando todos os bots do 8.60, e o OTC e mobile com bots incluídos no client.
     
    Pensei em utilizar as sprites do client 8.60 original, mas elas são muito limitadas a quantidade de opções, é difícil montar um set donate para cada vocação por exemplo, teria que ficar escolhendo itens a dedo e/ou tirando ele de drop de monstros, o que não é muito legal. Por isso vou utilizar de sprites editadas.
     
    Principalmente para aumentar a gama de opções de itens adquiríveis dentro e fora do game, bem como os sprites dos sistemas mais atuais: exercise trainer com os dummys e armas de treino e estatuas de treino, também nas versões mais atuais. Itens de house, armas destruction e tudo mais.
     
    Faço aqui então um convite para quem queira participar deste projeto junto comigo, sendo mapper, scripter C++, lua, web. Spriter, divulgador e afins.
     
    Tendo ajuda ou não vou abrir este servidor, vou também estar ajudando qualquer pessoa que tiver problemas para estar colocando ele online, dentro do meu alcance claro. 
     
    Obrigado para quem leu até aqui +)
     
     
     
     
     
     
     
     
     
  18. Haha
    vine96 recebeu reputação de Vodkart em Ajuda - Action que vende itens da BP   
    Olá, bom dia!
    Acho que não estou na seção correta, porém esta foi a única que consegui abrir um post, todas as outras mostra como somente visualização.
     
    Seguinte, tenho um script que vende os items, ele funciona como uma spellwand, você clica na spellwand e depois no item que quer vender e ele vende...
    Porém ele vende somente 1 quantidade, já varri todo este fórum, o otland e o xtibia e não achei o que preciso, fiquei mais ou menos umas 6 horas tentando resolver e só tive bugs kkkk.
     
    Preciso que por exemplo: o player tenha 100 magic plate armor's na BP, ao clicar em uma com a spellwand ele venda todas as mpas que o player possuí, somente isto.
     
    Alguém pode dar um help!?
     
    Meu code:
    local items = { [2537] = {value = 4800}, [2377] = {value = 480}, [2663] = {value = 600}, [2472] = {value = 90000}, [2475] = {value = 7200}, [2519] = {value = 8000}, [2497] = {value = 6000}, [2523] = {value = 180000}, [2494] = {value = 108000}, [2400] = {value = 144000}, [2491] = {value = 2500}, [2421] = {value = 108000}, [2646] = {value = 240000}, [2477] = {value = 5000}, [2656] = {value = 10000}, [2498] = {value = 30000}, [2647] = {value = 600}, [2534] = {value = 15000}, [7402] = {value = 15000}, [2466] = {value = 20000}, [2465] = {value = 240}, [2408] = {value = 120000}, [2518] = {value = 1800}, [2500] = {value = 3000}, [2470] = {value = 30000}, [2645] = {value = 30000}, [2434] = {value = 2000}, [2463] = {value = 480}, [2536] = {value = 9000}, [2387] = {value = 240}, [2396] = {value = 1000}, [2381] = {value = 450}, [2528] = {value = 8000}, [2409] = {value = 1800}, [2414] = {value = 9000}, [2427] = {value = 11000}, [2407] = {value = 7200}, [2383] = {value = 960}, [2392] = {value = 4000}, [2488] = {value = 12000}, [2525] = {value = 250}, [2423] = {value = 1000}, [2462] = {value = 4800}, [2520] = {value = 30000}, [2390] = {value = 180000}, [2417] = {value = 500}, [2436] = {value = 6000}, [5741] = {value = 40000}, [2378] = {value = 500}, [2487] = {value = 12000}, [2476] = {value = 5000}, [8891] = {value = 15000}, [2195] = {value = 30000}, [2391] = {value = 7200}, [8889] = {value = 18000}, [2432] = {value = 8000}, [2431] = {value = 108000}, [2492] = {value = 40000}, [2515] = {value = 2000}, [2430] = {value = 2000}, [2393] = {value = 17000}, [7419] = {value = 10000}, [2522] = {value = 120000}, [2514] = {value = 50000}, [7418] = {value = 35000} } function onUse(cid, item, frompos, itemEx, topos) if (itemEx.itemid == item.itemid) then local str = "" for i, k in pairs(items) do str = str ..getItemNameById(i):gsub("%a", string.upper, 1).. ": ".. k.value .. "\n" end doShowTextDialog(cid, 6533, "Item Name: Price\n-----------------------------\n".. str) return true end local i = items[itemEx.itemid] --local l = getPlayerItemCount(cid,items[itemEx.itemid]) if (i) then --for j, l in pairs(items) do doRemoveItem(itemEx.uid) doPlayerAddMoney(cid, i.value) doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Você vendeu 1 ".. getItemNameById(itemEx.itemid) .." por ".. i.value .." gold coins.") doSendMagicEffect(frompos, CONST_ME_MAGIC_RED) --end else doPlayerSendTextMessage(cid, MESSAGE_STATUS_CONSOLE_ORANGE, "Não foi possível vender esse item, use a spellwand nela mesma para ver a lista de items disponíveis.") doSendMagicEffect(frompos, CONST_ME_POFF) end return true end  
  19. Gostei
    vine96 recebeu reputação de Cat em [Novo Critical System] Critical System 2021   
    Belo script ? 
    Meu server já tem muita gente full critical que funciona somente em player...
    Ao ver o seu script tive uma idéia... seria possível adaptar este código para somente funcionar em monstros?
    E se teria como colocar para adquirir por pedras que nem o sistema de critical antigo. 
  20. Gostei
    vine96 recebeu reputação de Cat em [8.60 - TFS 1.3] Baiak Thunder - Oficial TibiaKing.com   
    show mt obrigado!
  21. Curtir
    vine96 deu reputação a Movie em [8.60 - TFS 1.3] Baiak Thunder - Oficial TibiaKing.com   
    Apenas se você editar a parte de sprites do cliente ou se não adaptar a parte de montarias das versões mais novas (10.x) para essa mais antiga (8.60)
  22. Gostei
    vine96 recebeu reputação de Cat em [8.60 - TFS 1.3] Baiak Thunder - Oficial TibiaKing.com   
    slc dahora demaiss vou utilizar hehe, sabe se é possível utilizar de montarias no client OTC ou Stand alone com essa base tfs 1.3?
  23. Gostei
    vine96 recebeu reputação de Vodkart em [Resolvido] [Ajuda] Items da house não vai para o depot!   
    compilei tudo certinho e mesmo assim continua não funcionando =/ ele não entrega os itens para o depot parece que falta mais algo para editar nas sources...
     
    Pois testei no testserver que é windows x64 e ele entrega os itens no depot, alguém sabe o que pode ser ou o que falta?
     
    Edit1: Consegui resolver, essa alteração realmente resolve, porém no meu server tinha algumas houses que estavam com o ID de outras cidades sem ser a da principal, minha ideia para arrumar foi o seguinte: em vez de recriar as houses com tiles da cidade principal eu criei uma area com depots de todas as cidades e em um desses depot estava lá os itens. E deixei acessiveis para o players já que a cidade principal já tava praticamente comprada todas as houses.
     
    Obrigado por esse tópico existir, feliz ano novo a todos xD
  24. Gostei
    vine96 recebeu reputação de paulo thush em Baiak-PvP [8.60] - Watch System + Cast Look   
    Bem simples de resolver ao criar o banco de dados para o server coloca como: utf8mb4_unicode_ci
    Galera vou fazer a minha boa ação de fim de ano.
     
    Explicando: essa base do Baiak PVP é realmente muito boa e bem estável eu estou a quase 2 meses ininterruptos com o server online e sem problemas de crash, rollback ou qualquer coisa do tipo, já testei diversos bugs conhecidos de derrubar servidor e nada acontece com essas sources, é uma base realmente muito sólida e ótima para um servidor 8.6.
     
    Porém recentemente descobri um bug que é o seguinte, ao player utilizar !leavehouse ou perder a house e afins, os seus itens não vão para o depot, eles simplesmente somem.
     
    O distro quem compilou foi eu com base nas sources disponibilizadas aqui mesmo, no caso compilei para ubuntu 14.04.
     
    Ao testar no testserver que possuo, e utilizando outra distro com sources acredito ser de outra revisão do TFS 0.4 esse bug não acontece, os itens são entregue normalmente ao depot do jogador.
     
    Descobri então que se trata de um bug nas sources, no caso a house.cpp
     
    Fiz uma alteração no arquivo e após isso ficou 100%, para tal vou disponibilizar o arquivo editado aqui para vocês.
     
    Troque todo o código do arquivo house.cpp por esse:
     
    //////////////////////////////////////////////////////////////////////// // OpenTibia - an opensource roleplaying game //////////////////////////////////////////////////////////////////////// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. //////////////////////////////////////////////////////////////////////// #include "otpch.h" #include "house.h" #include "tools.h" #include "database.h" #include "beds.h" #include "town.h" #include "iologindata.h" #include "ioguild.h" #include "iomapserialize.h" #include "configmanager.h" #include "game.h" extern ConfigManager g_config; extern Game g_game; House::House(uint32_t houseId) { guild = pendingTransfer = isprotected = false; name = "OTX headquarter (Flat 1, Area 42)"; entry = Position(); id = houseId; rent = price = townId = paidUntil = owner = rentWarnings = lastWarning = 0; syncFlags = HOUSE_SYNC_NAME | HOUSE_SYNC_TOWN | HOUSE_SYNC_SIZE | HOUSE_SYNC_PRICE | HOUSE_SYNC_RENT | HOUSE_SYNC_GUILD; } void House::addTile(HouseTile* tile) { tile->setFlag(TILESTATE_PROTECTIONZONE); houseTiles.push_back(tile); } void House::addBed(BedItem* bed) { bedsList.push_back(bed); bed->setHouse(this); } void House::addDoor(Door* door) { door->addRef(); doorList.push_back(door); door->setHouse(this); updateDoorDescription("", door); } void House::removeDoor(Door* door) { HouseDoorList::iterator it = std::find(doorList.begin(), doorList.end(), door); if(it != doorList.end()) { (*it)->unRef(); doorList.erase(it); } } Door* House::getDoorByNumber(uint8_t doorId) const { for(HouseDoorList::const_iterator it = doorList.begin(); it != doorList.end(); ++it) { if((*it)->getDoorId() == doorId) return (*it); } return NULL; } Door* House::getDoorByPosition(const Position& pos) { for(HouseDoorList::iterator it = doorList.begin(); it != doorList.end(); ++it) { if((*it)->getPosition() == pos) return (*it); } return NULL; } void House::setOwner(uint32_t guid) { owner = guid; updateDoorDescription(); } bool House::setOwnerEx(uint32_t guid, bool transfer) { if(owner == guid) return true; if(isGuild() && guid) { Player* player = g_game.getPlayerByGuidEx(guid); if(!player) return false; guid = player->getGuildId(); if(player->isVirtual()) delete player; } if(owner) { rentWarnings = paidUntil = 0; if(transfer) clean(); setAccessList(SUBOWNER_LIST, "", !transfer); setAccessList(GUEST_LIST, "", !transfer); for(HouseDoorList::iterator it = doorList.begin(); it != doorList.end(); ++it) (*it)->setAccessList(""); } setOwner(guid); lastWarning = guid ? time(NULL) : 0; Database* db = Database::getInstance(); DBTransaction trans; if(!trans.begin()) return false; IOMapSerialize::getInstance()->saveHouse(db, this); return trans.commit(); } bool House::isGuild() const { return g_config.getBool(ConfigManager::GUILD_HALLS) && guild; } bool House::isBidded() const { Database* db = Database::getInstance(); DBResult_ptr result; DBQuery query; query << "SELECT `house_id` FROM `house_auctions` WHERE `house_id` = " << id << " LIMIT 1"; if(!(result = db->storeQuery(query.str()))) return false; return true; } void House::updateDoorDescription(std::string _name/* = ""*/, Door* door/* = NULL*/) { std::string tmp = "house"; if(isGuild()) tmp = "hall"; char houseDescription[200]; if(owner) { if(isGuild()) IOGuild::getInstance()->getGuildById(_name, owner); else if(_name.empty()) IOLoginData::getInstance()->getNameByGuid(owner, _name); sprintf(houseDescription, "It belongs to %s '%s'. %s owns this %s.", tmp.c_str(), name.c_str(), _name.c_str(), tmp.c_str()); } else sprintf(houseDescription, "It belongs to %s '%s'. Nobody owns this %s. It costs %d gold coins.", tmp.c_str(), name.c_str(), tmp.c_str(), price); if(!door) { for(HouseDoorList::iterator it = doorList.begin(); it != doorList.end(); ++it) (*it)->setSpecialDescription(houseDescription); } else door->setSpecialDescription(houseDescription); } void House::removePlayer(Player* player, bool ignoreRights) { if(!ignoreRights && player->hasFlag(PlayerFlag_CanEditHouses)) return; Position curPos = player->getPosition(), newPos = g_game.getClosestFreeTile(player, entry, false, false); if(g_game.internalTeleport(player, newPos, false) == RET_NOERROR && !player->isGhost()) { g_game.addMagicEffect(curPos, MAGIC_EFFECT_POFF); g_game.addMagicEffect(newPos, MAGIC_EFFECT_TELEPORT); } } void House::removePlayers(bool ignoreInvites) { PlayerVector kickList; for(HouseTileList::iterator it = houseTiles.begin(); it != houseTiles.end(); ++it) { CreatureVector* creatures = (*it)->getCreatures(); if(!creatures) continue; Player* player = NULL; for(CreatureVector::iterator cit = creatures->begin(); cit != creatures->end(); ++cit) { if((player = (*cit)->getPlayer()) && !player->isRemoved() && (ignoreInvites || !isInvited(player))) kickList.push_back(player); } } if(kickList.empty()) return; for(PlayerVector::iterator it = kickList.begin(); it != kickList.end(); ++it) removePlayer((*it), false); } bool House::kickPlayer(Player* player, Player* target) { if(!target || target->isRemoved()) return false; HouseTile* houseTile = target->getTile()->getHouseTile(); if(!houseTile || houseTile->getHouse() != this) return false; bool self = player == target; if(getHouseAccessLevel(player) < getHouseAccessLevel(target) && !self) return false; removePlayer(target, self); return true; } void House::clean() { for(HouseBedList::iterator bit = bedsList.begin(); bit != bedsList.end(); ++bit) { if((*bit)->getSleeper()) (*bit)->wakeUp(); } removePlayers(true); transferToDepot(); } bool House::transferToDepot() { if(!townId) return false; Player* player = NULL; if(owner) { uint32_t tmp = owner; if(isGuild() && !IOGuild::getInstance()->swapGuildIdToOwner(tmp)) tmp = 0; if(tmp) player = g_game.getPlayerByGuidEx(tmp); } Item* item = NULL; Container* tmpContainer = NULL; ItemList moveList; for(HouseTileList::iterator it = houseTiles.begin(); it != houseTiles.end(); ++it) { for(uint32_t i = 0; i < (*it)->getThingCount(); ++i) { if(!(item = (*it)->__getThing(i)->getItem())) continue; if(item->isPickupable()) moveList.push_back(item); else if((tmpContainer = item->getContainer())) { for(ItemList::const_iterator it = tmpContainer->getItems(); it != tmpContainer->getEnd(); ++it) moveList.push_back(*it); } } } if(player) { Depot* depot = player->getDepot(townId, true); for(ItemList::iterator it = moveList.begin(); it != moveList.end(); ++it) g_game.internalMoveItem(NULL, (*it)->getParent(), depot, INDEX_WHEREEVER, (*it), (*it)->getItemCount(), NULL, FLAG_NOLIMIT); if(player->isVirtual()) { IOLoginData::getInstance()->savePlayer(player); delete player; } } else { for(ItemList::iterator it = moveList.begin(); it != moveList.end(); ++it) g_game.internalRemoveItem(NULL, (*it), (*it)->getItemCount(), false, FLAG_NOLIMIT); } return true; } bool House::isInvited(const Player* player) { return getHouseAccessLevel(player) != HOUSE_NO_INVITED; } AccessHouseLevel_t House::getHouseAccessLevel(const Player* player) { if(!player) return HOUSE_NO_INVITED; if(player->hasFlag(PlayerFlag_CanEditHouses)) return HOUSE_OWNER; if(!owner) return HOUSE_NO_INVITED; AccessHouseLevel_t tmp = HOUSE_NO_INVITED; if(isGuild()) { if(player->getGuildId() == owner) { switch(player->getGuildLevel()) { case GUILDLEVEL_LEADER: return HOUSE_OWNER; case GUILDLEVEL_VICE: return HOUSE_SUBOWNER; default: tmp = HOUSE_GUEST; } } } else if(player->getGUID() == owner/* || player->marriage == owner*/) return HOUSE_OWNER; if(subOwnerList.isInList(player)) return HOUSE_SUBOWNER; if(guestList.isInList(player)) return HOUSE_GUEST; return tmp; } bool House::canEditAccessList(uint32_t listId, const Player* player) { switch(getHouseAccessLevel(player)) { case HOUSE_OWNER: return true; case HOUSE_SUBOWNER: return listId == GUEST_LIST; default: break; } return false; } bool House::getAccessList(uint32_t listId, std::string& list) const { if(listId == GUEST_LIST) { guestList.getList(list); return true; } if(listId == SUBOWNER_LIST) { subOwnerList.getList(list); return true; } if(Door* door = getDoorByNumber(listId)) return door->getAccessList(list); #ifdef __DEBUG_HOUSES__ std::clog << "[Failure - House::getAccessList] door == NULL, listId = " << listId <<std::endl; #endif return false; } void House::setAccessList(uint32_t listId, const std::string& textlist, bool teleport/* = true*/) { if(listId == GUEST_LIST) guestList.parseList(textlist); else if(listId == SUBOWNER_LIST) subOwnerList.parseList(textlist); else { if(Door* door = getDoorByNumber(listId)) door->setAccessList(textlist); #ifdef __DEBUG_HOUSES__ else std::clog << "[Failure - House::setAccessList] door == NULL, listId = " << listId <<std::endl; #endif return; } if(teleport) removePlayers(false); } TransferItem* TransferItem::createTransferItem(House* house) { TransferItem* transferItem = new TransferItem(house); transferItem->addRef(); transferItem->setID(ITEM_HOUSE_TRANSFER); char buffer[150]; sprintf(buffer, "It is a %s transfer document for '%s'.", house->isGuild() ? "guild hall" : "house", house->getName().c_str()); transferItem->setSpecialDescription(buffer); transferItem->setSubType(1); return transferItem; } bool TransferItem::onTradeEvent(TradeEvents_t event, Player* owner, Player* seller) { switch(event) { case ON_TRADE_TRANSFER: { if(house) house->setOwnerEx(owner->getGUID(), true); g_game.internalRemoveItem(NULL, this, getItemCount()); seller->transferContainer.setParent(NULL); break; } case ON_TRADE_CANCEL: { owner->transferContainer.setParent(NULL); owner->transferContainer.__removeThing(this, getItemCount()); g_game.freeThing(this); break; } default: return false; } return true; } void AccessList::getList(std::string& _list) const { _list = list; } bool AccessList::parseList(const std::string& _list) { playerList.clear(); guildList.clear(); expressionList.clear(); regexList.clear(); list = _list; if(_list.empty()) return true; std::stringstream listStream(_list); std::string line; while(getline(listStream, line)) { trimString(line); trim_left(line, "\t"); trim_right(line, "\t"); trimString(line); toLowerCaseString(line); if(line.empty()) break; if(line.substr(0, 1) == "#" || line.length() > 100) continue; if(line.find("@") != std::string::npos) { std::string::size_type pos = line.find("@"); addGuild(line.substr(pos + 1), line.substr(0, pos)); } else if(line.find("!") != std::string::npos || line.find("*") != std::string::npos || line.find("?") != std::string::npos) addExpression(line); else addPlayer(line); } return true; } bool AccessList::isInList(const Player* player) { std::string name = player->getName(); boost::cmatch what; try { toLowerCaseString(name); for(RegexList::iterator it = regexList.begin(); it != regexList.end(); ++it) { if(boost::regex_match(name.c_str(), what, it->first)) return it->second; } } catch(...) {} if(playerList.find(player->getGUID()) != playerList.end()) return true; for(GuildList::iterator git = guildList.begin(); git != guildList.end(); ++git) { if(git->first == player->getGuildId() && ((uint32_t)git->second == player->getRankId() || git->second == -1)) return true; } return false; } bool AccessList::addPlayer(std::string& name) { std::string tmp = name; uint32_t guid; if(!IOLoginData::getInstance()->getGuidByName(guid, tmp) || playerList.find(guid) != playerList.end()) return false; playerList.insert(guid); return true; } bool AccessList::addGuild(const std::string& guildName, const std::string& rankName) { uint32_t guildId; if(!IOGuild::getInstance()->getGuildId(guildId, guildName)) return false; std::string tmp = rankName; int32_t rankId = IOGuild::getInstance()->getRankIdByName(guildId, tmp); if(!rankId && (tmp.find("?") == std::string::npos || tmp.find("!") == std::string::npos || tmp.find("*") == std::string::npos)) rankId = -1; if(!rankId) return false; for(GuildList::iterator git = guildList.begin(); git != guildList.end(); ++git) { if(git->first == guildId && git->second == rankId) return true; } guildList.push_back(std::make_pair(guildId, rankId)); return true; } bool AccessList::addExpression(const std::string& expression) { for(ExpressionList::iterator it = expressionList.begin(); it != expressionList.end(); ++it) { if((*it) == expression) return false; } std::string out, meta = ".[{}()\\+|^$"; for(std::string::const_iterator it = expression.begin(); it != expression.end(); ++it) { if(meta.find(*it) != std::string::npos) out += "\\"; out += (*it); } replaceString(out, "**", ""); replaceString(out, "*", ".*"); replaceString(out, "?", ".?"); try { if(out.length() > 0) { expressionList.push_back(out); if(out.substr(0, 1) == "!") { if(out.length() > 1) regexList.push_front(std::make_pair(boost::regex(out.substr(1)), false)); } else regexList.push_back(std::make_pair(boost::regex(out), true)); } } catch(...) {} return true; } Door::~Door() { delete accessList; } Attr_ReadValue Door::readAttr(AttrTypes_t attr, PropStream& propStream) { if(attr != ATTR_HOUSEDOORID) return Item::readAttr(attr, propStream); uint8_t _doorId = 0; if(!propStream.getByte(_doorId)) return ATTR_READ_ERROR; doorId = _doorId; return ATTR_READ_CONTINUE; } void Door::copyAttributes(Item* item) { Item::copyAttributes(item); if(Door* door = item->getDoor()) { doorId = door->getDoorId(); std::string list; if(door->getAccessList(list)) setAccessList(list); } } void Door::onRemoved() { Item::onRemoved(); if(house) house->removeDoor(this); } bool Door::canUse(const Player* player) { if(!house || house->getHouseAccessLevel(player) >= HOUSE_SUBOWNER) return true; return accessList->isInList(player); } void Door::setHouse(House* _house) { if(house) return; house = _house; if(!accessList) accessList = new AccessList(); } bool Door::getAccessList(std::string& list) const { if(!house) return false; accessList->getList(list); return true; } void Door::setAccessList(const std::string& textlist) { if(!accessList) accessList = new AccessList(); accessList->parseList(textlist); } Houses::Houses() { rentPeriod = RENTPERIOD_NEVER; std::string strValue = asLowerCaseString(g_config.getString(ConfigManager::HOUSE_RENT_PERIOD)); if(strValue == "yearly") rentPeriod = RENTPERIOD_YEARLY; else if(strValue == "monthly") rentPeriod = RENTPERIOD_MONTHLY; else if(strValue == "weekly") rentPeriod = RENTPERIOD_WEEKLY; else if(strValue == "daily") rentPeriod = RENTPERIOD_DAILY; } bool Houses::loadFromXml(std::string filename) { xmlDocPtr doc = xmlParseFile(filename.c_str()); if(!doc) { std::clog << "[Warning - Houses::loadFromXml] Cannot load houses file." << std::endl; std::clog << getLastXMLError() << std::endl; return false; } xmlNodePtr houseNode, root = xmlDocGetRootElement(doc); if(xmlStrcmp(root->name,(const xmlChar*)"houses")) { std::clog << "[Error - Houses::loadFromXml] Malformed houses file." << std::endl; xmlFreeDoc(doc); return false; } int32_t intValue; std::string strValue; houseNode = root->children; while(houseNode) { if(xmlStrcmp(houseNode->name,(const xmlChar*)"house")) { houseNode = houseNode->next; continue; } int32_t houseId = 0; if(!readXMLInteger(houseNode, "houseid", houseId)) { std::clog << "[Error - Houses::loadFromXml] Could not read houseId" << std::endl; xmlFreeDoc(doc); return false; } House* house = Houses::getInstance()->getHouse(houseId); if(!house) { std::clog << "[Error - Houses::loadFromXml] Unknown house with id: " << houseId << std::endl; xmlFreeDoc(doc); return false; } Position entry(0, 0, 0); if(readXMLInteger(houseNode, "entryx", intValue)) entry.x = intValue; if(readXMLInteger(houseNode, "entryy", intValue)) entry.y = intValue; if(readXMLInteger(houseNode, "entryz", intValue)) entry.z = intValue; if(readXMLString(houseNode, "name", strValue)) house->setName(strValue); else house->resetSyncFlag(House::HOUSE_SYNC_NAME); house->setEntry(entry); if(!entry.x || !entry.y) { std::clog << "[Warning - Houses::loadFromXml] House entry not set for: " << house->getName() << " (" << houseId << ")" << std::endl; } if(readXMLInteger(houseNode, "townid", intValue)) house->setTownId(intValue); else house->resetSyncFlag(House::HOUSE_SYNC_TOWN); if(readXMLInteger(houseNode, "size", intValue)) house->setSize(intValue); else house->resetSyncFlag(House::HOUSE_SYNC_SIZE); if(readXMLString(houseNode, "guildhall", strValue)) house->setGuild(booleanString(strValue)); else house->resetSyncFlag(House::HOUSE_SYNC_GUILD); uint32_t rent = 0; if(readXMLInteger(houseNode, "rent", intValue)) rent = intValue; uint32_t price = (house->getSize() + house->getBedsCount()) * g_config.getNumber(ConfigManager::HOUSE_PRICE); // we should let players to pay only for walkable tiles + beds as single units not two items. if(g_config.getBool(ConfigManager::HOUSE_RENTASPRICE) && rent) price = rent; house->setPrice(price); if(g_config.getBool(ConfigManager::HOUSE_PRICEASRENT)) house->setRent(price); else house->setRent(rent); house->setOwner(0); houseNode = houseNode->next; } xmlFreeDoc(doc); return true; } void Houses::check() { uint64_t start = OTSYS_TIME(); std::clog << "> Checking houses..." << std::endl; time_t currentTime = time(NULL); for(HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it) payHouse(it->second, currentTime, 0); std::clog << "Houses checked in " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl; } bool Houses::payRent(Player* player, House* house, uint32_t bid, time_t _time/* = 0*/) { if(rentPeriod == RENTPERIOD_NEVER || !house->getOwner() || house->getPaidUntil() > _time || !house->getRent() || player->hasCustomFlag(PlayerCustomFlag_IgnoreHouseRent)) return true; Town* town = Towns::getInstance()->getTown(house->getTownId()); if(!town) return false; bool paid = false; uint32_t amount = house->getRent() + bid; if(g_config.getBool(ConfigManager::BANK_SYSTEM) && player->balance >= amount) { player->balance -= amount; paid = true; } else if(Depot* depot = player->getDepot(town->getID(), true)) paid = g_game.removeMoney(depot, amount, FLAG_NOLIMIT); if(!paid) return false; if(!_time) _time = time(NULL); uint32_t paidUntil = _time; switch(rentPeriod) { case RENTPERIOD_DAILY: paidUntil += 86400; break; case RENTPERIOD_WEEKLY: paidUntil += 7 * 86400; break; case RENTPERIOD_MONTHLY: paidUntil += 30 * 86400; break; case RENTPERIOD_YEARLY: paidUntil += 365 * 86400; break; default: break; } house->setLastWarning(0); house->setRentWarnings(0); house->setPaidUntil(paidUntil); return true; } bool Houses::payHouse(House* house, time_t _time, uint32_t bid) { if(rentPeriod == RENTPERIOD_NEVER || !house->getOwner() || house->getPaidUntil() > _time || !house->getRent()) return true; Town* town = Towns::getInstance()->getTown(house->getTownId()); if(!town) return false; uint32_t owner = house->getOwner(); if(house->isGuild() && !IOGuild::getInstance()->swapGuildIdToOwner(owner)) { house->setOwnerEx(0, true); return false; } std::string name; if(!IOLoginData::getInstance()->getNameByGuid(owner, name)) { house->setOwnerEx(0, true); return false; } Player* player = g_game.getPlayerByNameEx(name); if(!player) return false; if(!player->isPremium() && g_config.getBool(ConfigManager::HOUSE_NEED_PREMIUM)) { house->setOwnerEx(0, true); if(player->isVirtual()) delete player; return false; } int32_t loginClean = g_config.getNumber(ConfigManager::HOUSE_CLEAN_OLD); if(loginClean && _time >= (player->getLastLogin() + loginClean)) { house->setOwnerEx(0, true); if(player->isVirtual()) delete player; return false; } if(payRent(player, house, bid, _time) || _time < (house->getLastWarning() + 86400)) { if(player->isVirtual()) { IOLoginData::getInstance()->savePlayer(player); delete player; } return true; } uint32_t warningsLimit = 7; switch(rentPeriod) { case RENTPERIOD_DAILY: warningsLimit = 1; break; case RENTPERIOD_WEEKLY: warningsLimit = 3; break; case RENTPERIOD_YEARLY: warningsLimit = 14; break; default: break; } uint32_t warnings = house->getRentWarnings(); if(warnings >= warningsLimit) { house->setOwnerEx(0, true); if(player->isVirtual()) delete player; return false; } if(Depot* depot = player->getDepot(town->getID(), true)) { if(Item* letter = Item::CreateItem(ITEM_LETTER_STAMPED)) { if(g_game.internalAddItem(NULL, depot, letter, INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR) { letter->setWriter(g_config.getString(ConfigManager::SERVER_NAME)); letter->setDate(std::time(NULL)); std::stringstream s; s << "Warning!\nThe "; switch(rentPeriod) { case RENTPERIOD_DAILY: s << "daily"; break; case RENTPERIOD_WEEKLY: s << "weekly"; break; case RENTPERIOD_MONTHLY: s << "monthly"; break; case RENTPERIOD_YEARLY: s << "annual"; break; default: break; } s << " rent of " << house->getRent() << " gold for your " << (house->isGuild() ? "guild hall" : "house") << " \"" << house->getName() << "\" has to be paid. Have it within " << (warningsLimit - warnings) << " days or you will lose your " << (house->isGuild() ? "guild hall" : "house") << "."; letter->setText(s.str().c_str()); if(player->isVirtual()) IOLoginData::getInstance()->savePlayer(player); } else g_game.freeThing(letter); } } house->setLastWarning(_time); house->setRentWarnings(++warnings); if(player->isVirtual()) delete player; return false; } House* Houses::getHouse(uint32_t houseId, bool add/*= false*/) { HouseMap::iterator it = houseMap.find(houseId); if(it != houseMap.end()) return it->second; if(!add) return NULL; houseMap[houseId] = new House(houseId); return houseMap[houseId]; } House* Houses::getHouseByPlayer(Player* player) { if(!player || player->isRemoved()) return NULL; HouseTile* houseTile = player->getTile()->getHouseTile(); if(!houseTile) return NULL; if(House* house = houseTile->getHouse()) return house; return NULL; } House* Houses::getHouseByPlayerId(uint32_t playerId) { for(HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it) { if(!it->second->isGuild() && it->second->getOwner() == playerId) return it->second; } return NULL; } House* Houses::getHouseByGuildId(uint32_t guildId) { for(HouseMap::iterator it = houseMap.begin(); it != houseMap.end(); ++it) { if(it->second->isGuild() && it->second->getOwner() == guildId) return it->second; } return NULL; } uint32_t Houses::getHousesCount(uint32_t accId) { Account account = IOLoginData::getInstance()->loadAccount(accId); uint32_t guid, count = 0; for(Characters::iterator it = account.charList.begin(); it != account.charList.end(); ++it) { #ifndef __LOGIN_SERVER__ if(IOLoginData::getInstance()->getGuidByName(guid, (*it)) && getHouseByPlayerId(guid)) #else if(IOLoginData::getInstance()->getGuidByName(guid, (std::string&)it->first) && getHouseByPlayerId(guid)) #endif count++; } return count; } Após recompile e o server não vai mais possuir este bug xD, feliz ano novo a todos!
  25. Obrigado
    vine96 deu reputação a Belmont em Cidade [8.60]   
    Meu primeiro mapa feito, estou despertando essa habilidade de mapear com ajuda de alguns integrantes da comunidade. @Coltera, @Nolis e @Astra Moskov. Obrigado pelas dicas, criticas construtivas. Pretendo melhorar o máximo possível.
     

     
     
    Phineasz.zip - Scan

Informação Importante

Confirmação de Termo