Itutorial
Legendary OT User
- Joined
- Dec 23, 2014
- Messages
- 2,370
- Solutions
- 68
- Reaction score
- 1,043
I spent way to long messing with this. A few hours. I am no pro but I learned how the code behaves and figured out a way IMO to make it better. It hasn't been tested to the limit but I have tested it with 50+ monsters following me and ran through a few obstacles.
There is a lot of things that can be done to make the code better as far as modifying how the paths behave based on certain scenarios.
This does not fix the problem with monsters not following correctly. However, it will help decrease the CPU usage a lot if you apply this fix for their following:
Solved - Weird monster behaviour in TFS 1.1? (https://otland.net/threads/weird-monster-behaviour-in-tfs-1-1.228021/#post-2200365)
Here is a video I made to demonstrate:
I have used a lot from this community and try to give back. This is one thing I know most did not want to look at. Hopefully this will help.
creature.cpp
replace
with
map.h
under
add
replace
with
map.cpp
replace this whole method
with
There is a lot of things that can be done to make the code better as far as modifying how the paths behave based on certain scenarios.
This does not fix the problem with monsters not following correctly. However, it will help decrease the CPU usage a lot if you apply this fix for their following:
Solved - Weird monster behaviour in TFS 1.1? (https://otland.net/threads/weird-monster-behaviour-in-tfs-1-1.228021/#post-2200365)
Here is a video I made to demonstrate:
I have used a lot from this community and try to give back. This is one thing I know most did not want to look at. Hopefully this will help.
creature.cpp
replace
C++:
bool Creature::getPathTo(const Position& targetPos, std::vector<Direction>& dirList, const FindPathParams& fpp) const
{
return g_game.map.getPathMatching(*this, dirList, FrozenPathingConditionCall(targetPos), fpp);
}
with
C++:
bool Creature::getPathTo(const Position& targetPos, std::vector<Direction>& dirList, const FindPathParams& fpp) const
{
return g_game.map.getPathMatching(*this, targetPos, dirList, FrozenPathingConditionCall(targetPos), fpp);
}
map.h
under
C++:
static constexpr int32_t MAP_DIAGONALWALKCOST = 25;
add
C++:
static int_fast32_t dirNeighbors[8][5][2] = {
{{-1, 0}, {0, 1}, {1, 0}, {1, 1}, {-1, 1}},
{{-1, 0}, {0, 1}, {0, -1}, {-1, -1}, {-1, 1}},
{{-1, 0}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}},
{{0, 1}, {1, 0}, {0, -1}, {1, -1}, {1, 1}},
{{1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}},
{{-1, 0}, {0, -1}, {-1, -1}, {1, -1}, {-1, 1}},
{{0, 1}, {1, 0}, {1, -1}, {1, 1}, {-1, 1}},
{{-1, 0}, {0, 1}, {-1, -1}, {1, 1}, {-1, 1}}
};
static int_fast32_t allNeighbors[8][2] = {
{-1, 0}, {0, 1}, {1, 0}, {0, -1}, {-1, -1}, {1, -1}, {1, 1}, {-1, 1}
};
replace
C++:
bool getPathMatching(const Creature& creature, std::vector<Direction>& dirList,
const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const;
with
C++:
bool getPathMatching(const Creature& creature, const Position& targetPos, std::vector<Direction>& dirList,
const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const;
map.cpp
replace this whole method
C++:
bool Map::getPathMatching(const Creature& creature, std::vector<Direction>& dirList, const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const
with
C++:
bool Map::getPathMatching(const Creature& creature, const Position& targetPos, std::vector<Direction>& dirList, const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) const
{
Position pos = creature.getPosition();
Position endPos;
const Position startPos = pos;
int32_t bestMatch = 0;
AStarNodes nodes(pos.x, pos.y);
AStarNode* found = nullptr;
while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) {
AStarNode* n = nodes.getBestNode();
if (!n) {
if (found) {
break;
}
return false;
}
const int_fast32_t x = n->x;
const int_fast32_t y = n->y;
pos.x = x;
pos.y = y;
if (pathCondition(startPos, pos, fpp, bestMatch)) {
found = n;
endPos = pos;
if (bestMatch == 0) {
break;
}
}
uint_fast32_t dirCount;
int_fast32_t* neighbors;
if (n->parent) {
const int_fast32_t offset_x = n->parent->x - x;
const int_fast32_t offset_y = n->parent->y - y;
if (offset_y == 0) {
if (offset_x == -1) {
neighbors = *dirNeighbors[DIRECTION_WEST];
}
else {
neighbors = *dirNeighbors[DIRECTION_EAST];
}
}
else if (!fpp.allowDiagonal || offset_x == 0) {
if (offset_y == -1) {
neighbors = *dirNeighbors[DIRECTION_NORTH];
}
else {
neighbors = *dirNeighbors[DIRECTION_SOUTH];
}
}
else if (offset_y == -1) {
if (offset_x == -1) {
neighbors = *dirNeighbors[DIRECTION_NORTHWEST];
}
else {
neighbors = *dirNeighbors[DIRECTION_NORTHEAST];
}
}
else if (offset_x == -1) {
neighbors = *dirNeighbors[DIRECTION_SOUTHWEST];
}
else {
neighbors = *dirNeighbors[DIRECTION_SOUTHEAST];
}
dirCount = fpp.allowDiagonal ? 5 : 3;
}
else {
dirCount = 8;
neighbors = *allNeighbors;
}
for (uint_fast32_t i = 0; i < dirCount; ++i) {
pos.x = x + *neighbors++;
pos.y = y + *neighbors++;
if (fpp.maxSearchDist != 0 && (Position::getDistanceX(startPos, pos) > fpp.maxSearchDist || Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) {
continue;
}
if (fpp.keepDistance && !pathCondition.isInRange(startPos, pos, fpp)) {
continue;
}
const Tile* tile;
AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y);
if (neighborNode) {
tile = getTile(pos.x, pos.y, pos.z);
}
else {
tile = canWalkTo(creature, pos);
if (!tile) {
continue;
}
}
//The cost to walk to this neighbor
const int_fast32_t G = AStarNodes::getMapWalkCost(n, pos);
const int_fast32_t E = AStarNodes::getTileWalkCost(creature, tile);
const int_fast32_t H = (Position::getDistanceX(pos, targetPos) + Position::getDistanceY(pos, targetPos));
int_fast32_t newf = G + (H + E);
if (neighborNode) {
if (neighborNode->f <= newf) {
//The node on the closed/open list is cheaper than this one
continue;
}
neighborNode->f = newf;
neighborNode->parent = n;
nodes.openNode(neighborNode);
}
else {
//Does not exist in the open/closed list, create a new node
//g_game.addMagicEffect(pos, CONST_ME_TELEPORT);
neighborNode = nodes.createOpenNode(n, pos.x, pos.y, newf);
if (!neighborNode) {
if (found) {
break;
}
return false;
}
}
}
nodes.closeNode(n);
}
if (!found) {
return false;
}
int_fast32_t prevx = endPos.x;
int_fast32_t prevy = endPos.y;
found = found->parent;
while (found) {
pos.x = found->x;
pos.y = found->y;
int_fast32_t dx = pos.getX() - prevx;
int_fast32_t dy = pos.getY() - prevy;
prevx = pos.x;
prevy = pos.y;
if (dx == 1 && dy == 1) {
dirList.push_back(DIRECTION_NORTHWEST);
}
else if (dx == -1 && dy == 1) {
dirList.push_back(DIRECTION_NORTHEAST);
}
else if (dx == 1 && dy == -1) {
dirList.push_back(DIRECTION_SOUTHWEST);
}
else if (dx == -1 && dy == -1) {
dirList.push_back(DIRECTION_SOUTHEAST);
}
else if (dx == 1) {
dirList.push_back(DIRECTION_WEST);
}
else if (dx == -1) {
dirList.push_back(DIRECTION_EAST);
}
else if (dy == 1) {
dirList.push_back(DIRECTION_NORTH);
}
else if (dy == -1) {
dirList.push_back(DIRECTION_SOUTH);
}
found = found->parent;
}
return true;
}
Last edited: