• 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!

C++ Monsters changing target for the player that obstacle it's path

Peonso

Godly Member
Joined
Jan 14, 2008
Messages
1,749
Solutions
30
Reaction score
1,534
I tracked this behavior from real tibia and want to replicate it on otserver (any version, avesta, tfs 0.4, tfs 1.x, otserv, othire, whatever): If a monster can change target, he is going in a straight line into a target and other player go in the middle, he will target that player instead.

IV9lmPO.gif


A video with some footage of it happening: changetargetbehavior.rar

I tryed some stuff but my C++ knowledge is really low/bad. Thought about adding something to check if the blocking creature is a player (like here) and if it is cancel the movement and pick it as target.
 
Solution
My fault, but it was already default at TFS 1.x.

I'm commiting it to OTHire GitHub soon.
at monster.cpp in void Monster::eek:nCreatureMove, replace:
Code:
if(!followCreature && !isSummon()){
            //we have no target lets try pick this one
            if(isOpponent(creature)){
                        selectTarget(const_cast<Creature*>(creature));
            }
}
with
Code:
if (!isSummon()) {
            if (followCreature) {
                const Position& followPosition = followCreature->getPosition();
                const Position& position = getPosition();
                int32_t dist_x = std::abs(position.x - followPosition.x);
                int32_t dist_y = std::abs(position.y - followPosition.y)...
Tfs 1.x

in
Code:
void Monster::onCreatureMove(Creature* creature, const Tile* newTile, const Position& newPos,
                             const Tile* oldTile, const Position& oldPos, bool teleport)

change:
Code:
if (isSummon()) {
    isMasterInRange = canSee(getMaster()->getPosition());
}
to:

Code:
if (isSummon()) {
    isMasterInRange = canSee(getMaster()->getPosition());
} else {
    const Creature* tileCreature = newTile->getCreature();
    if (tileCreature && tileCreature->getPlayer() && getAttackedCreature() != tileCreature) {
        selectTarget(creature);
    }
}
 
My fault, but it was already default at TFS 1.x.

I'm commiting it to OTHire GitHub soon.
at monster.cpp in void Monster::eek:nCreatureMove, replace:
Code:
if(!followCreature && !isSummon()){
            //we have no target lets try pick this one
            if(isOpponent(creature)){
                        selectTarget(const_cast<Creature*>(creature));
            }
}
with
Code:
if (!isSummon()) {
            if (followCreature) {
                const Position& followPosition = followCreature->getPosition();
                const Position& position = getPosition();
                int32_t dist_x = std::abs(position.x - followPosition.x);
                int32_t dist_y = std::abs(position.y - followPosition.y);
                if ((dist_x > 1 || dist_y > 1) && mType->changeTargetChance > 0) {
                    //get direction to move
                    Direction dir;
                    int32_t x_offset = (position.x - followPosition.x);
                    if (x_offset < 0) {
                        dir = EAST;
                        x_offset = std::abs(x_offset);
                    } else {
                        dir = WEST;
                    }

                    int32_t y_offset = (position.y - followPosition.y);
                    if (y_offset >= 0) {
                        if (y_offset > x_offset) {
                            dir = NORTH;
                        } else if (y_offset == x_offset) {
                            if (dir == EAST) {
                                dir = NORTHEAST;
                            } else {
                                dir = NORTHWEST;
                            }
                        }
                    } else {
                        y_offset = std::abs(y_offset);
                        if (y_offset > x_offset) {
                            dir = SOUTH;
                        } else if (y_offset == x_offset) {
                            if (dir == EAST) {
                                dir = SOUTHEAST;
                            } else {
                                dir = SOUTHWEST;
                            }
                        }
                    }
                    // with direction, get next position
                    Position& checkPosition = getPosition();
                    switch (dir) {
                        case NORTH:
                            checkPosition.y--;
                            break;

                        case SOUTH:
                            checkPosition.y++;
                            break;

                        case WEST:
                            checkPosition.x--;
                            break;

                        case EAST:
                            checkPosition.x++;
                            break;

                        case SOUTHWEST:
                            checkPosition.x--;
                            checkPosition.y++;
                            break;

                        case NORTHWEST:
                            checkPosition.x--;
                            checkPosition.y--;
                            break;

                        case NORTHEAST:
                            checkPosition.x++;
                            checkPosition.y--;
                            break;

                        case SOUTHEAST:
                            checkPosition.x++;
                            checkPosition.y++;
                            break;

                        default:
                            break;
                    }

                    Tile* tile = g_game.getTile(checkPosition);
                    if (tile) {
                        Creature* topCreature = tile->getTopCreature();
                        if (topCreature && followCreature != topCreature && isOpponent(topCreature)) {
                            selectTarget(topCreature);
                        }
                    }
                }
            } else if (isOpponent(creature)) {
                //we have no target lets try pick this one
                selectTarget(const_cast<Creature*>(creature));
            }
        }
 
Solution
My fault, but it was already default at TFS 1.x.

I'm commiting it to OTHire GitHub soon.
at monster.cpp in void Monster::eek:nCreatureMove, replace:
Code:
if(!followCreature && !isSummon()){
            //we have no target lets try pick this one
            if(isOpponent(creature)){
                        selectTarget(const_cast<Creature*>(creature));
            }
}
with
Code:
if (!isSummon()) {
            if (followCreature) {
                const Position& followPosition = followCreature->getPosition();
                const Position& position = getPosition();
                int32_t dist_x = std::abs(position.x - followPosition.x);
                int32_t dist_y = std::abs(position.y - followPosition.y);
                if ((dist_x > 1 || dist_y > 1) && mType->changeTargetChance > 0) {
                    //get direction to move
                    Direction dir;
                    int32_t x_offset = (position.x - followPosition.x);
                    if (x_offset < 0) {
                        dir = EAST;
                        x_offset = std::abs(x_offset);
                    } else {
                        dir = WEST;
                    }

                    int32_t y_offset = (position.y - followPosition.y);
                    if (y_offset >= 0) {
                        if (y_offset > x_offset) {
                            dir = NORTH;
                        } else if (y_offset == x_offset) {
                            if (dir == EAST) {
                                dir = NORTHEAST;
                            } else {
                                dir = NORTHWEST;
                            }
                        }
                    } else {
                        y_offset = std::abs(y_offset);
                        if (y_offset > x_offset) {
                            dir = SOUTH;
                        } else if (y_offset == x_offset) {
                            if (dir == EAST) {
                                dir = SOUTHEAST;
                            } else {
                                dir = SOUTHWEST;
                            }
                        }
                    }
                    // with direction, get next position
                    Position& checkPosition = getPosition();
                    switch (dir) {
                        case NORTH:
                            checkPosition.y--;
                            break;

                        case SOUTH:
                            checkPosition.y++;
                            break;

                        case WEST:
                            checkPosition.x--;
                            break;

                        case EAST:
                            checkPosition.x++;
                            break;

                        case SOUTHWEST:
                            checkPosition.x--;
                            checkPosition.y++;
                            break;

                        case NORTHWEST:
                            checkPosition.x--;
                            checkPosition.y--;
                            break;

                        case NORTHEAST:
                            checkPosition.x++;
                            checkPosition.y--;
                            break;

                        case SOUTHEAST:
                            checkPosition.x++;
                            checkPosition.y++;
                            break;

                        default:
                            break;
                    }

                    Tile* tile = g_game.getTile(checkPosition);
                    if (tile) {
                        Creature* topCreature = tile->getTopCreature();
                        if (topCreature && followCreature != topCreature && isOpponent(topCreature)) {
                            selectTarget(topCreature);
                        }
                    }
                }
            } else if (isOpponent(creature)) {
                //we have no target lets try pick this one
                selectTarget(const_cast<Creature*>(creature));
            }
        }
Default what? If you mean they are changing target like you want by default then not.
 
Back
Top