• 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!
  • If you're using Gesior 2012 or MyAAC, please review this thread for information about a serious security vulnerability and a fix.

Feature [TFS 1.3] Monster Levels

Rodrigo13

New Member
Joined
Jul 2, 2008
Messages
12
Reaction score
2
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
 

Pox

Advanced OT User
Joined
Apr 28, 2020
Messages
163
Solutions
10
Reaction score
170
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;
}
 

Svira

Member
Joined
Jan 27, 2008
Messages
206
Solutions
7
Reaction score
22
How can I add this script already with monster rates? shows me an error about duplicate functions...
 

115820

Member
Joined
Feb 27, 2011
Messages
193
Solutions
1
Reaction score
5
Location
London, England
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)
 

Derlexy

Well-Known Member
Joined
Jun 29, 2011
Messages
182
Reaction score
53
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
 

Gubailovo

Active Member
Joined
Dec 19, 2013
Messages
368
Solutions
2
Reaction score
46
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
 

Derlexy

Well-Known Member
Joined
Jun 29, 2011
Messages
182
Reaction score
53
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:

Roddet

Premium User
Support Team
Joined
May 1, 2013
Messages
808
Solutions
86
Reaction score
593
Location
Mex
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
 

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,241
Solutions
27
Reaction score
695
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
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.
 

alejandro762

Member
Joined
Sep 6, 2021
Messages
138
Reaction score
24
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:

Evil Puncker

I know nothing
TFS Developer
Joined
May 30, 2009
Messages
8,537
Solutions
260
Reaction score
4,526
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
 

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,241
Solutions
27
Reaction score
695
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
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 👍
 

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,241
Solutions
27
Reaction score
695
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
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!
 

Addams

1337
Senator
Premium User
Joined
Sep 29, 2009
Messages
2,835
Solutions
340
Reaction score
1,579
Location
Egypt
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:
Top