ReturnValue Tile::__queryAdd(int32_t, const Thing* thing, uint32_t,
uint32_t flags) const
{
const CreatureVector* creatures = getCreatures();
const TileItemVector* items = getItemList();
if(const Creature* creature = thing->getCreature())
{
if(hasBitSet(FLAG_NOLIMIT, flags))
return RET_NOERROR;
if(hasBitSet(FLAG_PATHFINDING, flags))
{
if(floorChange() || positionChange())
return RET_NOTPOSSIBLE;
}
if(!ground)
return RET_NOTPOSSIBLE;
if(const Monster* monster = creature->getMonster())
{
if(hasFlag(TILESTATE_PROTECTIONZONE))
return RET_NOTPOSSIBLE;
if(floorChange() || positionChange())
return RET_NOTPOSSIBLE;
if(monster->canPushCreatures() && !monster->isSummon())
{
if(creatures && !creatures->empty())
{
Creature* tmp = NULL;
for(uint32_t i = 0; i < creatures->size(); ++i)
{
tmp = creatures->at(i);
if(creature->canWalkthrough(tmp))
continue;
if(!tmp->getMonster() || !tmp->isPushable() || tmp->isPlayerSummon())
return RET_NOTPOSSIBLE;
}
}
}
else if(creatures && !creatures->empty())
{
for(CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
{
if(!creature->canWalkthrough(*cit))
return RET_NOTENOUGHROOM; //NOTPOSSIBLE
}
}
if(hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID))
return RET_NOTPOSSIBLE;
if(hasBitSet(FLAG_PATHFINDING, flags) && hasFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH))
return RET_NOTPOSSIBLE;
if((hasFlag(TILESTATE_BLOCKSOLID) || (hasBitSet(FLAG_PATHFINDING, flags) && hasFlag(TILESTATE_NOFIELDBLOCKPATH)))
&& (!(monster->canPushItems() || hasBitSet(FLAG_IGNOREBLOCKITEM, flags))))
return RET_NOTPOSSIBLE;
if(!items) // Do not seek for fields if there are no items
return RET_NOERROR;
MagicField* field = getFieldItem();
if(!field)
return RET_NOERROR;
if(field->isBlocking(creature))
return RET_NOTPOSSIBLE;
CombatType_t combatType = field->getCombatType();
//There is 3 options for a monster to enter a magic field
//1) Monster is immune
if(monster->isImmune(combatType))
return RET_NOERROR;
//1) Monster is "strong" enough to handle the damage
//2) Monster is already afflicated by this type of condition
if(!hasBitSet(FLAG_IGNOREFIELDDAMAGE, flags))
return RET_NOTPOSSIBLE;
return !monster->hasCondition(Combat::DamageToConditionType(combatType), -1, false)
&& !monster->canPushItems() ? RET_NOTPOSSIBLE : RET_NOERROR;
}
if(const Player* player = creature->getPlayer())
{
if(creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags))
{
for(CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
{
if(!creature->canWalkthrough(*cit))
return RET_NOTENOUGHROOM; //NOTPOSSIBLE
}
}
if(!player->getParent() && hasFlag(TILESTATE_NOLOGOUT)) //player is trying to login to a "no logout" tile
return RET_NOTPOSSIBLE;
if(player->isPzLocked() && !player->getTile()->hasFlag(TILESTATE_HARDCOREZONE) && hasFlag(TILESTATE_HARDCOREZONE)) //player is trying to enter a pvp zone while being pz-locked
return RET_PLAYERISPZLOCKEDENTERPVPZONE;
if(player->isPzLocked() && player->getTile()->hasFlag(TILESTATE_HARDCOREZONE) && !hasFlag(TILESTATE_HARDCOREZONE)) //player is trying to leave a pvp zone while being pz-locked
return RET_PLAYERISPZLOCKEDLEAVEPVPZONE;
if(hasFlag(TILESTATE_OPTIONALZONE) && player->isPzLocked())
return RET_PLAYERISPZLOCKED;
if(hasFlag(TILESTATE_PROTECTIONZONE) && player->isPzLocked())
return RET_PLAYERISPZLOCKED;
}
else if(creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags))
{
for(CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
{
if(!creature->canWalkthrough(*cit))
return RET_NOTENOUGHROOM; //NOTPOSSIBLE
}
}
if(items)
{
MagicField* field = getFieldItem();
if(field && field->isBlocking(creature))
return RET_NOTPOSSIBLE;
if(hasBitSet(FLAG_IGNOREBLOCKITEM, flags)) //if the FLAG_IGNOREBLOCKITEM bit isn't set we dont have to iterate every single item
{
//FLAG_IGNOREBLOCKITEM is set
if(ground)
{
const ItemType& iType = Item::items[ground->getID()];
if(ground->isBlocking(creature) && (!iType.moveable || (ground->isLoadedFromMap() &&
(ground->getUniqueId() || (ground->getActionId() && ground->getContainer())))))
return RET_NOTPOSSIBLE;
}
if(const TileItemVector* items = getItemList())
{
for(ItemVector::const_iterator it = items->begin(); it != items->end(); ++it)
{
const ItemType& iType = Item::items[(*it)->getID()];
if((*it)->isBlocking(creature) && (!iType.moveable || ((*it)->isLoadedFromMap() &&
((*it)->getUniqueId() || ((*it)->getActionId() && (*it)->getContainer())))))
return RET_NOTPOSSIBLE;
}
}
}
else if(hasFlag(TILESTATE_BLOCKSOLID))
return RET_NOTPOSSIBLE;
}
}
else if(const Item* item = thing->getItem())
{
#ifdef __DEBUG__
if(thing->getParent() == NULL && !hasBitSet(FLAG_NOLIMIT, flags))
std::clog << "[Notice - Tile::__queryAdd] thing->getParent() == NULL" << std::endl;
#endif
if(items && items->size() >= 0xFFFF)
return RET_NOTPOSSIBLE;
if(hasBitSet(FLAG_NOLIMIT, flags))
return RET_NOERROR;
bool itemIsHangable = item->isHangable();
if(!ground && !itemIsHangable)
return RET_NOTPOSSIBLE;
if(creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags))
{
for(CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit)
{
if(!(*cit)->isGhost() && item->isBlocking(*cit))
return RET_NOTENOUGHROOM; //NOTPOSSIBLE
}
}
const uint32_t itemLimit = g_config.getNumber(
hasFlag(TILESTATE_PROTECTIONZONE) ? ConfigManager::PROTECTION_TILE_LIMIT : ConfigManager::TILE_LIMIT);
if(itemLimit && getThingCount() > itemLimit)
return RET_TILEISFULL;
bool hasHangable = false, supportHangable = false;
if(items)
{
Thing* iThing = NULL;
for(uint32_t i = 0; i < getThingCount(); ++i)
{
iThing = __getThing(i);
if(const Item* iItem = iThing->getItem())
{
const ItemType& iType = Item::items[iItem->getID()];
if(iType.isHangable)
hasHangable = true;
if(iType.isHorizontal || iType.isVertical)
supportHangable = true;
if(itemIsHangable && (iType.isHorizontal || iType.isVertical))
continue;
else if(iItem->isBlocking(NULL))
{
if(!item->isPickupable())
return RET_NOTPOSSIBLE;
if(iType.allowPickupable)
continue;
if(!iType.hasHeight || iType.pickupable || iType.isBed())
return RET_NOTPOSSIBLE;
}
}
}
}
if(itemIsHangable && hasHangable && supportHangable)
return RET_NEEDEXCHANGE;
}
return RET_NOERROR;
}