• 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++ Creatures don't re-appear when invisible condition ends [Nostalrius/Sabrehaven]

X X X

Newb
Joined
Jul 26, 2015
Messages
148
Reaction score
13
As the title suggests. When a monster casts invisible, they stay invisible forever unless they take damage.

I have compared bits of code to other distributions, and everything that I've looked at so far looks the same, so I must be missing something or looking in the wrong place.

Her is what I checked so far:

The monster "defense" ability of invisible is here, in monsters.cpp:
C++:
else if (tmpName == "invisible") {
            int32_t duration = 10000;

            if ((attr = node.attribute("duration"))) {
                duration = pugi::cast<int32_t>(attr.value());
            }

            Condition* condition = Condition::createCondition(CONDITIONID_COMBAT, CONDITION_INVISIBLE, duration, 0);
            combat->setParam(COMBAT_PARAM_AGGRESSIVE, 0);
            combat->setCondition(condition);
pretty straightforward...if you don't declare a duration in the monster xml file, the default is 10 seconds, then it applies the condition.

The invisibility condition starting/stopping is here in condition.cpp, it looks the same as other distros:
C++:
bool ConditionInvisible::startCondition(Creature* creature)
{
    if (!Condition::startCondition(creature)) {
        return false;
    }

    g_game.internalCreatureChangeVisible(creature, false);
    return true;
}

void ConditionInvisible::endCondition(Creature* creature)
{
    if (!creature->isInvisible()) {
        g_game.internalCreatureChangeVisible(creature, true);
    }
}
Creatures get knocked out of invisibility if they take damage, this is working. The game checks using the "isInvisible" function:
C++:
void Monster::drainHealth(Creature* attacker, int32_t damage)
{
    Creature::drainHealth(attacker, damage);
    if (isInvisible()) {
        removeCondition(CONDITION_INVISIBLE);
    }
}
The "isInvisible" function looks fine too:
C++:
bool Creature::isInvisible() const
{
    return std::find_if(conditions.begin(), conditions.end(), [] (const Condition* condition) {
        return condition->getType() == CONDITION_INVISIBLE;
    }) != conditions.end();
}
I don't really know where else to look, or why the invisible condition never ends. It ends just fine for players who cast utana vid on themselves. Problem is only for monsters.
 
Solution
There is definitely something wrong with the invisible condition when it's applied through the monster's XML file in the generic format. I tested some prints in various source files, but I couldn't figure it out.

C++:
bool ConditionInvisible::startCondition(Creature* creature)
{
    if (!Condition::startCondition(creature)) {
        return false;
    }

    g_game.internalCreatureChangeVisible(creature, false);
    std::cout << "start invisible condition" << std::endl;
    return true;
}

void ConditionInvisible::endCondition(Creature* creature)
{
    if (!creature->isInvisible()) {
        std::cout << "end invisible condition" << std::endl;
        g_game.internalCreatureChangeVisible(creature, true);
    }
}
when a monster used...
There is definitely something wrong with the invisible condition when it's applied through the monster's XML file in the generic format. I tested some prints in various source files, but I couldn't figure it out.

C++:
bool ConditionInvisible::startCondition(Creature* creature)
{
    if (!Condition::startCondition(creature)) {
        return false;
    }

    g_game.internalCreatureChangeVisible(creature, false);
    std::cout << "start invisible condition" << std::endl;
    return true;
}

void ConditionInvisible::endCondition(Creature* creature)
{
    if (!creature->isInvisible()) {
        std::cout << "end invisible condition" << std::endl;
        g_game.internalCreatureChangeVisible(creature, true);
    }
}
when a monster used invisible, I would see the print "start invisible condition" when a monster turned invis, but would got the end print unless I hit them with a spell.
somewhere, the "duration" variable is not getting set correctly. So the monster casts the spell, and the duration is just set to infinity. a cheap fix? make a dedicated Lua script for the spell. I tested with the distro, and it works.

Take an assassin for example, they turn invis for 2 seconds.
assassin_invis.lua:
Lua:
local combat = Combat()
combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_MAGIC_BLUE)
combat:setParameter(COMBAT_PARAM_AGGRESSIVE, false)

local condition = Condition(CONDITION_INVISIBLE)
condition:setParameter(CONDITION_PARAM_TICKS, 2000)
combat:setCondition(condition)

function onCastSpell(creature, variant)
    return combat:execute(creature, variant)
end
spells.xml:
XML:
<instant name="assassin_invis" words="###XX" aggressive="1" blockwalls="1" needtarget="0" needlearn="1" script="spells/assassin_invis.lua"/>
then finally in assassin.xml:

XML:
<defenses armor="17" defense="40">
        <defense name="speed" speedchange="60" variation="5" duration="3000" chance="12">
            <attribute key="areaEffect" value="redshimmer" />
        </defense>
        <defense name="assassin_invis" chance="12" />
    </defenses>

honestly unless you have 100x different monsters that turn invis, making some separate monster Lua spells is going to be way faster than tracking down whatever bug in the C++ that's preventing the 'duration' variable from being passed into the condition.
 
Solution
Back
Top