Example #1
0
void Monster::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const
{
	Creature::getPathSearchParams(creature, fpp);
	fpp.minTargetDist = 1;
	fpp.maxTargetDist = mType->targetDistance;
	if(isSummon())
	{
		if(master == creature)
		{
			fpp.maxTargetDist = 2;
			fpp.fullPathSearch = true;
		}
		else if(mType->targetDistance <= 1)
			fpp.fullPathSearch = true;
		else
			fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
	}
	else if(isFleeing())
	{
		//Distance should be higher than the client view range (Map::maxClientViewportX/Map::maxClientViewportY)
		fpp.maxTargetDist = Map::maxViewportX;
		fpp.clearSight = fpp.fullPathSearch = false;
		fpp.keepDistance = true;
	}
	else if(mType->targetDistance <= 1)
		fpp.fullPathSearch = true;
	else
		fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
}
Example #2
0
void Monster::onThink(uint32_t interval)
{
	Creature::onThink(interval);

	if(despawn())
	{
		g_game.internalTeleport(this, masterPos);
		setIdle(true);
	}
	else
	{
		updateIdleStatus();
		if(!isIdle)
		{
			addEventWalk();

			if(isSummon())
			{
				if(!attackedCreature)
				{
					if(getMaster() && getMaster()->getAttackedCreature())
					{
						///This happens if the monster is summoned during combat
						selectTarget(getMaster()->getAttackedCreature());
					}
					else if(getMaster() != followCreature)
					{
						//Our master has not ordered us to attack anything, lets follow him around instead.
						setFollowCreature(getMaster());
					}
				}
				else if(attackedCreature == this)
					setFollowCreature(NULL);
				else if(followCreature != attackedCreature)
				{
					//This happens just after a master orders an attack, so lets follow it aswell.
					setFollowCreature(attackedCreature);
				}
			}
			else if(!targetList.empty())
			{
				if(!followCreature || !hasFollowPath)
					searchTarget();
				else if(isFleeing())
				{
					if(attackedCreature && !canUseAttack(getPosition(), attackedCreature))
						searchTarget(TARGETSEARCH_ATTACKRANGE);
				}
			}

			onThinkTarget(interval);
			onThinkYell(interval);
			onThinkDefense(interval);
		}
	}
}
Example #3
0
void Monster::onThink(uint32_t interval)

