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

Nostalrius burst arrow bug!

chucky91

Intermediate OT User
Joined
Apr 8, 2010
Messages
268
Solutions
9
Reaction score
148
I came here to post a correction in src/combat.cpp
obs: the configuration of the burst arrow is in items.srv. has no weapons.

The error is when the arrow deviates from the target and hits the ground and in turn it should explode, but what happened is that when the arrow goes to a random corner, the explosion area effect goes straight to the target.
so i did this analysis and changed the error in combat.cpp

Also, circleShapeSpell didn't limit the area effect, and the effects showed on the walls.

so i added:

Update combat.cpp

Code:
if (tile->hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID)) {
            continue;
        }

In:
C++:
void Combat::circleShapeSpell(Creature* attacker, const Position& toPos, int32_t range, int32_t animation, int32_t radius, DamageImpact* impact, int32_t effect)
{
    const Position& fromPos = attacker->getPosition();
    if (fromPos.z != toPos.z) {
        return;
    }

    int32_t distance = std::max<int32_t>(Position::getDistanceX(fromPos, toPos), Position::getDistanceY(fromPos, toPos));
    if (distance > range) {
        return;
    }

    if (animation && fromPos != toPos) {
        g_game.addDistanceEffect(fromPos, toPos, animation);
    }

    std::forward_list<Tile*> tiles;

    AreaCombat areaCombat;
    areaCombat.setupArea(radius);

    areaCombat.getList(toPos, toPos, tiles);

    for (Tile* tile : tiles) {
        if (tile->hasFlag(TILESTATE_PROTECTIONZONE)) {
            continue;
        }

        if (tile->hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID)) {
            continue;
        }

        if (CreatureVector* creatures = tile->getCreatures()) {
            for (Creature* creature : *creatures) {
                impact->handleCreature(creature);
            }
        }

        if (effect) {
            g_game.addMagicEffect(tile->getPosition(), effect);
        }
    }
}

and i made a change in:

C++:
bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fightMode)
{

        Tile* destTile = target->getTile();

        if (!Position::areInRange<1, 1, 0>(attacker->getPosition(), target->getPosition())) {
            static std::vector<std::pair<int32_t, int32_t>> destList{
                { -1, -1 },{ 0, -1 },{ 1, -1 },
                { -1,  0 },{ 0,  0 },{ 1,  0 },
                { -1,  1 },{ 0,  1 },{ 1,  1 }
            };
            std::shuffle(destList.begin(), destList.end(), getRandomGenerator());

            Position destPos = target->getPosition();

            for (const auto& dir : destList) {
                // Blocking tiles or tiles without ground ain't valid targets for spears
                Tile* tmpTile = g_game.map.getTile(destPos.x + dir.first, destPos.y + dir.second, destPos.z);
                if (tmpTile && !tmpTile->hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID) && tmpTile->getGround() != nullptr) {
                    destTile = tmpTile;
                    break;
                }
            }
        }

        if (specialEffect == 1) {
            if (hit) {
                const int32_t rounds = ammunition ? ammunition->getAttackStrength() : weapon->getAttackStrength();

                ConditionDamage* poisonDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_POISON);
                poisonDamage->setParam(CONDITION_PARAM_OWNER, attacker->getID());
                poisonDamage->setParam(CONDITION_PARAM_CYCLE, rounds);
                poisonDamage->setParam(CONDITION_PARAM_COUNT, 3);
                poisonDamage->setParam(CONDITION_PARAM_MAX_COUNT, 3);

                target->addCombatCondition(poisonDamage);
            }
        } else if (specialEffect == 2) {
            DamageImpact impact;
            impact.actor = attacker;
            impact.damage.type = COMBAT_PHYSICALDAMAGE;
            impact.damage.value = -Combat::computeDamage(attacker, attackStrength, attackVariation);
            impact.params.blockedByArmor = true;
            impact.params.blockedByShield = false;
            circleShapeSpell(attacker, destTile->getPosition(), 0xFF, 7, 3, &impact, 7);
        }

        if (!hit) {

            g_game.addMagicEffect(destTile->getPosition(), CONST_ME_POFF);
            g_game.addDistanceEffect(attackerPos, destTile->getPosition(), distanceEffect);

            if (moveWeapon) {
                g_game.internalMoveItem(weapon->getParent(), destTile, INDEX_WHEREEVER, weapon, 1, nullptr, FLAG_NOLIMIT);
            }

            return true;
        }

        g_game.addDistanceEffect(attackerPos, targetPos, distanceEffect);
        Combat::doCombatHealth(attacker, target, combatDamage, combatParams);

        if (moveWeapon) {
            g_game.internalMoveItem(weapon->getParent(), target->getTile(), INDEX_WHEREEVER, weapon, 1, nullptr, FLAG_NOLIMIT);
        }
    } 
    return true;
}

if yours had this problem comment there.
I tested the spears and arrows other derivatives and they are ok.
 
