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

Feature [TFS 1.3] Monster Levels

I wrote a separate placeCreature with level function:

C++:
bool Game::placeCreatureWithLevel(Creature* creature, const Position& pos, bool extendedPos /*=false*/, bool forced /*= false*/, int32_t level)
{
    if (!internalPlaceCreature(creature, pos, extendedPos, forced)) {
        return false;
    }

    creature->setMonsterLevel(level);

    SpectatorVec spectators;
    map.getSpectators(spectators, creature->getPosition(), true);
    for (Creature* spectator : spectators) {
        if (Player* tmpPlayer = spectator->getPlayer()) {
            tmpPlayer->sendCreatureAppear(creature, creature->getPosition(), true);
        }
    }

    for (Creature* spectator : spectators) {
        spectator->onCreatureAppear(creature, true);
    }

    creature->getParent()->postAddNotification(creature, nullptr, 0);

    addCreatureCheck(creature);
    creature->onPlacedCreature();
    return true;
}
Thanks for your reply Pox! But I got these errors when compiling:
Sin título.png
 
Thanks for your reply Pox! But I got these errors when compiling:
View attachment 58670


In game.cpp:
C++:
bool Game::placeCreatureWithLevel(Creature* creature, const Position& pos, bool extendedPos /*=false*/, bool forced /*= false*/, int32_t level)
{
    if (!internalPlaceCreature(creature, pos, extendedPos, forced)) {
        return false;
    }

    creature->setMonsterLevel(level);

    SpectatorVec spectators;
    map.getSpectators(spectators, creature->getPosition(), true);
    for (Creature* spectator : spectators) {
        if (Player* tmpPlayer = spectator->getPlayer()) {
            tmpPlayer->sendCreatureAppear(creature, creature->getPosition(), true);
        }
    }

    for (Creature* spectator : spectators) {
        spectator->onCreatureAppear(creature, true);
    }

    creature->getParent()->postAddNotification(creature, nullptr, 0);

    addCreatureCheck(creature);
    creature->onPlacedCreature();
    return true;
}

in game.h, below bool placeCreature(Creature* creature, const Position& pos, bool extendedPos = false, bool forced = false);
C++:
bool placeCreatureWithLevel(Creature* creature, const Position& pos, bool extendedPos /*=false*/, bool forced /*= false*/, int32_t level);

in creature.h, below bool setMaster(Creature* newMaster);
C++:
void setMonsterLevel(int32_t level) {
    this->level = level;
}
 
How can I add this script already with monster rates? shows me an error about duplicate functions...
 
how i add minlevel and maxlevel in this type of script.


Lua:
local mType = Game.createMonsterType("Rat")
local monster = {}

monster.description = "a rat"
monster.experience = 5
monster.outfit = {
    lookType = 21,
    lookHead = 0,
    lookBody = 0,
    lookLegs = 0,
    lookFeet = 0,
    lookAddons = 0,
    lookMount = 0
}

monster.raceId = 21
monster.Bestiary = {
    class = "Mammal",
    race = BESTY_RACE_MAMMAL,
    toKill = 250,
    FirstUnlock = 10,
    SecondUnlock = 100,
    CharmsPoints = 5,
    Stars = 1,
    Occurrence = 0,
    Locations = "Rookgaard and Mainland, in most sewers and caves near towns. \z
        They can be found almost everywhere in Tibia."
    }

monster.health = 20
monster.maxHealth = 20
monster.race = "blood"
monster.corpse = 5964
monster.speed = 134
monster.manaCost = 200
monster.maxSummons = 0

monster.changeTarget = {
    interval = 4000,
    chance = 0
}

monster.strategiesTarget = {
    nearest = 100,
}

monster.flags = {
    summonable = true,
    attackable = true,
    hostile = true,
    convinceable = true,
    pushable = true,
    rewardBoss = false,
    illusionable = true,
    canPushItems = false,
    canPushCreatures = false,
    staticAttackChance = 90,
    targetDistance = 1,
    runHealth = 5,
    healthHidden = false,
    isBlockable = false,
    canWalkOnEnergy = false,
    canWalkOnFire = false,
    canWalkOnPoison = false,
    pet = false
}