{
	Creature::onThink(interval);
	if(despawn())
	{
		g_game.removeCreature(this, true);
		setIdle(true);
		return;
	}

	updateIdleStatus();
	if(isIdle)
		return;

	if(teleportToMaster && doTeleportToMaster())
		teleportToMaster = false;

	addEventWalk();
	
	if(getMaster()){
    	if(getPosition().z != getMaster()->getPosition().z){
			g_game.internalTeleport(this, getMaster()->getPosition(), false);
			//g_game.addMagicEffect(getPosition(), MAGIC_EFFECT_SOUND_YELLOW);
		}
      } 
	
	if(isSummon())
	{
		if(!attackedCreature)
		{
            std::string strValue;
			if(getMaster() && getMaster()->getAttackedCreature()) //This happens if the monster is summoned during combat
				selectTarget(getMaster()->getAttackedCreature());
            else{
                setFollowCreature((getMaster()->getStorage(500, strValue) && strValue != "-1") ? NULL : getMaster());
            }

        }
		else if(attackedCreature == this)
			setFollowCreature(NULL);
		else if(followCreature != attackedCreature) //This happens just after a master orders an attack, so lets follow it aswell.
			setFollowCreature(attackedCreature);
	}
	else if(!targetList.empty())
	{
		if(!followCreature || !hasFollowPath)
			searchTarget();
		else if(isFleeing() && attackedCreature && !canUseAttack(getPosition(), attackedCreature))
			searchTarget(TARGETSEARCH_ATTACKRANGE);
	}

	onThinkTarget(interval);
	onThinkYell(interval);
	onThinkDefense(interval);
}
Example #4
0
void Actor::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const
{
  Creature::getPathSearchParams(creature, fpp);

  fpp.minTargetDist = 1;
  fpp.maxTargetDist = cType.targetDistance();

  if(isSummon()){
    if(getMaster() == creature){
      fpp.maxTargetDist = 2;
      fpp.fullPathSearch = true;
    }
    else{
      if(cType.targetDistance() <= 1){
        fpp.fullPathSearch = true;
      }
      else{
        fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
      }
    }
  }
  else{
    if(isFleeing()){
      //Distance should be higher than the client view range (Map_maxClientViewportX/Map_maxClientViewportY)
      fpp.maxTargetDist = Map_maxViewportX;
      fpp.clearSight = false;
      fpp.keepDistance = true;
      fpp.fullPathSearch = false;
    }
    else{
      if(cType.targetDistance() <= 1){
        fpp.fullPathSearch = true;
      }
      else{
        fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
      }
    }
  }
}
Example #5
0
void Monster::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const
{
	Creature::getPathSearchParams(creature, fpp);
	
        fpp.clearSight = false;
	
	fpp.minTargetDist = 1;
	fpp.maxTargetDist = mType->targetDistance; //aqui
	    std::string strValue;
		int32_t value;
				if(getStorage(502, strValue))
				{
				   value = atoi(strValue.c_str());
				   fpp.maxTargetDist  = value;
				}
	if(isSummon())
	{
		if(getMaster() == creature)
		{
			fpp.maxTargetDist = 2;
			fpp.fullPathSearch = true;
		}
		else if(mType->targetDistance <= 1)
			fpp.fullPathSearch = true;
		else
			fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
	}
	else if(isFleeing())
	{
		//Distance should be higher than the client view range (Map::maxClientViewportX/Map::maxClientViewportY)
		fpp.maxTargetDist = Map::maxViewportX;
	    fpp.fullPathSearch = false;
		fpp.keepDistance = true;
	}
	else if(mType->targetDistance <= 1)
		fpp.fullPathSearch = true;
	else
		fpp.fullPathSearch = !canUseAttack(getPosition(), creature);
}
Example #6
0
bool Actor::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAULT*/)
{
#ifdef __DEBUG__
  std::cout << "Searching target... " << std::endl;
#endif

  std::list<Creature*> resultList;
  const Position& myPos = getPosition();
  for(CreatureList::iterator it = targetList.begin(); it != targetList.end(); ++it){
    if(followCreature != (*it) && isTarget(*it)){
      if(searchType == TARGETSEARCH_RANDOM || canUseAttack(myPos, *it)){
        resultList.push_back(*it);
      }
    }
  }

  if(!resultList.empty()){
    uint32_t index = random_range(0, resultList.size() - 1);
    CreatureList::iterator it = resultList.begin();
    std::advance(it, index);
#ifdef __DEBUG__
    std::cout << "Selecting target " << (*it)->getName() << std::endl;
#endif
    return selectTarget(*it);
  }

  if(searchType == TARGETSEARCH_ATTACKRANGE){
    return false;
  }

  //lets just pick the first target in the list
  for(CreatureList::iterator it = targetList.begin(); it != targetList.end(); ++it){
    if(followCreature != (*it) && selectTarget(*it)){
#ifdef __DEBUG__
      std::cout << "Selecting target " << (*it)->getName() << std::endl;
#endif
      return true;
    }
  }

  return false;
}
Example #7
0
bool Actor::getDanceStep(const Position& creaturePos, Direction& dir,
  bool keepAttack /*= true*/, bool keepDistance /*= true*/)
{
  bool canDoAttackNow = canUseAttack(creaturePos, attackedCreature);

  assert(attackedCreature != NULL);
  const Position& centerPos = attackedCreature->getPosition();
  uint32_t centerToDist = std::max(std::abs(creaturePos.x - centerPos.x), std::abs(creaturePos.y - centerPos.y));
  uint32_t tmpDist;

  std::vector<Direction> dirList;

  if(!keepDistance || creaturePos.y - centerPos.y >= 0){
    tmpDist = std::max(std::abs((creaturePos.x) - centerPos.x), std::abs((creaturePos.y - 1) - centerPos.y));
    if(tmpDist == centerToDist && canWalkTo(creaturePos, NORTH)){
      bool result = true;
      if(keepAttack){
        result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x, creaturePos.y - 1, creaturePos.z), attackedCreature));
      }
      if(result){
        dirList.push_back(NORTH);
      }
    }
  }

  if(!keepDistance || creaturePos.y - centerPos.y <= 0){
    tmpDist = std::max(std::abs((creaturePos.x) - centerPos.x), std::abs((creaturePos.y + 1) - centerPos.y));
    if(tmpDist == centerToDist && canWalkTo(creaturePos, SOUTH)){
      bool result = true;
      if(keepAttack){
        result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x, creaturePos.y + 1, creaturePos.z), attackedCreature));
      }
      if(result){
        dirList.push_back(SOUTH);
      }
    }
  }

  if(!keepDistance || creaturePos.x - centerPos.x >= 0){
    tmpDist = std::max(std::abs((creaturePos.x + 1) - centerPos.x), std::abs((creaturePos.y) - centerPos.y));
    if(tmpDist == centerToDist && canWalkTo(creaturePos, EAST)){
      bool result = true;
      if(keepAttack){
        result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x + 1, creaturePos.y, creaturePos.z), attackedCreature));
      }
      if(result){
        dirList.push_back(EAST);
      }
    }
  }

  if(!keepDistance || creaturePos.x - centerPos.x <= 0){
    tmpDist = std::max(std::abs((creaturePos.x - 1) - centerPos.x), std::abs((creaturePos.y) - centerPos.y));
    if(tmpDist == centerToDist && canWalkTo(creaturePos, WEST)){
      bool result = true;
      if(keepAttack){
        result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x - 1, creaturePos.y, creaturePos.z), attackedCreature));
      }
      if(result){
        dirList.push_back(WEST);
      }
    }
  }

  if(!dirList.empty()){
    std::random_shuffle(dirList.begin(), dirList.end());
    dir = dirList[random_range(0, dirList.size() - 1)];
    return true;
  }

  return false;
}
Example #8
0
bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAULT*/)
{
#ifdef __DEBUG__
	std::clog << "Searching target... " << std::endl;
#endif

	std::list<Creature*> resultList;
	const Position& myPos = getPosition();
	for(CreatureList::iterator it = targetList.begin(); it != targetList.end(); ++it)
	{
		if(followCreature != (*it) && isTarget(*it) && (searchType == TARGETSEARCH_RANDOM
			|| canUseAttack(myPos, *it)))
			resultList.push_back(*it);
	}

	switch(searchType)
	{
		case TARGETSEARCH_NEAREST:
		{
			Creature* target = NULL;
			int32_t range = -1;
			for(CreatureList::iterator it = resultList.begin(); it != resultList.end(); ++it)
			{
				int32_t tmp = std::max(std::abs(myPos.x - (*it)->getPosition().x),
					std::abs(myPos.y - (*it)->getPosition().y));
				if(range >= 0 && tmp >= range)
					continue;

				target = *it;
				range = tmp;
			}

			if(target && selectTarget(target))
				return target;

			break;
		}
		default:
		{
			if(!resultList.empty())
			{
				CreatureList::iterator it = resultList.begin();
				std::advance(it, random_range(0, resultList.size() - 1));
#ifdef __DEBUG__

				std::clog << "Selecting target " << (*it)->getName() << std::endl;
#endif
				return selectTarget(*it);
			}

			if(searchType == TARGETSEARCH_ATTACKRANGE)
				return false;

			break;
		}
	}


	//lets just pick the first target in the list
	for(CreatureList::iterator it = targetList.begin(); it != targetList.end(); ++it)
	{
		if(followCreature == (*it) || !selectTarget(*it))
			continue;

#ifdef __DEBUG__
		std::clog << "Selecting target " << (*it)->getName() << std::endl;
#endif
		return true;
	}

	return false;
}
Example #9
0
bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAULT*/)
{
#ifdef __DEBUG__
	std::cout << "Searching target... " << std::endl;
#endif

	std::list<Creature*> resultList;
	const Position& myPos = getPosition();
	for(CreatureList::iterator it = targetList.begin(); it != targetList.end(); ++it)
	{
		if(followCreature != (*it) && isTarget(*it))
		{
			if(searchType == TARGETSEARCH_RANDOM || canUseAttack(myPos, *it))
				resultList.push_back(*it);
		}
	}

	switch(searchType)
	{
		case TARGETSEARCH_NEAREAST:
		{
			Creature* target = NULL;
			int32_t minRange = -1;
			for(std::list<Creature*>::iterator it = resultList.begin(); it != resultList.end(); ++it)
			{
				const Position& pos = (*it)->getPosition();
				if(minRange == -1 || std::max(std::abs(myPos.x - pos.x), std::abs(myPos.y - pos.y)) < minRange)
				{
					target = *it;
					minRange = std::max(std::abs(myPos.x - pos.x), std::abs(myPos.y - pos.y));
				}
			}

			if(target && selectTarget(target))
				return true;

			break;
		}

		case TARGETSEARCH_DEFAULT:
		case TARGETSEARCH_ATTACKRANGE:
		case TARGETSEARCH_RANDOM:
		default:
		{
			if(!resultList.empty())
			{
				uint32_t index = random_range(0, resultList.size() - 1);
				CreatureList::iterator it = resultList.begin();
				std::advance(it, index);
#ifdef __DEBUG__
				std::cout << "Selecting target " << (*it)->getName() << std::endl;
#endif
				return selectTarget(*it);
			}

			if(searchType == TARGETSEARCH_ATTACKRANGE)
				return false;

			break;
		}
	}

	//lets just pick the first target in the list
	for(CreatureList::iterator it = targetList.begin(); it != targetList.end(); ++it)
	{
		if(followCreature != (*it) && selectTarget(*it))
		{
#ifdef __DEBUG__
			std::cout << "Selecting target " << (*it)->getName() << std::endl;
#endif
			return true;
		}
	}
	return false;
}
Example #10
0
void Monster::onThink(uint32_t interval)
{
	Creature::onThink(interval);

	if (mType->info.thinkEvent != -1) {
		// onThink(self, interval)
		LuaScriptInterface* scriptInterface = mType->info.scriptInterface;
		if (!scriptInterface->reserveScriptEnv()) {
			std::cout << "[Error - Monster::onThink] Call stack overflow" << std::endl;
			return;
		}

		ScriptEnvironment* env = scriptInterface->getScriptEnv();
		env->setScriptId(mType->info.thinkEvent, scriptInterface);

		lua_State* L = scriptInterface->getLuaState();
		scriptInterface->pushFunction(mType->info.thinkEvent);

		LuaScriptInterface::pushUserdata<Monster>(L, this);
		LuaScriptInterface::setMetatable(L, -1, "Monster");

		lua_pushnumber(L, interval);

		if (scriptInterface->callFunction(2)) {
			return;
		}
	}

	if (!isInSpawnRange(position)) {
		g_game.internalTeleport(this, masterPos);
		setIdle(true);
	} else {
		updateIdleStatus();

		if (!isIdle) {
			addEventWalk();

			if (isSummon()) {
				if (!attackedCreature) {
					if (getMaster() && getMaster()->getAttackedCreature()) {
						//This happens if the monster is summoned during combat
						selectTarget(getMaster()->getAttackedCreature());
					} else if (getMaster() != followCreature) {
						//Our master has not ordered us to attack anything, lets follow him around instead.
						setFollowCreature(getMaster());
					}
				} else if (attackedCreature == this) {
					setFollowCreature(nullptr);
				} else if (followCreature != attackedCreature) {
					//This happens just after a master orders an attack, so lets follow it aswell.
					setFollowCreature(attackedCreature);
				}
			} else if (!targetList.empty()) {
				if (!followCreature || !hasFollowPath) {
					searchTarget();
				} else if (isFleeing()) {
					if (attackedCreature && !canUseAttack(getPosition(), attackedCreature)) {
						searchTarget(TARGETSEARCH_ATTACKRANGE);
					}
				}
			}

			onThinkTarget(interval);
			onThinkYell(interval);
			onThinkDefense(interval);
		}
	}
}
Example #11
0
bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAULT*/)
{
	std::list<Creature*> resultList;
	const Position& myPos = getPosition();

	for (Creature* creature : targetList) {
		if (followCreature != creature && isTarget(creature)) {
			if (searchType == TARGETSEARCH_RANDOM || canUseAttack(myPos, creature)) {
				resultList.push_back(creature);
			}
		}
	}

	switch (searchType) {
		case TARGETSEARCH_NEAREST: {
			Creature* target = nullptr;
			if (!resultList.empty()) {
				auto it = resultList.begin();
				target = *it;

				if (++it != resultList.end()) {
					const Position& targetPosition = target->getPosition();
					int32_t minRange = Position::getDistanceX(myPos, targetPosition) + Position::getDistanceY(myPos, targetPosition);
					do {
						const Position& pos = (*it)->getPosition();

						int32_t distance = Position::getDistanceX(myPos, pos) + Position::getDistanceY(myPos, pos);
						if (distance < minRange) {
							target = *it;
							minRange = distance;
						}
					} while (++it != resultList.end());
				}
			} else {
				int32_t minRange = std::numeric_limits<int32_t>::max();
				for (Creature* creature : targetList) {
					if (!isTarget(creature)) {
						continue;
					}

					const Position& pos = creature->getPosition();
					int32_t distance = Position::getDistanceX(myPos, pos) + Position::getDistanceY(myPos, pos);
					if (distance < minRange) {
						target = creature;
						minRange = distance;
					}
				}
			}

			if (target && selectTarget(target)) {
				return true;
			}
			break;
		}

		case TARGETSEARCH_DEFAULT:
		case TARGETSEARCH_ATTACKRANGE:
		case TARGETSEARCH_RANDOM:
		default: {
			if (!resultList.empty()) {
				auto it = resultList.begin();
				std::advance(it, uniform_random(0, resultList.size() - 1));
				return selectTarget(*it);
			}

			if (searchType == TARGETSEARCH_ATTACKRANGE) {
				return false;
			}

			break;
		}
	}

	//lets just pick the first target in the list
	for (Creature* target : targetList) {
		if (followCreature != target && selectTarget(target)) {
			return true;
		}
	}
	return false;
}
Example #12
0
bool Monster::getDanceStep(const Position& creaturePos, Direction& direction,
                           bool keepAttack /*= true*/, bool keepDistance /*= true*/)
{
	bool canDoAttackNow = canUseAttack(creaturePos, attackedCreature);

	assert(attackedCreature != nullptr);
	const Position& centerPos = attackedCreature->getPosition();

	int_fast32_t offset_x = Position::getOffsetX(creaturePos, centerPos);
	int_fast32_t offset_y = Position::getOffsetY(creaturePos, centerPos);

	int_fast32_t distance_x = std::abs(offset_x);
	int_fast32_t distance_y = std::abs(offset_y);

	uint32_t centerToDist = std::max<uint32_t>(distance_x, distance_y);

	std::vector<Direction> dirList;

	if (!keepDistance || offset_y >= 0) {
		uint32_t tmpDist = std::max<uint32_t>(distance_x, std::abs((creaturePos.getY() - 1) - centerPos.getY()));
		if (tmpDist == centerToDist && canWalkTo(creaturePos, DIRECTION_NORTH)) {
			bool result = true;

			if (keepAttack) {
				result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x, creaturePos.y - 1, creaturePos.z), attackedCreature));
			}

			if (result) {
				dirList.push_back(DIRECTION_NORTH);
			}
		}
	}

	if (!keepDistance || offset_y <= 0) {
		uint32_t tmpDist = std::max<uint32_t>(distance_x, std::abs((creaturePos.getY() + 1) - centerPos.getY()));
		if (tmpDist == centerToDist && canWalkTo(creaturePos, DIRECTION_SOUTH)) {
			bool result = true;

			if (keepAttack) {
				result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x, creaturePos.y + 1, creaturePos.z), attackedCreature));
			}

			if (result) {
				dirList.push_back(DIRECTION_SOUTH);
			}
		}
	}

	if (!keepDistance || offset_x <= 0) {
		uint32_t tmpDist = std::max<uint32_t>(std::abs((creaturePos.getX() + 1) - centerPos.getX()), distance_y);
		if (tmpDist == centerToDist && canWalkTo(creaturePos, DIRECTION_EAST)) {
			bool result = true;

			if (keepAttack) {
				result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x + 1, creaturePos.y, creaturePos.z), attackedCreature));
			}

			if (result) {
				dirList.push_back(DIRECTION_EAST);
			}
		}
	}

	if (!keepDistance || offset_x >= 0) {
		uint32_t tmpDist = std::max<uint32_t>(std::abs((creaturePos.getX() - 1) - centerPos.getX()), distance_y);
		if (tmpDist == centerToDist && canWalkTo(creaturePos, DIRECTION_WEST)) {
			bool result = true;

			if (keepAttack) {
				result = (!canDoAttackNow || canUseAttack(Position(creaturePos.x - 1, creaturePos.y, creaturePos.z), attackedCreature));
			}

			if (result) {
				dirList.push_back(DIRECTION_WEST);
			}
		}
	}

	if (!dirList.empty()) {
		std::shuffle(dirList.begin(), dirList.end(), getRandomGenerator());
		direction = dirList[uniform_random(0, dirList.size() - 1)];
		return true;
	}
	return false;
}
Example #13
0
Direction Monster::getDanceStep(bool keepAttack /*= true*/, bool keepDistance /*= true*/) const
{
	Position position = getPosition();

	assert(attackedCreature);
	bool canDoAttackNow = canUseAttack(position, attackedCreature);
	const Position& centerPos = attackedCreature->getPosition();

	uint32_t tmpDist, centerToDist = std::max(std::abs(static_cast<signed>(position.x) - static_cast<signed>(centerPos.x)), std::abs(static_cast<signed>(position.y) - static_cast<signed>(centerPos.y)));
	if (centerToDist == 0) {
		return getRandomStepDirection(false);
	}

	std::vector<Direction> dirVector;
	if(!keepDistance || position.y >= centerPos.y)
	{
		tmpDist = std::max(std::abs(static_cast<signed>(position.x) - static_cast<signed>(centerPos.x)), std::abs(static_cast<signed>(position.y - 1) - static_cast<signed>(centerPos.y)));
		if(tmpDist == centerToDist && canMoveTo(Direction::NORTH))
		{
			bool result = true;
			if(keepAttack)
				result = (!canDoAttackNow || canUseAttack(Position(position.x, position.y - 1, position.z), attackedCreature));

			if(result)
				dirVector.push_back(Direction::NORTH);
		}
	}

	if(!keepDistance || position.y <= centerPos.y)
	{
		tmpDist = std::max(std::abs(static_cast<signed>(position.x) - static_cast<signed>(centerPos.x)), std::abs(static_cast<signed>(position.y + 1) - static_cast<signed>(centerPos.y)));
		if(tmpDist == centerToDist && canMoveTo(Direction::SOUTH))
		{
			bool result = true;
			if(keepAttack)
				result = (!canDoAttackNow || canUseAttack(Position(position.x, position.y + 1, position.z), attackedCreature));

			if(result)
				dirVector.push_back(Direction::SOUTH);
		}
	}

	if(!keepDistance || position.x <= centerPos.x)
	{
		tmpDist = std::max(std::abs(static_cast<signed>(position.x + 1) - static_cast<signed>(centerPos.x)), std::abs(static_cast<signed>(position.y) - static_cast<signed>(centerPos.y)));
		if(tmpDist == centerToDist && canMoveTo(Direction::EAST))
		{
			bool result = true;
			if(keepAttack)
				result = (!canDoAttackNow || canUseAttack(Position(position.x + 1, position.y, position.z), attackedCreature));

			if(result)
				dirVector.push_back(Direction::EAST);
		}
	}

	if(!keepDistance || position.x >= centerPos.x)
	{
		tmpDist = std::max(std::abs(static_cast<signed>(position.x - 1) - static_cast<signed>(centerPos.x)), std::abs(static_cast<signed>(position.y) - static_cast<signed>(centerPos.y)));
		if(tmpDist == centerToDist && canMoveTo(Direction::WEST))
		{
			bool result = true;
			if(keepAttack)
				result = (!canDoAttackNow || canUseAttack(Position(position.x - 1, position.y, position.z), attackedCreature));

			if(result)
				dirVector.push_back(Direction::WEST);
		}
	}

	if(dirVector.empty())
		return Direction::NONE;

	return dirVector[random_range<uint32_t>(0, dirVector.size() - 1)];
}