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); }
bool Monster::canUseSpell(const Position& pos, const Position& targetPos, const spellBlock_t& sb, uint32_t interval, bool& inRange, bool& resetTicks) { inRange = true; if (sb.isMelee && isFleeing()) { return false; } if (extraMeleeAttack) { lastMeleeAttack = OTSYS_TIME(); } else if (sb.isMelee && (OTSYS_TIME() - lastMeleeAttack) < 1500) { return false; } if (!sb.isMelee || !extraMeleeAttack) { if (sb.speed > attackTicks) { resetTicks = false; return false; } if (attackTicks % sb.speed >= interval) { //already used this spell for this round return false; } } if (sb.range != 0 && std::max<uint32_t>(Position::getDistanceX(pos, targetPos), Position::getDistanceY(pos, targetPos)) > sb.range) { inRange = false; return false; } return true; }
Direction Monster::getWanderingDirection() const { if (!isAlive()) { return Direction::NONE; } Direction direction = Direction::NONE; if (attackedCreature != nullptr) { //target dancing if(isFleeing()) direction = getDanceStep(false, false); else if(_type->staticAttackChance < (uint32_t)random_range(1, 100)) direction = getDanceStep(); } else { direction = getRandomStepDirection(); } if(direction != Direction::NONE && (canPushItems() || canPushCreatures())) { if(Tile* tile = server.game().getTile(Spells::getCasterPosition(this, direction))) { // TODO refactor! if(canPushItems()) const_cast<Monster*>(this)->pushItems(tile); } } return direction; }
void Monster::doAttacking(uint32_t interval) { if(!attackedCreature || (isSummon() && attackedCreature == this)) return; bool updateLook = true, outOfRange = true; resetTicks = interval; attackTicks += interval; const Position& myPos = getPosition(); const Position& targetPos = attackedCreature->getPosition(); for(SpellList::iterator it = mType->spellAttackList.begin(); it != mType->spellAttackList.end(); ++it) { if(it->isMelee && isFleeing()) continue; bool inRange = false; if(canUseSpell(myPos, targetPos, *it, interval, inRange)) { if(it->chance >= (uint32_t)random_range(1, 100)) { if(updateLook) { updateLookDirection(); updateLook = false; } double multiplier; if(maxCombatValue > 0) //defense multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_DEFENSE); else //attack multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_ATTACK); minCombatValue = (int32_t)(it->minCombatValue * multiplier); maxCombatValue = (int32_t)(it->maxCombatValue * multiplier); it->spell->castSpell(this, attackedCreature); if(it->isMelee) extraMeleeAttack = false; #ifdef __DEBUG__ static uint64_t prevTicks = OTSYS_TIME(); std::clog << "doAttacking ticks: " << OTSYS_TIME() - prevTicks << std::endl; prevTicks = OTSYS_TIME(); #endif } } if(inRange) outOfRange = false; else if(it->isMelee) //melee swing out of reach extraMeleeAttack = true; } if(updateLook) updateLookDirection(); if(resetTicks) attackTicks = 0; }
bool Actor::getNextStep(Direction& dir, uint32_t& flags) { if(isIdle || getHealth() <= 0){ //we dont have anyone watching might aswell stop walking eventWalk = 0; return false; } bool result = false; if((!followCreature || !hasFollowPath) && !isSummon()){ if(followCreature){ result = getRandomStep(getPosition(), dir); }else{ if(getTimeSinceLastMove() > 1000){ //choose a random direction result = getRandomStep(getPosition(), dir); } } } else if(isSummon() || followCreature){ result = Creature::getNextStep(dir, flags); if(result){ flags |= FLAG_PATHFINDING; } else{ //target dancing if(attackedCreature && attackedCreature == followCreature){ if(isFleeing()){ result = getDanceStep(getPosition(), dir, false, false); } else if(cType.staticAttackChance() < (uint32_t)random_range(1, 100)){ result = getDanceStep(getPosition(), dir); } } } } if(result && (canPushItems() || canPushCreatures()) ){ const Position& pos = Combat::getCasterPosition(this, dir); Tile* tile = g_game.getParentTile(pos.x, pos.y, pos.z); if(tile){ if(canPushItems()){ pushItems(tile); } if(canPushCreatures()){ pushCreatures(tile); } } #ifdef __DEBUG__ else{ std::cout << "getNextStep - no tile." << std::endl; } #endif } return result; }
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); } } }
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); }
void Monster::doAttacking(uint32_t interval) { if(!attackedCreature) return; bool updateLook = true; resetTicks = (interval != 0); attackTicks += interval; const Position& myPos = getPosition(); for(SpellList::iterator it = _type->spellAttackList.begin(); it != _type->spellAttackList.end(); ++it) { if(!attackedCreature || !attackedCreature->isAlive()) break; const Position& targetPos = attackedCreature->getPosition(); if(it->isMelee && isFleeing()) continue; bool inRange = false; if(canUseSpell(myPos, targetPos, *it, interval, inRange)) { if(it->chance >= (uint32_t)random_range(1, 100)) { if(updateLook) { updateLookDirection(); updateLook = false; } double multiplier; if(maxCombatValue > 0) //defense multiplier = server.configManager().getDouble(ConfigManager::RATE_MONSTER_DEFENSE); else //attack multiplier = server.configManager().getDouble(ConfigManager::RATE_MONSTER_ATTACK); minCombatValue = (int32_t)(it->minCombatValue * multiplier); maxCombatValue = (int32_t)(it->maxCombatValue * multiplier); it->spell->castSpell(this, attackedCreature); if(it->isMelee) extraMeleeAttack = false; } } if(!inRange && it->isMelee) //melee swing out of reach extraMeleeAttack = true; } if(updateLook) updateLookDirection(); if(resetTicks) attackTicks = 0; }
bool Monster::getNextStep(Direction& dir, uint32_t& flags) { if(isIdle || getHealth() <= 0) { //we dont have anyone watching might aswell stop walking eventWalk = 0; return false; } bool result = false; if((!followCreature || !hasFollowPath) && !isSummon()) { if(followCreature || getTimeSinceLastMove() > 1000) //choose a random direction result = getRandomStep(getPosition(), dir); } else if(isSummon() || followCreature) { result = Creature::getNextStep(dir, flags); if(!result) { //target dancing if(attackedCreature && attackedCreature == followCreature) { if(isFleeing()) result = getDanceStep(getPosition(), dir, false, false); else if(mType->staticAttackChance < (uint32_t)random_range(1, 100)) result = getDanceStep(getPosition(), dir); } } else flags |= FLAG_PATHFINDING; } if(result && (canPushItems() || canPushCreatures())) { if(Tile* tile = g_game.getTile(Spells::getCasterPosition(this, dir))) { if(canPushItems()) pushItems(tile); if(canPushCreatures()) pushCreatures(tile); } #ifdef __DEBUG__ else std::clog << "[Warning - Monster::getNextStep] no tile found." << std::endl; #endif } return result; }
bool Monster::getNextStep(Direction& direction, uint32_t& flags) { if (isIdle || getHealth() <= 0) { //we dont have anyone watching might aswell stop walking eventWalk = 0; return false; } bool result = false; if ((!followCreature || !hasFollowPath) && (!isSummon() || !isMasterInRange)) { if (followCreature || getTimeSinceLastMove() > 1000) { //choose a random direction result = getRandomStep(getPosition(), direction); } } else if ((isSummon() && isMasterInRange) || followCreature) { result = Creature::getNextStep(direction, flags); if (result) { flags |= FLAG_PATHFINDING; } else { //target dancing if (attackedCreature && attackedCreature == followCreature) { if (isFleeing()) { result = getDanceStep(getPosition(), direction, false, false); } else if (mType->info.staticAttackChance < static_cast<uint32_t>(uniform_random(1, 100))) { result = getDanceStep(getPosition(), direction); } } } } if (result && (canPushItems() || canPushCreatures())) { const Position& pos = Spells::getCasterPosition(this, direction); Tile* tile = g_game.map.getTile(pos); if (tile) { if (canPushItems()) { Monster::pushItems(tile); } if (canPushCreatures()) { Monster::pushCreatures(tile); } } } return result; }
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); } } } }
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); }
void Monster::doAttacking(uint32_t interval) { if(!attackedCreature || (isSummon() && attackedCreature == this)) return; // aqui const Position& myPos = getPosition(); const Position& targetPos = attackedCreature->getPosition(); FindPathParams fpp; fpp.fullPathSearch = true; fpp.maxSearchDist = -1; fpp.minTargetDist = 0; fpp.maxTargetDist = 1; std::string valueString; std::list<Direction> dirList; if(attackedCreature->getPlayer()){ if(Creature* summon = attackedCreature->pushBackSummonOne()) selectTarget(summon); } /* if(!g_game.getPathToEx(this, targetPos, dirList, fpp) && attackedCreature->isSummon()){ selectTarget(attackedCreature->getMaster()); std::string strValue; int32_t value; if(getStorage(8085, strValue)) { value = atoi(strValue.c_str()); } if(value == 0) g_game.addAnimatedText(getPosition(), 215, "GRRR!"); setStorage(8085, "2"); } if(attackedCreature->getPlayer()){ if(Creature* summon = attackedCreature->pushBackSummonOne()){ if(g_game.getPathToEx(this, summon->getPosition(), dirList, fpp)){ selectTarget(summon); std::string strValue, playerStor; int32_t value, value2; if(getStorage(8085, strValue)) { value = atoi(strValue.c_str()); } if(value == 2) g_game.addAnimatedText(getPosition(), 215, "Hmpf"); setStorage(8085, "0"); } }else setStorage(8085, "1"); } */ bool updateLook = true, outOfRange = true; resetTicks = interval; attackTicks += interval; for(SpellList::iterator it = mType->spellAttackList.begin(); it != mType->spellAttackList.end(); ++it) { if(it->isMelee && isFleeing()) continue; bool inRange = false; if(canUseSpell(myPos, targetPos, *it, interval, inRange)) { if(it->chance >= (uint32_t)random_range(1, 100)) { if(updateLook) { updateLookDirection(); updateLook = false; } double multiplier; if(maxCombatValue > 0) //defense multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_DEFENSE); else //attack multiplier = g_config.getDouble(ConfigManager::RATE_MONSTER_ATTACK); minCombatValue = (int32_t)(it->minCombatValue * multiplier); maxCombatValue = (int32_t)(it->maxCombatValue * multiplier); it->spell->castSpell(this, attackedCreature); if(it->isMelee) extraMeleeAttack = false; #ifdef __DEBUG__ static uint64_t prevTicks = OTSYS_TIME(); std::cout << "doAttacking ticks: " << OTSYS_TIME() - prevTicks << std::endl; prevTicks = OTSYS_TIME(); #endif } } if(inRange) outOfRange = false; else if(it->isMelee) //melee swing out of reach extraMeleeAttack = true; } if(updateLook) updateLookDirection(); if(resetTicks) attackTicks = 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); } } }