forgottenserver/src/creature.cpp

1552 lines
37 KiB
C++
Raw Permalink Normal View History

2023-02-18 20:10:02 -03:00
// Copyright 2023 The Forgotten Server Authors. All rights reserved.
// Use of this source code is governed by the GPL-2.0 License that can be found in the LICENSE file.
2013-07-07 02:30:08 +02:00
#include "otpch.h"
#include "creature.h"
#include "combat.h"
#include "configmanager.h"
#include "events.h"
2013-07-07 02:30:08 +02:00
#include "game.h"
#include "monster.h"
#include "party.h"
2013-11-10 05:02:15 +01:00
#include "scheduler.h"
#include "spectators.h"
2013-07-07 02:30:08 +02:00
double Creature::speedA = 857.36;
double Creature::speedB = 261.29;
double Creature::speedC = -4795.01;
extern Game g_game;
extern CreatureEvents* g_creatureEvents;
Creature::Creature() { onIdleStatus(); }
2013-07-07 02:30:08 +02:00
Creature::~Creature()
{
for (Creature* summon : summons) {
summon->removeAttackedCreature();
summon->removeMaster();
2013-07-07 02:30:08 +02:00
}
for (Condition* condition : conditions) {
2013-12-27 11:36:41 +01:00
condition->endCondition(this);
}
for (auto condition : conditions) {
delete condition;
2013-07-07 02:30:08 +02:00
}
}
bool Creature::canSee(const Position& myPos, const Position& pos, int32_t viewRangeX, int32_t viewRangeY)
2013-07-07 02:30:08 +02:00
{
if (myPos.z <= 7) {
2021-02-22 00:34:23 -03:00
// we are on ground level or above (7 -> 0)
// view is from 7 -> 0
2013-07-07 02:30:08 +02:00
if (pos.z > 7) {
return false;
}
} else if (myPos.z >= 8) {
2021-02-22 00:34:23 -03:00
// we are underground (8 -> 15)
// we can't see floors above 8
if (pos.z < 8) {
return false;
}
2021-02-22 00:34:23 -03:00
// view is +/- 2 from the floor we stand on
if (myPos.getDistanceZ(pos) > 2) {
2013-07-07 02:30:08 +02:00
return false;
}
}
int32_t offsetz = myPos.getOffsetZ(pos);
return (pos.getX() >= myPos.getX() - viewRangeX + offsetz) && (pos.getX() <= myPos.getX() + viewRangeX + offsetz) &&
(pos.getY() >= myPos.getY() - viewRangeY + offsetz) && (pos.getY() <= myPos.getY() + viewRangeY + offsetz);
2013-07-07 02:30:08 +02:00
}
bool Creature::canSee(const Position& pos) const
{
return canSee(getPosition(), pos, Map::maxViewportX, Map::maxViewportY);
}
bool Creature::canSeeCreature(const Creature* creature) const
{
if (!canSeeGhostMode(creature) && creature->isInGhostMode()) {
return false;
}
2013-07-07 02:30:08 +02:00
if (!canSeeInvisibility() && creature->isInvisible()) {
return false;
}
return true;
}
void Creature::setSkull(Skulls_t newSkull)
{
skull = newSkull;
g_game.updateCreatureSkull(this);
}
2013-07-07 02:30:08 +02:00
int64_t Creature::getTimeSinceLastMove() const
{
if (lastStep) {
return OTSYS_TIME() - lastStep;
}
return std::numeric_limits<int64_t>::max();
2013-07-07 02:30:08 +02:00
}
int32_t Creature::getWalkDelay(Direction dir) const
{
if (lastStep == 0) {
return 0;
}
int64_t ct = OTSYS_TIME();
int64_t stepDuration = getStepDuration(dir);
return stepDuration - (ct - lastStep);
}
int32_t Creature::getWalkDelay() const
{
// Used for auto-walking
2013-07-07 02:30:08 +02:00
if (lastStep == 0) {
return 0;
}
int64_t ct = OTSYS_TIME();
int64_t stepDuration = getStepDuration() * lastStepCost;
return stepDuration - (ct - lastStep);
}
void Creature::onThink(uint32_t interval)
{
2013-12-14 00:15:30 +01:00
if (followCreature && master != followCreature && !canSeeCreature(followCreature)) {
2013-07-07 02:30:08 +02:00
onCreatureDisappear(followCreature, false);
}
2013-12-14 00:15:30 +01:00
if (attackedCreature && master != attackedCreature && !canSeeCreature(attackedCreature)) {
2013-07-07 02:30:08 +02:00
onCreatureDisappear(attackedCreature, false);
}
blockTicks += interval;
if (blockTicks >= 1000) {
blockCount = std::min<uint32_t>(blockCount + 1, 2);
blockTicks = 0;
}
// scripting event - onThink
const CreatureEventList& thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK);
for (CreatureEvent* thinkEvent : thinkEvents) {
thinkEvent->executeOnThink(this, interval);
2013-07-07 02:30:08 +02:00
}
}
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
void Creature::forceUpdatePath()
{
if (!attackedCreature && !followCreature) {
return;
}
lastPathUpdate = OTSYS_TIME() + getNumber(ConfigManager::PATHFINDING_DELAY);
g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); }));
}
2013-07-07 02:30:08 +02:00
void Creature::onAttacking(uint32_t interval)
{
if (!attackedCreature) {
return;
}
onAttacked();
attackedCreature->onAttacked();
if (g_game.isSightClear(getPosition(), attackedCreature->getPosition(), true)) {
doAttacking(interval);
}
}
void Creature::onIdleStatus()
{
2022-10-30 17:16:15 -03:00
if (!isDead()) {
2013-07-07 02:30:08 +02:00
damageMap.clear();
lastHitCreatureId = 0;
2013-07-07 02:30:08 +02:00
}
}
void Creature::onWalk()
{
if (getWalkDelay() <= 0) {
Direction dir;
uint32_t flags = FLAG_IGNOREFIELDDAMAGE;
if (getNextStep(dir, flags)) {
ReturnValue ret = g_game.internalMoveCreature(this, dir, flags);
if (ret != RETURNVALUE_NOERROR) {
2013-07-07 02:30:08 +02:00
if (Player* player = getPlayer()) {
player->sendCancelMessage(ret);
player->sendCancelWalk();
}
}
} else {
stopEventWalk();
2013-07-07 02:30:08 +02:00
if (listWalkDir.empty()) {
onWalkComplete();
}
}
}
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
removeFollowers();
updateFollowersPaths();
2013-07-07 02:30:08 +02:00
if (cancelNextWalk) {
listWalkDir.clear();
onWalkAborted();
cancelNextWalk = false;
}
if (eventWalk != 0) {
eventWalk = 0;
addEventWalk();
}
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
if (attackedCreature || followCreature) {
if (lastPathUpdate < OTSYS_TIME()) {
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
g_dispatcher.addTask(createTask([id = getID()]() { g_game.updateCreatureWalk(id); }));
lastPathUpdate = OTSYS_TIME() + getNumber(ConfigManager::PATHFINDING_DELAY);
}
}
2013-07-07 02:30:08 +02:00
}
void Creature::onWalk(Direction& dir)
{
if (!hasCondition(CONDITION_DRUNK)) {
return;
2013-07-07 02:30:08 +02:00
}
uint16_t rand = uniform_random(0, 399);
if (rand / 4 > getDrunkenness()) {
return;
}
dir = static_cast<Direction>(rand % 4);
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_SAY, "Hicks!", false);
2013-07-07 02:30:08 +02:00
}
2013-12-27 11:36:41 +01:00
bool Creature::getNextStep(Direction& dir, uint32_t&)
2013-07-07 02:30:08 +02:00
{
if (listWalkDir.empty()) {
return false;
}
dir = listWalkDir.back();
listWalkDir.pop_back();
2013-07-07 02:30:08 +02:00
onWalk(dir);
return true;
}
void Creature::startAutoWalk()
2013-07-07 02:30:08 +02:00
{
Player* player = getPlayer();
if (player && player->isMovementBlocked()) {
player->sendCancelWalk();
return;
}
addEventWalk(listWalkDir.size() == 1);
}
void Creature::startAutoWalk(Direction direction)
{
Player* player = getPlayer();
if (player && player->isMovementBlocked()) {
player->sendCancelWalk();
return;
}
listWalkDir.clear();
listWalkDir.push_back(direction);
addEventWalk(true);
}
void Creature::startAutoWalk(const std::vector<Direction>& listDir)
{
if (hasCondition(CONDITION_ROOT)) {
return;
}
Player* player = getPlayer();
if (player && player->isMovementBlocked()) {
player->sendCancelWalk();
return;
}
listWalkDir = listDir;
addEventWalk(listWalkDir.size() == 1);
2013-07-07 02:30:08 +02:00
}
void Creature::addEventWalk(bool firstStep)
{
cancelNextWalk = false;
if (getStepSpeed() <= 0) {
return;
}
if (eventWalk != 0) {
return;
}
int64_t ticks = getEventStepTicks(firstStep);
if (ticks <= 0) {
return;
}
// Take first step right away, but still queue the next
if (ticks == 1) {
g_game.checkCreatureWalk(getID());
}
2022-03-18 21:20:24 +01:00
eventWalk = g_scheduler.addEvent(createSchedulerTask(ticks, [id = getID()]() { g_game.checkCreatureWalk(id); }));
2013-07-07 02:30:08 +02:00
}
void Creature::stopEventWalk()
{
if (eventWalk != 0) {
g_scheduler.stopEvent(eventWalk);
2013-07-07 02:30:08 +02:00
eventWalk = 0;
}
}
void Creature::updateIcons() const
{
SpectatorVec spectators;
g_game.map.getSpectators(spectators, position, true, true);
for (Creature* spectator : spectators) {
assert(dynamic_cast<Player*>(spectator) != nullptr);
static_cast<Player*>(spectator)->sendUpdateCreatureIcons(this);
}
}
2024-11-07 19:33:27 -03:00
void Creature::onRemoveCreature(Creature* creature, bool) { onCreatureDisappear(creature, true); }
2013-07-07 02:30:08 +02:00
void Creature::onCreatureDisappear(const Creature* creature, bool isLogout)
{
if (attackedCreature == creature) {
removeAttackedCreature();
2013-07-07 02:30:08 +02:00
onAttackedCreatureDisappear(isLogout);
}
if (followCreature == creature) {
removeFollowCreature();
2013-07-07 02:30:08 +02:00
onFollowCreatureDisappear(isLogout);
}
}
void Creature::updateFollowCreaturePath(FindPathParams& fpp)
{
listWalkDir.clear();
if (getPathTo(followCreature->getPosition(), listWalkDir, fpp)) {
hasFollowPath = true;
startAutoWalk();
} else {
hasFollowPath = false;
}
}
2013-07-07 02:30:08 +02:00
void Creature::onChangeZone(ZoneType_t zone)
{
if (attackedCreature && zone == ZONE_PROTECTION) {
onCreatureDisappear(attackedCreature, false);
}
}
void Creature::onAttackedCreatureChangeZone(ZoneType_t zone)
{
if (zone == ZONE_PROTECTION) {
onCreatureDisappear(attackedCreature, false);
}
}
void Creature::onCreatureMove(Creature* creature, const Tile* newTile, const Position& newPos, const Tile* oldTile,
const Position& oldPos, bool teleport)
2013-07-07 02:30:08 +02:00
{
if (creature == this) {
lastStep = OTSYS_TIME();
lastStepCost = 1;
if (!teleport) {
if (oldPos.z != newPos.z) {
// floor change extra cost
lastStepCost = 2;
} else if (newPos.getDistanceX(oldPos) >= 1 && newPos.getDistanceY(oldPos) >= 1) {
// diagonal extra cost
2013-10-03 03:16:53 +02:00
lastStepCost = 3;
2013-07-07 02:30:08 +02:00
}
} else {
stopEventWalk();
}
if (!summons.empty()) {
// check if any of our summons is out of range (+/- 2 floors or 30 tiles away)
std::forward_list<Creature*> despawnList;
2013-09-25 02:39:10 +02:00
for (Creature* summon : summons) {
const Position& pos = summon->getPosition();
if (newPos.getDistanceZ(pos) > 2 || std::max(newPos.getDistanceX(pos), newPos.getDistanceY(pos)) > 30) {
despawnList.push_front(summon);
2013-07-07 02:30:08 +02:00
}
}
2013-09-25 02:39:10 +02:00
for (Creature* despawnCreature : despawnList) {
g_game.removeCreature(despawnCreature, true);
2013-07-07 02:30:08 +02:00
}
}
if (newTile->getZone() != oldTile->getZone()) {
tfs::events::creature::onChangeZone(this, oldTile->getZone(), newTile->getZone());
2013-07-07 02:30:08 +02:00
onChangeZone(getZone());
}
}
if (creature == followCreature || (creature == this && followCreature)) {
if (newPos.z != oldPos.z || !canSee(followCreature->getPosition())) {
onCreatureDisappear(followCreature, false);
}
}
if (creature == attackedCreature || (creature == this && attackedCreature)) {
if (newPos.z != oldPos.z || !canSee(attackedCreature->getPosition())) {
onCreatureDisappear(attackedCreature, false);
} else {
if (hasExtraSwing()) {
// our target is moving lets see if we can get in hit
g_dispatcher.addTask([id = getID()]() { g_game.checkCreatureAttack(id); });
2013-07-07 02:30:08 +02:00
}
if (newTile->getZone() != oldTile->getZone()) {
onAttackedCreatureChangeZone(attackedCreature->getZone());
}
}
}
}
2021-06-26 12:34:53 -04:00
CreatureVector Creature::getKillers()
{
CreatureVector killers;
const int64_t timeNow = OTSYS_TIME();
const uint32_t inFightTicks = getNumber(ConfigManager::PZ_LOCKED);
2021-06-26 12:34:53 -04:00
for (const auto& it : damageMap) {
Creature* attacker = g_game.getCreatureByID(it.first);
if (attacker && attacker != this && timeNow - it.second.ticks <= inFightTicks) {
killers.push_back(attacker);
}
}
return killers;
}
2013-07-07 02:30:08 +02:00
void Creature::onDeath()
{
bool lastHitUnjustified = false;
bool mostDamageUnjustified = false;
Creature* lastHitCreature = g_game.getCreatureByID(lastHitCreatureId);
2013-12-14 00:15:30 +01:00
Creature* lastHitCreatureMaster;
if (lastHitCreature) {
lastHitUnjustified = lastHitCreature->onKilledCreature(this);
lastHitCreatureMaster = lastHitCreature->getMaster();
2013-12-14 00:15:30 +01:00
} else {
lastHitCreatureMaster = nullptr;
}
2013-07-07 02:30:08 +02:00
2013-12-14 00:15:30 +01:00
Creature* mostDamageCreature = nullptr;
2013-07-07 02:30:08 +02:00
2013-12-14 00:15:30 +01:00
const int64_t timeNow = OTSYS_TIME();
const uint32_t inFightTicks = getNumber(ConfigManager::PZ_LOCKED);
2013-12-14 00:15:30 +01:00
int32_t mostDamage = 0;
2015-10-07 15:06:22 +02:00
std::map<Creature*, uint64_t> experienceMap;
2013-12-14 00:15:30 +01:00
for (const auto& it : damageMap) {
if (Creature* attacker = g_game.getCreatureByID(it.first)) {
CountBlock_t cb = it.second;
if ((cb.total > mostDamage && (timeNow - cb.ticks <= inFightTicks))) {
mostDamage = cb.total;
mostDamageCreature = attacker;
2013-07-07 02:30:08 +02:00
}
2015-10-07 15:06:22 +02:00
if (attacker != this) {
uint64_t gainExp = getGainedExperience(attacker);
if (Player* attackerPlayer = attacker->getPlayer()) {
attackerPlayer->removeAttacked(getPlayer());
Party* party = attackerPlayer->getParty();
if (party && party->getLeader() && party->isSharedExperienceActive() &&
party->isSharedExperienceEnabled()) {
2015-10-07 15:06:22 +02:00
attacker = party->getLeader();
}
}
2015-10-08 20:14:36 +02:00
auto tmpIt = experienceMap.find(attacker);
if (tmpIt == experienceMap.end()) {
2015-10-07 15:06:22 +02:00
experienceMap[attacker] = gainExp;
} else {
2015-10-08 20:14:36 +02:00
tmpIt->second += gainExp;
2015-10-07 15:06:22 +02:00
}
}
2013-07-07 02:30:08 +02:00
}
}
2015-10-07 15:06:22 +02:00
for (const auto& it : experienceMap) {
it.first->onGainExperience(it.second, this);
}
2013-12-14 00:15:30 +01:00
if (mostDamageCreature) {
if (mostDamageCreature != lastHitCreature && mostDamageCreature != lastHitCreatureMaster) {
2013-12-14 00:15:30 +01:00
Creature* mostDamageCreatureMaster = mostDamageCreature->getMaster();
if (lastHitCreature != mostDamageCreatureMaster &&
(!lastHitCreatureMaster || mostDamageCreatureMaster != lastHitCreatureMaster)) {
2013-12-14 00:15:30 +01:00
mostDamageUnjustified = mostDamageCreature->onKilledCreature(this, false);
}
2013-07-07 02:30:08 +02:00
}
}
bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
death(lastHitCreature);
2013-07-07 02:30:08 +02:00
2013-12-14 00:15:30 +01:00
if (master) {
2017-02-11 20:44:57 -03:00
setMaster(nullptr);
2013-07-07 02:30:08 +02:00
}
if (droppedCorpse) {
g_game.removeCreature(this, false);
}
}
bool Creature::dropCorpse(Creature* lastHitCreature, Creature* mostDamageCreature, bool lastHitUnjustified,
bool mostDamageUnjustified)
2013-07-07 02:30:08 +02:00
{
if (!lootDrop && getMonster()) {
2013-07-07 02:30:08 +02:00
if (master) {
// scripting event - onDeath
const CreatureEventList& deathEvents = getCreatureEvents(CREATURE_EVENT_DEATH);
for (CreatureEvent* deathEvent : deathEvents) {
deathEvent->executeOnDeath(this, nullptr, lastHitCreature, mostDamageCreature, lastHitUnjustified,
mostDamageUnjustified);
2013-07-07 02:30:08 +02:00
}
}
g_game.addMagicEffect(getPosition(), CONST_ME_POFF);
2013-07-07 02:30:08 +02:00
} else {
Item* splash;
2013-07-07 02:30:08 +02:00
switch (getRace()) {
case RACE_VENOM:
splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_SLIME);
2013-07-07 02:30:08 +02:00
break;
case RACE_BLOOD:
splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_BLOOD);
break;
case RACE_INK:
splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_INK);
break;
2013-07-07 02:30:08 +02:00
default:
splash = nullptr;
2013-07-07 02:30:08 +02:00
break;
}
Tile* tile = getTile();
if (splash) {
g_game.internalAddItem(tile, splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
g_game.startDecay(splash);
}
Item* corpse = getCorpse(lastHitCreature, mostDamageCreature);
2013-07-07 02:30:08 +02:00
if (corpse) {
g_game.internalAddItem(tile, corpse, INDEX_WHEREEVER, FLAG_NOLIMIT);
g_game.startDecay(corpse);
}
// scripting event - onDeath
for (CreatureEvent* deathEvent : getCreatureEvents(CREATURE_EVENT_DEATH)) {
deathEvent->executeOnDeath(this, corpse, lastHitCreature, mostDamageCreature, lastHitUnjustified,
mostDamageUnjustified);
2013-07-07 02:30:08 +02:00
}
if (corpse) {
dropLoot(corpse->getContainer(), lastHitCreature);
2013-07-07 02:30:08 +02:00
}
}
return true;
}
bool Creature::hasBeenAttacked(uint32_t attackerId)
{
2013-09-25 02:39:10 +02:00
auto it = damageMap.find(attackerId);
if (it == damageMap.end()) {
return false;
2013-07-07 02:30:08 +02:00
}
return (OTSYS_TIME() - it->second.ticks) <= getNumber(ConfigManager::PZ_LOCKED);
2013-07-07 02:30:08 +02:00
}
Item* Creature::getCorpse(Creature*, Creature*) { return Item::CreateItem(getLookCorpse()); }
2013-07-07 02:30:08 +02:00
void Creature::changeHealth(int32_t healthChange, bool sendHealthChange /* = true*/)
2013-07-07 02:30:08 +02:00
{
int32_t oldHealth = health;
if (healthChange > 0) {
2013-07-11 19:02:36 +02:00
health += std::min<int32_t>(healthChange, getMaxHealth() - health);
2013-07-07 02:30:08 +02:00
} else {
health = std::max<int32_t>(0, health + healthChange);
}
if (sendHealthChange && oldHealth != health) {
g_game.addCreatureHealth(this);
}
2022-10-30 17:16:15 -03:00
if (isDead()) {
g_dispatcher.addTask([id = getID()]() { g_game.executeDeath(id); });
}
2013-07-07 02:30:08 +02:00
}
2013-08-28 20:21:24 +02:00
void Creature::gainHealth(Creature* healer, int32_t healthGain)
{
changeHealth(healthGain);
if (healer) {
healer->onTargetCreatureGainHealth(this, healthGain);
}
}
2013-10-10 18:11:12 +02:00
void Creature::drainHealth(Creature* attacker, int32_t damage)
2013-07-07 02:30:08 +02:00
{
changeHealth(-damage, false);
if (attacker) {
attacker->onAttackedCreatureDrainHealth(this, damage);
2021-06-26 12:34:53 -04:00
} else {
lastHitCreatureId = 0;
2013-07-07 02:30:08 +02:00
}
}
BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
bool checkDefense /* = false */, bool checkArmor /* = false */, bool /* field = false */,
bool /* ignoreResistances = false */)
2013-07-07 02:30:08 +02:00
{
BlockType_t blockType = BLOCK_NONE;
if (isImmune(combatType)) {
damage = 0;
blockType = BLOCK_IMMUNITY;
2023-02-18 22:50:29 +01:00
} else if (combatType != COMBAT_HEALING && (checkDefense || checkArmor)) {
2013-07-07 02:30:08 +02:00
bool hasDefense = false;
if (blockCount > 0) {
--blockCount;
hasDefense = true;
}
if (checkDefense && hasDefense && canUseDefense) {
int32_t defense = getDefense();
damage -= uniform_random(defense / 2, defense);
2013-07-07 02:30:08 +02:00
if (damage <= 0) {
damage = 0;
blockType = BLOCK_DEFENSE;
checkArmor = false;
}
}
if (checkArmor) {
int32_t armor = getArmor();
if (armor > 3) {
damage -= uniform_random(armor / 2, armor - (armor % 2 + 1));
} else if (armor > 0) {
--damage;
2013-07-07 02:30:08 +02:00
}
if (damage <= 0) {
damage = 0;
blockType = BLOCK_ARMOR;
}
}
if (hasDefense && blockType != BLOCK_NONE) {
2013-12-27 11:36:41 +01:00
onBlockHit();
2013-07-07 02:30:08 +02:00
}
}
if (attacker) {
if (Player* attackerPlayer = attacker->getPlayer()) {
for (int32_t slot = CONST_SLOT_FIRST; slot <= CONST_SLOT_LAST; ++slot) {
if (!attackerPlayer->isItemAbilityEnabled(static_cast<slots_t>(slot))) {
continue;
}
Item* item = attackerPlayer->getInventoryItem(static_cast<slots_t>(slot));
if (!item) {
continue;
}
const uint16_t boostPercent = item->getBoostPercent(combatType);
if (boostPercent != 0) {
damage += std::round(damage * (boostPercent / 100.));
}
}
}
2013-07-07 02:30:08 +02:00
if (damage <= 0) {
damage = 0;
blockType = BLOCK_ARMOR;
}
2023-02-18 22:50:29 +01:00
if (combatType != COMBAT_HEALING) {
attacker->onAttackedCreature(this);
attacker->onAttackedCreatureBlockHit(blockType);
if (attacker->getMaster() && attacker->getMaster()->getPlayer()) {
Player* masterPlayer = attacker->getMaster()->getPlayer();
masterPlayer->onAttackedCreature(this);
}
2023-02-18 22:50:29 +01:00
}
2013-07-07 02:30:08 +02:00
}
2023-02-18 22:50:29 +01:00
if (combatType != COMBAT_HEALING) {
onAttacked();
}
2013-07-07 02:30:08 +02:00
return blockType;
}
void Creature::setAttackedCreature(Creature* creature)
2013-07-07 02:30:08 +02:00
{
if (isAttackingCreature(creature)) {
return;
}
2013-07-07 02:30:08 +02:00
if (!canAttackCreature(creature)) {
removeAttackedCreature();
return;
2013-07-07 02:30:08 +02:00
}
attackedCreature = creature;
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
creature->addFollower(this);
onAttackedCreature(attackedCreature);
attackedCreature->onAttacked();
forceUpdatePath();
for (Creature* summon : summons) {
summon->setAttackedCreature(creature);
2013-07-07 02:30:08 +02:00
}
}
void Creature::removeAttackedCreature()
{
attackedCreature = nullptr;
for (Creature* summon : summons) {
summon->removeAttackedCreature();
}
}
bool Creature::canAttackCreature(Creature* creature)
{
const auto& creaturePos = creature->getPosition();
if (creaturePos.z != getPosition().z) {
return false;
}
return canSee(creaturePos);
2013-07-07 02:30:08 +02:00
}
2013-12-27 11:36:41 +01:00
void Creature::getPathSearchParams(const Creature*, FindPathParams& fpp) const
2013-07-07 02:30:08 +02:00
{
fpp.fullPathSearch = !hasFollowPath;
fpp.clearSight = true;
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
fpp.maxSearchDist = Map::maxViewportX + Map::maxViewportY;
2013-07-07 02:30:08 +02:00
fpp.minTargetDist = 1;
fpp.maxTargetDist = 1;
}
void Creature::setFollowCreature(Creature* creature)
2013-07-07 02:30:08 +02:00
{
if (isFollowingCreature(creature)) {
return;
}
2013-07-07 02:30:08 +02:00
if (!canFollowCreature(creature)) {
removeFollowCreature();
return;
}
2013-07-07 02:30:08 +02:00
followCreature = creature;
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
creature->addFollower(this);
hasFollowPath = false;
onFollowCreature(creature);
forceUpdatePath();
}
2013-07-07 02:30:08 +02:00
void Creature::removeFollowCreature()
{
followCreature = nullptr;
onUnfollowCreature();
}
bool Creature::canFollowCreature(Creature* creature)
{
const auto& creaturePos = creature->getPosition();
if (creaturePos.z != getPosition().z) {
return false;
2013-07-07 02:30:08 +02:00
}
return canSee(creaturePos);
}
2013-07-07 02:30:08 +02:00
void Creature::onFollowCreature(const Creature*)
{
if (!listWalkDir.empty()) {
listWalkDir.clear();
onWalkAborted();
}
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
}
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
void Creature::onUnfollowCreature() { hasFollowPath = false; }
// Pathfinding Events
bool Creature::isFollower(const Creature* creature)
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
{
auto it = std::find(followers.begin(), followers.end(), creature);
return it != followers.end();
}
void Creature::addFollower(Creature* creature)
{
if (!isFollower(creature)) {
followers.push_back(creature);
creature->incrementReferenceCounter();
}
}
void Creature::removeFollower(Creature* creature)
{
auto it = std::find(followers.begin(), followers.end(), creature);
if (it != followers.end()) {
creature->decrementReferenceCounter();
followers.erase(it);
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
}
2013-07-07 02:30:08 +02:00
}
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
void Creature::removeFollowers()
{
const Position& position = getPosition();
followers.erase(std::remove_if(followers.begin(), followers.end(),
[&position](Creature* creature) {
const Position& followerPosition = creature->getPosition();
uint16_t distance = position.getDistanceX(followerPosition) +
position.getDistanceY(followerPosition);
bool isInRemoveRange = distance >= Map::maxViewportX + Map::maxViewportY ||
position.z != followerPosition.z;
if (isInRemoveRange) {
creature->decrementReferenceCounter();
}
return isInRemoveRange;
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
}),
followers.end());
}
void Creature::releaseFollowers()
{
for (const auto& follower : followers) {
follower->decrementReferenceCounter();
}
}
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
void Creature::updateFollowersPaths()
{
if (followers.empty()) {
return;
}
const Position& thisPosition = getPosition();
for (const auto& follower : followers) {
if (follower != nullptr) {
const Position& followerPosition = follower->getPosition();
if (follower->lastPathUpdate < OTSYS_TIME()) {
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
continue;
}
if (thisPosition.getDistanceX(followerPosition) >= Map::maxViewportX ||
thisPosition.getDistanceY(followerPosition) >= Map::maxViewportY) {
continue;
}
g_dispatcher.addTask(createTask([id = follower->getID()]() { g_game.updateCreatureWalk(id); }));
follower->lastPathUpdate = OTSYS_TIME() + getNumber(ConfigManager::PATHFINDING_DELAY);
}
}
}
2013-07-07 02:30:08 +02:00
double Creature::getDamageRatio(Creature* attacker) const
{
uint32_t totalDamage = 0;
uint32_t attackerDamage = 0;
2013-07-07 02:30:08 +02:00
2013-09-23 03:34:15 +02:00
for (const auto& it : damageMap) {
const CountBlock_t& cb = it.second;
2013-07-07 02:30:08 +02:00
totalDamage += cb.total;
2013-09-23 03:34:15 +02:00
if (it.first == attacker->getID()) {
2013-07-07 02:30:08 +02:00
attackerDamage += cb.total;
}
}
if (totalDamage == 0) {
return 0;
}
return (static_cast<double>(attackerDamage) / totalDamage);
2013-07-07 02:30:08 +02:00
}
uint64_t Creature::getGainedExperience(Creature* attacker) const
{
return std::floor(getDamageRatio(attacker) * getLostExperience());
}
void Creature::addDamagePoints(Creature* attacker, int32_t damagePoints)
{
if (damagePoints <= 0) {
return;
}
uint32_t attackerId = attacker->id;
2013-07-07 02:30:08 +02:00
2022-03-23 10:47:22 -07:00
auto& cb = damageMap[attackerId];
cb.ticks = OTSYS_TIME();
cb.total += damagePoints;
2013-07-07 02:30:08 +02:00
lastHitCreatureId = attackerId;
2013-07-07 02:30:08 +02:00
}
void Creature::onAddCondition(ConditionType_t type)
{
if (type == CONDITION_PARALYZE && hasCondition(CONDITION_HASTE)) {
removeCondition(CONDITION_HASTE);
} else if (type == CONDITION_HASTE && hasCondition(CONDITION_PARALYZE)) {
removeCondition(CONDITION_PARALYZE);
}
}
2013-12-27 11:36:41 +01:00
void Creature::onAddCombatCondition(ConditionType_t)
2013-07-07 02:30:08 +02:00
{
//
}
2013-12-27 11:36:41 +01:00
void Creature::onEndCondition(ConditionType_t)
2013-07-07 02:30:08 +02:00
{
//
}
void Creature::onTickCondition(ConditionType_t type, bool& bRemove)
{
const Tile* tile = getTile();
if (!tile) {
return;
}
const MagicField* field = tile->getFieldItem();
2013-07-07 02:30:08 +02:00
if (!field) {
return;
}
switch (type) {
case CONDITION_FIRE:
bRemove = (field->getCombatType() != COMBAT_FIREDAMAGE);
break;
case CONDITION_ENERGY:
bRemove = (field->getCombatType() != COMBAT_ENERGYDAMAGE);
break;
case CONDITION_POISON:
bRemove = (field->getCombatType() != COMBAT_EARTHDAMAGE);
break;
case CONDITION_FREEZING:
bRemove = (field->getCombatType() != COMBAT_ICEDAMAGE);
break;
case CONDITION_DAZZLED:
bRemove = (field->getCombatType() != COMBAT_HOLYDAMAGE);
break;
case CONDITION_CURSED:
bRemove = (field->getCombatType() != COMBAT_DEATHDAMAGE);
break;
case CONDITION_DROWN:
bRemove = (field->getCombatType() != COMBAT_DROWNDAMAGE);
break;
case CONDITION_BLEEDING:
bRemove = (field->getCombatType() != COMBAT_PHYSICALDAMAGE);
break;
default:
break;
}
}
void Creature::onCombatRemoveCondition(Condition* condition) { removeCondition(condition); }
2013-07-07 02:30:08 +02:00
void Creature::onAttacked()
{
//
}
void Creature::onAttackedCreatureDrainHealth(Creature* target, int32_t points)
{
target->addDamagePoints(this, points);
}
2013-12-27 11:36:41 +01:00
bool Creature::onKilledCreature(Creature* target, bool)
2013-07-07 02:30:08 +02:00
{
2013-12-14 00:15:30 +01:00
if (master) {
master->onKilledCreature(target);
2013-07-07 02:30:08 +02:00
}
// scripting event - onKill
const CreatureEventList& killEvents = getCreatureEvents(CREATURE_EVENT_KILL);
for (CreatureEvent* killEvent : killEvents) {
killEvent->executeOnKill(this, target);
2013-07-07 02:30:08 +02:00
}
return false;
}
void Creature::onGainExperience(uint64_t gainExp, Creature* target)
{
2015-03-28 03:24:35 +01:00
if (gainExp == 0 || !master) {
return;
}
2013-07-07 02:30:08 +02:00
2015-03-28 03:24:35 +01:00
gainExp /= 2;
master->onGainExperience(gainExp, target);
2013-07-07 02:30:08 +02:00
SpectatorVec spectators;
g_game.map.getSpectators(spectators, position, false, true);
if (spectators.empty()) {
2015-03-28 03:24:35 +01:00
return;
}
2013-07-07 02:30:08 +02:00
TextMessage message(MESSAGE_EXPERIENCE_OTHERS, ucfirst(getNameDescription()) + " gained " +
std::to_string(gainExp) +
(gainExp != 1 ? " experience points." : " experience point."));
message.position = position;
2015-03-28 03:24:35 +01:00
message.primary.color = TEXTCOLOR_WHITE_EXP;
message.primary.value = gainExp;
2013-07-07 02:30:08 +02:00
for (Creature* spectator : spectators) {
assert(dynamic_cast<Player*>(spectator) != nullptr);
static_cast<Player*>(spectator)->sendTextMessage(message);
2013-07-07 02:30:08 +02:00
}
}
bool Creature::setMaster(Creature* newMaster)
{
2017-02-11 20:44:57 -03:00
if (!newMaster && !master) {
return false;
}
2013-07-07 02:30:08 +02:00
2017-02-11 20:44:57 -03:00
if (newMaster) {
incrementReferenceCounter();
newMaster->summons.push_back(this);
2013-07-07 02:30:08 +02:00
}
2017-02-11 20:44:57 -03:00
Creature* oldMaster = master;
master = newMaster;
if (oldMaster) {
auto summon = std::find(oldMaster->summons.begin(), oldMaster->summons.end(), this);
if (summon != oldMaster->summons.end()) {
oldMaster->summons.erase(summon);
2017-02-11 20:44:57 -03:00
decrementReferenceCounter();
}
}
return true;
2013-07-07 02:30:08 +02:00
}
bool Creature::addCondition(Condition* condition, bool force /* = false*/)
2013-07-07 02:30:08 +02:00
{
if (!condition) {
2013-07-07 02:30:08 +02:00
return false;
}
if (!force && condition->getType() == CONDITION_HASTE && hasCondition(CONDITION_PARALYZE)) {
int64_t walkDelay = getWalkDelay();
if (walkDelay > 0) {
g_scheduler.addEvent(
createSchedulerTask(walkDelay, [=, id = getID()]() { g_game.forceAddCondition(id, condition); }));
2013-07-07 02:30:08 +02:00
return false;
}
}
Condition* prevCond = getCondition(condition->getType(), condition->getId(), condition->getSubId());
if (prevCond) {
prevCond->addCondition(this, condition);
delete condition;
return true;
}
if (condition->startCondition(this)) {
conditions.push_back(condition);
onAddCondition(condition->getType());
return true;
}
delete condition;
return false;
}
bool Creature::addCombatCondition(Condition* condition)
{
// Caution: condition variable could be deleted after the call to addCondition
2013-07-07 02:30:08 +02:00
ConditionType_t type = condition->getType();
if (!addCondition(condition)) {
return false;
}
onAddCombatCondition(type);
return true;
}
void Creature::removeCondition(ConditionType_t type, bool force /* = false*/)
2013-07-07 02:30:08 +02:00
{
2015-04-03 23:43:22 +02:00
auto it = conditions.begin(), end = conditions.end();
while (it != end) {
2013-09-17 05:54:42 +02:00
Condition* condition = *it;
if (condition->getType() != type) {
2013-07-07 02:30:08 +02:00
++it;
continue;
}
2013-12-25 22:54:30 +01:00
if (!force && type == CONDITION_PARALYZE) {
2013-07-07 02:30:08 +02:00
int64_t walkDelay = getWalkDelay();
if (walkDelay > 0) {
g_scheduler.addEvent(
createSchedulerTask(walkDelay, [=, id = getID()]() { g_game.forceRemoveCondition(id, type); }));
2013-07-07 02:30:08 +02:00
return;
}
}
it = conditions.erase(it);
2013-12-27 11:36:41 +01:00
condition->endCondition(this);
delete condition;
2013-07-07 02:30:08 +02:00
onEndCondition(type);
}
}
void Creature::removeCondition(ConditionType_t type, ConditionId_t conditionId, bool force /* = false*/)
2013-07-07 02:30:08 +02:00
{
2015-04-03 23:43:22 +02:00
auto it = conditions.begin(), end = conditions.end();
while (it != end) {
2013-08-01 00:33:33 +02:00
Condition* condition = *it;
2015-05-15 15:12:01 +02:00
if (condition->getType() != type || condition->getId() != conditionId) {
2013-07-07 02:30:08 +02:00
++it;
continue;
}
2013-12-25 22:54:30 +01:00
if (!force && type == CONDITION_PARALYZE) {
2013-07-07 02:30:08 +02:00
int64_t walkDelay = getWalkDelay();
if (walkDelay > 0) {
g_scheduler.addEvent(
createSchedulerTask(walkDelay, [=, id = getID()]() { g_game.forceRemoveCondition(id, type); }));
2013-07-07 02:30:08 +02:00
return;
}
}
it = conditions.erase(it);
2013-12-27 11:36:41 +01:00
condition->endCondition(this);
delete condition;
2013-07-07 02:30:08 +02:00
onEndCondition(type);
}
}
2013-12-27 11:36:41 +01:00
void Creature::removeCombatCondition(ConditionType_t type)
2013-07-07 02:30:08 +02:00
{
2013-09-17 05:54:42 +02:00
std::vector<Condition*> removeConditions;
for (Condition* condition : conditions) {
if (condition->getType() == type) {
removeConditions.push_back(condition);
2013-07-07 02:30:08 +02:00
}
}
2013-09-17 05:54:42 +02:00
for (Condition* condition : removeConditions) {
2013-12-27 11:36:41 +01:00
onCombatRemoveCondition(condition);
2013-09-17 05:54:42 +02:00
}
2013-07-07 02:30:08 +02:00
}
void Creature::removeCondition(Condition* condition, bool force /* = false*/)
2013-07-07 02:30:08 +02:00
{
2013-09-25 02:39:10 +02:00
auto it = std::find(conditions.begin(), conditions.end(), condition);
2013-07-07 02:30:08 +02:00
if (it == conditions.end()) {
return;
}
if (!force && condition->getType() == CONDITION_PARALYZE) {
int64_t walkDelay = getWalkDelay();
if (walkDelay > 0) {
g_scheduler.addEvent(createSchedulerTask(
walkDelay, [id = getID(), type = condition->getType()]() { g_game.forceRemoveCondition(id, type); }));
2013-07-07 02:30:08 +02:00
return;
}
}
conditions.erase(it);
2013-12-27 11:36:41 +01:00
condition->endCondition(this);
2013-07-07 02:30:08 +02:00
onEndCondition(condition->getType());
delete condition;
2013-07-07 02:30:08 +02:00
}
Condition* Creature::getCondition(ConditionType_t type) const
{
2013-09-17 05:54:42 +02:00
for (Condition* condition : conditions) {
if (condition->getType() == type) {
return condition;
2013-07-07 02:30:08 +02:00
}
}
2013-09-22 02:02:19 +02:00
return nullptr;
2013-07-07 02:30:08 +02:00
}
Condition* Creature::getCondition(ConditionType_t type, ConditionId_t conditionId, uint32_t subId /* = 0*/) const
2013-07-07 02:30:08 +02:00
{
2013-09-17 05:54:42 +02:00
for (Condition* condition : conditions) {
2015-05-15 15:12:01 +02:00
if (condition->getType() == type && condition->getId() == conditionId && condition->getSubId() == subId) {
2013-09-17 05:54:42 +02:00
return condition;
2013-07-07 02:30:08 +02:00
}
}
2013-09-22 02:02:19 +02:00
return nullptr;
2013-07-07 02:30:08 +02:00
}
void Creature::executeConditions(uint32_t interval)
{
ConditionList tempConditions{conditions};
for (Condition* condition : tempConditions) {
auto it = std::find(conditions.begin(), conditions.end(), condition);
if (it == conditions.end()) {
continue;
}
2015-04-03 23:43:22 +02:00
if (!condition->executeCondition(this, interval)) {
it = std::find(conditions.begin(), conditions.end(), condition);
if (it != conditions.end()) {
conditions.erase(it);
condition->endCondition(this);
onEndCondition(condition->getType());
delete condition;
}
2013-07-07 02:30:08 +02:00
}
}
}
bool Creature::hasCondition(ConditionType_t type, uint32_t subId /* = 0*/) const
2013-07-07 02:30:08 +02:00
{
if (isSuppress(type)) {
return false;
}
2013-11-16 04:46:24 +01:00
int64_t timeNow = OTSYS_TIME();
2013-09-23 03:34:15 +02:00
for (Condition* condition : conditions) {
if (condition->getType() != type || condition->getSubId() != subId) {
2013-07-07 02:30:08 +02:00
continue;
}
if (condition->getEndTime() >= timeNow || condition->getTicks() == -1) {
2013-07-07 02:30:08 +02:00
return true;
}
}
return false;
}
bool Creature::isImmune(CombatType_t type) const
{
2014-10-26 00:39:47 +02:00
return hasBitSet(static_cast<uint32_t>(type), getDamageImmunities());
2013-07-07 02:30:08 +02:00
}
bool Creature::isImmune(ConditionType_t type) const
{
2014-10-26 00:39:47 +02:00
return hasBitSet(static_cast<uint32_t>(type), getConditionImmunities());
2013-07-07 02:30:08 +02:00
}
bool Creature::isSuppress(ConditionType_t type) const
{
2014-10-26 00:39:47 +02:00
return hasBitSet(static_cast<uint32_t>(type), getConditionSuppressions());
2013-07-07 02:30:08 +02:00
}
2014-04-07 14:26:41 -04:00
int64_t Creature::getStepDuration(Direction dir) const
2013-07-07 02:30:08 +02:00
{
2014-04-07 14:26:41 -04:00
int64_t stepDuration = getStepDuration();
if ((dir & DIRECTION_DIAGONAL_MASK) != 0) {
2013-07-07 02:30:08 +02:00
stepDuration *= 3;
}
return stepDuration;
}
2014-04-07 14:26:41 -04:00
int64_t Creature::getStepDuration() const
2013-07-07 02:30:08 +02:00
{
if (isRemoved()) {
return 0;
}
uint32_t calculatedStepSpeed;
uint32_t groundSpeed;
int32_t stepSpeed = getStepSpeed();
if (stepSpeed > -Creature::speedB) {
calculatedStepSpeed =
floor((Creature::speedA * log((stepSpeed / 2) + Creature::speedB) + Creature::speedC) + 0.5);
if (calculatedStepSpeed == 0) {
2013-07-07 02:30:08 +02:00
calculatedStepSpeed = 1;
}
} else {
calculatedStepSpeed = 1;
}
Item* ground = tile->getGround();
2015-05-01 14:05:32 +02:00
if (ground) {
groundSpeed = Item::items[ground->getID()].speed;
2013-07-07 02:30:08 +02:00
if (groundSpeed == 0) {
groundSpeed = 150;
}
} else {
groundSpeed = 150;
}
double duration = std::floor(1000 * groundSpeed / calculatedStepSpeed);
2014-04-07 14:26:41 -04:00
int64_t stepDuration = std::ceil(duration / 50) * 50;
2013-07-07 02:30:08 +02:00
const Monster* monster = getMonster();
if (monster && monster->isTargetNearby() && !monster->isFleeing() && !monster->getMaster()) {
2013-09-25 02:39:10 +02:00
stepDuration *= 2;
2013-07-07 02:30:08 +02:00
}
return stepDuration;
}
int64_t Creature::getEventStepTicks(bool onlyDelay) const
{
int64_t ret = getWalkDelay();
if (ret <= 0) {
int64_t stepDuration = getStepDuration();
2013-07-07 02:30:08 +02:00
if (onlyDelay && stepDuration > 0) {
ret = 1;
} else {
ret = stepDuration * lastStepCost;
}
}
return ret;
}
LightInfo Creature::getCreatureLight() const { return internalLight; }
void Creature::setCreatureLight(LightInfo lightInfo) { internalLight = std::move(lightInfo); }
2013-07-07 02:30:08 +02:00
void Creature::setNormalCreatureLight() { internalLight = {}; }
2013-07-07 02:30:08 +02:00
bool Creature::registerCreatureEvent(const std::string& name)
{
CreatureEvent* event = g_creatureEvents->getEventByName(name);
if (!event) {
return false;
}
CreatureEventType_t type = event->getEventType();
if (hasEventRegistered(type)) {
for (CreatureEvent* creatureEvent : eventsList) {
if (creatureEvent == event) {
2013-07-07 02:30:08 +02:00
return false;
}
}
} else {
scriptEventsBitField |= static_cast<uint32_t>(1) << type;
2013-07-07 02:30:08 +02:00
}
eventsList.push_back(event);
return true;
}
bool Creature::unregisterCreatureEvent(const std::string& name)
{
CreatureEvent* event = g_creatureEvents->getEventByName(name);
if (!event) {
return false;
}
CreatureEventType_t type = event->getEventType();
if (!hasEventRegistered(type)) {
return false;
}
bool resetTypeBit = true;
2015-04-03 22:47:10 +02:00
2015-04-03 23:43:22 +02:00
auto it = eventsList.begin(), end = eventsList.end();
while (it != end) {
CreatureEvent* curEvent = *it;
if (curEvent == event) {
it = eventsList.erase(it);
2015-04-03 22:47:10 +02:00
continue;
}
if (curEvent->getEventType() == type) {
resetTypeBit = false;
}
2015-04-03 22:47:10 +02:00
++it;
}
if (resetTypeBit) {
scriptEventsBitField &= ~(static_cast<uint32_t>(1) << type);
}
return true;
}
2013-07-07 02:30:08 +02:00
CreatureEventList Creature::getCreatureEvents(CreatureEventType_t type)
{
CreatureEventList tmpEventList;
if (!hasEventRegistered(type)) {
return tmpEventList;
}
for (CreatureEvent* creatureEvent : eventsList) {
if (!creatureEvent->isLoaded()) {
continue;
}
if (creatureEvent->getEventType() == type) {
tmpEventList.push_back(creatureEvent);
2013-07-07 02:30:08 +02:00
}
}
return tmpEventList;
}
bool FrozenPathingConditionCall::isInRange(const Position& startPos, const Position& testPos,
const FindPathParams& fpp) const
2013-07-07 02:30:08 +02:00
{
if (fpp.fullPathSearch) {
if (testPos.x > targetPos.x + fpp.maxTargetDist) {
return false;
}
2013-07-07 02:30:08 +02:00
if (testPos.x < targetPos.x - fpp.maxTargetDist) {
return false;
}
2013-07-07 02:30:08 +02:00
if (testPos.y > targetPos.y + fpp.maxTargetDist) {
return false;
}
2013-07-07 02:30:08 +02:00
if (testPos.y < targetPos.y - fpp.maxTargetDist) {
return false;
}
} else {
int32_t dx = startPos.getOffsetX(targetPos);
2013-07-07 02:30:08 +02:00
int32_t dxMax = (dx >= 0 ? fpp.maxTargetDist : 0);
if (testPos.x > targetPos.x + dxMax) {
return false;
}
2013-07-07 02:30:08 +02:00
int32_t dxMin = (dx <= 0 ? fpp.maxTargetDist : 0);
if (testPos.x < targetPos.x - dxMin) {
return false;
}
2013-07-07 02:30:08 +02:00
int32_t dy = startPos.getOffsetY(targetPos);
2013-07-07 02:30:08 +02:00
int32_t dyMax = (dy >= 0 ? fpp.maxTargetDist : 0);
if (testPos.y > targetPos.y + dyMax) {
return false;
}
int32_t dyMin = (dy <= 0 ? fpp.maxTargetDist : 0);
if (testPos.y < targetPos.y - dyMin) {
return false;
}
}
2013-07-07 02:30:08 +02:00
return true;
}
bool FrozenPathingConditionCall::operator()(const Position& startPos, const Position& testPos,
const FindPathParams& fpp, int32_t& bestMatchDist) const
2013-07-07 02:30:08 +02:00
{
if (!isInRange(startPos, testPos, fpp)) {
return false;
}
if (fpp.clearSight && !g_game.isSightClear(testPos, targetPos, true)) {
return false;
}
int32_t testDist = std::max(targetPos.getDistanceX(testPos), targetPos.getDistanceY(testPos));
2013-07-07 02:30:08 +02:00
if (fpp.maxTargetDist == 1) {
if (testDist < fpp.minTargetDist || testDist > fpp.maxTargetDist) {
return false;
}
return true;
} else if (testDist <= fpp.maxTargetDist) {
if (testDist < fpp.minTargetDist) {
return false;
}
if (testDist == fpp.maxTargetDist) {
bestMatchDist = 0;
return true;
} else if (testDist > bestMatchDist) {
// not quite what we want, but the best so far
2013-07-07 02:30:08 +02:00
bestMatchDist = testDist;
return true;
}
}
return false;
}
2013-09-24 16:46:25 +02:00
bool Creature::isInvisible() const
{
return std::find_if(conditions.begin(), conditions.end(), [](const Condition* condition) {
return condition->getType() == CONDITION_INVISIBLE;
}) != conditions.end();
2013-09-24 16:46:25 +02:00
}
bool Creature::getPathTo(const Position& targetPos, std::vector<Direction>& dirList, const FindPathParams& fpp) const
{
Optimize pathfinding (#4637) * Optimize pathfinding * Minor fleeing monsters fix * Fix whitespace and else brackets * More cleanup * Cleanup * Remove uneeded variable name change * Cleanup * Move neighbor arrays back to map.cpp to fix unused variable failure * Fix some compiling warnings * Fix incorrect method call in game.cpp * Update to new creature isDead method * Update to clang format * Update to clang format * Fix maxSearchDist=0 searches and delayed reaction to onFollowCreature * Fix fleeing monster randomly turning * Reduce memory consumption and update pathmatching algorithm * Clang formatting * Clang formatting * Remove uneeded check on new nodes * Normalize pathfinding algorithm * Final Changes: Move pathfinding call to onWalk * Remove incorrect code * Move from Euclidean to standard A* * Fix overlooked typos and uneeded logic * Remove uneeded nullptr check and change iterations to int8_t * Revert int8_t * Fix creature label error and update algorithm * Remove uneeded resizing * Revert comment * Add missing pathmatching call * Allow force update path to be called more often * Fix sight blocked monsters path updating * Additional blocked sight fix * Allow paths to be drawn a little farther like rl tibia * Add delay to pathfinding and optimize code * Fix incorrect conditional * Move path delay to force update path * Change uint64_t to int64_t * Add pathfinding interval and delay to config.lua * Add viewport check * Fix memory leak * Add memory management to follow list and pathmatching * Replace std::sqrt for std::hypot * Update to new constexpr position methods * Revert int declarations in pathmatching * Change std::hypot for much faster std::sqrtf * Formatting * Add math.h * Revert sqrtf and math.h * Remove uneeded path call and add speed check * Fix rainsalt review * Update configmanager * Update configmanager * Fix configmanager after merge * Update to configermanager namespace methods * Clang format * Use getX()/getY() and remove calculateHueristic from AStarNodes * Replace AStarNodes:calculateHeuristic * Add a couple code optimizations * Move logic for better performance * Replace std::list for vector and modify datatypes * Replace push_back for emplace_back and revert calculateHeuristic * Replace followedByCreature for followers and update std::array * Change addFollowedByCreature to addFollower * Update method calls * Add additional checks for redundant pathfinding calls * Remove redundant check * Clang Format * Change updateFollowingCreaturePaths to updateFollowersPaths * Fix a problem in most recent path conditional * Fix bug in pre path conditional check * Fix logic in last commit * Add required nullptr check to stop crashes on creature death * Revert crash unrelated * Add updateCreaturesPath * Convert calculate heuristic to int * Convert to new code style * Fix memory leak in followers * Additional nodes clear for possible memory leak * Fix logic for when to remove follower * Dynamically allocated nodes MUST be deleted. * Remove nodes.clear() * Revert * Fix pathfinding delays. * Remove delay check in map.cpp and add in correct places. * Fix typo * Check for duplicate creatures, add optimization, and remove uneeded * Modify config values for best performance while maintaining proper following behavior * Fix datatype typo * Optimize removeFollower code && update datatypes. * Update CMake_Lists * Revert static const * Modify removefollower O(n2) to O(n) * Code cleanup, Comments, remove uneeded code
2025-05-11 08:51:45 -07:00
return g_game.map.getPathMatching(*this, targetPos, dirList, FrozenPathingConditionCall(targetPos), fpp);
}
bool Creature::getPathTo(const Position& targetPos, std::vector<Direction>& dirList, int32_t minTargetDist,
int32_t maxTargetDist, bool fullPathSearch /*= true*/, bool clearSight /*= true*/,
int32_t maxSearchDist /*= 0*/) const
{
FindPathParams fpp;
fpp.fullPathSearch = fullPathSearch;
fpp.maxSearchDist = maxSearchDist;
fpp.clearSight = clearSight;
fpp.minTargetDist = minTargetDist;
fpp.maxTargetDist = maxTargetDist;
return getPathTo(targetPos, dirList, fpp);
}
void Creature::setStorageValue(uint32_t key, std::optional<int32_t> value, bool isSpawn)
{
auto oldValue = getStorageValue(key);
if (value) {
storageMap.insert_or_assign(key, value.value());
} else {
storageMap.erase(key);
}
tfs::events::creature::onUpdateStorage(this, key, oldValue, value, isSpawn);
}
std::optional<int32_t> Creature::getStorageValue(uint32_t key) const
{
auto it = storageMap.find(key);
if (it == storageMap.end()) {
return std::nullopt;
}
return std::make_optional(it->second);
}