Ir para conteúdo
  • Cadastre-se

(Resolvido)Erro player.cpp


Ir para solução Resolvido por luanluciano93,

Posts Recomendados

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.

Link para o post
Compartilhar em outros sites

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: "OTServSuporte OTServSuporte de Scripts"

Para: "OTServSuporte OTServSuporte 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

I7Pm6ih.png

(obg ao @Beeny por fazer essa linda sign <3)

Link para o post
Compartilhar em outros sites
  • Solução

Se for mexer em C/C++ aprenda pelo menos o basico ...  ;D 

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!

Link para o post
Compartilhar em outros sites

Participe da conversa

Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.

Visitante
Responder

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emojis são permitidos.

×   Seu link foi automaticamente incorporado.   Mostrar como link

×   Seu conteúdo anterior foi restaurado.   Limpar o editor

×   Não é possível colar imagens diretamente. Carregar ou inserir imagens do URL.

  • Quem Está Navegando   0 membros estão online

    Nenhum usuário registrado visualizando esta página.


  • Conteúdo Similar

    • Por Doria Louro
      Olá senhores.
       
      Gostaria de uma ajuda com um script de summon que venho trabalhando no momento, gostaria que o summon andasse do lado do jogador, entretanto o mesmo sempre fica para trás ou a frente do jogador.
      Efetuei a alteração na source creature.cpp:
       
      void Creature::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const { fpp.fullPathSearch = !hasFollowPath; fpp.clearSight = true; if(creature->isPlayerSummon()) { if(creature->getName() == "Summon Name") fpp.clearSight = false; } fpp.maxSearchDist = 12; fpp.minTargetDist = fpp.maxTargetDist = 1; }  
      fpp.maxTargetDist = 1;
      Porém ele sempre mantem 1 de distancia do jogador, alterando para zero o "Zero" summon nem segue o jogador.
      Resultado:

       
      Agradeço desde já.
    • Por Imperius
      O propósito é criar uma nova função em creaturescripts que será acionada toda vez que um novo report (CTRL + R) for aberto.
       
      Eu implementei para enviar uma notificação no grupo do Telegram, contendo os dados do report.
       
      Isso garantirá que os GMs tenham acesso aos reports dos jogadores mesmo quando não estiverem logados, e também evitará que algum report seja perdido caso o jogador saia do servidor.
      A parte do Telegram é apenas um exemplo. Você pode ajustar o script para executar outras ações desejadas.
       
      creatureevent.cpp:
      Dentro deste arquivo, localize a função:
       
      uint32_t CreatureEvent::executeChannelLeave(Player* player, uint16_t channelId, UsersMap usersMap)  
      abaixo dela, adicione:
       
      uint32_t CreatureEvent::executeOpenRuleViolation(Player* player, std::string message) { if (!m_interface->reserveEnv()) { std::clog << "[Error - CreatureEvent::executeOpenRuleViolation] Call stack overflow." << std::endl; return 0; } ScriptEnviroment* env = m_interface->getEnv(); env->setScriptId(m_scriptId, m_interface); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(player)); lua_pushstring(L, message.c_str()); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; }  
      Após, procure por:
       
      std::string CreatureEvent::getScriptEventName() const  
      abaixo de:
       
      case CREATURE_EVENT_CHANNEL_LEAVE: return "onLeaveChannel";  
      adicione:
       
      case CREATURE_EVENT_OPEN_RULE_VIOLATION: return "onOpenRuleViolation";  
      Agora, procure por:
       
      std::string CreatureEvent::getScriptEventParams() const  
      abaixo de:
       
      case CREATURE_EVENT_CHANNEL_LEAVE: return "cid, channel, users";  
      adicione:
       
      case CREATURE_EVENT_OPEN_RULE_VIOLATION: return "cid, message";  
      Procure por:
       
      bool CreatureEvent::configureEvent(xmlNodePtr p)  
      abaixo de:
       
      else if(tmpStr == "leavechannel") m_type = CREATURE_EVENT_CHANNEL_LEAVE;  
      adicione:
       
      else if(tmpStr == "openruleviolation") m_type = CREATURE_EVENT_OPEN_RULE_VIOLATION;  
       
      creatureevent.h:
      Dentro deste arquivo, localize:
       
      enum CreatureEventType_t  
      adicione "CREATURE_EVENT_OPEN_RULE_VIOLATION" como o último item de enum CreatureEventType_t
       
      Exemplo:
       
      enum CreatureEventType_t { // ... CREATURE_EVENT_OPEN_RULE_VIOLATION };  
      Agora, procure por:
       
      uint32_t executeChannelLeave(Player* player, uint16_t channelId, UsersMap usersMap);  
      abaixo dela, adicione:
       
      uint32_t executeOpenRuleViolation(Player* player, std::string message);  
      game.cpp:
      Dentro deste arquivo, localize:
       
      bool Game::playerReportRuleViolation(Player* player, const std::string& text)  
      e substitua por:
       
      bool Game::playerReportRuleViolation(Player* player, const std::string& text) { //Do not allow reports on multiclones worlds since reports are name-based if(g_config.getNumber(ConfigManager::ALLOW_CLONES)) { player->sendTextMessage(MSG_INFO_DESCR, "Rule violation reports are disabled."); return false; } cancelRuleViolation(player); boost::shared_ptr<RuleViolation> rvr(new RuleViolation(player, text, time(NULL))); ruleViolations[player->getID()] = rvr; ChatChannel* channel = g_chat.getChannelById(CHANNEL_RVR); if(!channel) return false; for(UsersMap::const_iterator it = channel->getUsers().begin(); it != channel->getUsers().end(); ++it) it->second->sendToChannel(player, SPEAK_RVR_CHANNEL, text, CHANNEL_RVR, rvr->time); CreatureEventList joinEvents = player->getCreatureEvents(CREATURE_EVENT_OPEN_RULE_VIOLATION); for(CreatureEventList::iterator it = joinEvents.begin(); it != joinEvents.end(); ++it) (*it)->executeOpenRuleViolation(player, text); return true; }  
      Agora é só compilar a source.
       
      depois em "data > creaturescripts > creaturescripts.xml", adicione:
       
      <event type="login" name="loginNotifyRuleViolation" script="notifyRuleViolation.lua"/> <event type="openruleviolation" name="openNotifyRuleViolation" script="notifyRuleViolation.lua"/>  
      em "data > creaturescripts > scripts", crie um arquivo notifyRuleViolation.lua e adicione:
       
      function onOpenRuleViolation(cid, message) local config = { token = "", -- Token do seu BOT no Telegram chatId = "" -- ID do chat do Telegram que será enviado a notificação. } local message = "Player: "..getCreatureName(cid).."\n\nReport:\n"..message.."" message = string.gsub(message, "\n", "%%0A") local url = "https://api.telegram.org/bot"..config.token.."/sendMessage" local data = "chat_id="..config.chatId.."&text="..message.."" local curl = io.popen('curl -d "'..data..'" "'..url..'"'):read("*a") return true end function onLogin(cid) registerCreatureEvent(cid, "openNotifyRuleViolation") return true end  
       
      Demonstração:
      1. Jogador abre um novo report (CTRL + R)

      2. notifyRuleViolation.lua, definido em creaturescripts.xml, é acionado para enviar uma notificação ao grupo do Telegram.
       

       
    • Por FeeTads
      SALVE rapaziada do TK, esses dias vim pensando em novos scripts pro meu OT, e em um deles eu precisava que determinada area não contasse frag pro player que matasse outros, PORÉM eu precisava que os players que morressem nessa area ainda assim tivessem as penalidades da sua morte, procurei por ai, achei alguns scripts que apenas tiravam o SKULL e não realmente o FRAG do player.

      **script atualizado 22/10/2023** - melhorado e otimizado, levei o script pra puxar as infos por .lua / creatureScripts

      vou disponibilizar o code aqui, e o que fazer pra determinada area não contar frag.

      SOURCE OTX 2 / TFS 0.x, Funciona em TFS 1.x mudando as tags e ajeitando as sintaxes.

      vá em creatureevent.cpp

      procure por:
      else if(type == "preparedeath") _type = CREATURE_EVENT_PREPAREDEATH;
      Adiciona abaixo:
      else if(type == "nocountfrag") _type = CREATURE_EVENT_NOCOUNTFRAG;

      procure por:
      case CREATURE_EVENT_PREPAREDEATH: return "onPrepareDeath";  
      Adicione abaixo: 
      case CREATURE_EVENT_NOCOUNTFRAG: return "noCountFragArea";

      procure por:
      case CREATURE_EVENT_PREPAREDEATH: return "cid, deathList";
      Adicione abaixo:
      case CREATURE_EVENT_NOCOUNTFRAG: return "cid, target";

      agora no mesmo arquivo, vá até o final do arquivo e adicione essa função:
      uint32_t CreatureEvent::executeNoCountFragArea(Creature* creature, Creature* target) { //noCountFragArea(cid, target) if(m_interface->reserveEnv()) { ScriptEnviroment* env = m_interface->getEnv(); if(m_scripted == EVENT_SCRIPT_BUFFER) { env->setRealPos(creature->getPosition()); std::ostringstream scriptstream; scriptstream << "local cid = " << env->addThing(creature) << std::endl; scriptstream << "local target = " << env->addThing(target) << std::endl; if(m_scriptData) scriptstream << *m_scriptData; bool result = true; if(m_interface->loadBuffer(scriptstream.str())) { lua_State* L = m_interface->getState(); result = m_interface->getGlobalBool(L, "_result", true); } m_interface->releaseEnv(); return result; } else { #ifdef __DEBUG_LUASCRIPTS__ std::ostringstream desc; desc << creature->getName(); env->setEvent(desc.str()); #endif env->setScriptId(m_scriptId, m_interface); env->setRealPos(creature->getPosition()); lua_State* L = m_interface->getState(); m_interface->pushFunction(m_scriptId); lua_pushnumber(L, env->addThing(creature)); lua_pushnumber(L, env->addThing(target)); bool result = m_interface->callFunction(2); m_interface->releaseEnv(); return result; } } else { std::clog << "[Error - CreatureEvent::noCountFragArea] Call stack overflow." << std::endl; return 0; } }

      agora vá em creatureevent.h

      procure por:
      CREATURE_EVENT_PREPAREDEATH
      adicione abaixo:
      CREATURE_EVENT_NOCOUNTFRAG

      procure por:
      uint32_t executePrepareDeath(Creature* creature, DeathList deathList);
      Adicione abaixo:
      uint32_t executeNoCountFragArea(Creature* creature, Creature* target);

      agora vá em player.cpp

      procure por:
      bool Player::onKilledCreature(Creature* target, DeathEntry& entry)
      abaixo de:
      War_t enemy; if(targetPlayer->getEnemy(this, enemy)) { if(entry.isLast()) IOGuild::getInstance()->updateWar(enemy); entry.setWar(enemy); }
      Adicione o seguinte código:
      if (targetPlayer){ CreatureEventList killEvents = getCreatureEvents(CREATURE_EVENT_NOCOUNTFRAG); for (const auto &event : killEvents) { if (!event->executeNoCountFragArea(this, target)) { return true; } } }

      //

      Feito isso, tudo completo na sua source, agora é necessário adicionar o creaturescript dentro do servidor

      vá até creaturescripts/scripts
      crie um arquivo chamado, "noCountFragInArea.lua"
      e dentro dele cole o código:
       
      --[[ script feito por feetads / TibiaKing ]]-- --[[ discord: feetads / FeeTads#0246 ]]-- -- Add positions here for which you do not want to count frags local areas = { [1] = {from = {x = 91, y = 122, z = 7}, to = {x = 98, y = 127, z = 7}}, -- from = area superior esquerda / to = area inferior direita (formando um quadrado) } local onlyKillerInArea = false -- only killer need to be in area? function noCountFragArea(cid, target) if not isCreature(cid) or not isCreature(target) then return true end local posKiller = getPlayerPosition(cid) local posTarget = getPlayerPosition(target) for i = 1, #areas do local area = areas[i] if isInArea(posKiller, area.from, area.to) then if onlyKillerInArea then return false elseif isInArea(posTarget, area.from, area.to) then return false end end end return true end
      agora em creaturescripts.xml
      <event type="nocountfrag" name="fragarea" event="script" value="noCountFragInArea.lua"/>
      agora em creaturescripts/scripts/login.lua
       procure por OU semelhante a esse:
      registerCreatureEvent(cid, "AdvanceSave")
      e abaixo adicione:
      registerCreatureEvent(cid, "fragarea")

      //


      Agora tudo certo, quando quiser adiciona uma area que não pega frag, vá até o script e apenas coloque a area, igual o demonstrado no script

      Exemplo:
      local areas = { [1] = {from = {x = 91, y = 122, z = 7}, to = {x = 98, y = 127, z = 7}}, [2] = {from = {x = 1000, y = 1000, z = 7}, to = {x = 1100, y = 1100, z = 7}}, }
      assim somente colocando a area no script e abrindo o server ou dando /reload, já funcionará a area como não pegar frag.
      Esse sistema pode ser bom pra areas de pvp ativo, onde você ainda quer que o player que morrer perca os atributos, como se fosse uma morte normal, porém não conta frag pra quem matar.
      Bom pra sistemas tipo castle 48h (guild war), onde há diversas mortes e risco de pegar red, atrapalhando a war.

      Façam bom proveito dos scripts, e deixem os créditos no script rsrs

      **Eu fiz as alterações e o simples código por isso vim disponibilizar, créditos meus**
    • Por Mateus Robeerto
      Para quem deseja utilizar o 'IncreaseMagicPercent' no arquivo items.xml, que aumenta o dano mágico em porcentagem
       
       
      No arquivo game.cpp
      depois.
      Player* attackerPlayer; if (attacker) { attackerPlayer = attacker->getPlayer(); } else { attackerPlayer = nullptr; } Player* targetPlayer = target->getPlayer(); if (attackerPlayer && targetPlayer && attackerPlayer->getSkull() == SKULL_BLACK && attackerPlayer->getSkullClient(targetPlayer) == SKULL_NONE) { return false; } damage.primary.value = std::abs(damage.primary.value); damage.secondary.value = std::abs(damage.secondary.value); int32_t healthChange = damage.primary.value + damage.secondary.value; if (healthChange == 0) { return true; } adicionar
      // Inc Magic by lursky auto originList = { ORIGIN_RANGED, ORIGIN_MELEE, ORIGIN_CONDITION }; auto it = std::find(originList.begin(), originList.end(), damage.origin); if (attackerPlayer && it == originList.end()) { int32_t magicPercentBonus = 0; for (int32_t slot = CONST_SLOT_FIRST; slot <= CONST_SLOT_LAST; ++slot) { Item* item = attackerPlayer->inventory[slot]; if (item) { const ItemType& iiType = Item::items[item->getID()]; const int32_t& slotPosition = item->getSlotPosition(); if (iiType.increaseMagicPercent && (iiType.slotPosition & slotPosition)) { magicPercentBonus += iiType.increaseMagicPercent; } } } if (magicPercentBonus > 0) { damage.primary.value += damage.primary.value * (magicPercentBonus / 100.0f); } } No arquivo item.cpp
       
      post edit: Deve ter colocado duas vezes, ok? É só procurar no item.cpp essa linha e adicionar. Repita a busca pela mesma linha e adicione para exibir 'inc magic'. Pronto 

      depois.
      if (it.abilities) { for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; i++) { if (!it.abilities->skills[i]) { continue; } if (begin) { begin = false; s << " ("; } else { s << ", "; } s << getSkillName(i) << ' ' << std::showpos << it.abilities->skills[i] << std::noshowpos; } adicionar.
      if (it.increaseMagicPercent) { if (begin) { begin = false; s << " ("; } else { s << ", "; } s << "Inc.Magic " << std::showpos << it.increaseMagicPercent << '%' << std::noshowpos; } No arquivo items.cpp
      depois.
      {"worth", ITEM_PARSE_WORTH}, adicionar:
      { "increasemagicpercent", ITEM_PARSE_INCREASEMAGICPERCENT }, Novamente, no arquivo items.cpp:
      depois.
      case ITEM_PARSE_SUPPRESSCURSE: { if (valueAttribute.as_bool()) { abilities.conditionSuppressions |= CONDITION_CURSED; } break; } adicionar.
      case ITEM_PARSE_INCREASEMAGICPERCENT: { it.increaseMagicPercent = pugi::cast<int32_t>(valueAttribute.value()); break; } No arquivo items.h
      depois.
      uint64_t worth = 0; adicionar.
      int32_t increaseMagicPercent = 0; Novamente, no arquivo items.h:
      after.
      ITEM_PARSE_WORTH, adicionar:
      ITEM_PARSE_INCREASEMAGICPERCENT, FIM
      É só recompilar e testar
      Como funciona usar esses atributos? Veja aqui um exemplo
      item id="xxx" name="teste robe"> <attribute key="weight" value="7100"/> <attribute key="armor" value="18"/> <attribute key="slotType" value="body"/> <attribute key="increaseMagicPercent" value="50"/> </item>  
      Obs: Esses adições na source foram feitas por Mateus Roberto, e Lurskcy fez uma correção de erro que estava causando um .crash no arquivo games.cpp. Está funcionando bem.
       
      Espero que gostem
    • Por L3K0T
      Olá pessoal! Vamos resolver esse problema dos monstros não passarem por cima de outros corpse para te atacarem... Trata-se de uma pequena modificação no rev3777 tfs 0.4, um bug comum nesse TFS. Aqui está a alteração que fiz para que funcione!
       
      Tile.cpp:
       
      if(!creature->canWalkthrough(*cit))
      return NOTPOSSIBLE; //NOTPOSSIBLE
       
      Mude para:
       
      if (!creature->canWalkthrough(*cit) && (!cit->isCreature() || cit->isCorpse()))
          return NOTPOSSIBLE; // NOTPOSSIBLE
       
      Após isso, exclua todo o conteúdo da pasta "obj" e compile novamente. Pronto, o problema estará resolvido!
      Créditos para mim, @L3K0T
×
×
  • Criar Novo...

Informação Importante

Confirmação de Termo