Postado Outubro 21, 2014 10 anos Bom, to com um erro no meu servidor e é o seguinte. Quando eu ataco uma criatura, a mensagem aparecida é: 18:37 Voce causou 65 pontos de dano em a rotworm. Ela está correta. Porém, quando levo algum dano de qualquer criatura, a mensagem que aparece é: 18:37 Voce perdeu 5 ponto de vida por um ataque de um s. Como podem ver, não ta reconhecendo o nome da criatura quando eu tomo algum dano. Como posso corrigir isso? Aqui vai meu player.cpp //////////////////////////////////////////////////////////////////////// // 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 <iostream> #include "player.h" #include "manager.h" #include "iologindata.h" #include "ioban.h" #include "town.h" #include "house.h" #include "beds.h" #include "combat.h" #include "movement.h" #include "weapons.h" #include "creatureevent.h" #include "configmanager.h" #include "game.h" #include "chat.h" extern ConfigManager g_config; extern Game g_game; extern Chat g_chat; extern MoveEvents* g_moveEvents; extern Weapons* g_weapons; extern CreatureEvents* g_creatureEvents; AutoList<Player> Player::autoList; #ifdef __ENABLE_SERVER_DIAGNOSTIC__ uint32_t Player::playerCount = 0; #endif MuteCountMap Player::muteCountMap; Player::Player(const std::string& _name, ProtocolGame* p): Creature(), transferContainer(ITEM_LOCKER), name(_name), nameDescription(_name), client(p) { if(client) client->setPlayer(this); pzLocked = isConnecting = addAttackSkillPoint = requestedOutfit = false; saving = true; lastAttackBlockType = BLOCK_NONE; chaseMode = CHASEMODE_STANDSTILL; fightMode = FIGHTMODE_ATTACK; tradeState = TRADE_NONE; accountManager = MANAGER_NONE; guildLevel = GUILDLEVEL_NONE; promotionLevel = walkTaskEvent = actionTaskEvent = nextStepEvent = bloodHitCount = shieldBlockCount = 0; lastAttack = idleTime = marriage = blessings = balance = premiumDays = mana = manaMax = manaSpent = 0; soul = guildId = levelPercent = magLevelPercent = magLevel = experience = damageImmunities = 0; conditionImmunities = conditionSuppressions = groupId = vocationId = managerNumber2 = town = skullEnd = 0; lastLogin = lastLogout = lastIP = messageTicks = messageBuffer = nextAction = 0; editListId = maxWriteLen = windowTextId = rankId = 0; purchaseCallback = saleCallback = -1; level = shootRange = 1; rates[SKILL__MAGLEVEL] = rates[SKILL__LEVEL] = 1.0f; soulMax = 100; capacity = 400.00; stamina = STAMINA_MAX; lastLoad = lastPing = lastPong = OTSYS_TIME(); writeItem = NULL; group = NULL; editHouse = NULL; shopOwner = NULL; tradeItem = NULL; tradePartner = NULL; walkTask = NULL; weapon = NULL; setVocation(0); setParty(NULL); transferContainer.setParent(NULL); for(int32_t i = 0; i < 11; i++) { inventory[i] = NULL; inventoryAbilities[i] = false; } for(int32_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { skills[i][SKILL_LEVEL] = 10; skills[i][SKILL_TRIES] = skills[i][SKILL_PERCENT] = 0; rates[i] = 1.0f; } for(int32_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) varSkills[i] = 0; for(int32_t i = STAT_FIRST; i <= STAT_LAST; ++i) varStats[i] = 0; for(int32_t i = LOSS_FIRST; i <= LOSS_LAST; ++i) lossPercent[i] = 100; for(int32_t i = 0; i <= 12; i++) talkState[i] = false; #ifdef __ENABLE_SERVER_DIAGNOSTIC__ playerCount++; #endif } Player::~Player() { #ifdef __ENABLE_SERVER_DIAGNOSTIC__ playerCount--; #endif setWriteItem(NULL); for(int32_t i = 0; i < 11; i++) { if(inventory[i]) { inventory[i]->setParent(NULL); inventory[i]->unRef(); inventory[i] = NULL; inventoryAbilities[i] = false; } } setNextWalkActionTask(NULL); transferContainer.setParent(NULL); for(DepotMap::iterator it = depots.begin(); it != depots.end(); it++) it->second.first->unRef(); } void Player::setVocation(uint32_t id) { vocationId = id; vocation = Vocations::getInstance()->getVocation(id); soulMax = vocation->getGain(GAIN_SOUL); if(Condition* condition = getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT)) { condition->setParam(CONDITIONPARAM_HEALTHGAIN, vocation->getGainAmount(GAIN_HEALTH)); condition->setParam(CONDITIONPARAM_HEALTHTICKS, (vocation->getGainTicks(GAIN_HEALTH) * 1000)); condition->setParam(CONDITIONPARAM_MANAGAIN, vocation->getGainAmount(GAIN_MANA)); condition->setParam(CONDITIONPARAM_MANATICKS, (vocation->getGainTicks(GAIN_MANA) * 1000)); } } bool Player::isPushable() const { return accountManager == MANAGER_NONE && !hasFlag(PlayerFlag_CannotBePushed) && Creature::isPushable(); } std::string Player::getDescription(int32_t lookDistance) const { std::stringstream s; if(lookDistance == -1) { s << "Voce."; if(hasFlag(PlayerFlag_ShowGroupNameInsteadOfVocation)) s << " voce e " << group->getName(); else if(vocationId != 0) s << " voce e " << vocation->getDescription(); else s << " voce nao tem vocacao"; } else { s << nameDescription; if(!hasCustomFlag(PlayerCustomFlag_HideLevel)) s << " (Level " << level << ")"; s << ". " << (sex % 2 ? "Ele" : "Ela"); if(hasFlag(PlayerFlag_ShowGroupNameInsteadOfVocation)) s << " e " << group->getName(); else if(vocationId != 0) s << " e " << vocation->getDescription(); else s << " nao tem vocacao."; s << getSpecialDescription(); } std::string tmp; if(marriage && IOLoginData::getInstance()->getNameByGuid(marriage, tmp)) { s << ", "; if(vocationId == 0) { if(lookDistance == -1) s << "e voce e"; else s << "e e"; s << " "; } s << (sex % 2 ? "husband" : "wife") << " of " << tmp; } s << "."; if(guildId) { if(lookDistance == -1) s << " voce e "; else s << " " << (sex % 2 ? "Ele" : "Ela") << " e "; s << (rankName.empty() ? "um membro" : rankName)<< " do grupo " << guildName; if(!guildNick.empty()) s << " (" << guildNick << ")"; s << "."; } return s.str(); } Item* Player::getInventoryItem(slots_t slot) const { if(slot > SLOT_PRE_FIRST && slot < SLOT_LAST) return inventory[slot]; if(slot == SLOT_HAND) return inventory[SLOT_LEFT] ? inventory[SLOT_LEFT] : inventory[SLOT_RIGHT]; return NULL; } Item* Player::getEquippedItem(slots_t slot) const { Item* item = getInventoryItem(slot); if(!item) return NULL; switch(slot) { case SLOT_LEFT: case SLOT_RIGHT: return item->getWieldPosition() == SLOT_HAND ? item : NULL; default: break; } return item->getWieldPosition() == slot ? item : NULL; } void Player::setConditionSuppressions(uint32_t conditions, bool remove) { if(remove) conditionSuppressions &= ~conditions; else conditionSuppressions |= conditions; } Item* Player::getWeapon(bool ignoreAmmo) { if(weapon) return weapon; Item* item = NULL; for(int32_t slot = SLOT_RIGHT; slot <= SLOT_LEFT; ++slot) { if(!(item = getEquippedItem((slots_t)slot)) || item->getWeaponType() != WEAPON_DIST) continue; if(!ignoreAmmo && item->getAmmoType() != AMMO_NONE) { Item* ammoItem = getInventoryItem(SLOT_AMMO); if(ammoItem && ammoItem->getAmmoType() == item->getAmmoType()) { if(g_weapons->getWeapon(ammoItem)) { shootRange = item->getShootRange(); return ammoItem; } } } else if(g_weapons->getWeapon(item)) { shootRange = item->getShootRange(); return item; } } return NULL; } ItemVector Player::getWeapons() const { Item* item = NULL; ItemVector weapons; for(int32_t slot = SLOT_RIGHT; slot <= SLOT_LEFT; ++slot) { if(!(item = getEquippedItem((slots_t)slot))) continue; switch(item->getWeaponType()) { case WEAPON_DIST: if(item->getAmmoType() != AMMO_NONE) break; case WEAPON_SWORD: case WEAPON_CLUB: case WEAPON_AXE: case WEAPON_FIST: case WEAPON_WAND: { if(g_weapons->getWeapon(item)) weapons.push_back(item); break; } default: break; } } return weapons; } void Player::updateWeapon() { ItemVector weapons = getWeapons(); if(weapons.empty()) weapon = NULL; else if(!weapon || weapons.size() == 1 || weapons[1] == weapon) weapon = weapons[0]; else if(weapons[0] == weapon) weapon = weapons[1]; else weapon = NULL; if(weapon) shootRange = weapon->getShootRange(); } WeaponType_t Player::getWeaponType() { if(Item* item = getWeapon(false)) return item->getWeaponType(); return WEAPON_NONE; } int32_t Player::getWeaponSkill(const Item* item) const { if(!item) return getSkill(SKILL_FIST, SKILL_LEVEL); switch(item->getWeaponType()) { case WEAPON_SWORD: return getSkill(SKILL_SWORD, SKILL_LEVEL); case WEAPON_CLUB: return getSkill(SKILL_CLUB, SKILL_LEVEL); case WEAPON_AXE: return getSkill(SKILL_AXE, SKILL_LEVEL); case WEAPON_FIST: return getSkill(SKILL_FIST, SKILL_LEVEL); case WEAPON_DIST: return getSkill(SKILL_DIST, SKILL_LEVEL); default: break; } return 0; } int32_t Player::getArmor() const { int32_t i = SLOT_FIRST, armor = 0; for(; i < SLOT_LAST; ++i) { if(Item* item = getInventoryItem((slots_t)i)) armor += item->getArmor(); } if(vocation->getMultiplier(MULTIPLIER_ARMOR) != 1.0) return int32_t(armor * vocation->getMultiplier(MULTIPLIER_ARMOR)); return armor; } void Player::getShieldAndWeapon(const Item* &_shield, const Item* &_weapon) const { _shield = NULL; Item* item = NULL; for(uint32_t slot = SLOT_RIGHT; slot <= SLOT_LEFT; ++slot) { if(!(item = getInventoryItem((slots_t)slot)) || item->getWeaponType() != WEAPON_SHIELD) continue; if(!_shield || (_shield && item->getDefense() > _shield->getDefense())) _shield = item; } _weapon = weapon; } int32_t Player::getDefense() const { int32_t baseDefense = 5, defenseValue = 0, defenseSkill = 0, extraDefense = 0; float defenseFactor = getDefenseFactor(); const Item *_weapon = NULL, *_shield = NULL; getShieldAndWeapon(_shield, _weapon); if(_weapon) { extraDefense = _weapon->getExtraDefense(); defenseValue = baseDefense + _weapon->getDefense(); defenseSkill = getWeaponSkill(_weapon); } if(_shield && _shield->getDefense() > defenseValue) { if(_shield->getExtraDefense() > extraDefense) extraDefense = _shield->getExtraDefense(); defenseValue = baseDefense + _shield->getDefense(); defenseSkill = getSkill(SKILL_SHIELD, SKILL_LEVEL); } if(!defenseSkill) return 0; defenseValue += extraDefense; if(vocation->getMultiplier(MULTIPLIER_DEFENSE) != 1.0) defenseValue = int32_t(defenseValue * vocation->getMultiplier(MULTIPLIER_DEFENSE)); return ((int32_t)std::ceil(((float)(defenseSkill * (defenseValue * 0.015)) + (defenseValue * 0.1)) * defenseFactor)); } float Player::getAttackFactor() const { switch(fightMode) { case FIGHTMODE_BALANCED: return 1.2f; case FIGHTMODE_DEFENSE: return 2.0f; case FIGHTMODE_ATTACK: default: break; } return 1.0f; } float Player::getDefenseFactor() const { switch(fightMode) { case FIGHTMODE_BALANCED: return 1.2f; case FIGHTMODE_DEFENSE: { if((OTSYS_TIME() - lastAttack) < getAttackSpeed()) //attacking will cause us to get into normal defense return 1.0f; return 2.0f; } case FIGHTMODE_ATTACK: default: break; } return 1.0f; } void Player::sendIcons() const { if(!client) return; uint32_t icons = 0; for(ConditionList::const_iterator it = conditions.begin(); it != conditions.end(); ++it) { if(!isSuppress((*it)->getType())) icons |= (*it)->getIcons(); } if(getZone() == ZONE_PROTECTION) icons |= ICON_PROTECTIONZONE; if(pzLocked) icons |= ICON_PZ; client->sendIcons(icons); } void Player::updateInventoryWeight() { inventoryWeight = 0.00; if(hasFlag(PlayerFlag_HasInfiniteCapacity)) return; for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) { if(Item* item = getInventoryItem((slots_t)i)) inventoryWeight += item->getWeight(); } } void Player::updateInventoryGoods(uint32_t itemId) { if(Item::items[itemId].worth) { sendGoods(); return; } for(ShopInfoList::iterator it = shopOffer.begin(); it != shopOffer.end(); ++it) { if(it->itemId != itemId) continue; sendGoods(); break; } } int32_t Player::getPlayerInfo(playerinfo_t playerinfo) const { switch(playerinfo) { case PLAYERINFO_LEVEL: return level; case PLAYERINFO_LEVELPERCENT: return levelPercent; case PLAYERINFO_MAGICLEVEL: return std::max((int32_t)0, ((int32_t)magLevel + varStats[STAT_MAGICLEVEL])); case PLAYERINFO_MAGICLEVELPERCENT: return magLevelPercent; case PLAYERINFO_HEALTH: return health; case PLAYERINFO_MAXHEALTH: return std::max((int32_t)1, ((int32_t)healthMax + varStats[STAT_MAXHEALTH])); case PLAYERINFO_MANA: return mana; case PLAYERINFO_MAXMANA: return std::max((int32_t)0, ((int32_t)manaMax + varStats[STAT_MAXMANA])); case PLAYERINFO_SOUL: return std::max((int32_t)0, ((int32_t)soul + varStats[STAT_SOUL])); default: break; } return 0; } int32_t Player::getSkill(skills_t skilltype, skillsid_t skillinfo) const { int32_t ret = skills[skilltype][skillinfo]; if(skillinfo == SKILL_LEVEL) ret += varSkills[skilltype]; return std::max((int32_t)0, ret); } void Player::addSkillAdvance(skills_t skill, uint64_t count, bool useMultiplier/* = true*/) { if(!count) return; //player has reached max skill uint64_t currReqTries = vocation->getReqSkillTries(skill, skills[skill][SKILL_LEVEL]), nextReqTries = vocation->getReqSkillTries(skill, skills[skill][SKILL_LEVEL] + 1); if(currReqTries > nextReqTries) return; if(useMultiplier) count = uint64_t((double)count * rates[skill] * g_config.getDouble(ConfigManager::RATE_SKILL)); std::stringstream s; while(skills[skill][SKILL_TRIES] + count >= nextReqTries) { count -= nextReqTries - skills[skill][SKILL_TRIES]; skills[skill][SKILL_TRIES] = skills[skill][SKILL_PERCENT] = 0; skills[skill][SKILL_LEVEL]++; s.str(""); s << "You advanced in " << getSkillName(skill); if(g_config.getBool(ConfigManager::ADVANCING_SKILL_LEVEL)) s << " [" << skills[skill][SKILL_LEVEL] << "]"; s << "."; sendTextMessage(MSG_EVENT_ADVANCE, s.str().c_str()); CreatureEventList advanceEvents = getCreatureEvents(CREATURE_EVENT_ADVANCE); for(CreatureEventList::iterator it = advanceEvents.begin(); it != advanceEvents.end(); ++it) (*it)->executeAdvance(this, skill, (skills[skill][SKILL_LEVEL] - 1), skills[skill][SKILL_LEVEL]); currReqTries = nextReqTries; nextReqTries = vocation->getReqSkillTries(skill, skills[skill][SKILL_LEVEL] + 1); if(currReqTries > nextReqTries) { count = 0; break; } } if(count) skills[skill][SKILL_TRIES] += count; //update percent uint16_t newPercent = Player::getPercentLevel(skills[skill][SKILL_TRIES], nextReqTries); if(skills[skill][SKILL_PERCENT] != newPercent) { skills[skill][SKILL_PERCENT] = newPercent; sendSkills(); } else if(!s.str().empty()) sendSkills(); } void Player::setVarStats(stats_t stat, int32_t modifier) { varStats[stat] += modifier; switch(stat) { case STAT_MAXHEALTH: { if(getHealth() > getMaxHealth()) Creature::changeHealth(getMaxHealth() - getHealth()); else g_game.addCreatureHealth(this); break; } case STAT_MAXMANA: { if(getMana() > getMaxMana()) Creature::changeMana(getMaxMana() - getMana()); break; } default: break; } } int32_t Player::getDefaultStats(stats_t stat) { switch(stat) { case STAT_MAGICLEVEL: return getMagicLevel() - getVarStats(STAT_MAGICLEVEL); case STAT_MAXHEALTH: return getMaxHealth() - getVarStats(STAT_MAXHEALTH); case STAT_MAXMANA: return getMaxMana() - getVarStats(STAT_MAXMANA); case STAT_SOUL: return getSoul() - getVarStats(STAT_SOUL); default: break; } return 0; } Container* Player::getContainer(uint32_t cid) { for(ContainerVector::iterator it = containerVec.begin(); it != containerVec.end(); ++it) { if(it->first == cid) return it->second; } return NULL; } int32_t Player::getContainerID(const Container* container) const { for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl) { if(cl->second == container) return cl->first; } return -1; } void Player::addContainer(uint32_t cid, Container* container) { #ifdef __DEBUG__ std::clog << getName() << ", addContainer: " << (int32_t)cid << std::endl; #endif if(cid > 0xF) return; for(ContainerVector::iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl) { if(cl->first == cid) { cl->second = container; return; } } containerVec.push_back(std::make_pair(cid, container)); } void Player::closeContainer(uint32_t cid) { for(ContainerVector::iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl) { if(cl->first == cid) { containerVec.erase(cl); break; } } #ifdef __DEBUG__ std::clog << getName() << ", closeContainer: " << (int32_t)cid << std::endl; #endif } bool Player::canOpenCorpse(uint32_t ownerId) { return guid == ownerId || (party && party->canOpenCorpse(ownerId)) || hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges); } uint16_t Player::getLookCorpse() const { if(sex % 2) return ITEM_MALE_CORPSE; return ITEM_FEMALE_CORPSE; } void Player::dropLoot(Container* corpse) { if(!corpse || lootDrop != LOOT_DROP_FULL) return; uint32_t loss = lossPercent[LOSS_CONTAINERS]; if(g_config.getBool(ConfigManager::BLESSINGS)) { uint32_t start = g_config.getNumber(ConfigManager::BLESS_REDUCTION_BASE), bless = getBlessings(); while(bless > 0 && loss > 0) { loss -= start; start -= g_config.getNumber(ConfigManager::BLESS_REDUCTION_DECREMENT); bless--; } } uint32_t itemLoss = (uint32_t)std::floor((5. + loss) * lossPercent[LOSS_ITEMS] / 1000.); for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) { Item* item = inventory[i]; if(!item) continue; uint32_t tmp = random_range(1, 100); if(skull > SKULL_WHITE || (item->getContainer() && tmp < loss) || (!item->getContainer() && tmp < itemLoss)) { g_game.internalMoveItem(NULL, this, corpse, INDEX_WHEREEVER, item, item->getItemCount(), 0); sendRemoveInventoryItem((slots_t)i, inventory[(slots_t)i]); } } } bool Player::setStorage(const std::string& key, const std::string& value) { uint32_t numericKey = atol(key.c_str()); if(!IS_IN_KEYRANGE(numericKey, RESERVED_RANGE)) return Creature::setStorage(key, value); if(IS_IN_KEYRANGE(numericKey, OUTFITS_RANGE)) { uint32_t lookType = atoi(value.c_str()) >> 16, addons = atoi(value.c_str()) & 0xFF; if(addons < 4) { Outfit outfit; if(Outfits::getInstance()->getOutfit(lookType, outfit)) return addOutfit(outfit.outfitId, addons); } else std::clog << "[Warning - Player::setStorage] Invalid addons value key: " << key << ", value: " << value << " for player: " << getName() << std::endl; } else if(IS_IN_KEYRANGE(numericKey, OUTFITSID_RANGE)) { uint32_t outfitId = atoi(value.c_str()) >> 16, addons = atoi(value.c_str()) & 0xFF; if(addons < 4) return addOutfit(outfitId, addons); else std::clog << "[Warning - Player::setStorage] Invalid addons value key: " << key << ", value: " << value << " for player: " << getName() << std::endl; } else std::clog << "[Warning - Player::setStorage] Unknown reserved key: " << key << " for player: " << getName() << std::endl; return false; } void Player::eraseStorage(const std::string& key) { Creature::eraseStorage(key); if(IS_IN_KEYRANGE(atol(key.c_str()), RESERVED_RANGE)) std::clog << "[Warning - Player::eraseStorage] Unknown reserved key: " << key << " for player: " << name << std::endl; } bool Player::canSee(const Position& pos) const { if(client) return client->canSee(pos); return false; } bool Player::canSeeCreature(const Creature* creature) const { if(creature == this) return true; if(const Player* player = creature->getPlayer()) return !player->isGhost() || getGhostAccess() >= player->getGhostAccess(); return !creature->isInvisible() || canSeeInvisibility(); } bool Player::canWalkthrough(const Creature* creature) const { if(creature == this || hasCustomFlag(PlayerCustomFlag_CanWalkthrough) || creature->isWalkable() || (creature->getMaster() && creature->getMaster() != this && canWalkthrough(creature->getMaster()))) return true; const Player* player = creature->getPlayer(); if(!player) return false; if((((g_game.getWorldType() == WORLDTYPE_OPTIONAL && #ifdef __WAR_SYSTEM__ !player->isEnemy(this, true) && #endif player->getVocation()->isAttackable()) || (player->getVocation()->isAttackable() && player->getLevel() < (uint32_t)g_config.getNumber(ConfigManager::PROTECTION_LEVEL))) && player->getTile()->ground && Item::items[player->getTile()->ground->getID()].walkStack) && (!player->hasCustomFlag(PlayerCustomFlag_GamemasterPrivileges) || player->getAccess() <= getAccess())) return true; return (player->isGhost() && getGhostAccess() < player->getGhostAccess()) || (isGhost() && getGhostAccess() > player->getGhostAccess()); } Depot* Player::getDepot(uint32_t depotId, bool autoCreateDepot) { DepotMap::iterator it = depots.find(depotId); if(it != depots.end()) return it->second.first; //create a new depot? if(autoCreateDepot) { Item* locker = Item::CreateItem(ITEM_LOCKER); if(Container* container = locker->getContainer()) { if(Depot* depot = container->getDepot()) { container->__internalAddThing(Item::CreateItem(ITEM_DEPOT)); addDepot(depot, depotId); return depot; } } g_game.freeThing(locker); std::clog << "Failure: Creating a new depot with id: " << depotId << ", for player: " << getName() << std::endl; } return NULL; } bool Player::addDepot(Depot* depot, uint32_t depotId) { if(getDepot(depotId, false)) return false; depots[depotId] = std::make_pair(depot, false); depot->setMaxDepotLimit((group != NULL ? group->getDepotLimit(isPremium()) : 1000)); return true; } void Player::useDepot(uint32_t depotId, bool value) { DepotMap::iterator it = depots.find(depotId); if(it != depots.end()) depots[depotId] = std::make_pair(it->second.first, value); } void Player::sendCancelMessage(ReturnValue message) const { switch(message) { case RET_DESTINATIONOUTOFREACH: sendCancel("Destino esta fora do alcance."); break; case RET_NOTMOVABLE: sendCancel("Voce nao pode mover esse objeto."); break; case RET_DROPTWOHANDEDITEM: sendCancel("Largue o objeto de duas maos primeiro."); break; case RET_BOTHHANDSNEEDTOBEFREE: sendCancel("Suas maos precisam estar livre."); break; case RET_CANNOTBEDRESSED: sendCancel("Voce nao pode vestir esse objeto."); break; case RET_PUTTHISOBJECTINYOURHAND: sendCancel("Coloque esse objeto em sua mao."); break; case RET_PUTTHISOBJECTINBOTHHANDS: sendCancel("Coloque esse objeto com as duas maos."); break; case RET_CANONLYUSEONEWEAPON: sendCancel("Voce so pode usar uma arma."); break; case RET_TOOFARAWAY: sendCancel("Fora do alcance."); break; case RET_FIRSTGODOWNSTAIRS: sendCancel("Primeiro desca as escadas."); break; case RET_FIRSTGOUPSTAIRS: sendCancel("Primeiro suba as escadas."); break; case RET_NOTENOUGHCAPACITY: sendCancel("Esse objeto e pesado para voce no momento."); break; case RET_CONTAINERNOTENOUGHROOM: sendCancel("Voce nao pode mais colocar objetos aqui."); break; case RET_NEEDEXCHANGE: case RET_NOTENOUGHROOM: sendCancel("Nao ha espaco."); break; case RET_CANNOTPICKUP: sendCancel("Voce nao pode pegar esse objeto."); break; case RET_CANNOTTHROW: sendCancel("Voce nao pode jogar aqui."); break; case RET_THEREISNOWAY: sendCancel("Nao ha maneira."); break; case RET_THISISIMPOSSIBLE: sendCancel("E impossivel."); break; case RET_PLAYERISPZLOCKED: sendCancel("Voce nao pode entrar aqui se atacou outra pessoa."); break; case RET_PLAYERISNOTINVITED: sendCancel("Voce nao foi convidado."); break; case RET_CREATUREDOESNOTEXIST: sendCancel("Essa criatura nao existe."); break; case RET_DEPOTISFULL: sendCancel("Voce nao pode mais por itens nesse depósito."); break; case RET_CANNOTUSETHISOBJECT: sendCancel("Voce nao pode usar esse objeto."); break; case RET_PLAYERWITHTHISNAMEISNOTONLINE: sendCancel("O jogador com esse nome nao esta online."); break; case RET_NOTREQUIREDLEVELTOUSERUNE: sendCancel("Voce nao tem o level necessario para usar essa pedra."); break; case RET_YOUAREALREADYTRADING: sendCancel("Voce ja esta em negociacao."); break; case RET_THISPLAYERISALREADYTRADING: sendCancel("Esse jogador ja esta em negociacao."); break; case RET_YOUMAYNOTLOGOUTDURINGAFIGHT: sendCancel("Voce nao pode sair durante uma batalha!"); break; case RET_DIRECTPLAYERSHOOT: sendCancel("Voce nao tem permissao para atirar diretamente nos jogadores."); break; case RET_NOTENOUGHLEVEL: sendCancel("Voce nao tem level suficiente."); break; case RET_NOTENOUGHMAGICLEVEL: sendCancel("Voce nao tem level de magia suficiente."); break; case RET_NOTENOUGHMANA: sendCancel("Voce nao tem energia suficiente."); break; case RET_NOTENOUGHSOUL: sendCancel("Voce nao tem alma suficiente."); break; case RET_YOUAREEXHAUSTED: sendCancel("Voce esta exausto, espere um pouco."); break; case RET_CANONLYUSETHISRUNEONCREATURES: sendCancel("Voce só pode usar essa pedra diretamente em criaturas."); break; case RET_PLAYERISNOTREACHABLE: sendCancel("Jogador nao acessível."); break; case RET_CREATUREISNOTREACHABLE: sendCancel("Criatura nao acessível."); break; case RET_ACTIONNOTPERMITTEDINPROTECTIONZONE: sendCancel("Voce nao pode fazer isso em zona de protecao."); break; case RET_YOUMAYNOTATTACKTHISPLAYER: sendCancel("Voce nao pode atacar esse jogador."); break; case RET_YOUMAYNOTATTACKTHISCREATURE: sendCancel("Voce nao pode ataca-lo."); break; case RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE: sendCancel("Voce nao pode atacar alguem em zona de protecao."); break; case RET_YOUMAYNOTATTACKAPERSONWHILEINPROTECTIONZONE: sendCancel("Voce nao pode atacar alguem enquanto estiver em zona de protecao."); break; case RET_YOUCANONLYUSEITONCREATURES: sendCancel("Voce só pode usar isso em criaturas."); break; case RET_TURNSECUREMODETOATTACKUNMARKEDPLAYERS: sendCancel("Desligue o modo seguro para atacar jogadores."); break; case RET_YOUNEEDPREMIUMACCOUNT: sendCancel("Voce precisa de uma conta prêmio para isso."); break; case RET_YOUNEEDTOLEARNTHISSPELL: sendCancel("Voce precisa aprender essa magia primeiro."); break; case RET_YOURVOCATIONCANNOTUSETHISSPELL: sendCancel("Sua vocacao nao usa essa magia."); break; case RET_YOUNEEDAWEAPONTOUSETHISSPELL: sendCancel("Voce precisa equipar uma arma para usar essa magia."); break; case RET_PLAYERISPZLOCKEDLEAVEPVPZONE: sendCancel("Voce nao pode se mover de uma zona de protecao após atacar um jogador."); break; case RET_PLAYERISPZLOCKEDENTERPVPZONE: sendCancel("Voce nao pode entrar em uma zona de protecao após atacar um jogador."); break; case RET_ACTIONNOTPERMITTEDINANOPVPZONE: sendCancel("Essa acao nao e permitida em zona segura."); break; case RET_YOUCANNOTLOGOUTHERE: sendCancel("Voce nao pode deslogar aqui."); break; case RET_YOUNEEDAMAGICITEMTOCASTSPELL: sendCancel("Voce precisa de um item magico para essa magia."); break; case RET_CANNOTCONJUREITEMHERE: sendCancel("Voce nao pode conjurar itens aqui."); break; case RET_NAMEISTOOAMBIGUOUS: sendCancel("Nome muito curto."); break; case RET_CANONLYUSEONESHIELD: sendCancel("Voce só pode usar um escudo"); break; case RET_YOUARENOTTHEOWNER: sendCancel("Voce nao e o dono."); break; case RET_YOUMAYNOTCASTAREAONBLACKSKULL: sendCancel("Voce nao pode usar magia de area com caveira preta."); break; case RET_TILEISFULL: sendCancel("Voce nao pode mais jogar itens nesse piso."); break; case RET_DONTSHOWMESSAGE: break; case RET_NOTPOSSIBLE: default: sendCancel("Desculpe, nao e possível."); break; } } Item* Player::getWriteItem(uint32_t& _windowTextId, uint16_t& _maxWriteLen) { _windowTextId = windowTextId; _maxWriteLen = maxWriteLen; return writeItem; } void Player::setWriteItem(Item* item, uint16_t _maxWriteLen/* = 0*/) { windowTextId++; if(writeItem) writeItem->unRef(); if(item) { writeItem = item; maxWriteLen = _maxWriteLen; writeItem->addRef(); } else { writeItem = NULL; maxWriteLen = 0; } } House* Player::getEditHouse(uint32_t& _windowTextId, uint32_t& _listId) { _windowTextId = windowTextId; _listId = editListId; return editHouse; } void Player::setEditHouse(House* house, uint32_t listId/* = 0*/) { windowTextId++; editHouse = house; editListId = listId; } void Player::sendHouseWindow(House* house, uint32_t listId) const { if(!client) return; std::string text; if(house->getAccessList(listId, text)) client->sendHouseWindow(windowTextId, house, listId, text); } void Player::sendCreatureChangeVisible(const Creature* creature, Visible_t visible) { if(!client) return; const Player* player = creature->getPlayer(); if(player == this || (player && (visible < VISIBLE_GHOST_APPEAR || getGhostAccess() >= player->getGhostAccess())) || (!player && canSeeInvisibility())) sendCreatureChangeOutfit(creature, creature->getCurrentOutfit()); else if(visible == VISIBLE_DISAPPEAR || visible == VISIBLE_GHOST_DISAPPEAR) sendCreatureDisappear(creature, creature->getTile()->getClientIndexOfThing(this, creature)); else sendCreatureAppear(creature); } void Player::sendAddContainerItem(const Container* container, const Item* item) { if(!client) return; for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl) { if(cl->second == container) client->sendAddContainerItem(cl->first, item); } } void Player::sendUpdateContainerItem(const Container* container, uint8_t slot, const Item*, const Item* newItem) { if(!client) return; for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl) { if(cl->second == container) client->sendUpdateContainerItem(cl->first, slot, newItem); } } void Player::sendRemoveContainerItem(const Container* container, uint8_t slot, const Item*) { if(!client) return; for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl) { if(cl->second == container) client->sendRemoveContainerItem(cl->first, slot); } } void Player::onUpdateTileItem(const Tile* tile, const Position& pos, const Item* oldItem, const ItemType& oldType, const Item* newItem, const ItemType& newType) { Creature::onUpdateTileItem(tile, pos, oldItem, oldType, newItem, newType); if(oldItem != newItem) onRemoveTileItem(tile, pos, oldType, oldItem); if(tradeState != TRADE_TRANSFER && tradeItem && oldItem == tradeItem) g_game.internalCloseTrade(this); } void Player::onRemoveTileItem(const Tile* tile, const Position& pos, const ItemType& iType, const Item* item) { Creature::onRemoveTileItem(tile, pos, iType, item); if(tradeState == TRADE_TRANSFER) return; checkTradeState(item); if(tradeItem) { const Container* container = item->getContainer(); if(container && container->isHoldingItem(tradeItem)) g_game.internalCloseTrade(this); } } void Player::onCreatureAppear(const Creature* creature) { Creature::onCreatureAppear(creature); if(creature != this) return; Item* item = NULL; for(int32_t slot = SLOT_FIRST; slot < SLOT_LAST; ++slot) { if(!(item = getInventoryItem((slots_t)slot))) continue; item->__startDecaying(); g_moveEvents->onPlayerEquip(this, item, (slots_t)slot, false); } updateWeapon(); if(BedItem* bed = Beds::getInstance()->getBedBySleeper(guid)) bed->wakeUp(); Outfit outfit; if(Outfits::getInstance()->getOutfit(defaultOutfit.lookType, outfit)) outfitAttributes = Outfits::getInstance()->addAttributes(getID(), outfit.outfitId, sex, defaultOutfit.lookAddons); if(lastLogout && stamina < STAMINA_MAX) { int64_t ticks = (int64_t)time(NULL) - lastLogout - 600; if(ticks > 0) { ticks = (int64_t)((double)(ticks * 1000) / g_config.getDouble(ConfigManager::RATE_STAMINA_GAIN)); int64_t premium = g_config.getNumber(ConfigManager::STAMINA_LIMIT_TOP) * STAMINA_MULTIPLIER, period = ticks; if((int64_t)stamina <= premium) { period += stamina; if(period > premium) period -= premium; else period = 0; useStamina(ticks - period); } if(period > 0) { ticks = (int64_t)((g_config.getDouble(ConfigManager::RATE_STAMINA_GAIN) * period) / g_config.getDouble(ConfigManager::RATE_STAMINA_THRESHOLD)); if(stamina + ticks > STAMINA_MAX) ticks = STAMINA_MAX - stamina; useStamina(ticks); } sendStats(); } } g_game.checkPlayersRecord(this); if(!isGhost()) IOLoginData::getInstance()->updateOnlineStatus(guid, true); if(g_config.getBool(ConfigManager::DISPLAY_LOGGING)) std::clog << name << " acabou de logar." << std::endl; } void Player::onAttackedCreatureDisappear(bool isLogout) { sendCancelTarget(); if(!isLogout) sendTextMessage(MSG_STATUS_SMALL, "Alvo perdido."); } void Player::onFollowCreatureDisappear(bool isLogout) { sendCancelTarget(); if(!isLogout) sendTextMessage(MSG_STATUS_SMALL, "Alvo perdido."); } void Player::onChangeZone(ZoneType_t zone) { if(attackedCreature && zone == ZONE_PROTECTION && !hasFlag(PlayerFlag_IgnoreProtectionZone)) { setAttackedCreature(NULL); onAttackedCreatureDisappear(false); } sendIcons(); } void Player::onAttackedCreatureChangeZone(ZoneType_t zone) { if(zone == ZONE_PROTECTION && !hasFlag(PlayerFlag_IgnoreProtectionZone)) { setAttackedCreature(NULL); onAttackedCreatureDisappear(false); } else if(zone == ZONE_OPTIONAL && attackedCreature->getPlayer() && !hasFlag(PlayerFlag_IgnoreProtectionZone)) { setAttackedCreature(NULL); onAttackedCreatureDisappear(false); } else if(zone == ZONE_OPEN && g_game.getWorldType() == WORLDTYPE_OPTIONAL && attackedCreature->getPlayer() #ifdef __WAR_SYSTEM__ && !attackedCreature->getPlayer()->isEnemy(this, true) #endif ) { //attackedCreature can leave a pvp zone if not pzlocked setAttackedCreature(NULL); onAttackedCreatureDisappear(false); } } void Player::onCreatureDisappear(const Creature* creature, bool isLogout) { Creature::onCreatureDisappear(creature, isLogout); if(creature != this) return; if(isLogout) { loginPosition = getPosition(); lastLogout = time(NULL); } if(eventWalk) setFollowCreature(NULL); closeShopWindow(); if(tradePartner) g_game.internalCloseTrade(this); clearPartyInvitations(); if(party) party->leave(this); g_game.cancelRuleViolation(this); if(hasFlag(PlayerFlag_CanAnswerRuleViolations)) { PlayerVector closeReportList; for(RuleViolationsMap::const_iterator it = g_game.getRuleViolations().begin(); it != g_game.getRuleViolations().end(); ++it) { if(it->second->gamemaster == this) closeReportList.push_back(it->second->reporter); } for(PlayerVector::iterator it = closeReportList.begin(); it != closeReportList.end(); ++it) g_game.closeRuleViolation(*it); } g_chat.removeUserFromAllChannels(this); if(!isGhost()) IOLoginData::getInstance()->updateOnlineStatus(guid, false); if(g_config.getBool(ConfigManager::DISPLAY_LOGGING)) std::clog << getName() << " acabou de deslogar." << std::endl; bool saved = false; for(uint32_t tries = 0; !saved && tries < 3; ++tries) { if(IOLoginData::getInstance()->savePlayer(this)) saved = true; #ifdef __DEBUG__ else std::clog << "Error while saving player: " << getName() << ", strike " << tries << "." << std::endl; #endif } if(!saved) #ifndef __DEBUG__ std::clog << "Error while saving player: " << getName() << "." << std::endl; #else std::clog << "Player " << getName() << " couldn't be saved." << std::endl; #endif } void Player::openShopWindow() { sendShop(); sendGoods(); } void Player::closeShopWindow(bool send/* = true*/, Npc* npc/* = NULL*/, int32_t onBuy/* = -1*/, int32_t onSell/* = -1*/) { if(npc || (npc = getShopOwner(onBuy, onSell))) npc->onPlayerEndTrade(this, onBuy, onSell); if(shopOwner) { shopOwner = NULL; if(send) sendCloseShop(); } purchaseCallback = saleCallback = -1; shopOffer.clear(); } bool Player::canShopItem(uint16_t itemId, uint8_t subType, ShopEvent_t event) { for(ShopInfoList::iterator sit = shopOffer.begin(); sit != shopOffer.end(); ++sit) { if(sit->itemId != itemId || ((event != SHOPEVENT_BUY || sit->buyPrice < 0) && (event != SHOPEVENT_SELL || sit->sellPrice < 0))) continue; if(event == SHOPEVENT_SELL) return true; const ItemType& it = Item::items[id]; if(it.isFluidContainer() || it.isSplash()) return sit->subType == subType; return true; } return false; } void Player::onWalk(Direction& dir) { Creature::onWalk(dir); setNextActionTask(NULL); setNextAction(OTSYS_TIME() + getStepDuration(dir)); } void Player::onCreatureMove(const Creature* creature, const Tile* newTile, const Position& newPos, const Tile* oldTile, const Position& oldPos, bool teleport) { Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport); if(creature != this) return; if(getParty()) getParty()->updateSharedExperience(); //check if we should close trade if(tradeState != TRADE_TRANSFER && ((tradeItem && !Position::areInRange<1,1,0>(tradeItem->getPosition(), getPosition())) || (tradePartner && !Position::areInRange<2,2,0>(tradePartner->getPosition(), getPosition())))) g_game.internalCloseTrade(this); if((teleport || oldPos.z != newPos.z) && !hasCustomFlag(PlayerCustomFlag_CanStairhop)) { int32_t ticks = g_config.getNumber(ConfigManager::STAIRHOP_DELAY); if(ticks > 0) { addExhaust(ticks, EXHAUST_COMBAT); if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_PACIFIED, ticks)) addCondition(condition); } } } void Player::onAddContainerItem(const Container*, const Item* item) { checkTradeState(item); } void Player::onUpdateContainerItem(const Container* container, uint8_t slot, const Item* oldItem, const ItemType&, const Item* newItem, const ItemType&) { if(oldItem != newItem) onRemoveContainerItem(container, slot, oldItem); if(tradeState != TRADE_TRANSFER) checkTradeState(oldItem); } void Player::onRemoveContainerItem(const Container* container, uint8_t, const Item* item) { if(tradeState == TRADE_TRANSFER) return; checkTradeState(item); if(tradeItem) { if(tradeItem->getParent() != container && container->isHoldingItem(tradeItem)) g_game.internalCloseTrade(this); } } void Player::onCloseContainer(const Container* container) { if(!client) return; for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl) { if(cl->second == container) client->sendCloseContainer(cl->first); } } void Player::onSendContainer(const Container* container) { if(!client) return; bool hasParent = dynamic_cast<const Container*>(container->getParent()) != NULL; for(ContainerVector::const_iterator cl = containerVec.begin(); cl != containerVec.end(); ++cl) { if(cl->second == container) client->sendContainer(cl->first, container, hasParent); } } void Player::onUpdateInventoryItem(slots_t slot, Item* oldItem, const ItemType& , Item* newItem, const ItemType&) { if(oldItem != newItem) onRemoveInventoryItem(slot, oldItem); if(tradeState != TRADE_TRANSFER) checkTradeState(oldItem); } void Player::onRemoveInventoryItem(slots_t, Item* item) { if(tradeState == TRADE_TRANSFER) return; checkTradeState(item); if(tradeItem) { const Container* container = item->getContainer(); if(container && container->isHoldingItem(tradeItem)) g_game.internalCloseTrade(this); } } void Player::checkTradeState(const Item* item) { if(!tradeItem || tradeState == TRADE_TRANSFER) return; if(tradeItem != item) { const Container* container = dynamic_cast<const Container*>(item->getParent()); while(container != NULL) { if(container == tradeItem) { g_game.internalCloseTrade(this); break; } container = dynamic_cast<const Container*>(container->getParent()); } } else g_game.internalCloseTrade(this); } void Player::setNextWalkActionTask(SchedulerTask* task) { if(walkTaskEvent) { Scheduler::getInstance().stopEvent(walkTaskEvent); walkTaskEvent = 0; } delete walkTask; walkTask = task; setIdleTime(0); } void Player::setNextWalkTask(SchedulerTask* task) { if(nextStepEvent) { Scheduler::getInstance().stopEvent(nextStepEvent); nextStepEvent = 0; } if(task) { nextStepEvent = Scheduler::getInstance().addEvent(task); setIdleTime(0); } } void Player::setNextActionTask(SchedulerTask* task) { if(actionTaskEvent) { Scheduler::getInstance().stopEvent(actionTaskEvent); actionTaskEvent = 0; } if(task) { actionTaskEvent = Scheduler::getInstance().addEvent(task); setIdleTime(0); } } uint32_t Player::getNextActionTime() const { return (uint32_t)std::max((int64_t)SCHEDULER_MINTICKS, ((int64_t)nextAction - OTSYS_TIME())); } void Player::onThink(uint32_t interval) { Creature::onThink(interval); int64_t timeNow = OTSYS_TIME(); if(timeNow - lastPing >= 5000) { lastPing = timeNow; if(client) client->sendPing(); else if(g_config.getBool(ConfigManager::STOP_ATTACK_AT_EXIT)) setAttackedCreature(NULL); } if((timeNow - lastPong) >= 60000 && !getTile()->hasFlag(TILESTATE_NOLOGOUT) && !isConnecting && !pzLocked && !hasCondition(CONDITION_INFIGHT)) { if(client) client->logout(true, true); else if(g_creatureEvents->playerLogout(this, false)) g_game.removeCreature(this, true); } messageTicks += interval; if(messageTicks >= 1500) { messageTicks = 0; addMessageBuffer(); } } bool Player::isMuted(uint16_t channelId, SpeakClasses type, uint32_t& time) { time = 0; if(hasFlag(PlayerFlag_CannotBeMuted)) return false; int32_t muteTicks = 0; for(ConditionList::iterator it = conditions.begin(); it != conditions.end(); ++it) { if((*it)->getType() == CONDITION_MUTED && (*it)->getSubId() == 0 && (*it)->getTicks() > muteTicks) muteTicks = (*it)->getTicks(); } time = (uint32_t)muteTicks / 1000; return type != SPEAK_PRIVATE_PN && (type != SPEAK_CHANNEL_Y || (channelId != CHANNEL_GUILD && !g_chat.isPrivateChannel(channelId))); } void Player::addMessageBuffer() { if(!hasFlag(PlayerFlag_CannotBeMuted) && g_config.getNumber(ConfigManager::MAX_MESSAGEBUFFER) && messageBuffer) messageBuffer--; } void Player::removeMessageBuffer() { if(hasFlag(PlayerFlag_CannotBeMuted)) return; int32_t maxBuffer = g_config.getNumber(ConfigManager::MAX_MESSAGEBUFFER); if(!maxBuffer || messageBuffer > maxBuffer + 1 || ++messageBuffer <= maxBuffer) return; uint32_t muteCount = 1; MuteCountMap::iterator it = muteCountMap.find(guid); if(it != muteCountMap.end()) muteCount = it->second; uint32_t muteTime = 5 * muteCount * muteCount; muteCountMap[guid] = muteCount + 1; if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_MUTED, muteTime * 1000)) addCondition(condition); char buffer[50]; sprintf(buffer, "Voce foi mutado por %d segundos.", muteTime); sendTextMessage(MSG_STATUS_SMALL, buffer); } void Player::drainHealth(Creature* attacker, CombatType_t combatType, int32_t damage) { Creature::drainHealth(attacker, combatType, damage); char buffer[150]; if(attacker) sprintf(buffer, "Voce perdeu %d ponto de vida pelo ataque de um %s.", damage, (damage != 1 ? "s" : ""), attacker->getNameDescription().c_str()); else sprintf(buffer, "Voce perdeu %d ponto de vida.", damage, (damage != 1 ? "s" : "")); sendStats(); sendTextMessage(MSG_EVENT_DEFAULT, buffer); } void Player::drainMana(Creature* attacker, CombatType_t combatType, int32_t damage) { Creature::drainMana(attacker, combatType, damage); char buffer[150]; if(attacker) sprintf(buffer, "Voce perdeu %d ponto de energia pelo ataque de um %s.", damage, attacker->getNameDescription().c_str()); else sprintf(buffer, "Voce perdeu %d ponto de energia.", damage); sendStats(); sendTextMessage(MSG_EVENT_DEFAULT, buffer); } void Player::addManaSpent(uint64_t amount, bool useMultiplier/* = true*/) { if(!amount) return; uint64_t currReqMana = vocation->getReqMana(magLevel), nextReqMana = vocation->getReqMana(magLevel + 1); if(currReqMana > nextReqMana) //player has reached max magic level return; if(useMultiplier) amount = uint64_t((double)amount * rates[SKILL__MAGLEVEL] * g_config.getDouble(ConfigManager::RATE_MAGIC)); bool advance = false; while(manaSpent + amount >= nextReqMana) { amount -= nextReqMana - manaSpent; manaSpent = 0; magLevel++; char advMsg[50]; sprintf(advMsg, "Voce avancou para inteligencia %d.", magLevel); sendTextMessage(MSG_EVENT_ADVANCE, advMsg); advance = true; CreatureEventList advanceEvents = getCreatureEvents(CREATURE_EVENT_ADVANCE); for(CreatureEventList::iterator it = advanceEvents.begin(); it != advanceEvents.end(); ++it) (*it)->executeAdvance(this, SKILL__MAGLEVEL, (magLevel - 1), magLevel); currReqMana = nextReqMana; nextReqMana = vocation->getReqMana(magLevel + 1); if(currReqMana > nextReqMana) { amount = 0; break; } } if(amount) manaSpent += amount; uint16_t newPercent = Player::getPercentLevel(manaSpent, nextReqMana); if(magLevelPercent != newPercent) { magLevelPercent = newPercent; sendStats(); } else if(advance) sendStats(); } void Player::addExperience(uint64_t exp) { uint32_t prevLevel = level; uint64_t nextLevelExp = Player::getExpForLevel(level + 1); if(Player::getExpForLevel(level) > nextLevelExp) { //player has reached max level levelPercent = 0; sendStats(); return; } experience += exp; while(experience >= nextLevelExp) { healthMax += vocation->getGain(GAIN_HEALTH); health += vocation->getGain(GAIN_HEALTH); manaMax += vocation->getGain(GAIN_MANA); mana += vocation->getGain(GAIN_MANA); capacity += vocation->getGainCap(); ++level; nextLevelExp = Player::getExpForLevel(level + 1); if(Player::getExpForLevel(level) > nextLevelExp) //player has reached max level break; } if(prevLevel != level) { updateBaseSpeed(); g_game.changeSpeed(this, 0); g_game.addCreatureHealth(this); if(party) party->updateSharedExperience(); char advMsg[60]; sprintf(advMsg, "Voce avancou do level %d para o level %d.", prevLevel, level); sendTextMessage(MSG_EVENT_ADVANCE, advMsg); CreatureEventList advanceEvents = getCreatureEvents(CREATURE_EVENT_ADVANCE); for(CreatureEventList::iterator it = advanceEvents.begin(); it != advanceEvents.end(); ++it) (*it)->executeAdvance(this, SKILL__LEVEL, prevLevel, level); } uint64_t currLevelExp = Player::getExpForLevel(level); nextLevelExp = Player::getExpForLevel(level + 1); levelPercent = 0; if(nextLevelExp > currLevelExp) levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp); sendStats(); } void Player::removeExperience(uint64_t exp, bool updateStats/* = true*/) { uint32_t prevLevel = level; experience -= std::min(exp, experience); while(level > 1 && experience < Player::getExpForLevel(level)) { level--; healthMax = std::max((int32_t)0, (healthMax - (int32_t)vocation->getGain(GAIN_HEALTH))); manaMax = std::max((int32_t)0, (manaMax - (int32_t)vocation->getGain(GAIN_MANA))); capacity = std::max((double)0, (capacity - (double)vocation->getGainCap())); } if(prevLevel != level) { if(updateStats) { updateBaseSpeed(); g_game.changeSpeed(this, 0); g_game.addCreatureHealth(this); } char advMsg[90]; sprintf(advMsg, "Voce voltou do level %d para o level %d.", prevLevel, level); sendTextMessage(MSG_EVENT_ADVANCE, advMsg); } uint64_t currLevelExp = Player::getExpForLevel(level), nextLevelExp = Player::getExpForLevel(level + 1); if(nextLevelExp > currLevelExp) levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp); else levelPercent = 0; if(updateStats) sendStats(); } uint16_t Player::getPercentLevel(uint64_t count, uint64_t nextLevelCount) { if(nextLevelCount > 0) return std::min((uint32_t)100, std::max((uint32_t)0, uint32_t(count * 100 / nextLevelCount))); return 0; } void Player::onBlockHit(BlockType_t) { if(shieldBlockCount > 0) { --shieldBlockCount; if(hasShield()) addSkillAdvance(SKILL_SHIELD, 1); } } void Player::onAttackedCreatureBlockHit(Creature* target, BlockType_t blockType) { Creature::onAttackedCreatureBlockHit(target, blockType); lastAttackBlockType = blockType; switch(blockType) { case BLOCK_NONE: { bloodHitCount = shieldBlockCount = 30; addAttackSkillPoint = true; break; } case BLOCK_DEFENSE: case BLOCK_ARMOR: { //need to draw blood every 30 hits if(bloodHitCount > 0) { addAttackSkillPoint = true; --bloodHitCount; } else addAttackSkillPoint = false; break; } default: { addAttackSkillPoint = false; break; } } } bool Player::hasShield() const { Item* item = getInventoryItem(SLOT_LEFT); return (item && item->getWeaponType() == WEAPON_SHIELD) || ((item = getInventoryItem(SLOT_RIGHT)) && item->getWeaponType() == WEAPON_SHIELD); } BlockType_t Player::blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage, bool checkDefense/* = false*/, bool checkArmor/* = false*/, bool reflect/* = true*/) { BlockType_t blockType = Creature::blockHit(attacker, combatType, damage, checkDefense, checkArmor); if(attacker) { int16_t color = g_config.getNumber(ConfigManager::SQUARE_COLOR); if(color < 0) color = random_range(0, 254); sendCreatureSquare(attacker, color); } if(blockType != BLOCK_NONE) return blockType; if(vocation->getMultiplier(MULTIPLIER_MAGICDEFENSE) != 1.0 && combatType != COMBAT_NONE && combatType != COMBAT_PHYSICALDAMAGE && combatType != COMBAT_UNDEFINEDDAMAGE && combatType != COMBAT_DROWNDAMAGE) damage -= (int32_t)std::ceil((double)(damage * vocation->getMultiplier(MULTIPLIER_MAGICDEFENSE)) / 100.); if(damage <= 0) return blockType; int32_t blocked = 0, reflected = 0; if(reflect) reflect = attacker && !attacker->isRemoved() && attacker->getHealth() > 0; Item* item = NULL; for(int32_t slot = SLOT_FIRST; slot < SLOT_LAST; ++slot) { if(!(item = getInventoryItem((slots_t)slot)) || item->isRemoved() || (g_moveEvents->hasEquipEvent(item) && !isItemAbilityEnabled((slots_t)slot))) continue; const ItemType& it = Item::items[item->getID()]; if(it.abilities.absorb[combatType]) { blocked += (int32_t)std::ceil((double)(damage * it.abilities.absorb[combatType]) / 100.); if(item->hasCharges()) g_game.transformItem(item, item->getID(), std::max((int32_t)0, (int32_t)item->getCharges() - 1)); } if(!reflect) continue; if(it.abilities.reflect[REFLECT_PERCENT][combatType] && random_range(1, 100) < it.abilities.reflect[REFLECT_CHANCE][combatType]) { reflected += (int32_t)std::ceil((double)(damage * it.abilities.reflect[REFLECT_PERCENT][combatType]) / 100.); if(item->hasCharges() && !it.abilities.absorb[combatType]) g_game.transformItem(item, item->getID(), std::max((int32_t)0, (int32_t)item->getCharges() - 1)); } } if(outfitAttributes) { uint32_t tmp = Outfits::getInstance()->getOutfitAbsorb(defaultOutfit.lookType, sex, combatType); if(tmp) blocked += (int32_t)std::ceil((double)(damage * tmp) / 100.); if(reflect) { tmp = Outfits::getInstance()->getOutfitReflect(defaultOutfit.lookType, sex, combatType); if(tmp) reflected += (int32_t)std::ceil((double)(damage * tmp) / 100.); } } if(vocation->getAbsorb(combatType)) blocked += (int32_t)std::ceil((double)(damage * vocation->getAbsorb(combatType)) / 100.); if(reflect && vocation->getReflect(combatType)) reflected += (int32_t)std::ceil((double)(damage * vocation->getReflect(combatType)) / 100.); damage -= blocked; if(damage <= 0) { damage = 0; blockType = BLOCK_DEFENSE; } if(reflected) { if(combatType != COMBAT_HEALING) reflected = -reflected; if(attacker->blockHit(this, combatType, reflected, false, false, false) == BLOCK_NONE) g_game.combatChangeHealth(combatType, NULL, attacker, reflected); } return blockType; } uint32_t Player::getIP() const { if(client) return client->getIP(); return lastIP; } bool Player::onDeath() { Item* preventLoss = NULL; Item* preventDrop = NULL; if(getZone() == ZONE_HARDCORE) { setDropLoot(LOOT_DROP_NONE); setLossSkill(false); } else if(skull < SKULL_RED) { Item* item = NULL; for(int32_t i = SLOT_FIRST; ((skillLoss || lootDrop == LOOT_DROP_FULL) && i < SLOT_LAST); ++i) { if(!(item = getInventoryItem((slots_t)i)) || item->isRemoved() || (g_moveEvents->hasEquipEvent(item) && !isItemAbilityEnabled((slots_t)i))) continue; const ItemType& it = Item::items[item->getID()]; if(lootDrop == LOOT_DROP_FULL && it.abilities.preventDrop) { setDropLoot(LOOT_DROP_PREVENT); preventDrop = item; } if(skillLoss && !preventLoss && it.abilities.preventLoss) preventLoss = item; } } if(!Creature::onDeath()) { if(preventDrop) setDropLoot(LOOT_DROP_FULL); return false; } if(preventLoss) { setLossSkill(false); if(preventLoss->getCharges() > 1) //weird, but transform failed to remove for some hosters g_game.transformItem(preventLoss, preventLoss->getID(), std::max(0, ((int32_t)preventLoss->getCharges() - 1))); else g_game.internalRemoveItem(NULL, preventDrop); } if(preventDrop && preventDrop != preventLoss) { if(preventDrop->getCharges() > 1) //weird, but transform failed to remove for some hosters g_game.transformItem(preventDrop, preventDrop->getID(), std::max(0, ((int32_t)preventDrop->getCharges() - 1))); else g_game.internalRemoveItem(NULL, preventDrop); } removeConditions(CONDITIONEND_DEATH); if(skillLoss) { uint64_t lossExperience = getLostExperience(); removeExperience(lossExperience, false); double percent = 1. - ((double)(experience - lossExperience) / experience); //Magic level loss uint64_t sumMana = 0, lostMana = 0; for(uint32_t i = 1; i <= magLevel; ++i) sumMana += vocation->getReqMana(i); sumMana += manaSpent; lostMana = (uint64_t)std::ceil(sumMana * ((double)(percent * lossPercent[LOSS_MANA]) / 100.)); while(lostMana > manaSpent && magLevel > 0) { lostMana -= manaSpent; manaSpent = vocation->getReqMana(magLevel); magLevel--; } manaSpent -= std::max((int32_t)0, (int32_t)lostMana); uint64_t nextReqMana = vocation->getReqMana(magLevel + 1); if(nextReqMana > vocation->getReqMana(magLevel)) magLevelPercent = Player::getPercentLevel(manaSpent, nextReqMana); else magLevelPercent = 0; //Skill loss uint64_t lostSkillTries, sumSkillTries; for(int16_t i = 0; i < 7; ++i) //for each skill { lostSkillTries = sumSkillTries = 0; for(uint32_t c = 11; c <= skills[i][SKILL_LEVEL]; ++c) //sum up all required tries for all skill levels sumSkillTries += vocation->getReqSkillTries(i, c); sumSkillTries += skills[i][SKILL_TRIES]; lostSkillTries = (uint64_t)std::ceil(sumSkillTries * ((double)(percent * lossPercent[LOSS_SKILLS]) / 100.)); while(lostSkillTries > skills[i][SKILL_TRIES]) { lostSkillTries -= skills[i][SKILL_TRIES]; skills[i][SKILL_TRIES] = vocation->getReqSkillTries(i, skills[i][SKILL_LEVEL]); if(skills[i][SKILL_LEVEL] < 11) { skills[i][SKILL_LEVEL] = 10; skills[i][SKILL_TRIES] = lostSkillTries = 0; break; } else skills[i][SKILL_LEVEL]--; } skills[i][SKILL_TRIES] = std::max((int32_t)0, (int32_t)(skills[i][SKILL_TRIES] - lostSkillTries)); } blessings = 0; loginPosition = masterPosition; if(!inventory[SLOT_BACKPACK]) __internalAddThing(SLOT_BACKPACK, Item::CreateItem(g_config.getNumber(ConfigManager::DEATH_CONTAINER))); sendIcons(); sendStats(); sendSkills(); g_creatureEvents->playerLogout(this, true); g_game.removeCreature(this, false); sendReLoginWindow(); } else { setLossSkill(true); if(preventLoss) { loginPosition = masterPosition; g_creatureEvents->playerLogout(this, true); g_game.removeCreature(this, false); sendReLoginWindow(); } } return true; } void Player::dropCorpse(DeathList deathList) { if(lootDrop == LOOT_DROP_NONE) { pzLocked = false; if(health <= 0) { health = healthMax; mana = manaMax; } setDropLoot(LOOT_DROP_FULL); sendStats(); sendIcons(); onIdleStatus(); g_game.addCreatureHealth(this); g_game.internalTeleport(this, masterPosition, false); } else { Creature::dropCorpse(deathList); if(g_config.getBool(ConfigManager::DEATH_LIST)) IOLoginData::getInstance()->playerDeath(this, deathList); } } Item* Player::createCorpse(DeathList deathList) { Item* corpse = Creature::createCorpse(deathList); if(!corpse) return NULL; std::stringstream ss; ss << "Voce reconhece " << getNameDescription() << ". " << (sex % 2 ? "Ele" : "Ela") << " morreu para "; if(deathList[0].isCreatureKill()) { ss << deathList[0].getKillerCreature()->getNameDescription(); if(deathList[0].getKillerCreature()->getMaster()) ss << " sumonado por " << deathList[0].getKillerCreature()->getMaster()->getNameDescription(); } else ss << deathList[0].getKillerName(); if(deathList.size() > 1) { if(deathList[0].getKillerType() != deathList[1].getKillerType()) { if(deathList[1].isCreatureKill()) { ss << " e " << deathList[1].getKillerCreature()->getNameDescription(); if(deathList[1].getKillerCreature()->getMaster()) ss << " sumonado por " << deathList[1].getKillerCreature()->getMaster()->getNameDescription(); } else ss << " e " << deathList[1].getKillerName(); } else if(deathList[1].isCreatureKill()) { if(deathList[0].getKillerCreature()->getName() != deathList[1].getKillerCreature()->getName()) { ss << " e " << deathList[1].getKillerCreature()->getNameDescription(); if(deathList[1].getKillerCreature()->getMaster()) ss << " sumonado por " << deathList[1].getKillerCreature()->getMaster()->getNameDescription(); } } else if(asLowerCaseString(deathList[0].getKillerName()) != asLowerCaseString(deathList[1].getKillerName())) ss << " e " << deathList[1].getKillerName(); } ss << "."; corpse->setSpecialDescription(ss.str().c_str()); return corpse; } void Player::addExhaust(uint32_t ticks, Exhaust_t type) { if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_EXHAUST, ticks, 0, false, (uint32_t)type)) addCondition(condition); } void Player::addInFightTicks(bool pzLock, int32_t ticks/* = 0*/) { if(hasFlag(PlayerFlag_NotGainInFight)) return; if(!ticks) ticks = g_config.getNumber(ConfigManager::PZ_LOCKED); else ticks = std::max(-1, ticks); if(pzLock) pzLocked = true; if(Condition* condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_INFIGHT, ticks)) addCondition(condition); } void Player::addDefaultRegeneration(uint32_t addTicks) { Condition* condition = getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT); if(condition) condition->setTicks(condition->getTicks() + addTicks); else if((condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_REGENERATION, addTicks))) { condition->setParam(CONDITIONPARAM_HEALTHGAIN, vocation->getGainAmount(GAIN_HEALTH)); condition->setParam(CONDITIONPARAM_HEALTHTICKS, vocation->getGainTicks(GAIN_HEALTH) * 1000); condition->setParam(CONDITIONPARAM_MANAGAIN, vocation->getGainAmount(GAIN_MANA)); condition->setParam(CONDITIONPARAM_MANATICKS, vocation->getGainTicks(GAIN_MANA) * 1000); addCondition(condition); } } void Player::removeList() { Manager::getInstance()->removeUser(id); autoList.erase(id); if(!isGhost()) { for(AutoList<Player>::iterator it = autoList.begin(); it != autoList.end(); ++it) it->second->notifyLogOut(this); } else { for(AutoList<Player>::iterator it = autoList.begin(); it != autoList.end(); ++it) { if(it->second->canSeeCreature(this)) it->second->notifyLogOut(this); } } } void Player::addList() { if(!isGhost()) { for(AutoList<Player>::iterator it = autoList.begin(); it != autoList.end(); ++it) it->second->notifyLogIn(this); } else { for(AutoList<Player>::iterator it = autoList.begin(); it != autoList.end(); ++it) { if(it->second->canSeeCreature(this)) it->second->notifyLogIn(this); } } autoList[id] = this; Manager::getInstance()->addUser(this); } void Player::kick(bool displayEffect, bool forceLogout) { if(!client) { if(g_creatureEvents->playerLogout(this, forceLogout)) g_game.removeCreature(this); } else client->logout(displayEffect, forceLogout); } void Player::notifyLogIn(Player* loginPlayer) { if(!client) return; VIPSet::iterator it = VIPList.find(loginPlayer->getGUID()); if(it != VIPList.end()) client->sendVIPLogIn(loginPlayer->getGUID()); } void Player::notifyLogOut(Player* logoutPlayer) { if(!client) return; VIPSet::iterator it = VIPList.find(logoutPlayer->getGUID()); if(it != VIPList.end()) client->sendVIPLogOut(logoutPlayer->getGUID()); } bool Player::removeVIP(uint32_t _guid) { VIPSet::iterator it = VIPList.find(_guid); if(it == VIPList.end()) return false; VIPList.erase(it); return true; } bool Player::addVIP(uint32_t _guid, std::string& name, bool isOnline, bool internal/* = false*/) { if(guid == _guid) { if(!internal) sendTextMessage(MSG_STATUS_SMALL, "Voce nao pode se adicionar."); return false; } if(VIPList.size() > (group ? group->getMaxVips(isPremium()) : g_config.getNumber(ConfigManager::VIPLIST_DEFAULT_LIMIT))) { if(!internal) sendTextMessage(MSG_STATUS_SMALL, "Voce nao pode adicionar mais jogadores."); return false; } VIPSet::iterator it = VIPList.find(_guid); if(it != VIPList.end()) { if(!internal) sendTextMessage(MSG_STATUS_SMALL, "Esse jogador esta na sua lista."); return false; } VIPList.insert(_guid); if(client && !internal) client->sendVIP(_guid, name, isOnline); return true; } //close container and its child containers void Player::autoCloseContainers(const Container* container) { typedef std::vector<uint32_t> CloseList; CloseList closeList; for(ContainerVector::iterator it = containerVec.begin(); it != containerVec.end(); ++it) { Container* tmp = it->second; while(tmp != NULL) { if(tmp->isRemoved() || tmp == container) { closeList.push_back(it->first); break; } tmp = dynamic_cast<Container*>(tmp->getParent()); } } for(CloseList::iterator it = closeList.begin(); it != closeList.end(); ++it) { closeContainer(*it); if(client) client->sendCloseContainer(*it); } } bool Player::hasCapacity(const Item* item, uint32_t count) const { if(hasFlag(PlayerFlag_CannotPickupItem)) return false; if(hasFlag(PlayerFlag_HasInfiniteCapacity) || item->getTopParent() == this) return true; double itemWeight = 0; if(item->isStackable()) itemWeight = Item::items[item->getID()].weight * count; else itemWeight = item->getWeight(); return (itemWeight < getFreeCapacity()); } ReturnValue Player::__queryAdd(int32_t index, const Thing* thing, uint32_t count, uint32_t flags) const { const Item* item = thing->getItem(); if(!item) return RET_NOTPOSSIBLE; bool childOwner = ((flags & FLAG_CHILDISOWNER) == FLAG_CHILDISOWNER), skipLimit = ((flags & FLAG_NOLIMIT) == FLAG_NOLIMIT); if(childOwner) { //a child container is querying the player, just check if enough capacity if(skipLimit || hasCapacity(item, count)) return RET_NOERROR; return RET_NOTENOUGHCAPACITY; } if(!item->isPickupable()) return RET_CANNOTPICKUP; ReturnValue ret = RET_NOERROR; if((item->getSlotPosition() & SLOTP_HEAD) || (item->getSlotPosition() & SLOTP_NECKLACE) || (item->getSlotPosition() & SLOTP_BACKPACK) || (item->getSlotPosition() & SLOTP_ARMOR) || (item->getSlotPosition() & SLOTP_LEGS) || (item->getSlotPosition() & SLOTP_FEET) || (item->getSlotPosition() & SLOTP_RING)) ret = RET_CANNOTBEDRESSED; else if(item->getSlotPosition() & SLOTP_TWO_HAND) ret = RET_PUTTHISOBJECTINBOTHHANDS; else if((item->getSlotPosition() & SLOTP_RIGHT) || (item->getSlotPosition() & SLOTP_LEFT)) ret = RET_PUTTHISOBJECTINYOURHAND; switch(index) { case SLOT_HEAD: if(item->getSlotPosition() & SLOTP_HEAD) ret = RET_NOERROR; break; case SLOT_NECKLACE: if(item->getSlotPosition() & SLOTP_NECKLACE) ret = RET_NOERROR; break; case SLOT_BACKPACK: if(item->getSlotPosition() & SLOTP_BACKPACK) ret = RET_NOERROR; break; case SLOT_ARMOR: if(item->getSlotPosition() & SLOTP_ARMOR) ret = RET_NOERROR; break; case SLOT_RIGHT: if(item->getSlotPosition() & SLOTP_RIGHT) { //check if we already carry an item in the other hand if(item->getSlotPosition() & SLOTP_TWO_HAND) { if(inventory[SLOT_LEFT] && inventory[SLOT_LEFT] != item) ret = RET_BOTHHANDSNEEDTOBEFREE; else ret = RET_NOERROR; } else if(inventory[SLOT_LEFT]) { const Item* leftItem = inventory[SLOT_LEFT]; WeaponType_t type = item->getWeaponType(), leftType = leftItem->getWeaponType(); if(leftItem->getSlotPosition() & SLOTP_TWO_HAND) ret = RET_DROPTWOHANDEDITEM; else if(item == leftItem && item->getItemCount() == count) ret = RET_NOERROR; else if(leftType == WEAPON_SHIELD && type == WEAPON_SHIELD) ret = RET_CANONLYUSEONESHIELD; else if(!leftItem->isWeapon() || !item->isWeapon() || leftType == WEAPON_AMMO || type == WEAPON_AMMO || leftType == WEAPON_SHIELD || type == WEAPON_SHIELD || (leftItem->isDualWield() && item->isDualWield())) ret = RET_NOERROR; else ret = RET_CANONLYUSEONEWEAPON; } else ret = RET_NOERROR; } break; case SLOT_LEFT: if(item->getSlotPosition() & SLOTP_LEFT) { //check if we already carry an item in the other hand if(item->getSlotPosition() & SLOTP_TWO_HAND) { if(inventory[SLOT_RIGHT] && inventory[SLOT_RIGHT] != item) ret = RET_BOTHHANDSNEEDTOBEFREE; else ret = RET_NOERROR; } else if(inventory[SLOT_RIGHT]) { const Item* rightItem = inventory[SLOT_RIGHT]; WeaponType_t type = item->getWeaponType(), rightType = rightItem->getWeaponType(); if(rightItem->getSlotPosition() & SLOTP_TWO_HAND) ret = RET_DROPTWOHANDEDITEM; else if(item == rightItem && item->getItemCount() == count) ret = RET_NOERROR; else if(rightType == WEAPON_SHIELD && type == WEAPON_SHIELD) ret = RET_CANONLYUSEONESHIELD; else if(!rightItem->isWeapon() || !item->isWeapon() || rightType == WEAPON_AMMO || type == WEAPON_AMMO || rightType == WEAPON_SHIELD || type == WEAPON_SHIELD || (rightItem->isDualWield() && item->isDualWield())) ret = RET_NOERROR; else ret = RET_CANONLYUSEONEWEAPON; } else ret = RET_NOERROR; } break; case SLOT_LEGS: if(item->getSlotPosition() & SLOTP_LEGS) ret = RET_NOERROR; break; case SLOT_FEET: if(item->getSlotPosition() & SLOTP_FEET) ret = RET_NOERROR; break; case SLOT_RING: if(item->getSlotPosition() & SLOTP_RING) ret = RET_NOERROR; break; case SLOT_AMMO: if(item->getSlotPosition() & SLOTP_AMMO) ret = RET_NOERROR; break; case SLOT_WHEREEVER: case -1: ret = RET_NOTENOUGHROOM; break; default: ret = RET_NOTPOSSIBLE; break; } if(ret == RET_NOERROR || ret == RET_NOTENOUGHROOM) { //need an exchange with source? if(getInventoryItem((slots_t)index) != NULL && (!getInventoryItem((slots_t)index)->isStackable() || getInventoryItem((slots_t)index)->getID() != item->getID())) return RET_NEEDEXCHANGE; if(!g_moveEvents->onPlayerEquip(const_cast<Player*>(this), const_cast<Item*>(item), (slots_t)index, true)) return RET_CANNOTBEDRESSED; //check if enough capacity if(!hasCapacity(item, count)) return RET_NOTENOUGHCAPACITY; } return ret; } ReturnValue Player::__queryMaxCount(int32_t index, const Thing* thing, uint32_t count, uint32_t& maxQueryCount, uint32_t flags) const { const Item* item = thing->getItem(); if(!item) { maxQueryCount = 0; return RET_NOTPOSSIBLE; } if(index == INDEX_WHEREEVER) { uint32_t n = 0; for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) { if(Item* inventoryItem = inventory[i]) { if(Container* subContainer = inventoryItem->getContainer()) { uint32_t queryCount = 0; subContainer->__queryMaxCount(INDEX_WHEREEVER, item, item->getItemCount(), queryCount, flags); //iterate through all items, including sub-containers (deep search) n += queryCount; for(ContainerIterator cit = subContainer->begin(); cit != subContainer->end(); ++cit) { if(Container* tmpContainer = (*cit)->getContainer()) { queryCount = 0; tmpContainer->__queryMaxCount(INDEX_WHEREEVER, item, item->getItemCount(), queryCount, flags); n += queryCount; } } } else if(inventoryItem->isStackable() && item->getID() == inventoryItem->getID() && inventoryItem->getItemCount() < 100) { uint32_t remainder = (100 - inventoryItem->getItemCount()); if(__queryAdd(i, item, remainder, flags) == RET_NOERROR) n += remainder; } } else if(__queryAdd(i, item, item->getItemCount(), flags) == RET_NOERROR) { if(item->isStackable()) n += 100; else n += 1; } } maxQueryCount = n; } else { const Thing* destThing = __getThing(index); const Item* destItem = NULL; if(destThing) destItem = destThing->getItem(); if(destItem) { if(destItem->isStackable() && item->getID() == destItem->getID() && destItem->getItemCount() < 100) maxQueryCount = 100 - destItem->getItemCount(); else maxQueryCount = 0; } else if(__queryAdd(index, item, count, flags) == RET_NOERROR) { if(item->isStackable()) maxQueryCount = 100; else maxQueryCount = 1; return RET_NOERROR; } } if(maxQueryCount < count) return RET_NOTENOUGHROOM; return RET_NOERROR; } ReturnValue Player::__queryRemove(const Thing* thing, uint32_t count, uint32_t flags) const { int32_t index = __getIndexOfThing(thing); if(index == -1) return RET_NOTPOSSIBLE; const Item* item = thing->getItem(); if(!item) return RET_NOTPOSSIBLE; if(!count || (item->isStackable() && count > item->getItemCount())) return RET_NOTPOSSIBLE; if(!item->isMovable() && !hasBitSet(FLAG_IGNORENOTMOVABLE, flags)) return RET_NOTMOVABLE; return RET_NOERROR; } Cylinder* Player::__queryDestination(int32_t& index, const Thing* thing, Item** destItem, uint32_t& flags) { if(!index /*drop to capacity window*/ || index == INDEX_WHEREEVER) { *destItem = NULL; const Item* item = thing->getItem(); if(!item) return this; std::list<std::pair<Container*, int32_t> > containers; std::list<std::pair<Cylinder*, int32_t> > freeSlots; bool autoStack = !((flags & FLAG_IGNOREAUTOSTACK) == FLAG_IGNOREAUTOSTACK); for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) { if(Item* invItem = inventory[i]) { if(invItem == item || invItem == tradeItem) continue; if(autoStack && item->isStackable() && __queryAdd(i, item, item->getItemCount(), 0) == RET_NOERROR && invItem->getID() == item->getID() && invItem->getItemCount() < 100) { *destItem = invItem; index = i; return this; } if(Container* container = invItem->getContainer()) { if(!autoStack && container->__queryAdd(INDEX_WHEREEVER, item, item->getItemCount(), flags) == RET_NOERROR) { index = INDEX_WHEREEVER; return container; } containers.push_back(std::make_pair(container, 0)); } } else if(!autoStack) { if(__queryAdd(i, item, item->getItemCount(), 0) == RET_NOERROR) { index = i; return this; } } else freeSlots.push_back(std::make_pair(this, i)); } int32_t deepness = g_config.getNumber(ConfigManager::PLAYER_DEEPNESS); while(!containers.empty()) { Container* tmpContainer = containers.front().first; int32_t level = containers.front().second; containers.pop_front(); if(!tmpContainer) continue; for(uint32_t n = 0; n < tmpContainer->capacity(); ++n) { if(Item* tmpItem = tmpContainer->getItem(n)) { if(tmpItem == item || tmpItem == tradeItem) continue; if(autoStack && item->isStackable() && tmpContainer->__queryAdd(n, item, item->getItemCount(), 0) == RET_NOERROR && tmpItem->getID() == item->getID() && tmpItem->getItemCount() < 100) { index = n; *destItem = tmpItem; return tmpContainer; } if(Container* container = tmpItem->getContainer()) { if(!autoStack && container->__queryAdd(INDEX_WHEREEVER, item, item->getItemCount(), flags) == RET_NOERROR) { index = INDEX_WHEREEVER; return container; } if(deepness < 0 || level < deepness) containers.push_back(std::make_pair(container, level + 1)); } } else { if(!autoStack) { if(tmpContainer->__queryAdd(n, item, item->getItemCount(), 0) == RET_NOERROR) { index = n; return tmpContainer; } } else freeSlots.push_back(std::make_pair(tmpContainer, n)); break; // one slot to check is definitely enough. } } } if(autoStack) { while(!freeSlots.empty()) { Cylinder* tmpCylinder = freeSlots.front().first; int32_t i = freeSlots.front().second; freeSlots.pop_front(); if(!tmpCylinder) continue; if(tmpCylinder->__queryAdd(i, item, item->getItemCount(), flags) == RET_NOERROR) { index = i; return tmpCylinder; } } } return this; } Thing* destThing = __getThing(index); if(destThing) *destItem = destThing->getItem(); if(Cylinder* subCylinder = dynamic_cast<Cylinder*>(destThing)) { index = INDEX_WHEREEVER; *destItem = NULL; return subCylinder; } return this; } void Player::__addThing(Creature* actor, Thing* thing) { __addThing(actor, 0, thing); } void Player::__addThing(Creature*, int32_t index, Thing* thing) { if(index < 0 || index > 11) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__addThing], " << "player: " << getName() << ", index: " << index << ", index < 0 || index > 11" << std::endl; #endif return /*RET_NOTPOSSIBLE*/; } if(!index) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__addThing], " << "player: " << getName() << ", index == 0" << std::endl; #endif return /*RET_NOTENOUGHROOM*/; } Item* item = thing->getItem(); if(!item) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__addThing], " << "player: " << getName() << ", item == NULL" << std::endl; #endif return /*RET_NOTPOSSIBLE*/; } item->setParent(this); inventory[index] = item; //send to client sendAddInventoryItem((slots_t)index, item); //event methods onAddInventoryItem((slots_t)index, item); } void Player::__updateThing(Thing* thing, uint16_t itemId, uint32_t count) { int32_t index = __getIndexOfThing(thing); if(index == -1) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__updateThing], " << "player: " << getName() << ", index == -1" << std::endl; #endif return /*RET_NOTPOSSIBLE*/; } Item* item = thing->getItem(); if(!item) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__updateThing], " << "player: " << getName() << ", item == NULL" << std::endl; #endif return /*RET_NOTPOSSIBLE*/; } const ItemType& oldType = Item::items[item->getID()]; const ItemType& newType = Item::items[itemId]; item->setID(itemId); item->setSubType(count); //send to client sendUpdateInventoryItem((slots_t)index, item, item); //event methods onUpdateInventoryItem((slots_t)index, item, oldType, item, newType); } void Player::__replaceThing(uint32_t index, Thing* thing) { if(index > 11) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__replaceThing], " << "player: " << getName() << ", index: " << index << ", index < 0 || index > 11" << std::endl; #endif return /*RET_NOTPOSSIBLE*/; } Item* oldItem = getInventoryItem((slots_t)index); if(!oldItem) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__updateThing], " << "player: " << getName() << ", oldItem == NULL" << std::endl; #endif return /*RET_NOTPOSSIBLE*/; } Item* item = thing->getItem(); if(!item) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__updateThing], " << "player: " << getName() << ", item == NULL" << std::endl; #endif return /*RET_NOTPOSSIBLE*/; } const ItemType& oldType = Item::items[oldItem->getID()]; const ItemType& newType = Item::items[item->getID()]; //send to client sendUpdateInventoryItem((slots_t)index, oldItem, item); //event methods onUpdateInventoryItem((slots_t)index, oldItem, oldType, item, newType); item->setParent(this); inventory[index] = item; } void Player::__removeThing(Thing* thing, uint32_t count) { Item* item = thing->getItem(); if(!item) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__removeThing], " << "player: " << getName() << ", item == NULL" << std::endl; #endif return /*RET_NOTPOSSIBLE*/; } int32_t index = __getIndexOfThing(thing); if(index == -1) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__removeThing], " << "player: " << getName() << ", index == -1" << std::endl; #endif return /*RET_NOTPOSSIBLE*/; } if(item->isStackable()) { if(count == item->getItemCount()) { //send change to client sendRemoveInventoryItem((slots_t)index, item); //event methods onRemoveInventoryItem((slots_t)index, item); item->setParent(NULL); inventory[index] = NULL; } else { item->setItemCount(std::max(0, (int32_t)(item->getItemCount() - count))); const ItemType& it = Item::items[item->getID()]; //send change to client sendUpdateInventoryItem((slots_t)index, item, item); //event methods onUpdateInventoryItem((slots_t)index, item, it, item, it); } } else { //send change to client sendRemoveInventoryItem((slots_t)index, item); //event methods onRemoveInventoryItem((slots_t)index, item); item->setParent(NULL); inventory[index] = NULL; } } Thing* Player::__getThing(uint32_t index) const { if(index > SLOT_PRE_FIRST && index < SLOT_LAST) return inventory[index]; return NULL; } int32_t Player::__getIndexOfThing(const Thing* thing) const { for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) { if(inventory[i] == thing) return i; } return -1; } int32_t Player::__getFirstIndex() const { return SLOT_FIRST; } int32_t Player::__getLastIndex() const { return SLOT_LAST; } uint32_t Player::__getItemTypeCount(uint16_t itemId, int32_t subType /*= -1*/) const { Item* item = NULL; Container* container = NULL; uint32_t count = 0; for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) { if(!(item = inventory[i])) continue; if(item->getID() != itemId) { if(!(container = item->getContainer())) continue; for(ContainerIterator it = container->begin(), end = container->end(); it != end; ++it) { if((*it)->getID() == itemId) count += Item::countByType(*it, subType); } } else count += Item::countByType(item, subType); } return count; } std::map<uint32_t, uint32_t>& Player::__getAllItemTypeCount(std::map<uint32_t, uint32_t>& countMap) const { Item* item = NULL; Container* container = NULL; for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) { if(!(item = inventory[i])) continue; countMap[item->getID()] += Item::countByType(item, -1); if(!(container = item->getContainer())) continue; for(ContainerIterator it = container->begin(), end = container->end(); it != end; ++it) countMap[(*it)->getID()] += Item::countByType(*it, -1); } return countMap; } void Player::postAddNotification(Creature*, Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link /*= LINK_OWNER*/) { if(link == LINK_OWNER) //calling movement scripts g_moveEvents->onPlayerEquip(this, thing->getItem(), (slots_t)index, false); bool requireListUpdate = true; if(link == LINK_OWNER || link == LINK_TOPPARENT) { if(const Item* item = (oldParent ? oldParent->getItem() : NULL)) { assert(item->getContainer() != NULL); requireListUpdate = item->getContainer()->getHoldingPlayer() != this; } else requireListUpdate = oldParent != this; updateInventoryWeight(); updateItemsLight(); updateWeapon(); sendStats(); } if(const Item* item = thing->getItem()) { if(const Container* container = item->getContainer()) onSendContainer(container); if(shopOwner && requireListUpdate) updateInventoryGoods(item->getID()); } else if(const Creature* creature = thing->getCreature()) { if(creature != this) return; std::vector<Container*> containers; for(ContainerVector::iterator it = containerVec.begin(); it != containerVec.end(); ++it) { if(!Position::areInRange<1,1,0>(it->second->getPosition(), getPosition())) containers.push_back(it->second); } for(std::vector<Container*>::const_iterator it = containers.begin(); it != containers.end(); ++it) autoCloseContainers(*it); } } void Player::postRemoveNotification(Creature*, Thing* thing, const Cylinder* newParent, int32_t index, bool isCompleteRemoval, cylinderlink_t link /*= LINK_OWNER*/) { if(link == LINK_OWNER) //calling movement scripts g_moveEvents->onPlayerDeEquip(this, thing->getItem(), (slots_t)index, isCompleteRemoval); bool requireListUpdate = true; if(link == LINK_OWNER || link == LINK_TOPPARENT) { if(const Item* item = (newParent ? newParent->getItem() : NULL)) { assert(item->getContainer() != NULL); requireListUpdate = item->getContainer()->getHoldingPlayer() != this; } else requireListUpdate = newParent != this; updateInventoryWeight(); updateItemsLight(); updateWeapon(); sendStats(); } if(const Item* item = thing->getItem()) { if(const Container* container = item->getContainer()) { if(container->isRemoved() || !Position::areInRange<1,1,0>(getPosition(), container->getPosition())) autoCloseContainers(container); else if(container->getTopParent() == this) onSendContainer(container); else if(const Container* topContainer = dynamic_cast<const Container*>(container->getTopParent())) { if(const Depot* depot = dynamic_cast<const Depot*>(topContainer)) { bool isOwner = false; for(DepotMap::iterator it = depots.begin(); it != depots.end(); ++it) { if(it->second.first != depot) continue; isOwner = true; onSendContainer(container); } if(!isOwner) autoCloseContainers(container); } else onSendContainer(container); } else autoCloseContainers(container); } if(shopOwner && requireListUpdate) updateInventoryGoods(item->getID()); } } void Player::__internalAddThing(Thing* thing) { __internalAddThing(0, thing); } void Player::__internalAddThing(uint32_t index, Thing* thing) { #ifdef __DEBUG_MOVESYS__ std::clog << "[Player::__internalAddThing] index: " << index << std::endl; #endif if(!index || index > 11) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__internalAddThing] index == 0 || index > 11" << std::endl; #endif return; } if(inventory[index]) { #ifdef __DEBUG_MOVESYS__ std::clog << "Warning: [Player::__internalAddThing], player: " << getName() << ", items[index] is not empty." << std::endl; #endif return; } Item* item = thing->getItem(); if(!item) { #ifdef __DEBUG_MOVESYS__ std::clog << "Failure: [Player::__internalAddThing] item == NULL" << std::endl; #endif return; } inventory[index] = item; item->setParent(this); } bool Player::setFollowCreature(Creature* creature, bool fullPathSearch /*= false*/) { bool deny = false; CreatureEventList followEvents = getCreatureEvents(CREATURE_EVENT_FOLLOW); for(CreatureEventList::iterator it = followEvents.begin(); it != followEvents.end(); ++it) { if(creature && !(*it)->executeFollow(this, creature)) deny = true; } if(!deny && Creature::setFollowCreature(creature, fullPathSearch)) return true; setFollowCreature(NULL); setAttackedCreature(NULL); if(!deny) sendCancelMessage(RET_THEREISNOWAY); sendCancelTarget(); cancelNextWalk = true; return false; } bool Player::setAttackedCreature(Creature* creature) { if(!Creature::setAttackedCreature(creature)) { sendCancelTarget(); return false; } if(chaseMode == CHASEMODE_FOLLOW && creature) { if(followCreature != creature) //chase opponent setFollowCreature(creature); } else setFollowCreature(NULL); if(creature) Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::checkCreatureAttack, &g_game, getID()))); return true; } void Player::goToFollowCreature() { if(!walkTask) Creature::goToFollowCreature(); } void Player::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const { Creature::getPathSearchParams(creature, fpp); fpp.fullPathSearch = true; } void Player::doAttacking(uint32_t) { if(!lastAttack) lastAttack = OTSYS_TIME() - getAttackSpeed() - 1; else if((OTSYS_TIME() - lastAttack) < getAttackSpeed()) return; if(hasCondition(CONDITION_PACIFIED) && !hasCustomFlag(PlayerCustomFlag_IgnorePacification)) { lastAttack = OTSYS_TIME(); return; } Item* item = getWeapon(false); if(const Weapon* _weapon = g_weapons->getWeapon(item)) { if(_weapon->interruptSwing() && !canDoAction()) { SchedulerTask* task = createSchedulerTask(getNextActionTime(), boost::bind(&Game::checkCreatureAttack, &g_game, getID())); setNextActionTask(task); } else { if((!_weapon->hasExhaustion() || !hasCondition(CONDITION_EXHAUST, EXHAUST_COMBAT)) && _weapon->useWeapon(this, item, attackedCreature)) lastAttack = OTSYS_TIME(); updateWeapon(); } } else if(Weapon::useFist(this, attackedCreature)) lastAttack = OTSYS_TIME(); } double Player::getGainedExperience(Creature* attacker) const { if(!skillLoss) return 0; double rate = g_config.getDouble(ConfigManager::RATE_PVP_EXPERIENCE); if(rate <= 0) return 0; Player* attackerPlayer = attacker->getPlayer(); if(!attackerPlayer || attackerPlayer == this) return 0; double attackerLevel = (double)attackerPlayer->getLevel(), min = g_config.getDouble( ConfigManager::EFP_MIN_THRESHOLD), max = g_config.getDouble(ConfigManager::EFP_MAX_THRESHOLD); if((min > 0 && level < (uint32_t)std::floor(attackerLevel * min)) || (max > 0 && level > (uint32_t)std::floor(attackerLevel * max))) return 0; /* Formula a = attackers level * 0.9 b = victims level c = victims experience result = (1 - (a / b)) * 0.05 * c Not affected by special multipliers(!) */ uint32_t a = (uint32_t)std::floor(attackerLevel * 0.9), b = level; uint64_t c = getExperience(); return (double)std::max((uint64_t)0, (uint64_t)std::floor(getDamageRatio(attacker) * std::max((double)0, ((double)(1 - (((double)a / b))))) * 0.05 * c)) * rate; } void Player::onFollowCreature(const Creature* creature) { if(!creature) cancelNextWalk = true; } void Player::setChaseMode(chaseMode_t mode) { chaseMode_t prevChaseMode = chaseMode; chaseMode = mode; if(prevChaseMode == chaseMode) return; if(chaseMode == CHASEMODE_FOLLOW) { if(!followCreature && attackedCreature) //chase opponent setFollowCreature(attackedCreature); } else if(attackedCreature) { setFollowCreature(NULL); cancelNextWalk = true; } } void Player::onWalkAborted() { setNextWalkActionTask(NULL); sendCancelWalk(); } void Player::onWalkComplete() { if(!walkTask) return; walkTaskEvent = Scheduler::getInstance().addEvent(walkTask); walkTask = NULL; } void Player::getCreatureLight(LightInfo& light) const { if(internalLight.level > itemsLight.level) light = internalLight; else light = itemsLight; } void Player::updateItemsLight(bool internal/* = false*/) { LightInfo maxLight, curLight; Item* item = NULL; for(int32_t i = SLOT_FIRST; i < SLOT_LAST; ++i) { if(!(item = getInventoryItem((slots_t)i))) continue; item->getLight(curLight); if(curLight.level > maxLight.level) maxLight = curLight; } if(maxLight.level > itemsLight.level || (maxLight.level == itemsLight.level && maxLight.color != itemsLight.color)) { itemsLight = maxLight; if(!internal) g_game.changeLight(this); } } void Player::onAddCondition(ConditionType_t type, bool hadCondition) { Creature::onAddCondition(type, hadCondition); if(getLastPosition().x && type != CONDITION_GAMEMASTER) // don't send if player have just logged in (its already done in protocolgame), or condition have no icons sendIcons(); } void Player::onAddCombatCondition(ConditionType_t type, bool) { std::string tmp; switch(type) { //client hardcoded case CONDITION_FIRE: tmp = "queimando"; break; case CONDITION_POISON: tmp = "envenenado"; break; case CONDITION_ENERGY: tmp = "eletrificado"; break; case CONDITION_FREEZING: tmp = "congelado"; break; case CONDITION_DAZZLED: tmp = "deslumbrado"; break; case CONDITION_CURSED: tmp = "amaldicoado"; break; case CONDITION_DROWN: tmp = "afogado"; break; case CONDITION_DRUNK: tmp = "bêbado"; break; case CONDITION_PARALYZE: tmp = "paralizado"; break; /*case CONDITION_MANASHIELD: tmp = "protegido por escudo de energia"; break; case CONDITION_HASTE: tmp = "comecou a correr"; break; case CONDITION_ATTRIBUTES: tmp = "mais forca"; break;*/ default: break; } if(!tmp.empty()) sendTextMessage(MSG_STATUS_DEFAULT, "Voce e " + tmp + "."); } void Player::onEndCondition(ConditionType_t type) { Creature::onEndCondition(type); if(type == CONDITION_INFIGHT) { onIdleStatus(); clearAttacked(); pzLocked = false; if(skull < SKULL_RED) setSkull(SKULL_NONE); g_game.updateCreatureSkull(this); } sendIcons(); } void Player::onCombatRemoveCondition(const Creature*, Condition* condition) { //Creature::onCombatRemoveCondition(attacker, condition); bool remove = true; if(condition->getId() > 0) { remove = false; //Means the condition is from an item, id == slot if(g_game.getWorldType() == WORLDTYPE_HARDCORE) { if(Item* item = getInventoryItem((slots_t)condition->getId())) { //25% chance to destroy the item if(random_range(1, 100) < 26) g_game.internalRemoveItem(NULL, item); } } } if(remove) { if(!canDoAction()) { int32_t delay = getNextActionTime(); delay -= (delay % EVENT_CREATURE_THINK_INTERVAL); if(delay < 0) removeCondition(condition); else condition->setTicks(delay); } else removeCondition(condition); } } void Player::onTickCondition(ConditionType_t type, int32_t interval, bool& _remove) { Creature::onTickCondition(type, interval, _remove); if(type == CONDITION_HUNTING) useStamina(-(interval * g_config.getNumber(ConfigManager::RATE_STAMINA_LOSS))); } void Player::onAttackedCreature(Creature* target) { Creature::onAttackedCreature(target); if(hasFlag(PlayerFlag_NotGainInFight)) return; addInFightTicks(false); Player* targetPlayer = target->getPlayer(); if(!targetPlayer) return; addAttacked(targetPlayer); if(targetPlayer == this && targetPlayer->getZone() != ZONE_HARDCORE) { targetPlayer->sendCreatureSkull(this); return; } if(Combat::isInPvpZone(this, targetPlayer) || isPartner(targetPlayer) || #ifdef __WAR_SYSTEM__ isAlly(targetPlayer) || #endif (g_config.getBool(ConfigManager::ALLOW_FIGHTBACK) && targetPlayer->hasAttacked(this) #ifdef __WAR_SYSTEM__ && !targetPlayer->isEnemy(this, false) #endif )) return; if(!pzLocked) { pzLocked = true; sendIcons(); } if(getZone() != target->getZone() || skull != SKULL_NONE #ifdef __WAR_SYSTEM__ || targetPlayer->isEnemy(this, true) #endif ) return; if(targetPlayer->getSkull() != SKULL_NONE) targetPlayer->sendCreatureSkull(this); else if(!hasCustomFlag(PlayerCustomFlag_NotGainSkull)) { setSkull(SKULL_WHITE); g_game.updateCreatureSkull(this); } } void Player::onSummonAttackedCreature(Creature* summon, Creature* target) { Creature::onSummonAttackedCreature(summon, target); onAttackedCreature(target); } void Player::onAttacked() { Creature::onAttacked(); addInFightTicks(false); } bool Player::checkLoginDelay(uint32_t playerId) const { return (!hasCustomFlag(PlayerCustomFlag_IgnoreLoginDelay) && OTSYS_TIME() <= (lastLoad + g_config.getNumber( ConfigManager::LOGIN_PROTECTION)) && !hasBeenAttacked(playerId)); } void Player::onIdleStatus() { Creature::onIdleStatus(); if(getParty()) getParty()->clearPlayerPoints(this); } void Player::onPlacedCreature() { //scripting event - onLogin if(!g_creatureEvents->playerLogin(this)) kick(true, true); } void Player::onAttackedCreatureDrain(Creature* target, int32_t points) { Creature::onAttackedCreatureDrain(target, points); if(party && target && (!target->getMaster() || !target->getMaster()->getPlayer()) && target->getMonster() && target->getMonster()->isHostile()) //we have fulfilled a requirement for shared experience getParty()->addPlayerDamageMonster(this, points); char buffer[100]; sprintf(buffer, "Voce causou %d pontos de dano em %s.", points, target->getNameDescription().c_str()); sendTextMessage(MSG_STATUS_DEFAULT, buffer); } void Player::onSummonAttackedCreatureDrain(Creature* summon, Creature* target, int32_t points) { Creature::onSummonAttackedCreatureDrain(summon, target, points); char buffer[100]; sprintf(buffer, "Voce causou %d pontos de dano em %s", summon->getName().c_str(), points, target->getNameDescription().c_str()); sendTextMessage(MSG_EVENT_DEFAULT, buffer); } void Player::onTargetCreatureGainHealth(Creature* target, int32_t points) { Creature::onTargetCreatureGainHealth(target, points); if(target && getParty()) { Player* tmpPlayer = NULL; if(target->getPlayer()) tmpPlayer = target->getPlayer(); else if(target->getMaster() && target->getMaster()->getPlayer()) tmpPlayer = target->getMaster()->getPlayer(); if(isPartner(tmpPlayer)) party->addPlayerHealedMember(this, points); } } #ifdef __WAR_SYSTEM__ GuildEmblems_t Player::getGuildEmblem(const Creature* creature) const { const Player* player = creature->getPlayer(); if(!player || !player->hasEnemy()) return Creature::getGuildEmblem(creature); if(player->isEnemy(this, false)) return EMBLEM_RED; return player->getGuildId() == guildId ? EMBLEM_GREEN : EMBLEM_BLUE; } bool Player::getEnemy(const Player* player, War_t& data) const { if(!guildId || !player || player->isRemoved()) return false; uint32_t guild = player->getGuildId(); if(!guild) return false; WarMap::const_iterator it = warMap.find(guild); if(it == warMap.end()) return false; data = it->second; return true; } bool Player::isEnemy(const Player* player, bool allies) const { if(!guildId || !player || player->isRemoved()) return false; uint32_t guild = player->getGuildId(); if(!guild) return false; return !warMap.empty() && (((g_game.getWorldType() != WORLDTYPE_OPTIONAL || g_config.getBool( ConfigManager::OPTIONAL_WAR_ATTACK_ALLY)) && allies && guildId == guild) || warMap.find(guild) != warMap.end()); } bool Player::isAlly(const Player* player) const { return !warMap.empty() && player && player->getGuildId() == guildId; } #endif bool Player::onKilledCreature(Creature* target, DeathEntry& entry) { if(!Creature::onKilledCreature(target, entry)) return false; if(hasFlag(PlayerFlag_NotGenerateLoot)) target->setDropLoot(LOOT_DROP_NONE); Condition* condition = NULL; if(target->getMonster() && !target->isPlayerSummon() && !hasFlag(PlayerFlag_HasInfiniteStamina) && (condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_HUNTING, g_config.getNumber(ConfigManager::HUNTING_DURATION)))) addCondition(condition); if(hasFlag(PlayerFlag_NotGainInFight) || getZone() != target->getZone()) return true; Player* targetPlayer = target->getPlayer(); if(!targetPlayer || Combat::isInPvpZone(this, targetPlayer) || isPartner(targetPlayer) #ifdef __WAR_SYSTEM__ || isAlly(targetPlayer) #endif ) return true; #ifdef __WAR_SYSTEM__ War_t enemy; if(targetPlayer->getEnemy(this, enemy) && (!entry.isLast() || IOGuild::getInstance()->updateWar(enemy))) entry.setWar(enemy); #endif if(!entry.isJustify() || !hasCondition(CONDITION_INFIGHT)) return true; if(!targetPlayer->hasAttacked(this) && target->getSkull() == SKULL_NONE && targetPlayer != this && (addUnjustifiedKill(targetPlayer, #ifndef __WAR_SYSTEM__ true #else !enemy.war #endif ) || entry.isLast())) entry.setUnjustified(); addInFightTicks(true, g_config.getNumber(ConfigManager::WHITE_SKULL_TIME)); return true; } bool Player::gainExperience(double& gainExp, bool fromMonster) { if(!rateExperience(gainExp, fromMonster)) return false; //soul regeneration if(gainExp >= level) { if(Condition* condition = Condition::createCondition( CONDITIONID_DEFAULT, CONDITION_SOUL, 4 * 60 * 1000)) { condition->setParam(CONDITIONPARAM_SOULGAIN, vocation->getGainAmount(GAIN_SOUL)); condition->setParam(CONDITIONPARAM_SOULTICKS, (vocation->getGainTicks(GAIN_SOUL) * 1000)); addCondition(condition); } } addExperience((uint64_t)gainExp); return true; } bool Player::rateExperience(double& gainExp, bool fromMonster) { if(hasFlag(PlayerFlag_NotGainExperience) || gainExp <= 0) return false; if(!fromMonster) return true; gainExp *= rates[SKILL__LEVEL] * g_game.getExperienceStage(level, vocation->getExperienceMultiplier()); if(!hasFlag(PlayerFlag_HasInfiniteStamina)) { int32_t minutes = getStaminaMinutes(); if(minutes >= g_config.getNumber(ConfigManager::STAMINA_LIMIT_TOP)) { if(isPremium() || !g_config.getNumber(ConfigManager::STAMINA_BONUS_PREMIUM)) gainExp *= g_config.getDouble(ConfigManager::RATE_STAMINA_ABOVE); } else if(minutes < (g_config.getNumber(ConfigManager::STAMINA_LIMIT_BOTTOM)) && minutes > 0) gainExp *= g_config.getDouble(ConfigManager::RATE_STAMINA_UNDER); else if(minutes <= 0) gainExp = 0; } else if(isPremium() || !g_config.getNumber(ConfigManager::STAMINA_BONUS_PREMIUM)) gainExp *= g_config.getDouble(ConfigManager::RATE_STAMINA_ABOVE); return true; } void Player::onGainExperience(double& gainExp, bool fromMonster, bool multiplied) { if(party && party->isSharedExperienceEnabled() && party->isSharedExperienceActive()) { party->shareExperience(gainExp, fromMonster, multiplied); rateExperience(gainExp, fromMonster); return; //we will get a share of the experience through the sharing mechanism } if(gainExperience(gainExp, fromMonster)) Creature::onGainExperience(gainExp, fromMonster, true); } void Player::onGainSharedExperience(double& gainExp, bool fromMonster, bool) { if(gainExperience(gainExp, fromMonster)) Creature::onGainSharedExperience(gainExp, fromMonster, true); } bool Player::isImmune(CombatType_t type) const { return hasCustomFlag(PlayerCustomFlag_IsImmune) || Creature::isImmune(type); } bool Player::isImmune(ConditionType_t type) const { return hasCustomFlag(PlayerCustomFlag_IsImmune) || Creature::isImmune(type); } bool Player::isAttackable() const { return (!hasFlag(PlayerFlag_CannotBeAttacked) && !isAccountManager()); } void Player::changeHealth(int32_t healthChange) { Creature::changeHealth(healthChange); sendStats(); } void Player::changeMana(int32_t manaChange) { if(!hasFlag(PlayerFlag_HasInfiniteMana)) Creature::changeMana(manaChange); sendStats(); } void Player::changeSoul(int32_t soulChange) { if(!hasFlag(PlayerFlag_HasInfiniteSoul)) soul = std::min((int32_t)soulMax, (int32_t)soul + soulChange); sendStats(); } bool Player::changeOutfit(Outfit_t outfit, bool checkList) { uint32_t outfitId = Outfits::getInstance()->getOutfitId(outfit.lookType); if(checkList && (!canWearOutfit(outfitId, outfit.lookAddons) || !requestedOutfit)) return false; requestedOutfit = false; if(outfitAttributes) { uint32_t oldId = Outfits::getInstance()->getOutfitId(defaultOutfit.lookType); outfitAttributes = !Outfits::getInstance()->removeAttributes(getID(), oldId, sex); } defaultOutfit = outfit; outfitAttributes = Outfits::getInstance()->addAttributes(getID(), outfitId, sex, defaultOutfit.lookAddons); return true; } bool Player::canWearOutfit(uint32_t outfitId, uint32_t addons) { OutfitMap::iterator it = outfits.find(outfitId); if(it == outfits.end() || (it->second.isPremium && !isPremium()) || getAccess() < it->second.accessLevel || ((it->second.addons & addons) != addons && !hasCustomFlag(PlayerCustomFlag_CanWearAllAddons))) return false; if(it->second.storageId.empty()) return true; std::string value; getStorage(it->second.storageId, value); bool ret = value == it->second.storageValue; if(ret) return ret; int32_t tmp = atoi(value.c_str()); if(!tmp && value != "0") return ret; tmp = atoi(it->second.storageValue.c_str()); if(!tmp && it->second.storageValue != "0") return ret; return atoi(value.c_str()) >= tmp; } bool Player::addOutfit(uint32_t outfitId, uint32_t addons) { Outfit outfit; if(!Outfits::getInstance()->getOutfit(outfitId, sex, outfit)) return false; OutfitMap::iterator it = outfits.find(outfitId); if(it != outfits.end()) outfit.addons |= it->second.addons; outfit.addons |= addons; outfits[outfitId] = outfit; return true; } bool Player::removeOutfit(uint32_t outfitId, uint32_t addons) { OutfitMap::iterator it = outfits.find(outfitId); if(it == outfits.end()) return false; if(addons == 0xFF) //remove outfit outfits.erase(it); else //remove addons outfits[outfitId].addons = it->second.addons & (~addons); return true; } void Player::generateReservedStorage() { uint32_t key = PSTRG_OUTFITSID_RANGE_START + 1; const OutfitMap& defaultOutfits = Outfits::getInstance()->getOutfits(sex); for(OutfitMap::const_iterator it = outfits.begin(); it != outfits.end(); ++it) { OutfitMap::const_iterator dit = defaultOutfits.find(it->first); if(dit == defaultOutfits.end() || (dit->second.isDefault && (dit->second.addons & it->second.addons) == it->second.addons)) continue; std::stringstream k, v; k << key++; // this may not work as intended, revalidate it v << ((it->first << 16) | (it->second.addons & 0xFF)); storageMap[k.str()] = v.str(); if(key <= PSTRG_OUTFITSID_RANGE_START + PSTRG_OUTFITSID_RANGE_SIZE) continue; std::clog << "[Warning - Player::genReservedStorageRange] Player " << getName() << " with more than 500 outfits!" << std::endl; break; } } void Player::setSex(uint16_t newSex) { sex = newSex; const OutfitMap& defaultOutfits = Outfits::getInstance()->getOutfits(sex); for(OutfitMap::const_iterator it = defaultOutfits.begin(); it != defaultOutfits.end(); ++it) { if(it->second.isDefault) addOutfit(it->first, it->second.addons); } } Skulls_t Player::getSkull() const { if(hasFlag(PlayerFlag_NotGainInFight) || hasCustomFlag(PlayerCustomFlag_NotGainSkull)) return SKULL_NONE; return skull; } Skulls_t Player::getSkullType(const Creature* creature) const { if(const Player* player = creature->getPlayer()) { if(g_game.getWorldType() != WORLDTYPE_OPEN) return SKULL_NONE; if((player == this || (skull != SKULL_NONE && player->getSkull() < SKULL_RED)) && player->hasAttacked(this) #ifdef __WAR_SYSTEM__ && !player->isEnemy(this, false) #endif ) return SKULL_YELLOW; if(player->getSkull() == SKULL_NONE && #ifndef __WAR_SYSTEM__ isPartner(player) && #else (isPartner(player) || isAlly(player)) && #endif g_game.getWorldType() != WORLDTYPE_OPTIONAL) return SKULL_GREEN; } return Creature::getSkullType(creature); } bool Player::hasAttacked(const Player* attacked) const { return !hasFlag(PlayerFlag_NotGainInFight) && attacked && attackedSet.find(attacked->getID()) != attackedSet.end(); } void Player::addAttacked(const Player* attacked) { if(hasFlag(PlayerFlag_NotGainInFight) || !attacked) return; uint32_t attackedId = attacked->getID(); if(attackedSet.find(attackedId) == attackedSet.end()) attackedSet.insert(attackedId); } void Player::setSkullEnd(time_t _time, bool login, Skulls_t _skull) { if(g_game.getWorldType() != WORLDTYPE_OPEN || hasFlag(PlayerFlag_NotGainInFight) || hasCustomFlag(PlayerCustomFlag_NotGainSkull)) return; bool requireUpdate = false; if(_time > time(NULL)) { requireUpdate = true; setSkull(_skull); } else if(skull == _skull) { requireUpdate = true; setSkull(SKULL_NONE); _time = 0; } if(requireUpdate) { skullEnd = _time; if(!login) g_game.updateCreatureSkull(this); } } bool Player::addUnjustifiedKill(const Player* attacked, bool countNow) { if(!g_config.getBool(ConfigManager::USE_FRAG_HANDLER) || hasFlag( PlayerFlag_NotGainInFight) || g_game.getWorldType() != WORLDTYPE_OPEN || hasCustomFlag(PlayerCustomFlag_NotGainUnjustified) || hasCustomFlag( PlayerCustomFlag_NotGainSkull) || attacked == this) return false; if(client && countNow) { char buffer[90]; sprintf(buffer, "Cuidado! O assassinato de %s nao teve justificativa.", attacked->getName().c_str()); client->sendTextMessage(MSG_STATUS_WARNING, buffer); } time_t now = time(NULL), today = (now - 84600), week = (now - (7 * 84600)); std::vector<time_t> dateList; IOLoginData::getInstance()->getUnjustifiedDates(guid, dateList, now); if(countNow) dateList.push_back(now); uint32_t tc = 0, wc = 0, mc = dateList.size(); for(std::vector<time_t>::iterator it = dateList.begin(); it != dateList.end(); ++it) { if((*it) > week) wc++; if((*it) > today) tc++; } uint32_t d = g_config.getNumber(ConfigManager::RED_DAILY_LIMIT), w = g_config.getNumber( ConfigManager::RED_WEEKLY_LIMIT), m = g_config.getNumber(ConfigManager::RED_MONTHLY_LIMIT); if(skull < SKULL_RED && ((d > 0 && tc >= d) || (w > 0 && wc >= w) || (m > 0 && mc >= m))) setSkullEnd(now + g_config.getNumber(ConfigManager::RED_SKULL_LENGTH), false, SKULL_RED); if(!g_config.getBool(ConfigManager::USE_BLACK_SKULL)) { d += g_config.getNumber(ConfigManager::BAN_DAILY_LIMIT); w += g_config.getNumber(ConfigManager::BAN_WEEKLY_LIMIT); m += g_config.getNumber(ConfigManager::BAN_MONTHLY_LIMIT); if((d <= 0 || tc < d) && (w <= 0 || wc < w) && (m <= 0 || mc < m)) return true; if(!IOBan::getInstance()->addAccountBanishment(accountId, (now + g_config.getNumber( ConfigManager::KILLS_BAN_LENGTH)), 20, ACTION_BANISHMENT, "Matou um jogador injustamente.", 0, guid)) return true; sendTextMessage(MSG_INFO_DESCR, "Voce foi banido."); g_game.addMagicEffect(getPosition(), MAGIC_EFFECT_WRAPS_GREEN); Scheduler::getInstance().addEvent(createSchedulerTask(1000, boost::bind( &Game::kickPlayer, &g_game, getID(), false))); } else { d += g_config.getNumber(ConfigManager::BLACK_DAILY_LIMIT); w += g_config.getNumber(ConfigManager::BLACK_WEEKLY_LIMIT); m += g_config.getNumber(ConfigManager::BLACK_MONTHLY_LIMIT); if(skull < SKULL_BLACK && ((d > 0 && tc >= d) || (w > 0 && wc >= w) || (m > 0 && mc >= m))) { setSkullEnd(now + g_config.getNumber(ConfigManager::BLACK_SKULL_LENGTH), false, SKULL_BLACK); setAttackedCreature(NULL); destroySummons(); } } return true; } void Player::setPromotionLevel(uint32_t pLevel) { if(pLevel > promotionLevel) { uint32_t tmpLevel = 0, currentVoc = vocationId; for(uint32_t i = promotionLevel; i < pLevel; ++i) { currentVoc = Vocations::getInstance()->getPromotedVocation(currentVoc); if(!currentVoc) break; tmpLevel++; Vocation* voc = Vocations::getInstance()->getVocation(currentVoc); if(voc->isPremiumNeeded() && !isPremium() && g_config.getBool(ConfigManager::PREMIUM_FOR_PROMOTION)) continue; vocationId = currentVoc; } promotionLevel += tmpLevel; } else if(pLevel < promotionLevel) { uint32_t tmpLevel = 0, currentVoc = vocationId; for(uint32_t i = pLevel; i < promotionLevel; ++i) { Vocation* voc = Vocations::getInstance()->getVocation(currentVoc); if(voc->getFromVocation() == currentVoc) break; tmpLevel++; currentVoc = voc->getFromVocation(); if(voc->isPremiumNeeded() && !isPremium() && g_config.getBool(ConfigManager::PREMIUM_FOR_PROMOTION)) continue; vocationId = currentVoc; } promotionLevel -= tmpLevel; } setVocation(vocationId); } uint16_t Player::getBlessings() const { if(!g_config.getBool(ConfigManager::BLESSINGS) || (!isPremium() && g_config.getBool(ConfigManager::BLESSING_ONLY_PREMIUM))) return 0; uint16_t count = 0; for(int16_t i = 0; i < 16; ++i) { if(hasBlessing(i)) count++; } return count; } uint64_t Player::getLostExperience() const { if(!skillLoss) return 0; double percent = (double)(lossPercent[LOSS_EXPERIENCE] - vocation->getLessLoss() - (getBlessings() * g_config.getNumber( ConfigManager::BLESS_REDUCTION))) / 100.; if(level <= 25) return (uint64_t)std::floor((double)(experience * percent) / 10.); int32_t base = level; double levels = (double)(base + 50) / 100.; uint64_t lost = 0; while(levels > 1.0f) { lost += (getExpForLevel(base) - getExpForLevel(base - 1)); base--; levels -= 1.; } if(levels > 0.) lost += (uint64_t)std::floor((double)(getExpForLevel(base) - getExpForLevel(base - 1)) * levels); return (uint64_t)std::floor((double)(lost * percent)); } uint32_t Player::getAttackSpeed() const { return ((weapon && weapon->getAttackSpeed() != 0) ? weapon->getAttackSpeed() : (vocation->getAttackSpeed() / std::max((size_t)1, getWeapons().size()))); } void Player::learnInstantSpell(const std::string& name) { if(!hasLearnedInstantSpell(name)) learnedInstantSpellList.push_back(name); } void Player::unlearnInstantSpell(const std::string& name) { if(!hasLearnedInstantSpell(name)) return; LearnedInstantSpellList::iterator it = std::find(learnedInstantSpellList.begin(), learnedInstantSpellList.end(), name); if(it != learnedInstantSpellList.end()) learnedInstantSpellList.erase(it); } bool Player::hasLearnedInstantSpell(const std::string& name) const { if(hasFlag(PlayerFlag_CannotUseSpells)) return false; if(hasFlag(PlayerFlag_IgnoreSpellCheck)) return true; for(LearnedInstantSpellList::const_iterator it = learnedInstantSpellList.begin(); it != learnedInstantSpellList.end(); ++it) { if(!strcasecmp((*it).c_str(), name.c_str())) return true; } return false; } void Player::manageAccount(const std::string &text) { std::stringstream msg; msg << "Gerenciando Conta "; bool noSwap = true; switch(accountManager) { case MANAGER_NAMELOCK: { if(!talkState[1]) { managerString = text; trimString(managerString); if(managerString.length() < 3) msg << "Esse nome e pequeno, por favor escolha um nome maior."; else if(managerString.length() > 30) msg << "Esse nome e grande, por favor escolha um nome menor."; else if(!isValidName(managerString)) msg << "Voce nao pode adicionar alguns símbolos em seu nome."; else if(IOLoginData::getInstance()->playerExists(managerString, true)) msg << "Ja existe um jogador com esse nome, por favor tente outro."; else { std::string tmp = asLowerCaseString(managerString); if(tmp.substr(0, 4) != "god " && tmp.substr(0, 3) != "adm " && tmp.substr(0, 3) != "gm ") { talkState[1] = true; talkState[2] = true; msg << managerString << ", voce tem certeza?"; } else msg << "Seu personagem nao faz parte da equipe, selecione outro nome"; } } else if(checkText(text, "nao") && talkState[2]) { talkState[1] = talkState[2] = false; msg << "Voce esta certo que quer esse nome?"; } else if(checkText(text, "sim") && talkState[2]) { if(!IOLoginData::getInstance()->playerExists(managerString, true)) { uint32_t tmp; if(IOLoginData::getInstance()->getGuidByName(tmp, managerString2) && IOLoginData::getInstance()->changeName(tmp, managerString, managerString2) && IOBan::getInstance()->removePlayerBanishment(tmp, PLAYERBAN_LOCK)) { if(House* house = Houses::getInstance()->getHouseByPlayerId(tmp)) house->updateDoorDescription(managerString); talkState[1] = true; talkState[2] = false; msg << "Seu personagem foi renomeado com sucesso, agora voce pode acessar o jogo sem problemas."; } else { talkState[1] = talkState[2] = false; msg << "Falha ao renomear nome, tente novamente."; } } else { talkState[1] = talkState[2] = false; msg << "Ja existe um jogador com esse nome, por favor tente outro."; } } else msg << "Desculpe, nao te entendi, repita por favor!"; break; } case MANAGER_ACCOUNT: { Account account = IOLoginData::getInstance()->loadAccount(managerNumber); if(checkText(text, "cancelar") || (checkText(text, "conta") && !talkState[1])) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; msg << "Voce quer modificar sua 'senha', puxar uma 'chave de recuperacao', adicionar um 'personagem', ou 'deletar' um personagem?"; } else if(checkText(text, "deletar") && talkState[1]) { talkState[1] = false; talkState[2] = true; msg << "Que personagem voce quer deletar?"; } else if(talkState[2]) { std::string tmp = text; trimString(tmp); if(!isValidName(tmp, false)) msg << "Esse nome tem carateres invalidos, voce pode ter escrito errado, tente novamente."; else { talkState[2] = false; talkState[3] = true; managerString = tmp; msg << "Voce tem certeza que quer excluir o personagem chamado " << managerString << "?"; } } else if(checkText(text, "sim") && talkState[3]) { switch(IOLoginData::getInstance()->deleteCharacter(managerNumber, managerString)) { case DELETE_INTERNAL: msg << "Ocorreu um erro. Ou o personagem nao pertence a voce ou ele nao existe."; break; case DELETE_SUCCESS: msg << "Seu personagem foi deletado."; break; case DELETE_HOUSE: msg << "Seu personagem possui uma casa em seu nome, para deleta-lo voce precisa se desfazer dela."; break; case DELETE_LEADER: msg << "Seu personagem e líder de um grupo, para deleta-lo voce precisa se desfazer dele."; break; case DELETE_ONLINE: msg << "O personagem com esse nome esta online, por favor, tente quando estiver offline."; break; } talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; } else if(checkText(text, "nao") && talkState[3]) { talkState[1] = true; talkState[3] = false; msg << "Diga-me que personagem voce quer deletar."; } else if(checkText(text, "senha") && talkState[1]) { talkState[1] = false; talkState[4] = true; msg << "Diga-me uma nova senha."; } else if(talkState[4]) { std::string tmp = text; trimString(tmp); if(tmp.length() < 4) msg << "Essa senha e pequena, sua senha precisa de no mínimo 4 carateres, tente novamente"; else if(!isValidPassword(tmp)) msg << "Sua senha contem símbolos invalidos, tente novamente."; else { talkState[4] = false; talkState[5] = true; managerString = tmp; msg << "Por acaso '" << managerString << "' e sua nova senha?"; } } else if(checkText(text, "sim") && talkState[5]) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; IOLoginData::getInstance()->setPassword(managerNumber, managerString); msg << "Sua senha foi alterada."; } else if(checkText(text, "nao") && talkState[5]) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; msg << "Entao nao."; } else if(checkText(text, "personagem") && talkState[1]) { if(account.charList.size() <= 15) { talkState[1] = false; talkState[6] = true; msg << "Qual vai ser o nome do seu personagem?"; } else { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; msg << "Sua conta atingiu um maximo de 15 personagens, tente 'deletar' algum deles para criar um novo."; } } else if(talkState[6]) { managerString = text; trimString(managerString); if(managerString.length() < 4) msg << "Esse nome e pequeno, por favor escolha um nome maior."; else if(managerString.length() > 20) msg << "Esse nome e grande, por favor escolha um nome menor."; else if(!isValidName(managerString)) msg << "Voce nao pode adicionar alguns símbolos em seu nome."; else if(IOLoginData::getInstance()->playerExists(managerString, true)) msg << "Ja existe um jogador com esse nome, por favor tente outro."; else { std::string tmp = asLowerCaseString(managerString); if(tmp.substr(0, 4) != "god " && tmp.substr(0, 3) != "adm " && tmp.substr(0, 3) != "gm ") { talkState[6] = false; talkState[7] = true; msg << managerString << ", voce tem certeza?"; } else msg << "Seu personagem nao faz parte da equipe, selecione outro nome!"; } } else if(checkText(text, "nao") && talkState[7]) { talkState[6] = true; talkState[7] = false; msg << "Voce gostaria de nomear assim seu personagem?"; } else if(checkText(text, "sim") && talkState[7]) { talkState[7] = false; talkState[8] = true; msg << "Por favor, escolha entre um 'homem' ou uma 'mulher'."; } else if(talkState[8] && (checkText(text, "mulher") || checkText(text, "homem"))) { talkState[8] = false; talkState[9] = true; if(checkText(text, "mulher")) { msg << "Uma mulher, voce tem certeza?"; managerSex = PLAYERSEX_FEMALE; } else { msg << "Um homem, voce tem certeza?"; managerSex = PLAYERSEX_MALE; } } else if(checkText(text, "nao") && talkState[9]) { talkState[8] = true; talkState[9] = false; msg << "Diga-me... voce quer ser um 'homem' ou uma 'mulher'?"; } else if(checkText(text, "sim") && talkState[9]) { if(g_config.getBool(ConfigManager::START_CHOOSEVOC)) { talkState[9] = false; talkState[11] = true; bool firstPart = true; for(VocationsMap::iterator it = Vocations::getInstance()->getFirstVocation(); it != Vocations::getInstance()->getLastVocation(); ++it) { if(it->first == it->second->getFromVocation() && it->first != 0) { if(firstPart) { msg << "Voce quer ser... " << it->second->getDescription(); firstPart = false; } else if(it->first - 1 != 0) msg << ", " << it->second->getDescription(); else msg << " ou " << it->second->getDescription() << "."; } } } else if(!IOLoginData::getInstance()->playerExists(managerString, true)) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; if(IOLoginData::getInstance()->createCharacter(managerNumber, managerString, managerNumber2, (uint16_t)managerSex)) msg << "Seu personagem foi criado."; else msg << "Seu personagem nao pode ser criado, tente novamente."; } else { talkState[6] = true; talkState[9] = false; msg << "Ja existe um jogador com esse nome, por favor tente outro."; } } else if(talkState[11]) { for(VocationsMap::iterator it = Vocations::getInstance()->getFirstVocation(); it != Vocations::getInstance()->getLastVocation(); ++it) { std::string tmp = asLowerCaseString(it->second->getName()); if(checkText(text, tmp) && it != Vocations::getInstance()->getLastVocation() && it->first == it->second->getFromVocation() && it->first != 0) { msg << "Voce quer ser um " << it->second->getDescription() << "... correto?"; managerNumber2 = it->first; talkState[11] = false; talkState[12] = true; } } if(msg.str().length() == 17) msg << "Nao entendi o que voce pretende ser, pode dizer novamente por favor?"; } else if(checkText(text, "sim") && talkState[12]) { if(!IOLoginData::getInstance()->playerExists(managerString, true)) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; if(IOLoginData::getInstance()->createCharacter(managerNumber, managerString, managerNumber2, (uint16_t)managerSex)) msg << "Seu personagem foi criado."; else msg << "Seu personagem nao pode ser criado, tente novamente."; } else { talkState[6] = true; talkState[9] = false; msg << "Ja existe um jogador com esse nome, por favor tente outro."; } } else if(checkText(text, "nao") && talkState[12]) { talkState[11] = true; talkState[12] = false; msg << "Nao? Entao o que gostaria de ser?"; } else if(checkText(text, "chave de recuperacao") && talkState[1]) { talkState[1] = false; talkState[10] = true; msg << "Gostaria de uma chave de recuperacao?"; } else if(checkText(text, "sim") && talkState[10]) { if(account.recoveryKey != "0") msg << "Desculpe, voce ja tem uma chave de recuperacao, por motivos de seguranca nao posso fornecer-lhe outra."; else { managerString = generateRecoveryKey(4, 4); IOLoginData::getInstance()->setRecoveryKey(managerNumber, managerString); msg << "Sua chave de recuperacao e: " << managerString << "."; } talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; } else if(checkText(text, "nao") && talkState[10]) { msg << "Entao nao."; talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; } else msg << "Por favor, leia a última mensagem especificada, nao entendo o que quer dizer."; break; } case MANAGER_NEW: { if(checkText(text, "conta") && !talkState[1]) { msg << "Como gostaria que fosse sua senha?"; talkState[1] = true; talkState[2] = true; } else if(talkState[2]) { std::string tmp = text; trimString(tmp); if(tmp.length() < 6) msg << "Essa senha e pequena, por favor escolha uma maior."; else if(!isValidPassword(tmp)) msg << "Voce nao pode adicionar alguns símbolos em sua senha, por favor escolha outra."; else { talkState[3] = true; talkState[2] = false; managerString = tmp; msg << managerString << " e isso? 'sim' ou 'nao'?"; } } else if(checkText(text, "sim") && talkState[3]) { if(g_config.getBool(ConfigManager::GENERATE_ACCOUNT_NUMBER)) { do sprintf(managerChar, "%d%d%d%d%d%d%d", random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9)); while(IOLoginData::getInstance()->accountNameExists(managerChar)); uint32_t id = (uint32_t)IOLoginData::getInstance()->createAccount(managerChar, managerString); if(id) { accountManager = MANAGER_ACCOUNT; managerNumber = id; noSwap = talkState[1] = false; msg << "Sua conta foi criada e agora voce pode gerencia-la, lembre-se, sua conta e: '" << managerChar << "' e sua senha e: '" << managerString << "'! Se for difícil para voce decorar, anote em algum local."; } else msg << "Sua conta nao pode ser criada, tente novamente."; for(int8_t i = 2; i <= 5; i++) talkState[i] = false; } else { msg << "Como gostaria que fosse sua conta?"; talkState[3] = false; talkState[4] = true; } } else if(checkText(text, "nao") && talkState[3]) { talkState[2] = true; talkState[3] = false; msg << "Como gostaria que fosse sua senha?"; } else if(talkState[4]) { std::string tmp = text; trimString(tmp); if(tmp.length() < 3) msg << "Esse nome de conta e muito curto, utilize no mímimo 3 carateres. Por favor escolha um nome maior."; else if(tmp.length() > 25) msg << "Esse nome de conta e muito extenso, utilize no maximo 25 carateres. Por favor escolha um nome menor."; else if(!isValidAccountName(tmp)) msg << "Voce nao pode adicionar alguns símbolos no nome da sua conta."; else if(asLowerCaseString(tmp) == asLowerCaseString(managerString)) msg << "O nome da sua conta nao pode ser igual à sua senha."; else { sprintf(managerChar, "%s", tmp.c_str()); msg << managerChar << ", tem certeza?"; talkState[4] = false; talkState[5] = true; } } else if(checkText(text, "sim") && talkState[5]) { if(!IOLoginData::getInstance()->accountNameExists(managerChar)) { uint32_t id = (uint32_t)IOLoginData::getInstance()->createAccount(managerChar, managerString); if(id) { accountManager = MANAGER_ACCOUNT; managerNumber = id; noSwap = talkState[1] = false; msg << "Sua conta foi criada e agora voce pode gerencia-la, lembre-se, sua conta e: '" << managerChar << "' e sua senha e: '" << managerString << "'!"; } else msg << "Sua conta nao pode ser criada, tente novamente."; for(int8_t i = 2; i <= 5; i++) talkState[i] = false; } else { msg << "Uma conta com esse nome ja existe, por favor escolha outra."; talkState[4] = true; talkState[5] = false; } } else if(checkText(text, "nao") && talkState[5]) { talkState[5] = false; talkState[4] = true; msg << "Como gostaria que fosse o nome da sua conta?"; } else if(checkText(text, "recuperar") && !talkState[6]) { talkState[6] = true; talkState[7] = true; msg << "Qual o nome da sua conta?"; } else if(talkState[7]) { managerString = text; if(IOLoginData::getInstance()->getAccountId(managerString, (uint32_t&)managerNumber)) { talkState[7] = false; talkState[8] = true; msg << "Qual sua chave de recuperacao?"; } else { msg << "Sorry, but account with such name doesn't exists."; talkState[6] = talkState[7] = false; } } else if(talkState[8]) { managerString2 = text; if(IOLoginData::getInstance()->validRecoveryKey(managerNumber, managerString2) && managerString2 != "0") { sprintf(managerChar, "%s%d", g_config.getString(ConfigManager::SERVER_NAME).c_str(), random_range(100, 999)); IOLoginData::getInstance()->setPassword(managerNumber, managerChar); msg << "Correct! Your new password is: " << managerChar << "."; } else msg << "Sorry, but this key doesn't match to account you gave me."; talkState[7] = talkState[8] = false; } else msg << "Sorry, but I can't understand you, please try to repeat that."; break; } default: return; break; } sendTextMessage(MSG_STATUS_CONSOLE_BLUE, msg.str().c_str()); if(!noSwap) sendTextMessage(MSG_STATUS_CONSOLE_ORANGE, "Ola. Selecione 'conta' para gerencia-la ou 'cancelar' para cancelar."); } bool Player::isGuildInvited(uint32_t guildId) const { for(InvitedToGuildsList::const_iterator it = invitedToGuildsList.begin(); it != invitedToGuildsList.end(); ++it) { if((*it) == guildId) return true; } return false; } void Player::leaveGuild() { sendClosePrivate(CHANNEL_GUILD); #ifdef __WAR_SYSTEM__ warMap.clear(); g_game.updateCreatureEmblem(this); #endif guildLevel = GUILDLEVEL_NONE; guildId = rankId = 0; guildName = rankName = guildNick = std::string(); } bool Player::isPremium() const { if(g_config.getBool(ConfigManager::FREE_PREMIUM) || hasFlag(PlayerFlag_IsAlwaysPremium)) return true; return premiumDays; } bool Player::setGuildLevel(GuildLevel_t newLevel, uint32_t rank/* = 0*/) { std::string name; if(!IOGuild::getInstance()->getRankEx(rank, name, guildId, newLevel)) return false; guildLevel = newLevel; rankName = name; rankId = rank; return true; } void Player::setGroupId(int32_t newId) { if(Group* tmp = Groups::getInstance()->getGroup(newId)) { groupId = newId; group = tmp; } } void Player::setGroup(Group* newGroup) { if(!newGroup) return; group = newGroup; groupId = group->getId(); } PartyShields_t Player::getPartyShield(const Creature* creature) const { const Player* player = creature->getPlayer(); if(!player) return Creature::getPartyShield(creature); if(Party* party = getParty()) { if(party->getLeader() == player) { if(!party->isSharedExperienceActive()) return SHIELD_YELLOW; if(party->isSharedExperienceEnabled()) return SHIELD_YELLOW_SHAREDEXP; if(party->canUseSharedExperience(player)) return SHIELD_YELLOW_NOSHAREDEXP; return SHIELD_YELLOW_NOSHAREDEXP_BLINK; } if(party->isPlayerMember(player)) { if(!party->isSharedExperienceActive()) return SHIELD_BLUE; if(party->isSharedExperienceEnabled()) return SHIELD_BLUE_SHAREDEXP; if(party->canUseSharedExperience(player)) return SHIELD_BLUE_NOSHAREDEXP; return SHIELD_BLUE_NOSHAREDEXP_BLINK; } if(isInviting(player)) return SHIELD_WHITEBLUE; } if(player->isInviting(this)) return SHIELD_WHITEYELLOW; return SHIELD_NONE; } bool Player::isInviting(const Player* player) const { if(!player || player->isRemoved() || !party || party->getLeader() != this) return false; return party->isPlayerInvited(player); } bool Player::isPartner(const Player* player) const { return player && player->getParty() && player->getParty() == party; } bool Player::getHideHealth() const { if(hasFlag(PlayerFlag_HideHealth)) return true; return hideHealth; } void Player::sendPlayerIcons(Player* player) { sendCreatureShield(player); sendCreatureSkull(player); } bool Player::addPartyInvitation(Party* party) { if(!party) return false; PartyList::iterator it = std::find(invitePartyList.begin(), invitePartyList.end(), party); if(it != invitePartyList.end()) return false; invitePartyList.push_back(party); return true; } bool Player::removePartyInvitation(Party* party) { if(!party) return false; PartyList::iterator it = std::find(invitePartyList.begin(), invitePartyList.end(), party); if(it != invitePartyList.end()) { invitePartyList.erase(it); return true; } return false; } void Player::clearPartyInvitations() { if(invitePartyList.empty()) return; PartyList list; for(PartyList::iterator it = invitePartyList.begin(); it != invitePartyList.end(); ++it) list.push_back(*it); invitePartyList.clear(); for(PartyList::iterator it = list.begin(); it != list.end(); ++it) (*it)->removeInvite(this); } void Player::increaseCombatValues(int32_t& min, int32_t& max, bool useCharges, bool countWeapon) { if(min > 0) min = (int32_t)(min * vocation->getMultiplier(MULTIPLIER_HEALING)); else min = (int32_t)(min * vocation->getMultiplier(MULTIPLIER_MAGIC)); if(max > 0) max = (int32_t)(max * vocation->getMultiplier(MULTIPLIER_HEALING)); else max = (int32_t)(max * vocation->getMultiplier(MULTIPLIER_MAGIC)); Item* item = NULL; int32_t minValue = 0, maxValue = 0, i = SLOT_FIRST; for(; i < SLOT_LAST; ++i) { if(!(item = getInventoryItem((slots_t)i)) || item->isRemoved() || (g_moveEvents->hasEquipEvent(item) && !isItemAbilityEnabled((slots_t)i))) continue; const ItemType& it = Item::items[item->getID()]; if(min > 0) { minValue += it.abilities.increment[HEALING_VALUE]; if(it.abilities.increment[HEALING_PERCENT]) min = (int32_t)std::ceil((double)(min * it.abilities.increment[HEALING_PERCENT]) / 100.); } else { minValue -= it.abilities.increment[MAGIC_VALUE]; if(it.abilities.increment[MAGIC_PERCENT]) min = (int32_t)std::ceil((double)(min * it.abilities.increment[MAGIC_PERCENT]) / 100.); } if(max > 0) { maxValue += it.abilities.increment[HEALING_VALUE]; if(it.abilities.increment[HEALING_PERCENT]) max = (int32_t)std::ceil((double)(max * it.abilities.increment[HEALING_PERCENT]) / 100.); } else { maxValue -= it.abilities.increment[MAGIC_VALUE]; if(it.abilities.increment[MAGIC_PERCENT]) max = (int32_t)std::ceil((double)(max * it.abilities.increment[MAGIC_PERCENT]) / 100.); } bool removeCharges = false; for(int32_t j = INCREMENT_FIRST; j <= INCREMENT_LAST; ++j) { if(!it.abilities.increment[(Increment_t)j]) continue; removeCharges = true; break; } if(useCharges && removeCharges && (countWeapon || item != weapon) && item->hasCharges()) g_game.transformItem(item, item->getID(), std::max((int32_t)0, (int32_t)item->getCharges() - 1)); } min += minValue; max += maxValue; } bool Player::transferMoneyTo(const std::string& name, uint64_t amount) { if(!g_config.getBool(ConfigManager::BANK_SYSTEM) || amount > balance) return false; Player* target = g_game.getPlayerByNameEx(name); if(!target) return false; balance -= amount; target->balance += amount; if(target->isVirtual()) { IOLoginData::getInstance()->savePlayer(target); delete target; } return true; } void Player::sendCritical() const { if(g_config.getBool(ConfigManager::DISPLAY_CRITICAL_HIT)) g_game.addAnimatedText(getPosition(), COLOR_DARKRED, "CRITICO!"); } Skype @kaiquegabriel__ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Atenciosamente, kaiquegabriel. Não dou suporte via pm. Em caso de dúvidas, crie um tópico e espere o suporte.
Postado Outubro 21, 2014 10 anos O tópico foi movido para a área correta, preste mais atenção da próxima vez! Leia as regras do fórum: http://tibiaking.com/forum/topic/1281-regras-gerais/?p=7680 Este tópico foi movido: De: "OTServ → Suporte OTServ → Suporte de Scripts" Para: "OTServ → Suporte OTServ → Suporte de Programação" Todos os meus trabalhos importantes estão na seção "Sobre mim" no meu perfil; Dá uma passada lá! "Há três caminhos para o fracasso: não ensinar o que se sabe, não praticar o que se ensina, e não perguntar o que se ignora." - São Beda (obg ao @Beeny por fazer essa linda sign <3)
Postado Outubro 21, 2014 10 anos Solução Se for mexer em C/C++ aprenda pelo menos o basico ... Mude isso: sprintf(buffer, "Voce perdeu %d ponto de vida pelo ataque de um %s.", damage, (damage != 1 ? "s" : ""), attacker->getNameDescription().c_str()); else sprintf(buffer, "Voce perdeu %d ponto de vida.", damage, (damage != 1 ? "s" : "")); Para isso: sprintf(buffer, "Voce perdeu %d ponto%s de vida pelo ataque de um %s.", damage, (damage != 1 ? "s" : ""), attacker->getNameDescription().c_str()); else sprintf(buffer, "Voce perdeu %d ponto%s de vida.", damage, (damage != 1 ? "s" : "")); Bjs gatu! STYLLER OT 2022
Participe da conversa
Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.