• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Solved Weird monster behaviour in TFS 1.1?

Ahilphino

Excellent OT User
Joined
Jun 5, 2013
Messages
1,667
Solutions
1
Reaction score
728
The monster AI in tfs 1.1 (idk about 1.0) is EXTREMELY dumb. This has discouraged me from using TFS 1.1 even though i've spent so much time with it.

A couple of examples:

If you chase any ranged mob, let's take lizard legionaire, they will turn around every time they make an attack and this causes them to barely run away even if you set their speed to 2000.

If you're getting chased by a fast monster, let's say a grim reaper - he will stop at times. Especially when you're in melee range, then just decide to run away. It will take him like one second to react and start running after you.


There's youtube videos about it a couple of posts below
 
Last edited:
So I decided to compare a 0.4 distro (rev 3777) and latest TFS, the difference in how monsters behave is HUGE. Maybe i'll make a youtube video showing their different behaviour on clean distros later today so that people understand. This has really discouraged me from using TFS 1.1, the monsters are so much more stupid... :(
 
yeah just made sure, installed both clean distros
will be making gifs and ull see

this is silly :(

edit: uploading right now
but yeah this is really stupid =_=
 
Last edited:
As you can see in the first video (TFS 0.4 REV 3777), there's really nothing weird about how the monster behaves, it instantly follows you when you run away etc.

In the second video however (LATEST TFS 1.1 REV), the monster always stops for awhile if you're running away and sometimes he just stops at random times when chasing you.

It's not only this, I've also noticed other weird behaviour from monsters in tfs 1.1. Also these are both fresh compiled distros with NO changes at all.

This has really discouraged me from working on 1.1. I've done lots of work on my server but having monsters as dumb as these is really discouraging. I've tried lowering EVENT_CREATURE_THINK_INTERVAL 1000, it doesn't help at all. And this isn't something that I can fix on my own. Hopefully this can get fixed.
 
Last edited:
As you can see in the first video (TFS 0.4 REV 3777), there's really nothing weird about how the monster behaves, it instantly follows you when you run away etc.

In the second video however (LATEST TFS 1.1 REV), the monster always stops for awhile if you're running away and sometimes he just stops at random times when chasing you.

It's not only this, I've also noticed other weird behaviour from monsters in tfs 1.1. Also these are both fresh compiled distros with NO changes at all.

This has really discouraged me from working on 1.1. I've done lots of work on my server but having monsters as dumb as these is really discouraging. I've tried lowering EVENT_CREATURE_THINK_INTERVAL 1000, it doesn't help at all. And this isn't something that I can fix on my own. Hopefully this can get fixed.
omggggg
 
kk this is apparently working as intended... all i can say is WTF
wow really?
i though its a bug too..
Very annoying stuff, i though im doing something wrong with monster.xml file

I though there is something fishy about when monster chased me, they were thinking about something always and then act, but didn't seem so much of an issue when simply speeding up their movement.

But i wanted to make 1 monster to always escape and keep distance. Now we have problem..
Its like each time monster takes a step he thinks for 1 second.. and then realizes o deam while i was thinking player stepped 3 tiles toawrds me, i better run away. 1 step. xD

EDIT:
I didn't find anything what would make the monster think, before he is doing the fleeing steps, so idk even how could it be possible to change it.
function what calls for running away function
Code:
void Creature::goToFollowCreature()
{
    if (followCreature) {
        FindPathParams fpp;
        getPathSearchParams(followCreature, fpp);

        Monster* monster = getMonster();
        if (monster && !monster->getMaster() && (monster->isFleeing() || fpp.maxTargetDist > 1)) {
            Direction dir = NODIR;

            if (monster->isFleeing()) {
                monster->getDistanceStep(followCreature->getPosition(), dir, true);
            } else { //maxTargetDist > 1
                if (!monster->getDistanceStep(followCreature->getPosition(), dir)) {
                    // if we can't get anything then let the A* calculate
                    listWalkDir.clear();
                    if (getPathTo(followCreature->getPosition(), listWalkDir, fpp)) {
                        hasFollowPath = true;
                        startAutoWalk(listWalkDir);
                    } else {
                        hasFollowPath = false;
                    }

                    return;
                }
            }

            if (dir != NODIR) {
                listWalkDir.clear();
                listWalkDir.push_back(dir);

                hasFollowPath = true;
                startAutoWalk(listWalkDir);
            }
        } else {
            listWalkDir.clear();
            if (getPathTo(followCreature->getPosition(), listWalkDir, fpp)) {
                hasFollowPath = true;
                startAutoWalk(listWalkDir);
            } else {
                hasFollowPath = false;
            }
        }
    }

    onFollowCreatureComplete(followCreature);
}
this is the function what makes flee or check for distance
Code:
bool Monster::getDistanceStep(const Position& targetPos, Direction& dir, bool flee /* = false */)
{
    const Position& creaturePos = getPosition();

    int_fast32_t dx = Position::getDistanceX(creaturePos, targetPos);
    int_fast32_t dy = Position::getDistanceY(creaturePos, targetPos);

    int32_t distance = std::max<int32_t>(dx, dy);

    if (!flee && (distance > mType->targetDistance || !g_game.isSightClear(creaturePos, targetPos, true))) {
        return false;    // let the A* calculate it
    } else if (!flee && distance == mType->targetDistance) {
        return true;    // we don't really care here, since it's what we wanted to reach (a dancestep will take of dancing in that position)
    }

    int_fast32_t offsetx = Position::getOffsetX(creaturePos, targetPos);
    int_fast32_t offsety = Position::getOffsetY(creaturePos, targetPos);

    if (dx <= 1 && dy <= 1) {
        //seems like a target is near, it this case we need to slow down our movements (as a monster)
        if (stepDuration < 2) {
            stepDuration++;
        }
    } else if (stepDuration > 0) {
        stepDuration--;
    }

    if (offsetx == 0 && offsety == 0) {
        return getRandomStep(creaturePos, dir);    // player is "on" the monster so let's get some random step and rest will be taken care later.
    }

    if (dx == dy) {
        //player is diagonal to the monster
        if (offsetx >= 1 && offsety >= 1) {
            // player is NW
            //escape to SE, S or E [and some extra]
            bool s = canWalkTo(creaturePos, SOUTH);
            bool e = canWalkTo(creaturePos, EAST);

            if (s && e) {
                dir = boolean_random() ? SOUTH : EAST;
                return true;
            } else if (s) {
                dir = SOUTH;
                return true;
            } else if (e) {
                dir = EAST;
                return true;
            } else if (canWalkTo(creaturePos, SOUTHEAST)) {
                dir = SOUTHEAST;
                return true;
            }

            /* fleeing */
            bool n = canWalkTo(creaturePos, NORTH);
            bool w = canWalkTo(creaturePos, WEST);

            if (flee) {
                if (n && w) {
                    dir = boolean_random() ? NORTH : WEST;
                    return true;
                } else if (n) {
                    dir = NORTH;
                    return true;
                } else if (w) {
                    dir = WEST;
                    return true;
                }
            }

            /* end of fleeing */

            if (w && canWalkTo(creaturePos, SOUTHWEST)) {
                dir = WEST;
            } else if (n && canWalkTo(creaturePos, NORTHEAST)) {
                dir = NORTH;
            }

            return true;
        } else if (offsetx <= -1 && offsety <= -1) {
            //player is SE
            //escape to NW , W or N [and some extra]
            bool w = canWalkTo(creaturePos, WEST);
            bool n = canWalkTo(creaturePos, NORTH);

            if (w && n) {
                dir = boolean_random() ? WEST : NORTH;
                return true;
            } else if (w) {
                dir = WEST;
                return true;
            } else if (n) {
                dir = NORTH;
                return true;
            }

            if (canWalkTo(creaturePos, NORTHWEST)) {
                dir = NORTHWEST;
                return true;
            }

            /* fleeing */
            bool s = canWalkTo(creaturePos, SOUTH);
            bool e = canWalkTo(creaturePos, EAST);

            if (flee) {
                if (s && e) {
                    dir = boolean_random() ? SOUTH : EAST;
                    return true;
                } else if (s) {
                    dir = SOUTH;
                    return true;
                } else if (e) {
                    dir = EAST;
                    return true;
                }
            }

            /* end of fleeing */

            if (s && canWalkTo(creaturePos, SOUTHWEST)) {
                dir = SOUTH;
            } else if (e && canWalkTo(creaturePos, NORTHEAST)) {
                dir = EAST;
            }

            return true;
        } else if (offsetx >= 1 && offsety <= -1) {
            //player is SW
            //escape to NE, N, E [and some extra]
            bool n = canWalkTo(creaturePos, NORTH);
            bool e = canWalkTo(creaturePos, EAST);

            if (n && e) {
                dir = boolean_random() ? NORTH : EAST;
                return true;
            } else if (n) {
                dir = NORTH;
                return true;
            } else if (e) {
                dir = EAST;
                return true;
            }

            if (canWalkTo(creaturePos, NORTHEAST)) {
                dir = NORTHEAST;
                return true;
            }

            /* fleeing */
            bool s = canWalkTo(creaturePos, SOUTH);
            bool w = canWalkTo(creaturePos, WEST);

            if (flee) {
                if (s && w) {
                    dir = boolean_random() ? SOUTH : WEST;
                    return true;
                } else if (s) {
                    dir = SOUTH;
                    return true;
                } else if (w) {
                    dir = WEST;
                    return true;
                }
            }

            /* end of fleeing */

            if (w && canWalkTo(creaturePos, NORTHWEST)) {
                dir = WEST;
            } else if (s && canWalkTo(creaturePos, SOUTHEAST)) {
                dir = SOUTH;
            }

            return true;
        } else if (offsetx <= -1 && offsety >= 1) {
            // player is NE
            //escape to SW, S, W [and some extra]
            bool w = canWalkTo(creaturePos, WEST);
            bool s = canWalkTo(creaturePos, SOUTH);

            if (w && s) {
                dir = boolean_random() ? WEST : SOUTH;
                return true;
            } else if (w) {
                dir = WEST;
                return true;
            } else if (s) {
                dir = SOUTH;
                return true;
            } else if (canWalkTo(creaturePos, SOUTHWEST)) {
                dir = SOUTHWEST;
                return true;
            }

            /* fleeing */
            bool n = canWalkTo(creaturePos, NORTH);
            bool e = canWalkTo(creaturePos, EAST);

            if (flee) {
                if (n && e) {
                    dir = boolean_random() ? NORTH : EAST;
                    return true;
                } else if (n) {
                    dir = NORTH;
                    return true;
                } else if (e) {
                    dir = EAST;
                    return true;
                }
            }

            /* end of fleeing */

            if (e && canWalkTo(creaturePos, SOUTHEAST)) {
                dir = EAST;
            } else if (n && canWalkTo(creaturePos, NORTHWEST)) {
                dir = NORTH;
            }

            return true;
        }
    }

    //Now let's decide where the player is located to the monster (what direction) so we can decide where to escape

>>here was code what simply checked player posittions<<
    return true;
}
 
Last edited:
That's crazy, I can't believe this is the intended way for monsters to behave.... You showed perfectly the differences between the old distro and the new one.... What is the point? Why are they intended to behave this way? To save some resources? Looked like you were lagging more in 1.x from the recalculation of the monster than versus the monster in the older version anyways...
 
If it bothers you so much, open up creature.cpp and change:
Code:
        if (hasFollowPath) {
            isUpdatingPath = true;
        }
to:
Code:
        if (hasFollowPath) {
            isUpdatingPath = false;
            g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
        }
 
If it bothers you so much, open up creature.cpp and change:
Code:
        if (hasFollowPath) {
            isUpdatingPath = true;
        }
to:
Code:
        if (hasFollowPath) {
            isUpdatingPath = false;
            g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
        }
best
 
If it bothers you so much, open up creature.cpp and change:
Code:
        if (hasFollowPath) {
            isUpdatingPath = true;
        }
to:
Code:
        if (hasFollowPath) {
            isUpdatingPath = false;
            g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
        }
godlike
 
If it bothers you so much, open up creature.cpp and change:
Code:
        if (hasFollowPath) {
            isUpdatingPath = true;
        }
to:
Code:
        if (hasFollowPath) {
            isUpdatingPath = false;
            g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
        }

Tried it! WAY better! I used a basic 220 base speed player, vs a behemoth, before code changed, I could run away very very easily, now the behemoth won't get off my nuts :D

Only thing I noticed that may still be improved upon, is that the behemoth will sometimes go up or down instead of the same straight line I am going down, and for that he will lose a square when he does so, but, still he catches back up :D
 
If it bothers you so much, open up creature.cpp and change:
Code:
        if (hasFollowPath) {
            isUpdatingPath = true;
        }
to:
Code:
        if (hasFollowPath) {
            isUpdatingPath = false;
            g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
        }
But does this have any negative affects on the performance? Else why is it not added on the offical tfs project :p?
 
Back
Top