monster.light = {
    level = 0,
    color = 0
}

monster.voices = {
    interval = 5000,
    chance = 10,
    {text = "Meep!", yell = false}
}

monster.loot = {
    {name = "gold coin", chance = 100000, maxCount = 4},
    {id = 2696, chance = 39410}
}

monster.attacks = {
    {name ="melee", interval = 2000, chance = 100, minDamage = 0, maxDamage = -10}
}

monster.defenses = {
    defense = 5,
    armor = 5
}

monster.elements = {
    {type = COMBAT_PHYSICALDAMAGE, percent = 0},
    {type = COMBAT_ENERGYDAMAGE, percent = 0},
    {type = COMBAT_EARTHDAMAGE, percent = 25},
    {type = COMBAT_FIREDAMAGE, percent = 0},
    {type = COMBAT_LIFEDRAIN, percent = 0},
    {type = COMBAT_MANADRAIN, percent = 0},
    {type = COMBAT_DROWNDAMAGE, percent = 0},
    {type = COMBAT_ICEDAMAGE, percent = -10},
    {type = COMBAT_HOLYDAMAGE , percent = 20},
    {type = COMBAT_DEATHDAMAGE , percent = -10}
}

monster.immunities = {
    {type = "paralyze", condition = false},
    {type = "outfit", condition = false},
    {type = "invisible", condition = false},
    {type = "bleed", condition = false}
}

mType:register(monster)
 
For those who are asking about mosnter with skull, follows:

On monster.cpp place the logic as follows:
C++:
Monster::Monster(MonsterType* mtype) :
    Creature(),
    strDescription(asLowerCaseString(mtype->nameDescription)),
    mType(mtype)
{
    defaultOutfit = mType->info.outfit;
    currentOutfit = mType->info.outfit;
    skull = mType->info.skull;

    level = uniform_random(mType->info.minLevel, mType->info.maxLevel);

    // Elite Monsters skull by LEVEL:
    if (level >= 10 && level <= 50) {
        skull = SKULL_WHITE;
    }
    else if (level >= 51 && level <= 75) {
        skull = SKULL_YELLOW;
    }
    else if (level >= 76) {
        skull = SKULL_RED;
    }

    health = mType->info.health;
    healthMax = mType->info.healthMax;
    baseSpeed = mType->info.baseSpeed;
    internalLight = mType->info.light;
    if (level > 0) {
        float bonusHp = g_config.getFloat(ConfigManager::MLVL_BONUSHP) * level;
        if (bonusHp != 0.0) {
            healthMax += healthMax * bonusHp;
            health += health * bonusHp;
        }
        float bonusSpeed = g_config.getFloat(ConfigManager::MLVL_BONUSSPEED) * level;
        if (bonusSpeed != 0.0) {
            baseSpeed += baseSpeed * bonusSpeed;
        }
    }

    // register creature events
    for (const std::string& scriptName : mType->info.scripts) {
        if (!registerCreatureEvent(scriptName)) {
            std::cout << "[Warning - Monster::Monster] Unknown event name: " << scriptName << std::endl;
        }
    }
}

Result:
testeskull.png
 
everything compiled without errors. added 2 more skulls. (to split by 20)

C++:
    // Elite Monsters skull by LEVEL:
    if (level >= 1 && level <= 20) {
        skull = SKULL_WHITE;
    }
    else if (level >= 21 && level <= 45) {
        skull = SKULL_YELLOW;
    }
    else if (level >= 45 && level <= 65) {
        skull = SKULL_GREEN;
    }
    else if (level >= 65 && level <= 85) {
        skull = SKULL_RED;
    }
    else if (level >= 86) {
        skull = SKULL_BLACK;
    }
Скриншот 31-03-2022 231941.jpg
 