Last edited:
I came here to post a correction in src/combat.cpp
obs: the configuration of the burst arrow is in items.srv. has no weapons.

The error is when the arrow deviates from the target and hits the ground and in turn it should explode, but what happened is that when the arrow goes to a random corner, the explosion area effect goes straight to the target.
so i did this analysis and changed the error in combat.cpp

Also, circleShapeSpell didn't limit the area effect, and the effects showed on the walls.

so i added:

Update combat.cpp

Code:
if (tile->hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID)) {
            continue;
        }

In:
C++:
void Combat::circleShapeSpell(Creature* attacker, const Position& toPos, int32_t range, int32_t animation, int32_t radius, DamageImpact* impact, int32_t effect)
{
    const Position& fromPos = attacker->getPosition();
    if (fromPos.z != toPos.z) {
        return;
    }

    int32_t distance = std::max<int32_t>(Position::getDistanceX(fromPos, toPos), Position::getDistanceY(fromPos, toPos));
    if (distance > range) {
        return;
    }

    if (animation && fromPos != toPos) {
        g_game.addDistanceEffect(fromPos, toPos, animation);
    }

    std::forward_list<Tile*> tiles;

    AreaCombat areaCombat;
    areaCombat.setupArea(radius);

    areaCombat.getList(toPos, toPos, tiles);

    for (Tile* tile : tiles) {
        if (tile->hasFlag(TILESTATE_PROTECTIONZONE)) {
            continue;
        }

        if (tile->hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID)) {
            continue;
        }

        if (CreatureVector* creatures = tile->getCreatures()) {
            for (Creature* creature : *creatures) {
                impact->handleCreature(creature);
            }
        }

        if (effect) {
            g_game.addMagicEffect(tile->getPosition(), effect);
        }
    }
}

and i made a change in:

C++:
bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fightMode)
{

        Tile* destTile = target->getTile();

        if (!Position::areInRange<1, 1, 0>(attacker->getPosition(), target->getPosition())) {
            static std::vector<std::pair<int32_t, int32_t>> destList{
                { -1, -1 },{ 0, -1 },{ 1, -1 },
                { -1,  0 },{ 0,  0 },{ 1,  0 },
                { -1,  1 },{ 0,  1 },{ 1,  1 }
            };
            std::shuffle(destList.begin(), destList.end(), getRandomGenerator());

            Position destPos = target->getPosition();

            for (const auto& dir : destList) {
                // Blocking tiles or tiles without ground ain't valid targets for spears
                Tile* tmpTile = g_game.map.getTile(destPos.x + dir.first, destPos.y + dir.second, destPos.z);
                if (tmpTile && !tmpTile->hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID) && tmpTile->getGround() != nullptr) {
                    destTile = tmpTile;
                    break;
                }
            }
        }

        if (specialEffect == 1) {
            if (hit) {
                const int32_t rounds = ammunition ? ammunition->getAttackStrength() : weapon->getAttackStrength();

                ConditionDamage* poisonDamage = new ConditionDamage(CONDITIONID_COMBAT, CONDITION_POISON);
                poisonDamage->setParam(CONDITION_PARAM_OWNER, attacker->getID());
                poisonDamage->setParam(CONDITION_PARAM_CYCLE, rounds);
                poisonDamage->setParam(CONDITION_PARAM_COUNT, 3);
                poisonDamage->setParam(CONDITION_PARAM_MAX_COUNT, 3);

                target->addCombatCondition(poisonDamage);
            }
        } else if (specialEffect == 2) {
            DamageImpact impact;
            impact.actor = attacker;
            impact.damage.type = COMBAT_PHYSICALDAMAGE;
            impact.damage.value = -Combat::computeDamage(attacker, attackStrength, attackVariation);
            impact.params.blockedByArmor = true;
            impact.params.blockedByShield = false;
            circleShapeSpell(attacker, destTile->getPosition(), 0xFF, 7, 3, &impact, 7);
        }

        if (!hit) {

            g_game.addMagicEffect(destTile->getPosition(), CONST_ME_POFF);
            g_game.addDistanceEffect(attackerPos, destTile->getPosition(), distanceEffect);

            if (moveWeapon) {
                g_game.internalMoveItem(weapon->getParent(), destTile, INDEX_WHEREEVER, weapon, 1, nullptr, FLAG_NOLIMIT);
            }

            return true;
        }

        g_game.addDistanceEffect(attackerPos, targetPos, distanceEffect);
        Combat::doCombatHealth(attacker, target, combatDamage, combatParams);

        if (moveWeapon) {
            g_game.internalMoveItem(weapon->getParent(), target->getTile(), INDEX_WHEREEVER, weapon, 1, nullptr, FLAG_NOLIMIT);
        }
    }
    return true;
}

if yours had this problem comment there.
I tested the spears and arrows other derivatives and they are ok.


It's not clear what changes you made here bool Combat::rangeAttack(Creature* attacker, Creature* target, fightMode_t fightMode)
 
Back
Top