Cylinder* Tile::__queryDestination(int32_t& index, const Thing* thing, Item** destItem, uint32_t& flags) { Tile* destTile = NULL; *destItem = NULL; if(floorChangeDown()){ int dx = getTilePosition().x; int dy = getTilePosition().y; int dz = getTilePosition().z + 1; Tile* downTile = g_game.getTile(dx, dy, dz); if(downTile){ if(downTile->floorChange(NORTH)) dy += 1; if(downTile->floorChange(SOUTH)) dy -= 1; if(downTile->floorChange(EAST)) dx -= 1; if(downTile->floorChange(WEST)) dx += 1; destTile = g_game.getTile(dx, dy, dz); } } else if(floorChange()){ int dx = getTilePosition().x; int dy = getTilePosition().y; int dz = getTilePosition().z - 1; if(floorChange(NORTH)) dy -= 1; if(floorChange(SOUTH)) dy += 1; if(floorChange(EAST)) dx += 1; if(floorChange(WEST)) dx -= 1; destTile = g_game.getTile(dx, dy, dz); } if(destTile == NULL){ destTile = this; } else{ flags |= FLAG_NOLIMIT; //Will ignore that there is blocking items/creatures } if(destTile){ Thing* destThing = destTile->getTopDownItem(); if(destThing) *destItem = destThing->getItem(); } return destTile; }
ReturnValue Tile::__queryAdd(int32_t index, const Thing* thing, uint32_t count, 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) { Creature* creature; for (uint32_t i = 0; i < creatures->size(); ++i) { creature = creatures->at(i); if (monster->canWalkthrough(creature)) { continue; } if (!creature->getMonster() || !creature->isPushable() || (creature->getMonster()->isPlayerSummon())) { return RET_NOTPOSSIBLE; } } } } else if (creatures && !creatures->empty()) { for (CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit) { if (!monster->canWalkthrough(*cit)) { return RET_NOTENOUGHROOM; } } } 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))) { if (!(monster->canPushItems() || hasBitSet(FLAG_IGNOREBLOCKITEM, flags))) { return RET_NOTPOSSIBLE; } } MagicField* field = getFieldItem(); if (field && !field->isBlocking(monster)) { CombatType_t combatType = field->getCombatType(); //There are 3 options for a monster to enter a magic field //1) Monster is immune if (!monster->isImmune(combatType)) { //2) Monster is "strong" enough to handle the damage and was attacked //3) Monster is already afflicated by this type of condition if (hasBitSet(FLAG_IGNOREFIELDDAMAGE, flags)) { if (!monster->hasCondition(Combat::DamageToConditionType(combatType), false)) { if (!monster->canPushItems() || !monster->hadRecentBattle()) { return RET_NOTPOSSIBLE; } } } else { return RET_NOTPOSSIBLE; } } } } else 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 (!player->canWalkthrough(*cit)) { return RET_NOTENOUGHROOM; //RET_NOTPOSSIBLE } } } if (!player->getParent() && hasFlag(TILESTATE_NOLOGOUT)) { //player is trying to login to a "no logout" tile return RET_NOTPOSSIBLE; } if (player->getTile()) { if (player->isPzLocked() && !player->getTile()->hasFlag(TILESTATE_PVPZONE) && hasFlag(TILESTATE_PVPZONE)) { //player is trying to enter a pvp zone while being pz-locked return RET_PLAYERISPZLOCKEDENTERPVPZONE; } if (player->isPzLocked() && player->getTile()->hasFlag(TILESTATE_PVPZONE) && !hasFlag(TILESTATE_PVPZONE)) { //player is trying to leave a pvp zone while being pz-locked return RET_PLAYERISPZLOCKEDLEAVEPVPZONE; } } if (hasFlag(TILESTATE_NOPVPZONE) && 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; } } } } 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 if (hasFlag(TILESTATE_BLOCKSOLID)) { return RET_NOTENOUGHROOM; } } else { //FLAG_IGNOREBLOCKITEM is set if (ground) { const ItemType& iiType = Item::items[ground->getID()]; if (ground->isBlocking(creature) && (!iiType.moveable || ground->getUniqueId() != 0)) { return RET_NOTPOSSIBLE; } } if (const TileItemVector* items = getItemList()) { Item* iitem; for (ItemVector::const_iterator it = items->begin(); it != items->end(); ++it) { iitem = (*it); const ItemType& iiType = Item::items[iitem->getID()]; if (iitem->isBlocking(creature) && (!iiType.moveable || iitem->getUniqueId() != 0)) { return RET_NOTPOSSIBLE; } } } } } } else if (const Item* item = thing->getItem()) { #ifdef __DEBUG__ if (!thing->getParent() && !hasBitSet(FLAG_NOLIMIT, flags)) { std::cout << "Notice: Tile::__queryAdd() - thing->getParent() == NULL" << std::endl; } #endif if (items) { int64_t c = g_config.getNumber(ConfigManager::MAX_STACK_SIZE); //acceptable stack sizes should be higher than 100 and <= than 65535 uint16_t max_stack_size = uint16_t(std::max(std::min(c, int64_t(0xFFFF)), int64_t(100))); if (items->size() >= max_stack_size) { 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)->getPlayer() || !(*cit)->getPlayer()->hasSomeInvisibilityFlag()) && item->isBlocking(*cit)) { return RET_NOTENOUGHROOM; } } } 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; bool supportHangable = false; if (items) { Thing* iithing = NULL; for (uint32_t i = 0; i < getThingCount(); ++i) { iithing = __getThing(i); if (const Item* iitem = iithing->getItem()) { const ItemType& iiType = Item::items[iitem->getID()]; if (iiType.isHangable) { hasHangable = true; } if (iiType.isHorizontal || iiType.isVertical) { supportHangable = true; } if (itemIsHangable && (iiType.isHorizontal || iiType.isVertical)) { // } else if (iiType.blockSolid || iiType.isSolidForItems()) { if (item->isPickupable()) { if (iiType.allowPickupable) { continue; } if (!iiType.hasHeight || iiType.pickupable || iiType.isBed()) { return RET_NOTENOUGHROOM; } } else { return RET_NOTENOUGHROOM; } } } } } if (itemIsHangable && hasHangable && supportHangable) { return RET_NEEDEXCHANGE; } } return RET_NOERROR; }
Tile* Tile::queryDestination(int32_t&, const Thing&, Item** destItem, uint32_t& flags) { Tile* destTile = nullptr; *destItem = nullptr; if (floorChangeDown()) { uint16_t dx = tilePos.x; uint16_t dy = tilePos.y; uint8_t dz = tilePos.z + 1; Tile* southDownTile = g_game.map.getTile(dx, dy - 1, dz); if (southDownTile && southDownTile->floorChange(DIRECTION_SOUTH_ALT)) { dy -= 2; destTile = g_game.map.getTile(dx, dy, dz); } else { Tile* eastDownTile = g_game.map.getTile(dx - 1, dy, dz); if (eastDownTile && eastDownTile->floorChange(DIRECTION_EAST_ALT)) { dx -= 2; destTile = g_game.map.getTile(dx, dy, dz); } else { Tile* downTile = g_game.map.getTile(dx, dy, dz); if (downTile) { if (downTile->floorChange(DIRECTION_NORTH)) { ++dy; } if (downTile->floorChange(DIRECTION_SOUTH)) { --dy; } if (downTile->floorChange(DIRECTION_SOUTH_ALT)) { dy -= 2; } if (downTile->floorChange(DIRECTION_EAST)) { --dx; } if (downTile->floorChange(DIRECTION_EAST_ALT)) { dx -= 2; } if (downTile->floorChange(DIRECTION_WEST)) { ++dx; } destTile = g_game.map.getTile(dx, dy, dz); } } } } else if (floorChange()) { uint16_t dx = tilePos.x; uint16_t dy = tilePos.y; uint8_t dz = tilePos.z - 1; if (floorChange(DIRECTION_NORTH)) { --dy; } if (floorChange(DIRECTION_SOUTH)) { ++dy; } if (floorChange(DIRECTION_EAST)) { ++dx; } if (floorChange(DIRECTION_WEST)) { --dx; } if (floorChange(DIRECTION_SOUTH_ALT)) { dy += 2; } if (floorChange(DIRECTION_EAST_ALT)) { dx += 2; } destTile = g_game.map.getTile(dx, dy, dz); } if (destTile == nullptr) { destTile = this; } else { flags |= FLAG_NOLIMIT; //Will ignore that there is blocking items/creatures } if (destTile) { Thing* destThing = destTile->getTopDownItem(); if (destThing) { *destItem = destThing->getItem(); } } return destTile; }
ReturnValue Tile::queryAdd(int32_t, const Thing& thing, uint32_t, uint32_t flags, Creature*) const { if (const Creature* creature = thing.getCreature()) { if (hasBitSet(FLAG_NOLIMIT, flags)) { return RETURNVALUE_NOERROR; } if (hasBitSet(FLAG_PATHFINDING, flags)) { if (floorChange() || positionChange()) { return RETURNVALUE_NOTPOSSIBLE; } } if (ground == nullptr) { return RETURNVALUE_NOTPOSSIBLE; } if (const Monster* monster = creature->getMonster()) { if (hasFlag(TILESTATE_PROTECTIONZONE)) { return RETURNVALUE_NOTPOSSIBLE; } if (floorChange() || positionChange()) { return RETURNVALUE_NOTPOSSIBLE; } const CreatureVector* creatures = getCreatures(); if (monster->canPushCreatures() && !monster->isSummon()) { if (creatures) { for (Creature* tileCreature : *creatures) { if (tileCreature->getPlayer() && tileCreature->getPlayer()->isInGhostMode()) { continue; } const Monster* creatureMonster = tileCreature->getMonster(); if (!creatureMonster || !tileCreature->isPushable() || (creatureMonster->isSummon() && creatureMonster->getMaster()->getPlayer())) { return RETURNVALUE_NOTPOSSIBLE; } } } } else if (creatures && !creatures->empty()) { for (const Creature* tileCreature : *creatures) { if (!tileCreature->isInGhostMode()) { return RETURNVALUE_NOTENOUGHROOM; } } } if (hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID)) { return RETURNVALUE_NOTPOSSIBLE; } if (hasBitSet(FLAG_PATHFINDING, flags) && hasFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH)) { return RETURNVALUE_NOTPOSSIBLE; } if (hasFlag(TILESTATE_BLOCKSOLID) || (hasBitSet(FLAG_PATHFINDING, flags) && hasFlag(TILESTATE_NOFIELDBLOCKPATH))) { if (!(monster->canPushItems() || hasBitSet(FLAG_IGNOREBLOCKITEM, flags))) { return RETURNVALUE_NOTPOSSIBLE; } } MagicField* field = getFieldItem(); if (field && !field->isBlocking()) { 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)) { //1) Monster is "strong" enough to handle the damage //2) Monster is already afflicated by this type of condition if (hasBitSet(FLAG_IGNOREFIELDDAMAGE, flags)) { if (!(monster->canPushItems() || monster->hasCondition(Combat::DamageToConditionType(combatType)))) { return RETURNVALUE_NOTPOSSIBLE; } } else { return RETURNVALUE_NOTPOSSIBLE; } } } return RETURNVALUE_NOERROR; } const CreatureVector* creatures = getCreatures(); if (const Player* player = creature->getPlayer()) { if (creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags) && !player->isAccessPlayer()) { for (const Creature* tileCreature : *creatures) { if (!player->canWalkthrough(tileCreature)) { return RETURNVALUE_NOTPOSSIBLE; } } } if (player->getParent() == nullptr && hasFlag(TILESTATE_NOLOGOUT)) { //player is trying to login to a "no logout" tile return RETURNVALUE_NOTPOSSIBLE; } const Tile* playerTile = player->getTile(); if (playerTile && player->isPzLocked()) { if (!playerTile->hasFlag(TILESTATE_PVPZONE)) { //player is trying to enter a pvp zone while being pz-locked if (hasFlag(TILESTATE_PVPZONE)) { return RETURNVALUE_PLAYERISPZLOCKEDENTERPVPZONE; } } else if (!hasFlag(TILESTATE_PVPZONE)) { // player is trying to leave a pvp zone while being pz-locked return RETURNVALUE_PLAYERISPZLOCKEDLEAVEPVPZONE; } if ((!playerTile->hasFlag(TILESTATE_NOPVPZONE) && hasFlag(TILESTATE_NOPVPZONE)) || (!playerTile->hasFlag(TILESTATE_PROTECTIONZONE) && hasFlag(TILESTATE_PROTECTIONZONE))) { // player is trying to enter a non-pvp/protection zone while being pz-locked return RETURNVALUE_PLAYERISPZLOCKED; } } } else if (creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags)) { for (const Creature* tileCreature : *creatures) { if (!tileCreature->isInGhostMode()) { return RETURNVALUE_NOTENOUGHROOM; } } } const TileItemVector* items = getItemList(); if (items) { if (!hasBitSet(FLAG_IGNOREBLOCKITEM, flags)) { //If the FLAG_IGNOREBLOCKITEM bit isn't set we dont have to iterate every single item if (hasFlag(TILESTATE_BLOCKSOLID)) { return RETURNVALUE_NOTENOUGHROOM; } } else { //FLAG_IGNOREBLOCKITEM is set if (ground) { const ItemType& iiType = Item::items[ground->getID()]; if (iiType.blockSolid && (!iiType.moveable || ground->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID))) { return RETURNVALUE_NOTPOSSIBLE; } } for (const Item* item : *items) { const ItemType& iiType = Item::items[item->getID()]; if (iiType.blockSolid && (!iiType.moveable || item->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID))) { return RETURNVALUE_NOTPOSSIBLE; } } } } } else if (const Item* item = thing.getItem()) { const TileItemVector* items = getItemList(); if (items && items->size() >= 0xFFFF) { return RETURNVALUE_NOTPOSSIBLE; } if (hasBitSet(FLAG_NOLIMIT, flags)) { return RETURNVALUE_NOERROR; } bool itemIsHangable = item->isHangable(); if (ground == nullptr && !itemIsHangable) { return RETURNVALUE_NOTPOSSIBLE; } const CreatureVector* creatures = getCreatures(); if (creatures && !creatures->empty() && item->isBlocking() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags)) { for (const Creature* tileCreature : *creatures) { if (!tileCreature->isInGhostMode()) { return RETURNVALUE_NOTENOUGHROOM; } } } if (itemIsHangable && hasFlag(TILESTATE_SUPPORTS_HANGABLE)) { if (items) { for (const Item* tileItem : *items) { if (tileItem->isHangable()) { return RETURNVALUE_NEEDEXCHANGE; } } } } else { if (ground) { const ItemType& iiType = Item::items[ground->getID()]; if (iiType.blockSolid) { if (!iiType.allowPickupable || item->isMagicField() || item->isBlocking()) { if (!item->isPickupable()) { return RETURNVALUE_NOTENOUGHROOM; } if (!iiType.hasHeight || iiType.pickupable || iiType.isBed()) { return RETURNVALUE_NOTENOUGHROOM; } } } } if (items) { for (const Item* tileItem : *items) { const ItemType& iiType = Item::items[tileItem->getID()]; if (!iiType.blockSolid) { continue; } if (iiType.allowPickupable && !item->isMagicField() && !item->isBlocking()) { continue; } if (!item->isPickupable()) { return RETURNVALUE_NOTENOUGHROOM; } if (!iiType.hasHeight || iiType.pickupable || iiType.isBed()) { return RETURNVALUE_NOTENOUGHROOM; } } } } } return RETURNVALUE_NOERROR; }
ReturnValue Tile::isBlocking(int objectstate, bool ignoreCreature /* = false*/, bool ignoreMoveableBlocking /*=false*/) const { if(isPz() && ((objectstate & BLOCK_PZ) == BLOCK_PZ)) { return RET_PROTECTIONZONE; } if(((objectstate & BLOCK_PATHFIND) == BLOCK_PATHFIND) && (floorChange() || getTeleportItem())) { return RET_THEREISNOWAY; } if(ground) { const ItemType& groundType = Item::items[ground->getID()]; if(((objectstate & BLOCK_PROJECTILE) == BLOCK_PROJECTILE) && groundType.blockProjectile) return RET_CANNOTTHROW; /* if((groundType.blockPathFind || groundType.blockSolid) && ((objectstate & BLOCK_PATHFIND) == BLOCK_PATHFIND)) return RET_THEREISNOWAY; */ if(((objectstate & BLOCK_PICKUPABLE) == BLOCK_PICKUPABLE)) { if(groundType.blockSolid && (!groundType.hasHeight || groundType.pickupable)) return RET_NOTENOUGHROOM; } if(((objectstate & BLOCK_SOLID) == BLOCK_SOLID) && groundType.blockSolid) return RET_NOTENOUGHROOM; } else if( !((objectstate & BLOCK_PROJECTILE) == BLOCK_PROJECTILE)) { return RET_NOTILE; } if(!ignoreCreature && !creatures.empty() && ((objectstate & BLOCK_SOLID) == BLOCK_SOLID)) return RET_CREATUREBLOCK; ItemVector::const_iterator iit; for (iit = topItems.begin(); iit != topItems.end(); ++iit) { const ItemType& iiType = Item::items[(*iit)->getID()]; if(((objectstate & BLOCK_PROJECTILE) == BLOCK_PROJECTILE)) { if(iiType.blockProjectile) return RET_CANNOTTHROW; /*else continue;*/ } /* if((iiType.blockPathFind || iiType.blockSolid) && ((objectstate & BLOCK_PATHFIND) == BLOCK_PATHFIND) && !(ignoreMoveableBlocking && iiType.moveable)) return RET_THEREISNOWAY; */ if(((objectstate & BLOCK_PICKUPABLE) == BLOCK_PICKUPABLE)) { if(iiType.blockSolid && (!iiType.hasHeight || iiType.pickupable)) return RET_NOTENOUGHROOM; } if(((objectstate & BLOCK_SOLID) == BLOCK_SOLID) && iiType.blockSolid && !(ignoreMoveableBlocking && iiType.moveable)) return RET_NOTENOUGHROOM; } for (iit = downItems.begin(); iit != downItems.end(); ++iit) { const ItemType& iiType = Item::items[(*iit)->getID()]; if(((objectstate & BLOCK_PROJECTILE) == BLOCK_PROJECTILE)) { if(iiType.blockProjectile) return RET_CANNOTTHROW; /*else continue;*/ } /* if((iiType.blockPathFind || iiType.blockSolid) && ((objectstate & BLOCK_PATHFIND) == BLOCK_PATHFIND) && !(ignoreMoveableBlocking && iiType.moveable)) return RET_THEREISNOWAY; */ if(((objectstate & BLOCK_PICKUPABLE) == BLOCK_PICKUPABLE)) { if(iiType.blockSolid && (!iiType.hasHeight || iiType.pickupable)) return RET_NOTENOUGHROOM; } if(((objectstate & BLOCK_SOLID) == BLOCK_SOLID) && iiType.blockSolid && !(ignoreMoveableBlocking && iiType.moveable)) return RET_NOTENOUGHROOM; } //return false; return RET_NOERROR; }
ReturnValue Tile::__queryAdd(int32_t index, const Thing* thing, uint32_t count, uint32_t flags, Creature* actor/* = NULL*/) 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 == NULL) { 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) { Creature* creature; for (uint32_t i = 0; i < creatures->size(); ++i) { creature = creatures->at(i); if (creature->getPlayer() && creature->getPlayer()->isInGhostMode()) { continue; } const Monster* creatureMonster = creature->getMonster(); if (!creatureMonster || !creature->isPushable() || (creatureMonster->isSummon() && creatureMonster->getMaster()->getPlayer())) { return RET_NOTPOSSIBLE; } } } } else if (creatures && !creatures->empty()) { for (CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit) { if (!(*cit)->isInGhostMode()) { return RET_NOTENOUGHROOM; } } } 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))) { if (!(monster->canPushItems() || hasBitSet(FLAG_IGNOREBLOCKITEM, flags))) { return RET_NOTPOSSIBLE; } } MagicField* field = getFieldItem(); if (field && !field->isBlocking()) { 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)) { //1) Monster is "strong" enough to handle the damage //2) Monster is already afflicated by this type of condition if (hasBitSet(FLAG_IGNOREFIELDDAMAGE, flags)) { if (!(monster->canPushItems() || monster->hasCondition(Combat::DamageToConditionType(combatType)))) { return RET_NOTPOSSIBLE; } } else { return RET_NOTPOSSIBLE; } } } return RET_NOERROR; } else if (const Player* player = creature->getPlayer()) { if (creatures && !creatures->empty() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags) && !player->isAccessPlayer()) { for (CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit) { if (!player->canWalkthrough(*cit)) { return RET_NOTPOSSIBLE; } } } if (player->getParent() == NULL && hasFlag(TILESTATE_NOLOGOUT)) { //player is trying to login to a "no logout" tile return RET_NOTPOSSIBLE; } if (player->getTile() && player->isPzLocked()) { if (!player->getTile()->hasFlag(TILESTATE_PVPZONE)) { //player is trying to enter a pvp zone while being pz-locked if (hasFlag(TILESTATE_PVPZONE)) { return RET_PLAYERISPZLOCKEDENTERPVPZONE; } } else if (!hasFlag(TILESTATE_PVPZONE)) { //player is trying to leave a pvp zone while being pz-locked return RET_PLAYERISPZLOCKEDLEAVEPVPZONE; } } if ((hasFlag(TILESTATE_NOPVPZONE) || 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 (!(*cit)->isInGhostMode()) { return RET_NOTENOUGHROOM; } } } if (items) { if (!hasBitSet(FLAG_IGNOREBLOCKITEM, flags)) { //If the FLAG_IGNOREBLOCKITEM bit isn't set we dont have to iterate every single item if (hasFlag(TILESTATE_BLOCKSOLID)) { return RET_NOTENOUGHROOM; } } else { //FLAG_IGNOREBLOCKITEM is set if (ground) { const ItemType& iiType = Item::items[ground->getID()]; if (iiType.blockSolid && (!iiType.moveable || ground->getUniqueId() != 0)) { return RET_NOTPOSSIBLE; } } if (const TileItemVector* items = getItemList()) { Item* iitem; for (ItemVector::const_iterator it = items->begin(); it != items->end(); ++it) { iitem = (*it); const ItemType& iiType = Item::items[iitem->getID()]; if (iiType.blockSolid && (!iiType.moveable || iitem->getUniqueId() != 0)) { return RET_NOTPOSSIBLE; } } } } } } else if (const Item* item = thing->getItem()) { if (items && items->size() >= 0xFFFF) { return RET_NOTPOSSIBLE; } if (hasBitSet(FLAG_NOLIMIT, flags)) { return RET_NOERROR; } bool itemIsHangable = item->isHangable(); if (ground == NULL && !itemIsHangable) { return RET_NOTPOSSIBLE; } if (creatures && !creatures->empty() && item->isBlocking() && !hasBitSet(FLAG_IGNOREBLOCKCREATURE, flags)) { for (CreatureVector::const_iterator cit = creatures->begin(); cit != creatures->end(); ++cit) { if (!(*cit)->isInGhostMode()) { return RET_NOTENOUGHROOM; } } } if (itemIsHangable && hasFlag(TILESTATE_SUPPORTS_HANGABLE)) { if (items) { for (ItemVector::const_iterator it = items->begin(), end = items->end(); it != end; ++it) { if ((*it)->isHangable()) { return RET_NEEDEXCHANGE; } } } } else { if (ground) { const ItemType& iiType = Item::items[ground->getID()]; if (iiType.blockSolid) { if (!iiType.allowPickupable || item->isMagicField() || item->isBlocking()) { if (!item->isPickupable()) { return RET_NOTENOUGHROOM; } if (!iiType.hasHeight || iiType.pickupable || iiType.isBed()) { return RET_NOTENOUGHROOM; } } } } if (items) { for (ItemVector::const_iterator it = items->begin(), end = items->end(); it != end; ++it) { const ItemType& iiType = Item::items[(*it)->getID()]; if (!iiType.blockSolid) { continue; } if (iiType.allowPickupable && !item->isMagicField() && !item->isBlocking()) { continue; } if (!item->isPickupable()) { return RET_NOTENOUGHROOM; } if (!iiType.hasHeight || iiType.pickupable || iiType.isBed()) { return RET_NOTENOUGHROOM; } } } } } return RET_NOERROR; }
Cylinder* Tile::__queryDestination(int32_t& index, const Thing* thing, Item** destItem, uint32_t& flags) { Tile* destTile = NULL; *destItem = NULL; Position _pos = pos; if(floorChange(CHANGE_DOWN)) { _pos.z++; if(Creature* creature = (Creature*) thing->getCreature()){ CreatureEventList moveEvents = creature->getCreatureEvents(CREATURE_EVENT_MOVE); for(CreatureEventList::iterator it = moveEvents.begin(); it != moveEvents.end(); ++it) (*it)->executeMove(creature, creature->getPosition(), _pos); } for(int32_t i = CHANGE_FIRST_EX; i < CHANGE_LAST; ++i) { Position __pos = _pos; Tile* tmpTile = NULL; switch(i) { case CHANGE_NORTH_EX: __pos.y++; if((tmpTile = g_game.getTile(__pos))) __pos.y++; break; case CHANGE_SOUTH_EX: __pos.y--; if((tmpTile = g_game.getTile(__pos))) __pos.y--; break; case CHANGE_EAST_EX: __pos.x--; if((tmpTile = g_game.getTile(__pos))) __pos.x--; break; case CHANGE_WEST_EX: __pos.x++; if((tmpTile = g_game.getTile(__pos))) __pos.x++; break; default: break; } if(!tmpTile || !tmpTile->floorChange((FloorChange_t)i)) continue; destTile = g_game.getTile(__pos); break; } if(!destTile) { if(Tile* downTile = g_game.getTile(_pos)) { if(downTile->floorChange(CHANGE_NORTH) || downTile->floorChange(CHANGE_NORTH_EX)) _pos.y++; if(downTile->floorChange(CHANGE_SOUTH) || downTile->floorChange(CHANGE_SOUTH_EX)) _pos.y--; if(downTile->floorChange(CHANGE_EAST) || downTile->floorChange(CHANGE_EAST_EX)) _pos.x--; if(downTile->floorChange(CHANGE_WEST) || downTile->floorChange(CHANGE_WEST_EX)) _pos.x++; destTile = g_game.getTile(_pos); } } } else if(floorChange()) { _pos.z--; if(floorChange(CHANGE_NORTH)) _pos.y--; if(floorChange(CHANGE_SOUTH)) _pos.y++; if(floorChange(CHANGE_EAST)) _pos.x++; if(floorChange(CHANGE_WEST)) _pos.x--; if(floorChange(CHANGE_NORTH_EX)) _pos.y -= 2; if(floorChange(CHANGE_SOUTH_EX)) _pos.y += 2; if(floorChange(CHANGE_EAST_EX)) _pos.x += 2; if(floorChange(CHANGE_WEST_EX)) _pos.x -= 2; destTile = g_game.getTile(_pos); if(Creature* creature = (Creature*) thing->getCreature()){ CreatureEventList moveEvents = creature->getCreatureEvents(CREATURE_EVENT_MOVE); for(CreatureEventList::iterator it = moveEvents.begin(); it != moveEvents.end(); ++it) (*it)->executeMove(creature, creature->getPosition(), _pos); } } if(!destTile) destTile = this; else flags |= FLAG_NOLIMIT; //will ignore that there is blocking items/creatures if(destTile) { Thing* destThing = destTile->getTopDownItem(); if(destThing && !destThing->isRemoved()) *destItem = destThing->getItem(); } return destTile; }
ReturnValue Tile::__queryAdd(int32_t index, const Thing* thing, uint32_t count, uint32_t flags) const { const CreatureVector* creatures = getCreatures(); const TileItemVector* items = getItemList(); if(const Creature* creature = thing->getCreature()) { if(ground) { if(const Monster* monster = creature->getMonster()) { const ItemType& iType = Item::items[ground->getID()]; if(ground->getID() == 11756) return RET_NOTPOSSIBLE; if(ground->getID() == 4821) return RET_NOTPOSSIBLE; if(ground->getID() == 4822) return RET_NOTPOSSIBLE; if(ground->getID() == 4823) return RET_NOTPOSSIBLE; if(ground->getID() == 4824) return RET_NOTPOSSIBLE; if(ground->getID() == 4825) return RET_NOTPOSSIBLE; } } 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)) && monster->isSummon()) return RET_NOERROR; if(floorChange() || positionChange()) return RET_NOTPOSSIBLE; if(monster->canPushCreatures() && !monster->isSummon()) { if(creatures) { 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->getMonster()->isSummon() && tmp->getMonster()->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; } } 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; MagicField* field = getFieldItem(); if(field && !field->isBlocking(monster)) { 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)) { //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; if(!monster->canPushItems() && !monster->hasCondition( Combat::DamageToConditionType(combatType), false)) return RET_NOTPOSSIBLE; } } return RET_NOERROR; } else 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; //RET_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_PVPZONE) && hasFlag(TILESTATE_PVPZONE)) //player is trying to enter a pvp zone while being pz-locked return RET_PLAYERISPZLOCKEDENTERPVPZONE; if(player->isPzLocked() && player->getTile()->hasFlag(TILESTATE_PVPZONE) && !hasFlag(TILESTATE_PVPZONE)) //player is trying to leave a pvp zone while being pz-locked return RET_PLAYERISPZLOCKEDLEAVEPVPZONE; if(hasFlag(TILESTATE_NOPVPZONE) && 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; } } 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 if(hasFlag(TILESTATE_BLOCKSOLID)) return RET_NOTENOUGHROOM; } else { //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()) { Item* iItem = NULL; for(ItemVector::const_iterator it = items->begin(); it != items->end(); ++it) { iItem = (*it); const ItemType& iType = Item::items[iItem->getID()]; if(iItem->isBlocking(creature) && (!iType.moveable || (iItem->isLoadedFromMap() && (iItem->getUniqueId() || (iItem->getActionId() && iItem->getContainer()))))) return RET_NOTPOSSIBLE; } } } } } else if(const Item* item = thing->getItem()) { #ifdef __DEBUG__ if(thing->getParent() == NULL && !hasBitSet(FLAG_NOLIMIT, flags)) std::cout << "[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; } } if(hasFlag(TILESTATE_PROTECTIONZONE)) { const uint32_t itemLimit = g_config.getNumber(ConfigManager::ITEMLIMIT_PROTECTIONZONE); 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(iType.blockSolid) { if(!item->isPickupable()) return RET_NOTENOUGHROOM; if(iType.allowPickupable) continue; if(!iType.hasHeight || iType.pickupable || iType.isBed()) return RET_NOTENOUGHROOM; } } } } if(itemIsHangable && hasHangable && supportHangable) return RET_NEEDEXCHANGE; } return RET_NOERROR; }
Cylinder* Tile::__queryDestination(int32_t& index, const Thing* thing, Item** destItem) { Tile* destTile = NULL; *destItem = NULL; if(floorChange()){ if(floorChange(NORTH) && floorChange(EAST)){ destTile = g_game.getTile(getTilePosition().x + 1, getTilePosition().y - 1, getTilePosition().z - 1); } else if(floorChange(NORTH) && floorChange(WEST)){ destTile = g_game.getTile(getTilePosition().x - 1, getTilePosition().y - 1, getTilePosition().z - 1); } else if(floorChange(SOUTH) && floorChange(EAST)){ destTile = g_game.getTile(getTilePosition().x + 1, getTilePosition().y + 1, getTilePosition().z - 1); } else if(floorChange(SOUTH) && floorChange(WEST)){ destTile = g_game.getTile(getTilePosition().x - 1, getTilePosition().y + 1, getTilePosition().z - 1); } else if(floorChange(NORTH)){ destTile = g_game.getTile(getTilePosition().x, getTilePosition().y - 1, getTilePosition().z - 1); } else if(floorChange(SOUTH)){ destTile = g_game.getTile(getTilePosition().x, getTilePosition().y + 1, getTilePosition().z - 1); } else if(floorChange(EAST)){ destTile = g_game.getTile(getTilePosition().x + 1, getTilePosition().y, getTilePosition().z - 1); } else if(floorChange(WEST)){ destTile = g_game.getTile(getTilePosition().x - 1, getTilePosition().y, getTilePosition().z - 1); } } if(destTile == NULL){ destTile = this; } if(destTile->floorChangeDown()){ destTile = g_game.getTile(getTilePosition().x, getTilePosition().y, getTilePosition().z + 1); if(destTile == NULL){ return this; } else if(destTile->floorChange(NORTH) && destTile->floorChange(EAST)){ destTile = g_game.getTile(getTilePosition().x - 1, getTilePosition().y + 1, getTilePosition().z + 1); } else if(destTile->floorChange(NORTH) && destTile->floorChange(WEST)){ destTile = g_game.getTile(getTilePosition().x + 1, getTilePosition().y + 1, getTilePosition().z + 1); } else if(destTile->floorChange(SOUTH) && destTile->floorChange(EAST)){ destTile = g_game.getTile(getTilePosition().x - 1, getTilePosition().y - 1, getTilePosition().z + 1); } else if(destTile->floorChange(SOUTH) && destTile->floorChange(WEST)){ destTile = g_game.getTile(getTilePosition().x + 1, getTilePosition().y - 1, getTilePosition().z + 1); } else if(destTile->floorChange(NORTH)){ destTile = g_game.getTile(getTilePosition().x, getTilePosition().y + 1, getTilePosition().z + 1); } else if(destTile->floorChange(SOUTH)){ destTile = g_game.getTile(getTilePosition().x, getTilePosition().y - 1, getTilePosition().z + 1); } else if(destTile->floorChange(EAST)){ destTile = g_game.getTile(getTilePosition().x - 1, getTilePosition().y, getTilePosition().z + 1); } else if(destTile->floorChange(WEST)){ destTile = g_game.getTile(getTilePosition().x + 1, getTilePosition().y, getTilePosition().z + 1); } } Thing* destThing = destTile->getTopDownItem(); if(destThing) *destItem = destThing->getItem(); return destTile; }
ReturnValue Tile::__queryAdd(int32_t index, const Thing* thing, uint32_t count, bool childIsOwner /*= false*/) const { Thing* iithing = NULL; if(const Creature* creature = thing->getCreature()){ if(!creatures.empty()) return RET_NOTPOSSIBLE; if(ground == NULL) return RET_NOTPOSSIBLE; if(const Monster* monster = creature->getMonster()){ if(hasFlag(TILESTATE_PROTECTIONZONE)) return RET_NOTPOSSIBLE; if(const MagicEffectItem* fieldItem = getFieldItem()){ const MagicEffectTargetCreatureCondition* magicTargetCondition = fieldItem->getCondition(); if(magicTargetCondition){ if((monster->getImmunities() & magicTargetCondition->attackType) != magicTargetCondition->attackType){ return RET_NOTPOSSIBLE; } } } if(floorChange() || getTeleportItem()){ return RET_NOTPOSSIBLE; } for(uint32_t i = 0; i < getThingCount(); ++i){ iithing = __getThing(i); if(const Item* iitem = iithing->getItem()){ const ItemType& iiType = Item::items[iitem->getID()]; if(iiType.blockSolid){ if(!monster->canPushItems() || !iiType.moveable){ return RET_NOTPOSSIBLE; } } } } return RET_NOERROR; } else if(const Player* player = creature->getPlayer()){ if(hasFlag(TILESTATE_PROTECTIONZONE) && player->pzLocked){ return RET_PLAYERISPZLOCKED; } } for(uint32_t i = 0; i < getThingCount(); ++i){ iithing = __getThing(i); if(const Item* iitem = iithing->getItem()){ const ItemType& iiType = Item::items[iitem->getID()]; if(iiType.blockSolid){ //check if this a creature that just is about to login/spawn //those can be placed here if the blocking item is moveable if(!creature->getParent()){ if(!iiType.moveable) return RET_NOTPOSSIBLE; } else return RET_NOTPOSSIBLE; } } } } else if(const Item* item = thing->getItem()){ //If its a new (summoned item) always accept it if(thing->getParent() == NULL){ return RET_NOERROR; } if(ground == NULL) return RET_NOTPOSSIBLE; if(!creatures.empty() && item->isBlocking()) return RET_NOTENOUGHROOM; for(uint32_t i = 0; i < getThingCount(); ++i){ iithing = __getThing(i); if(const Item* iitem = iithing->getItem()){ const ItemType& iiType = Item::items[iitem->getID()]; if(iiType.blockSolid){ if(item->isPickupable()){ //experimental //if((iiType.isVertical || iiType.isHorizontal) && item->isHangable()){ // ItemVector::const_iterator iit; // for(iit = downItems.begin(); iit != downItems.end(); ++iit){ // if((*iit)->isHangable()) // return RET_NOTENOUGHROOM; // } //} //else if(!iiType.hasHeight /*|| !iiType.moveable*/) return RET_NOTENOUGHROOM; else if(iiType.pickupable) return RET_NOTENOUGHROOM; } else return RET_NOTENOUGHROOM; } } } } return RET_NOERROR; }
Cylinder* Tile::__queryDestination(int32_t&, const Thing*, Item** destItem, uint32_t& flags) { Tile* destTile = NULL; Position destPosition = pos; *destItem = NULL; if(floorChange(CHANGE_DOWN)) { destPosition.z++; for(int32_t i = CHANGE_FIRST_EX; i < CHANGE_LAST; ++i) { Position tmpPosition = destPosition; Tile* tmpTile = NULL; switch(i) { case CHANGE_NORTH_EX: tmpPosition.y++; if((tmpTile = g_game.getTile(tmpPosition))) tmpPosition.y++; break; case CHANGE_SOUTH_EX: tmpPosition.y--; if((tmpTile = g_game.getTile(tmpPosition))) tmpPosition.y--; break; case CHANGE_EAST_EX: tmpPosition.x--; if((tmpTile = g_game.getTile(tmpPosition))) tmpPosition.x--; break; case CHANGE_WEST_EX: tmpPosition.x++; if((tmpTile = g_game.getTile(tmpPosition))) tmpPosition.x++; break; default: break; } if(!tmpTile || !tmpTile->floorChange((FloorChange_t)i)) continue; destTile = g_game.getTile(tmpPosition); break; } if(!destTile) { if(Tile* downTile = g_game.getTile(destPosition)) { if(downTile->floorChange(CHANGE_NORTH) || downTile->floorChange(CHANGE_NORTH_EX)) destPosition.y++; if(downTile->floorChange(CHANGE_SOUTH) || downTile->floorChange(CHANGE_SOUTH_EX)) destPosition.y--; if(downTile->floorChange(CHANGE_EAST) || downTile->floorChange(CHANGE_EAST_EX)) destPosition.x--; if(downTile->floorChange(CHANGE_WEST) || downTile->floorChange(CHANGE_WEST_EX)) destPosition.x++; destTile = g_game.getTile(destPosition); } } } else if(floorChange()) { destPosition.z--; Position tmpPosition = destPosition; if(floorChange(CHANGE_NORTH_EX)) { tmpPosition.y--; if((destTile = g_game.getTile(tmpPosition))) tmpPosition.y--; } else if(floorChange(CHANGE_SOUTH_EX)) { tmpPosition.y++; if((destTile = g_game.getTile(tmpPosition))) tmpPosition.y++; } else if(floorChange(CHANGE_EAST_EX)) { tmpPosition.x++; if((destTile = g_game.getTile(tmpPosition))) tmpPosition.x++; } else if(floorChange(CHANGE_WEST_EX)) { tmpPosition.x--; if((destTile = g_game.getTile(tmpPosition))) tmpPosition.x--; } if(!destTile) { if(floorChange(CHANGE_NORTH)) destPosition.y--; if(floorChange(CHANGE_SOUTH)) destPosition.y++; if(floorChange(CHANGE_EAST)) destPosition.x++; if(floorChange(CHANGE_WEST)) destPosition.x--; destTile = g_game.getTile(destPosition); } else if(destTile->floorChange(CHANGE_DOWN)) { if(Tile* tmpTile = g_game.getTile(tmpPosition)) destTile = tmpTile; } } if(!destTile) destTile = this; else flags |= FLAG_NOLIMIT; //will ignore that there is blocking items/creatures if(destTile) { if(Item* item = destTile->getTopDownItem()) *destItem = item; } return destTile; }