It works successfully in my TFS 1.3. But, after I add that system in my server, all monsters (same having tag hostile = 0 in xml) are hostile. Monsters like Rabbit for example, are attacking me.

How I fix this problem?

I got the same problem here. After the implementation all monsters got hostile, even that we do not changed anything about it in the source code.

See below:
sheeps.png

I guess the changes messed something up.
Trying to fix it, feel free to help.

I have identified the problem already. If i comment this code highlighted in red, monsters starts to flee again:
problem.png

I maneged to fix it. Looks like we can set the health, healthMax and baseSpeed just once. So i moved the code back up and worked with temporary variables. Once i finished all the math, i just declared the health, healthMax and baseSpeed once after.

Also, you have to change the mosnters XML the runonhealth flag, cuz this system adds health to the mosnters.
 
Last edited:
I got the same problem here. After the implementation all monsters got hostile, even that we do not changed anything about it in the source code.

See below:
View attachment 66603

I guess the changes messed something up.
Trying to fix it, feel free to help.

I have identified the problem already. If i comment this code highlighted in red, monsters starts to flee again:
View attachment 66604

I maneged to fix it. Looks like we can set the health, healthMax and baseSpeed just once. So i moved the code back up and worked with temporary variables. Once i finished all the math, i just declared the health, healthMax and baseSpeed once after.

Also, you have to change the mosnters XML the runonhealth flag, cuz this system adds health to the mosnters.

I think a new condition would be enough if (mType->info.isHostile) that way you avoid non-hostile monsters on code
 
Works perfectly! Thanks, also added the extra experience from here @Pox

Here's my clean-up

everything compiled without errors. added 2 more skulls. (to split by 20)

C++:
    // Elite Monsters skull by LEVEL:
    if (level >= 1 && level <= 20) {
        skull = SKULL_WHITE;
    }
    else if (level >= 21 && level <= 45) {
        skull = SKULL_YELLOW;
    }
    else if (level >= 45 && level <= 65) {
        skull = SKULL_GREEN;
    }
    else if (level >= 65 && level <= 85) {
        skull = SKULL_RED;
    }
    else if (level >= 86) {
        skull = SKULL_BLACK;
    }

Tried to merge that but didn't work, used in a raw 8.6 client, it is possible that cipsoft client doesnt support skulls for monsters or something? Thanks in advance.
 
how to add it here ?
Compilation works, it show:
You see a wolf, it is level 0.
But can't add monster.minLevel = 5 / monster.maxLevel = 100
or adding it into monster.defenses or something else, minLevel = 5 / maxLevel = 100
doesn't work, anyone know ?

Also tried:

Lua:
monster.level = {
    min = 5,
    max = 100
}
 
Last edited:
how to add it here ?
Compilation works, it show:
You see a wolf, it is level 0.
But can't add monster.minLevel = 5 / monster.maxLevel = 100
or adding it into monster.defenses or something else, minLevel = 5 / maxLevel = 100
doesn't work, anyone know ?

Also tried:

Lua:
monster.level = {
    min = 5,
    max = 100
}

the code by @Infernum was made specifically to work on TFS, not canary/otservbr or what else that engine is called, if you guys need specific help, open a support thread and don't pollute this thread with non TFS stuff
 
Works perfectly! Thanks, also added the extra experience from here @Pox

Here's my clean-up



Tried to merge that but didn't work, used in a raw 8.6 client, it is possible that cipsoft client doesnt support skulls for monsters or something? Thanks in advance.

If someone still wishes to add skulls, just patch with this

Hi,
Does it work on tfs 1.5 ?

Worked well for me 👍
 
how i add minlevel and maxlevel in this type of script.


Lua:
local mType = Game.createMonsterType("Rat")
local monster = {}

monster.description = "a rat"
monster.experience = 5
monster.outfit = {
    lookType = 21,
    lookHead = 0,
    lookBody = 0,
    lookLegs = 0,
    lookFeet = 0,
    lookAddons = 0,
    lookMount = 0
}

monster.raceId = 21
monster.Bestiary = {
    class = "Mammal",
    race = BESTY_RACE_MAMMAL,
    toKill = 250,
    FirstUnlock = 10,
    SecondUnlock = 100,
    CharmsPoints = 5,
    Stars = 1,
    Occurrence = 0,
    Locations = "Rookgaard and Mainland, in most sewers and caves near towns. \z
        They can be found almost everywhere in Tibia."
    }

monster.health = 20
monster.maxHealth = 20
monster.race = "blood"
monster.corpse = 5964
monster.speed = 134
monster.manaCost = 200
monster.maxSummons = 0

monster.changeTarget = {
    interval = 4000,
    chance = 0
}

monster.strategiesTarget = {
    nearest = 100,
}

monster.flags = {
    summonable = true,
    attackable = true,
    hostile = true,
    convinceable = true,
    pushable = true,
    rewardBoss = false,
    illusionable = true,
    canPushItems = false,
    canPushCreatures = false,
    staticAttackChance = 90,
    targetDistance = 1,
    runHealth = 5,
    healthHidden = false,
    isBlockable = false,
    canWalkOnEnergy = false,
    canWalkOnFire = false,
    canWalkOnPoison = false,
    pet = false
}

monster.light = {
    level = 0,
    color = 0
}

monster.voices = {
    interval = 5000,
    chance = 10,
    {text = "Meep!", yell = false}
}

monster.loot = {
    {name = "gold coin", chance = 100000, maxCount = 4},
    {id = 2696, chance = 39410}
}

monster.attacks = {
    {name ="melee", interval = 2000, chance = 100, minDamage = 0, maxDamage = -10}
}

monster.defenses = {
    defense = 5,
    armor = 5
}

monster.elements = {
    {type = COMBAT_PHYSICALDAMAGE, percent = 0},
    {type = COMBAT_ENERGYDAMAGE, percent = 0},
    {type = COMBAT_EARTHDAMAGE, percent = 25},
    {type = COMBAT_FIREDAMAGE, percent = 0},
    {type = COMBAT_LIFEDRAIN, percent = 0},
    {type = COMBAT_MANADRAIN, percent = 0},
    {type = COMBAT_DROWNDAMAGE, percent = 0},
    {type = COMBAT_ICEDAMAGE, percent = -10},
    {type = COMBAT_HOLYDAMAGE , percent = 20},
    {type = COMBAT_DEATHDAMAGE , percent = -10}
}

monster.immunities = {
    {type = "paralyze", condition = false},
    {type = "outfit", condition = false},
    {type = "invisible", condition = false},
    {type = "bleed", condition = false}
}

mType:register(monster)

Same question, how do I set the level if the creature is written with revscriptsys? Should I convert it to old syntaxis? Regards!
 
Worked well for me 👍
You still using those skulls in C++? Any issues you found?
nvm, I didn't notice you had the server public on Github, Checked it there and you have it included, Thanks!
C++:
if (level >= 1 && level <= 20) {
        skull = SKULL_WHITE;
    }
    else if (level >= 21 && level <= 45) {
        skull = SKULL_YELLOW;
    }
    else if (level >= 45 && level <= 65) {
        skull = SKULL_GREEN;
    }
    else if (level >= 65 && level <= 85) {
        skull = SKULL_RED;
    }
    else if (level >= 86) {
        skull = SKULL_BLACK;
}
I wrote some quick Lua to randomize skulls yesterday but still wondered if I should add this one to the source instead.
Lua:
local skullsTable = {
    {SKULL_BLACK, 1},
    {SKULL_RED, 5},
    {SKULL_WHITE, 7}
}

local ec = EventCallback

function ec.onSpawn(monster, position, startup, artificial)
    local chance = math.random(0, 100)
    for i, skullName in ipairs(skullsTable) do
        if chance <= skullName[2] then
            monster:setSkull(skullName[1])
            break
        end
    end
    return true
end

ec:register(-1)
 
Last edited:
did someone do this for 1.4.2? compilation failed for me
 
Back
Top