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

Lua [TFS 1.3] Free Scripting Service 📝

Status
Not open for further replies.

Sarah Wesker

ƐƖєgαηт Sуηтαx ❤
Staff member
TFS Developer
Support Team
Joined
Mar 16, 2017
Messages
1,430
Solutions
156
Reaction score
2,004
Location
London
GitHub
MillhioreBT
Twitch
millhiorebt
I am bored, and I have some days in which I will not have much to do, if you need a script you can post here what you want and if it meets the requirements below, I will do it for you

🗒 Requirements:
🔶 TFS engine 1.3+
🔶 That does not include changes in the sources (if you don't know what this is, you can still ask💬)
🔶 I'll only do one script per person so don't spam🔇too much, until a second chance ...
🔶 It depends on what you ask, I will make the decision to accept or not to do it👀
🔶 I know that several people have posted threads similar to this one, but to add more variety, also not all can be available at the same time👌

Don't be afraid to ask 🤗

👍 If I like your post it means that I have taken the task! 👍
 
Last edited:
What you ask is not very specific, however it is quite simple ...

When I read your publication, i imagine more things than you have asked, however those things require changes in the sources to be viable, the truth would have been beautiful, unfortunately in my publication I mentioned that I will not make changes in the sources.

Anyway, I made you a small script which generates a monster of the same type with an increased amount of life, when generated, an explosion effect is sent to give it a more dramatic touch.

data/scripts/yourscriptname.lua
Lua:
local spawnbosses = {
    ["Rotworm"] = {
        chance = 50,
        newHppc = 2.50
    },
    ["Dragon"] = {
        chance = 50,
        newHppc = 1.10
    }
}

local cSpawnBossWhenDie = CreatureEvent("SpawnBossWhenDie")
function cSpawnBossWhenDie.onDeath(creature, corpse, killer, mostDamageKiller, unjustified, mostDamageUnjustified)
    local prop = spawnbosses[creature:getName()]
    if prop and math.random(100) <= prop.chance then
        local name = creature:getName()
        local maxHp = creature:getMaxHealth()
        if maxHp == MonsterType(name):getMaxHealth() then
            local pos = creature:getPosition()
            local boss = Game.createMonster(name, pos)
            if boss then
                pos:sendMagicEffect(CONST_ME_EXPLOSIONAREA)
                local newMaxHp = maxHp * prop.newHppc
                boss:setMaxHealth(newMaxHp)
                boss:addHealth(newMaxHp)
            end
        end
    end
    return true
end
cSpawnBossWhenDie:register()

local ev = EventCallback
function ev.onTargetCombat(creature, target)
    if creature:isPlayer() and target:isMonster() and spawnbosses[target:getName()] then
        target:registerEvent("SpawnBossWhenDie")
    end
    return RETURNVALUE_NOERROR
end

View attachment 54473

Normally what would be expected of a miniboss is that it has: name, damage and other different properties, but without changes in the sources it is not possible, only the health per default, I hope this script will help you, or at least as an example, maybe for the next round you can imagine something that is more within reach ;)
Thanks for helping me out with this, the script looks great! I didn't thought it would require to edit sources as I had the idea that I would only need to create a copy of the xml file of the monsters and edit them to make them stronger, so when the original monster is killed, the script would summon the stronger version. I should have explained that by miniboss I only meant a stronger version of the monster, as that is what makes it confusing and complicated. Anyways, the script does what I wanted and its a great help, thanks again for making it.
 
Thanks for helping me out with this, the script looks great! I didn't thought it would require to edit sources as I had the idea that I would only need to create a copy of the xml file of the monsters and edit them to make them stronger, so when the original monster is killed, the script would summon the stronger version. I should have explained that by miniboss I only meant a stronger version of the monster, as that is what makes it confusing and complicated. Anyways, the script does what I wanted and its a great help, thanks again for making it.
i Edit the code in a moment so you can add your custom monsters as mini boss, you just have to wait a few minutes ;) thanks
 
Hello if you have time, and do you want to create something like this...

[Automatic MultiPromotion System with bonuses]

on level 1 we start as a druid on level 20 automatically transforms us into an elder druid then at 50 into Royal Druid
20 lvl bonus +150hp and +500mp and new outfit druid (with 2 addons)
50 lvl bonus +25speed and 500mp and new outfit summoner (with 2 addons)
 
Hello Sarah.
I need EXP online players bonus
5 - 19EXP +5%
20 - 49EXP +10%
50 - 99EXP +15%
100 - 249EXP +20%
250 - 399EXP +25%
400+EXP +30%
tfs 1.3
 
Last edited:
Hello Sarah, good scripts you doing here ^^.
Can you make one for outfit and mounts bonuses? Each full outfit/mount obtained you gain some bonuses like +hp, +mana, +skills, they being in intervals: First mount/outfit: +1%hp, Second mount/outfit: +1%mp, third mount/outfit: +1skills (sword,axe,club,ml), Fourth mount/outfit: +1%hp and so on
 
Hi

I would like to request a spell which is based mostly on random direction

The spell will cast 4 distance effect in a row with small delays with random direction

1612385733988.png
 
Hi Sarah, I don't know if you read me or not you can help me but I wanted a door scripts with storage since the one I have is bugeada ..
I just want a scrits .. that in order to open the door you have the quest done
 
Hi Sarah, I don't know if you read me or not you can help me but I wanted a door scripts with storage since the one I have is bugeada ..
I just want a scrits .. that in order to open the door you have the quest done
you'd be better off posting in support for this, and post your data/scripts/other/doors.lua script
 
Normally what would be expected of a miniboss is that it has: name, damage and other different properties, but without changes in the sources it is not possible, only the health per default, I hope this script will help you, or at least as an example, maybe for the next round you can imagine something that is more within reach ;)
I'd like to say that's not true.

You could use these to create boss MonsterTypes in batches:
C++:
registerMethod("Game", "getMonsterTypes", LuaScriptInterface::luaGameGetMonsterTypes);
registerMethod("Game", "createMonsterType", LuaScriptInterface::luaGameCreateMonsterType);

Then you could use all of these to make a copy of the monsters and buff them:
C++:
    // MonsterType
    registerClass("MonsterType", "", LuaScriptInterface::luaMonsterTypeCreate);
    registerMetaMethod("MonsterType", "__eq", LuaScriptInterface::luaUserdataCompare);

    registerMethod("MonsterType", "isAttackable", LuaScriptInterface::luaMonsterTypeIsAttackable);
    registerMethod("MonsterType", "isConvinceable", LuaScriptInterface::luaMonsterTypeIsConvinceable);
    registerMethod("MonsterType", "isSummonable", LuaScriptInterface::luaMonsterTypeIsSummonable);
    registerMethod("MonsterType", "isIllusionable", LuaScriptInterface::luaMonsterTypeIsIllusionable);
    registerMethod("MonsterType", "isHostile", LuaScriptInterface::luaMonsterTypeIsHostile);
    registerMethod("MonsterType", "isPushable", LuaScriptInterface::luaMonsterTypeIsPushable);
    registerMethod("MonsterType", "isHealthHidden", LuaScriptInterface::luaMonsterTypeIsHealthHidden);
    registerMethod("MonsterType", "isBoss", LuaScriptInterface::luaMonsterTypeIsBoss);

    registerMethod("MonsterType", "canPushItems", LuaScriptInterface::luaMonsterTypeCanPushItems);
    registerMethod("MonsterType", "canPushCreatures", LuaScriptInterface::luaMonsterTypeCanPushCreatures);

    registerMethod("MonsterType", "name", LuaScriptInterface::luaMonsterTypeName);

    registerMethod("MonsterType", "nameDescription", LuaScriptInterface::luaMonsterTypeNameDescription);

    registerMethod("MonsterType", "health", LuaScriptInterface::luaMonsterTypeHealth);
    registerMethod("MonsterType", "maxHealth", LuaScriptInterface::luaMonsterTypeMaxHealth);
    registerMethod("MonsterType", "runHealth", LuaScriptInterface::luaMonsterTypeRunHealth);
    registerMethod("MonsterType", "experience", LuaScriptInterface::luaMonsterTypeExperience);
    registerMethod("MonsterType", "skull", LuaScriptInterface::luaMonsterTypeSkull);

    registerMethod("MonsterType", "combatImmunities", LuaScriptInterface::luaMonsterTypeCombatImmunities);
    registerMethod("MonsterType", "conditionImmunities", LuaScriptInterface::luaMonsterTypeConditionImmunities);

    registerMethod("MonsterType", "getAttackList", LuaScriptInterface::luaMonsterTypeGetAttackList);
    registerMethod("MonsterType", "addAttack", LuaScriptInterface::luaMonsterTypeAddAttack);

    registerMethod("MonsterType", "getDefenseList", LuaScriptInterface::luaMonsterTypeGetDefenseList);
    registerMethod("MonsterType", "addDefense", LuaScriptInterface::luaMonsterTypeAddDefense);

    registerMethod("MonsterType", "getElementList", LuaScriptInterface::luaMonsterTypeGetElementList);
    registerMethod("MonsterType", "addElement", LuaScriptInterface::luaMonsterTypeAddElement);

    registerMethod("MonsterType", "getVoices", LuaScriptInterface::luaMonsterTypeGetVoices);
    registerMethod("MonsterType", "addVoice", LuaScriptInterface::luaMonsterTypeAddVoice);

    registerMethod("MonsterType", "getLoot", LuaScriptInterface::luaMonsterTypeGetLoot);
    registerMethod("MonsterType", "addLoot", LuaScriptInterface::luaMonsterTypeAddLoot);

    registerMethod("MonsterType", "getCreatureEvents", LuaScriptInterface::luaMonsterTypeGetCreatureEvents);
    registerMethod("MonsterType", "registerEvent", LuaScriptInterface::luaMonsterTypeRegisterEvent);

    registerMethod("MonsterType", "eventType", LuaScriptInterface::luaMonsterTypeEventType);
    registerMethod("MonsterType", "onThink", LuaScriptInterface::luaMonsterTypeEventOnCallback);
    registerMethod("MonsterType", "onAppear", LuaScriptInterface::luaMonsterTypeEventOnCallback);
    registerMethod("MonsterType", "onDisappear", LuaScriptInterface::luaMonsterTypeEventOnCallback);
    registerMethod("MonsterType", "onMove", LuaScriptInterface::luaMonsterTypeEventOnCallback);
    registerMethod("MonsterType", "onSay", LuaScriptInterface::luaMonsterTypeEventOnCallback);

    registerMethod("MonsterType", "getSummonList", LuaScriptInterface::luaMonsterTypeGetSummonList);
    registerMethod("MonsterType", "addSummon", LuaScriptInterface::luaMonsterTypeAddSummon);

    registerMethod("MonsterType", "maxSummons", LuaScriptInterface::luaMonsterTypeMaxSummons);

    registerMethod("MonsterType", "armor", LuaScriptInterface::luaMonsterTypeArmor);
    registerMethod("MonsterType", "defense", LuaScriptInterface::luaMonsterTypeDefense);
    registerMethod("MonsterType", "outfit", LuaScriptInterface::luaMonsterTypeOutfit);
    registerMethod("MonsterType", "race", LuaScriptInterface::luaMonsterTypeRace);
    registerMethod("MonsterType", "corpseId", LuaScriptInterface::luaMonsterTypeCorpseId);
    registerMethod("MonsterType", "manaCost", LuaScriptInterface::luaMonsterTypeManaCost);
    registerMethod("MonsterType", "baseSpeed", LuaScriptInterface::luaMonsterTypeBaseSpeed);
    registerMethod("MonsterType", "light", LuaScriptInterface::luaMonsterTypeLight);

    registerMethod("MonsterType", "staticAttackChance", LuaScriptInterface::luaMonsterTypeStaticAttackChance);
    registerMethod("MonsterType", "targetDistance", LuaScriptInterface::luaMonsterTypeTargetDistance);
    registerMethod("MonsterType", "yellChance", LuaScriptInterface::luaMonsterTypeYellChance);
    registerMethod("MonsterType", "yellSpeedTicks", LuaScriptInterface::luaMonsterTypeYellSpeedTicks);
    registerMethod("MonsterType", "changeTargetChance", LuaScriptInterface::luaMonsterTypeChangeTargetChance);
    registerMethod("MonsterType", "changeTargetSpeed", LuaScriptInterface::luaMonsterTypeChangeTargetSpeed);
 
I want an NPC which a player can face against on a combat of trivial pursuit
Because the information you provided was very limited, I had to search the internet a bit, and use a bit of my imagination, this is the result:

data/npc/Trivial.xml
XML:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Trivial" script="trivial.lua" walkinterval="2000" speed="0" floorchange="0">
    <health now="100" max="100" />
    <look type="472" head="114" body="95" legs="76" feet="19" addons="3"/>
</npc>

data/npc/scripts/trivial.lua
Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

function onCreatureAppear(cid)              npcHandler:onCreatureAppear(cid)            end
function onCreatureDisappear(cid)           npcHandler:onCreatureDisappear(cid)         end
function onCreatureSay(cid, type, msg)      npcHandler:onCreatureSay(cid, type, msg)    end
function onThink()                          npcHandler:onThink()                        end

local function irandom_prefix(from, to, prefix)
    return string.format("%d %s", math.random(from, to), prefix)
end

local talkHppc = {
    player = 100,
    npc = 100,
    damage = function() return math.random(10, 20) end
}
local rewards = {
    exp = 1000000,
    items = {
        {2160, 100},
        {2160, 100}
    }
}

local questions = {
    {
        type = "select",
        name = "How far is the earth from the moon?",
        options = {
            irandom_prefix(1, 100, "km"),
            irandom_prefix(5000, 9999, "km"),
            irandom_prefix(1, 999, "km"),
            "384400 km"
        },
        answer = 4
    },
    {
        type = "select",
        name = "Who is the president of the united states?",
        options = {
            "Kamala Harris",
            "Donald Trump",
            "Joe Biden",
            "Barack Obama"
        },
        answer = 3
    },
    {
        type = "select",
        name = "Which is the vocation that has more magic damage?",
        options = {
            "Knight",
            "Sorcerer",
            "Paladin",
            "No Vocation"
        },
        answer = 2
    },
    {
        type = "math",
        name = "What is the result of %d %s %d?",
        options = 4
    }
}

local function shuffle(tbl)
  for i = #tbl, 2, -1 do
    local j = math.random(i)
    tbl[i], tbl[j] = tbl[j], tbl[i]
  end
end

local function delaySay(msg, interval, npcid, cid)
    addEvent(function(msg, npcid, cid)
        local npc = Npc(npcid)
        if npc then
            npc:say(msg, TALKTYPE_PRIVATE_NP, false, cid)
        end
    end, interval, msg, npcid, cid)
end

local talkPlayer = 0
local talkQuest = nil
local talkState = {}
local afterQuests = nil

local function getRandomQuest()
    local quest
    if not afterQuests then
        afterQuests = math.random(1, #questions)
        quest = questions[afterQuests]
    else
        local nrandom = math.random(1, #questions)
        quest = questions[nrandom]
        while afterQuests == nrandom do
            quest = questions[nrandom]
        end
        afterQuests = nrandom
    end
    if quest then
        if quest.type == "select" then
            local options = {}
            for i = 1, #quest.options do
                local option = quest.options[i]
                if type(option) == "function" then
                    options[#options +1] = option()
                elseif type(option) == "string" then
                    options[#options +1] = option
                end
            end
            shuffle(options)
            local answer = 1
            for i = 1, #options do
                if options[i] == quest.options[quest.answer] then
                    answer = i
                    break
                end
            end
            return {
                name = quest.name,
                options = options,
                answer = answer
            }
        elseif quest.type == "math" then
            local operator = ({'+','-','/','*'})[math.random(1, 4)]
            local n1, n2 = math.random(1, 100), math.random(1, 100)
            local o_result = loadstring(string.format("return %d%s%d", n1, operator, n2))()
            local name = string.format(quest.name, n1, operator, n2)
            local options = {o_result}
            for i = 1, quest.options -1 do
                options[#options +1] = math.random(1, 999)
            end
            shuffle(options)
            local answer = 1
            for i = 1, #options do
                if options[i] == o_result then
                    answer = i
                    break
                end
            end
            return {
                name = name,
                options = options,
                answer = answer
            }
        end
    end
end

local function sendNewQuest(cid, nid)
    talkQuest = getRandomQuest()
    local text = string.format("%s\nOptions: ", talkQuest.name)
    for i = 1, #talkQuest.options do
        text = string.format("%s[ {%d} ]: %s%s", text, i, talkQuest.options[i], (i ~= #talkQuest.options and " | " or ""))
    end
    delaySay(text, 1000, nid, cid)
end

local function sendRewards(player)
    local bag = Game.createItem(2002, 1)
    if bag then
        local description = "You rewards: "
        for _, reward in pairs(rewards.items) do
            bag:addItem(reward[1], reward[2], INDEX_WHEREEVER, FLAG_NOLIMIT)
            description = string.format("%s%d %s%s", description, reward[2], ItemType(reward[1]):getName(), (_ == #rewards.items and '.' or ', '))
        end
        local inbox = player:getInbox()
        if inbox then
            inbox:addItemEx(bag, INDEX_WHEREEVER, FLAG_NOLIMIT)
            player:sendTextMessage(MESSAGE_INFO_DESCR, description..'\nCheck your depot inbox.')
        end
    end
    if rewards.exp then
        player:addExperience(rewards.exp, true)
    end
end

function creatureSayCallback(cid, typ, msg)
    if not npcHandler:isFocused(cid) then
        return false
    end

    local nid = getNpcCid()
    local npc = Npc(nid)
    local npcPos = npc:getPosition()

    local player = Player(cid)
    local playerPos = player:getPosition()

    if not talkState[cid] then
        if msgcontains(msg, "yes") then
            selfSay("Here are some questions which you have to answer, I'll play too ;D", cid)
            sendNewQuest(cid, nid)
            npcPos:sendMagicEffect(CONST_ME_CRAPS)
            talkState[cid] = 1
        elseif msgcontains(msg, "no") then
            selfSay("Come back when you have the courage to face me.", cid)
            npcHandler:releaseFocus(cid)
        end
    elseif talkState[cid] == 1 then
        if talkQuest then
            local select_n = tonumber(msg)
            if select_n and select_n > 0 and select_n <= #talkQuest.options then
                local npc_correct = math.random(1, #talkQuest.options) == talkQuest.answer
                if select_n == talkQuest.answer then
                    if npc_correct then
                        selfSay("Your answer is correct, mine is also correct, so neither will take damage.", cid)
                        npcPos:sendMagicEffect(CONST_ME_POFF)
                        playerPos:sendMagicEffect(CONST_ME_POFF)
                    else
                        selfSay("Your answer is correct, mine is not, so I will take damage.", cid)
                        playerPos:sendMagicEffect(CONST_ME_POFF)
                        playerPos:sendDistanceEffect(npcPos, CONST_ANI_DEATH)
                        npcPos:sendMagicEffect(CONST_ME_MORTAREA)
                        talkHppc.npc = math.max(0, talkHppc.npc - talkHppc.damage())
                    end
                else
                    if npc_correct then
                        selfSay("Your answer is wrong, mine is correct, you will receive damage.", cid)
                        npcPos:sendMagicEffect(CONST_ME_POFF)
                        npcPos:sendDistanceEffect(playerPos, CONST_ANI_DEATH)
                        playerPos:sendMagicEffect(CONST_ME_MORTAREA)
                        talkHppc.player = math.max(0, talkHppc.player - talkHppc.damage())
                    else
                        selfSay("Your answer is wrong, I was wrong too, we both received damage.", cid)
                        playerPos:sendDistanceEffect(npcPos, CONST_ANI_DEATH)
                        npcPos:sendMagicEffect(CONST_ME_MORTAREA)
                        npcPos:sendDistanceEffect(playerPos, CONST_ANI_DEATH)
                        playerPos:sendMagicEffect(CONST_ME_MORTAREA)
                        talkHppc.player = math.max(0, talkHppc.player - talkHppc.damage())
                        talkHppc.npc = math.max(0, talkHppc.npc - talkHppc.damage())
                    end
                end
                delaySay(string.format("Current status:\nYour health: {%d}/100\nNpc health: {%d}/100", talkHppc.player, talkHppc.npc), 1000, nid, cid)
                if talkHppc.player <= 0 then
                    delaySay("You have been defeated, it was a good fight.", 1500, nid, cid)
                    npc:say("I have won the trivial battle hahahaha.", TALKTYPE_MONSTER_SAY)
                    npcHandler:releaseFocus(cid)
                elseif talkHppc.npc <= 0 then
                    delaySay("You're the winner, it was a good fight.", 1500, nid, cid)
                    player:say("I have won the trivial battle hahahaha.", TALKTYPE_MONSTER_SAY)
                    sendRewards(player)
                    playerPos:sendMagicEffect(CONST_ME_FIREWORK_YELLOW)
                    npcHandler:releaseFocus(cid)
                else
                    delaySay("Ready for the next round?", 1500, nid, cid)
                    talkState[cid] = 2
                end
            else
                selfSay(string.format("Please select one of the available options, for example: {%d}", math.random(1, #talkQuest.options)), cid)
            end
        end
    elseif talkState[cid] == 2 then
        if msgcontains(msg, "yes") then
            selfSay(({"Mmmmm...", "Ok...", "I Think..."})[math.random(1, 3)], cid)
            sendNewQuest(cid, nid)
            npcPos:sendMagicEffect(CONST_ME_CRAPS)
            talkState[cid] = 1
        elseif msgcontains(msg, "no") then
            selfSay("Come back when you have the courage to face me.", cid)
            npcHandler:releaseFocus(cid)
        end
    end

    return true
end

function creatureReleaseFocusCallback(cid)
    talkState[cid] = nil
    talkPlayer = 0
    talkHppc.player = 100
    talkHppc.npc = 100
    return true
end

function creatureGreetCallback(cid)
    local player = Player(talkPlayer)
    if not player then
        player = Player(cid)
        selfSay(string.format("Hello {%s}, would you like to answer some questions and earn rewards?", player:getName()), cid)
        talkPlayer = cid
        npcHandler:addFocus(cid)
    elseif player ~= Player(cid) then
        selfSay(string.format("Estoy ocupado jugando con {%s}, por favor espera tu turno.", player:getName()), cid)
        talkPlayer = 0
    end
    return false
end

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:setCallback(CALLBACK_GREET, creatureGreetCallback)
npcHandler:setCallback(CALLBACK_ONRELEASEFOCUS, creatureReleaseFocusCallback)
npcHandler:addModule(FocusModule:new())

GIF 04-02-2021 12-29-09 a. m..gif
If you win then you get a reward. 🤑
If you lose nothing happens, the npc will simply make fun of you for being a fool. 🤣

Note: it is worth mentioning that there are not many questions, this job is for you, enrich the npc with too many questions to make it very realistic and fun
I know it is not perfect, but I hope it will help you or an example for something you want to do
 
Hi @Sopago
It's probably not exactly what you wanted, I don't know if I understood you correctly, but here is the script as I could understand it

data/scripts/yourscriptname.lua
Lua:
local summonSpellConfig = {
    ["Rat"] = {
        area = createCombatArea(AREA_CIRCLE2X2),
        formula = {
            level = 3,
            magLvl = 2,
            minDmg = 1.2,
            maxDmg = 1.5,
            speed = 1.5
        },
        effect = CONST_ME_FIREAREA,
        combat = COMBAT_FIREDAMAGE
    },
    ["Rotworm"] = {
        area = createCombatArea(AREA_CIRCLE2X2),
        formula = {
            level = 4,
            magLvl = 4,
            minDmg = 1.2,
            maxDmg = 1.5,
            speed = 1.5
        },
        effect = CONST_ME_FIREAREA,
        combat = COMBAT_FIREDAMAGE
    }
}

local cExplosionSummonDie = CreatureEvent("ExplosionSummonDie")
function cExplosionSummonDie.onDeath(creature, corpse, killer, mostDamageKiller, unjustified, mostDamageUnjustified)
    local prop = summonSpellConfig[creature:getName()]
    if prop then
        local master = creature:getMaster()
        if master then
            local min = ((master:getLevel() * prop.formula.level) + (master:getMagicLevel() * prop.formula.magLvl)) * prop.formula.minDmg
            local max = ((master:getLevel() * prop.formula.level) + (master:getMagicLevel() * prop.formula.magLvl)) * prop.formula.maxDmg
            doAreaCombatHealth(master:getId(), prop.combat, creature:getPosition(), prop.area, -min, -max, prop.effect, ORIGIN_SPELL)
        end
    end
    return true
end
cExplosionSummonDie:register()

local cExplosionSummonThink = CreatureEvent("ExplosionSummonThink")
function cExplosionSummonThink.onThink(creature, interval, item, position, lastPosition, fromPosition, toPosition)
    local prop = summonSpellConfig[creature:getName()]
    if prop then
        local master = creature:getMaster()
        if master then
            local target = master:getTarget()
            local masterPos = master:getPosition()
            local creaturePos = creature:getPosition()
            if target and target:getPosition():getDistance(creaturePos) <= 1 then
                local min = ((master:getLevel() * prop.formula.level) + (master:getMagicLevel() * prop.formula.magLvl)) * prop.formula.minDmg
                local max = ((master:getLevel() * prop.formula.level) + (master:getMagicLevel() * prop.formula.magLvl)) * prop.formula.maxDmg
                doAreaCombatHealth(master:getId(), prop.combat, creature:getPosition(), prop.area, -min, -max, prop.effect, ORIGIN_SPELL)
                creature:remove()
            elseif creaturePos:getDistance(masterPos) > 7 or creaturePos.z ~= masterPos.z then
                creaturePos:sendMagicEffect(CONST_ME_POFF)
                creature:teleportTo(masterPos)
                masterPos:sendMagicEffect(CONST_ME_TELEPORT)
            end
        end
    end
    return true
end
cExplosionSummonThink:register()

local spell = Spell(SPELL_INSTANT)

function spell.onCastSpell(creature, variant)
    local summons = creature:getSummons()
    if #summons >= 2 then
        creature:sendCancelMessage("You can only have 2 summons maximum.")
        return false
    end
    local monsterName = variant:getString()
    local prop = summonSpellConfig[monsterName]
    if prop then
        local monster = Game.createMonster(monsterName, creature:getPosition())
        if monster then
            monster:registerEvent("ExplosionSummonDie")
            monster:registerEvent("ExplosionSummonThink")
            monster:changeSpeed(creature:getBaseSpeed() * prop.formula.speed)
            local maxHp = creature:getMaxHealth()
            monster:setMaxHealth(maxHp)
            monster:addHealth(maxHp)
            creature:addSummon(monster)
            return true
        end
        creature:sendCancelMessage(RETURNVALUE_NOTENOUGHROOM)
        return false
    end
    creature:sendCancelMessage("Summon name does not exist.")
    return false
end

spell:name("Summon Bomb Spell")
spell:words("make bomb")
spell:hasParams(true)
spell:group("attack")
spell:vocation("sorcerer", "master sorecerer")
spell:id(1)
spell:cooldown(1000)
spell:level(200)
spell:range(6)
spell:manaPercent(13)
spell:isPremium(true)
spell:register()
In this example I used a Rat and a Rotworm as explosive summons, but you must have your own custom monsters which will use this script.
You can try executing the spell make bomb" Rat or make bomb" Rotworm, in the configuration each one of them has different properties, such as the formula of the damage and the affected area and or effects.

View attachment 54508View attachment 54509
I have checked the script and i think it works as intended , thank you very much!
 
Because the information you provided was very limited, I had to search the internet a bit, and use a bit of my imagination, this is the result:

data/npc/Trivial.xml
XML:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Trivial" script="trivial.lua" walkinterval="2000" speed="0" floorchange="0">
    <health now="100" max="100" />
    <look type="472" head="114" body="95" legs="76" feet="19" addons="3"/>
</npc>

data/npc/scripts/trivial.lua
Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

function onCreatureAppear(cid)              npcHandler:onCreatureAppear(cid)            end
function onCreatureDisappear(cid)           npcHandler:onCreatureDisappear(cid)         end
function onCreatureSay(cid, type, msg)      npcHandler:onCreatureSay(cid, type, msg)    end
function onThink()                          npcHandler:onThink()                        end

local function irandom_prefix(from, to, prefix)
    return string.format("%d %s", math.random(from, to), prefix)
end

local talkHppc = {
    player = 100,
    npc = 100,
    damage = function() return math.random(10, 20) end
}
local rewards = {
    exp = 1000000,
    items = {
        {2160, 100},
        {2160, 100}
    }
}

local questions = {
    {
        type = "select",
        name = "How far is the earth from the moon?",
        options = {
            irandom_prefix(1, 100, "km"),
            irandom_prefix(5000, 9999, "km"),
            irandom_prefix(1, 999, "km"),
            "384400 km"
        },
        answer = 4
    },
    {
        type = "select",
        name = "Who is the president of the united states?",
        options = {
            "Kamala Harris",
            "Donald Trump",
            "Joe Biden",
            "Barack Obama"
        },
        answer = 3
    },
    {
        type = "select",
        name = "Which is the vocation that has more magic damage?",
        options = {
            "Knight",
            "Sorcerer",
            "Paladin",
            "No Vocation"
        },
        answer = 2
    },
    {
        type = "math",
        name = "What is the result of %d %s %d?",
        options = 4
    }
}

local function shuffle(tbl)
  for i = #tbl, 2, -1 do
    local j = math.random(i)
    tbl[i], tbl[j] = tbl[j], tbl[i]
  end
end

local function delaySay(msg, interval, npcid, cid)
    addEvent(function(msg, npcid, cid)
        local npc = Npc(npcid)
        if npc then
            npc:say(msg, TALKTYPE_PRIVATE_NP, false, cid)
        end
    end, interval, msg, npcid, cid)
end

local talkPlayer = 0
local talkQuest = nil
local talkState = {}
local afterQuests = nil

local function getRandomQuest()
    local quest
    if not afterQuests then
        afterQuests = math.random(1, #questions)
        quest = questions[afterQuests]
    else
        local nrandom = math.random(1, #questions)
        quest = questions[nrandom]
        while afterQuests == nrandom do
            quest = questions[nrandom]
        end
        afterQuests = nrandom
    end
    if quest then
        if quest.type == "select" then
            local options = {}
            for i = 1, #quest.options do
                local option = quest.options[i]
                if type(option) == "function" then
                    options[#options +1] = option()
                elseif type(option) == "string" then
                    options[#options +1] = option
                end
            end
            shuffle(options)
            local answer = 1
            for i = 1, #options do
                if options[i] == quest.options[quest.answer] then
                    answer = i
                    break
                end
            end
            return {
                name = quest.name,
                options = options,
                answer = answer
            }
        elseif quest.type == "math" then
            local operator = ({'+','-','/','*'})[math.random(1, 4)]
            local n1, n2 = math.random(1, 100), math.random(1, 100)
            local o_result = loadstring(string.format("return %d%s%d", n1, operator, n2))()
            local name = string.format(quest.name, n1, operator, n2)
            local options = {o_result}
            for i = 1, quest.options -1 do
                options[#options +1] = math.random(1, 999)
            end
            shuffle(options)
            local answer = 1
            for i = 1, #options do
                if options[i] == o_result then
                    answer = i
                    break
                end
            end
            return {
                name = name,
                options = options,
                answer = answer
            }
        end
    end
end

local function sendNewQuest(cid, nid)
    talkQuest = getRandomQuest()
    local text = string.format("%s\nOptions: ", talkQuest.name)
    for i = 1, #talkQuest.options do
        text = string.format("%s[ {%d} ]: %s%s", text, i, talkQuest.options[i], (i ~= #talkQuest.options and " | " or ""))
    end
    delaySay(text, 1000, nid, cid)
end

local function sendRewards(player)
    local bag = Game.createItem(2002, 1)
    if bag then
        local description = "You rewards: "
        for _, reward in pairs(rewards.items) do
            bag:addItem(reward[1], reward[2], INDEX_WHEREEVER, FLAG_NOLIMIT)
            description = string.format("%s%d %s%s", description, reward[2], ItemType(reward[1]):getName(), (_ == #rewards.items and '.' or ', '))
        end
        local inbox = player:getInbox()
        if inbox then
            inbox:addItemEx(bag, INDEX_WHEREEVER, FLAG_NOLIMIT)
            player:sendTextMessage(MESSAGE_INFO_DESCR, description..'\nCheck your depot inbox.')
        end
    end
    if rewards.exp then
        player:addExperience(rewards.exp, true)
    end
end

function creatureSayCallback(cid, typ, msg)
    if not npcHandler:isFocused(cid) then
        return false
    end

    local nid = getNpcCid()
    local npc = Npc(nid)
    local npcPos = npc:getPosition()

    local player = Player(cid)
    local playerPos = player:getPosition()

    if not talkState[cid] then
        if msgcontains(msg, "yes") then
            selfSay("Here are some questions which you have to answer, I'll play too ;D", cid)
            sendNewQuest(cid, nid)
            npcPos:sendMagicEffect(CONST_ME_CRAPS)
            talkState[cid] = 1
        elseif msgcontains(msg, "no") then
            selfSay("Come back when you have the courage to face me.", cid)
            npcHandler:releaseFocus(cid)
        end
    elseif talkState[cid] == 1 then
        if talkQuest then
            local select_n = tonumber(msg)
            if select_n and select_n > 0 and select_n <= #talkQuest.options then
                local npc_correct = math.random(1, #talkQuest.options) == talkQuest.answer
                if select_n == talkQuest.answer then
                    if npc_correct then
                        selfSay("Your answer is correct, mine is also correct, so neither will take damage.", cid)
                        npcPos:sendMagicEffect(CONST_ME_POFF)
                        playerPos:sendMagicEffect(CONST_ME_POFF)
                    else
                        selfSay("Your answer is correct, mine is not, so I will take damage.", cid)
                        playerPos:sendMagicEffect(CONST_ME_POFF)
                        playerPos:sendDistanceEffect(npcPos, CONST_ANI_DEATH)
                        npcPos:sendMagicEffect(CONST_ME_MORTAREA)
                        talkHppc.npc = math.max(0, talkHppc.npc - talkHppc.damage())
                    end
                else
                    if npc_correct then
                        selfSay("Your answer is wrong, mine is correct, you will receive damage.", cid)
                        npcPos:sendMagicEffect(CONST_ME_POFF)
                        npcPos:sendDistanceEffect(playerPos, CONST_ANI_DEATH)
                        playerPos:sendMagicEffect(CONST_ME_MORTAREA)
                        talkHppc.player = math.max(0, talkHppc.player - talkHppc.damage())
                    else
                        selfSay("Your answer is wrong, I was wrong too, we both received damage.", cid)
                        playerPos:sendDistanceEffect(npcPos, CONST_ANI_DEATH)
                        npcPos:sendMagicEffect(CONST_ME_MORTAREA)
                        npcPos:sendDistanceEffect(playerPos, CONST_ANI_DEATH)
                        playerPos:sendMagicEffect(CONST_ME_MORTAREA)
                        talkHppc.player = math.max(0, talkHppc.player - talkHppc.damage())
                        talkHppc.npc = math.max(0, talkHppc.npc - talkHppc.damage())
                    end
                end
                delaySay(string.format("Current status:\nYour health: {%d}/100\nNpc health: {%d}/100", talkHppc.player, talkHppc.npc), 1000, nid, cid)
                if talkHppc.player <= 0 then
                    delaySay("You have been defeated, it was a good fight.", 1500, nid, cid)
                    npc:say("I have won the trivial battle hahahaha.", TALKTYPE_MONSTER_SAY)
                    npcHandler:releaseFocus(cid)
                elseif talkHppc.npc <= 0 then
                    delaySay("You're the winner, it was a good fight.", 1500, nid, cid)
                    player:say("I have won the trivial battle hahahaha.", TALKTYPE_MONSTER_SAY)
                    sendRewards(player)
                    playerPos:sendMagicEffect(CONST_ME_FIREWORK_YELLOW)
                    npcHandler:releaseFocus(cid)
                else
                    delaySay("Ready for the next round?", 1500, nid, cid)
                    talkState[cid] = 2
                end
            else
                selfSay(string.format("Please select one of the available options, for example: {%d}", math.random(1, #talkQuest.options)), cid)
            end
        end
    elseif talkState[cid] == 2 then
        if msgcontains(msg, "yes") then
            selfSay(({"Mmmmm...", "Ok...", "I Think..."})[math.random(1, 3)], cid)
            sendNewQuest(cid, nid)
            npcPos:sendMagicEffect(CONST_ME_CRAPS)
            talkState[cid] = 1
        elseif msgcontains(msg, "no") then
            selfSay("Come back when you have the courage to face me.", cid)
            npcHandler:releaseFocus(cid)
        end
    end

    return true
end

function creatureReleaseFocusCallback(cid)
    talkState[cid] = nil
    talkPlayer = 0
    talkHppc.player = 100
    talkHppc.npc = 100
    return true
end

function creatureGreetCallback(cid)
    local player = Player(talkPlayer)
    if not player then
        player = Player(cid)
        selfSay(string.format("Hello {%s}, would you like to answer some questions and earn rewards?", player:getName()), cid)
        talkPlayer = cid
        npcHandler:addFocus(cid)
    elseif player ~= Player(cid) then
        selfSay(string.format("Estoy ocupado jugando con {%s}, por favor espera tu turno.", player:getName()), cid)
        talkPlayer = 0
    end
    return false
end

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:setCallback(CALLBACK_GREET, creatureGreetCallback)
npcHandler:setCallback(CALLBACK_ONRELEASEFOCUS, creatureReleaseFocusCallback)
npcHandler:addModule(FocusModule:new())

View attachment 54517
If you win then you get a reward. 🤑
If you lose nothing happens, the npc will simply make fun of you for being a fool. 🤣

Note: it is worth mentioning that there are not many questions, this job is for you, enrich the npc with too many questions to make it very realistic and fun
I know it is not perfect, but I hope it will help you or an example for something you want to do
Great work Sarah. Very clean code, cheers mate :)
 
Hello if you have time, and do you want to create something like this...

[Automatic MultiPromotion System with bonuses]

on level 1 we start as a druid on level 20 automatically transforms us into an elder druid then at 50 into Royal Druid
20 lvl bonus +150hp and +500mp and new outfit druid (with 2 addons)
50 lvl bonus +25speed and 500mp and new outfit summoner (with 2 addons)

Hi @Avandia

data/scripts/yourscriptname.lua
Lua:
local storage = 777666 -- make sure the storage is unique and is not being used on another system
local advanceConfig = {
    {
        level = 20,
        nextVocation = "Elder Druid",
        extraHp = 150,
        extraMp = 500,
        outfit = {148, 144, 3} -- Druid for male and female with 2 addons
    },
    {
        level = 50,
        nextVocation = "Royal Druid",
        extraMp = 500,
        extraSpeed = 25,
        outfit = {141, 133, 3} -- Summoner for male and female with 2 addons
    }
}

local cAdvanceEvent = CreatureEvent("AdvanceRewardByLvl")
function cAdvanceEvent.onAdvance(player, skill, oldLevel, newLevel)
    if skill == SKILL_LEVEL then
        local load_level = player:getStorageValue(storage)
        for i, info in pairs(advanceConfig) do
            if newLevel >= info.level and load_level < info.level then
                player:setStorageValue(storage, info.level)
                local description = ""
                if info.nextVocation then
                    local newVocation = Vocation(info.nextVocation)
                    if newVocation then
                        player:setVocation(newVocation)
                        description = string.format("You have been promoted to %s.", info.nextVocation)
                    end
                end
                if info.extraHp then
                    local maxHp = player:getMaxHealth()
                    player:setMaxHealth(maxHp + info.extraHp)
                    description = string.format("%s\nYour max health has increased by %d points.", description, info.extraHp)
                end
                if info.extraMp then
                    local maxMp = player:getMaxMana()
                    player:setMaxMana(maxMp + info.extraMp)
                    description = string.format("%s\nYour max mana has increased by %d points.", description, info.extraMp)
                end
                if info.extraSpeed then
                    local baseSpeed = player:getBaseSpeed()
                    player:changeSpeed(baseSpeed + info.extraSpeed)
                    description = string.format("%s\nYour speed has increased by %d.", description, info.extraSpeed)
                end
                if info.outfit then
                    if not player:hasOutfit(info.outfit[1], info.outfit[3]) or not player:hasOutfit(info.outfit[2], info.outfit[3]) then
                        player:addOutfitAddon(info.outfit[1], info.outfit[3])
                        player:addOutfitAddon(info.outfit[2], info.outfit[3])
                        description = string.format("%s\nYou now have got %s outfit.", description, Outfit(info.outfit[1]).name)
                    end
                end
                player:sendTextMessage(MESSAGE_INFO_DESCR, description)
            end
        end
    end
    return true
end
cAdvanceEvent:register()

local cLoginEvent = CreatureEvent("AdvanceRewardLogin")
function cLoginEvent.onLogin(player)
    player:registerEvent("AdvanceRewardByLvl")
    local load_level = player:getStorageValue(storage)
    for i, info in pairs(advanceConfig) do
        if load_level >= info.level then
            if info.extraSpeed then
                local baseSpeed = player:getBaseSpeed()
                player:changeSpeed(baseSpeed + info.extraSpeed)
            end
        end
    end
    return true
end
cLoginEvent:register()

GIF 04-02-2021 11-43-47 a. m..gif
 
Last edited:
Hi @Avandia

data/scripts/yourscriptname.lua
Lua:
local storage = 777666 -- make sure the storage is unique and is not being used on another system
local advanceConfig = {
    {
        level = 20,
        nextVocation = "Elder Druid",
        extraHp = 150,
        extraMp = 500,
        outfit = {148, 144, 3} -- Druid for male and female with 2 addons
    },
    {
        level = 50,
        nextVocation = "Royal Druid",
        extraMp = 500,
        extraSpeed = 25,
        outfit = {141, 133, 3} -- Summoner for male and female with 2 addons
    }
}

local cAdvanceEvent = CreatureEvent("AdvanceRewardByLvl")
function cAdvanceEvent.onAdvance(player, skill, oldLevel, newLevel)
    if skill == SKILL_LEVEL then
        local load_level = player:getStorageValue(storage)
        for i, info in pairs(advanceConfig) do
            if newLevel >= info.level and load_level < info.level then
                player:setStorageValue(storage, info.level)
                local description = ""
                if info.nextVocation then
                    local newVocation = Vocation(info.nextVocation)
                    if newVocation then
                        player:setVocation(newVocation)
                        description = string.format("You have been promoted to %s.", info.nextVocation)
                    end
                end
                if info.extraHp then
                    local maxHp = player:getMaxHealth()
                    player:setMaxHealth(maxHp + info.extraHp)
                    description = string.format("%s\nYour max health has increased by %d points.", description, info.extraHp)
                end
                if info.extraMp then
                    local maxMp = player:getMaxMana()
                    player:setMaxMana(maxMp + info.extraMp)
                    description = string.format("%s\nYour max mana has increased by %d points.", description, info.extraMp)
                end
                if info.extraSpeed then
                    local baseSpeed = player:getBaseSpeed()
                    player:changeSpeed(baseSpeed + info.extraSpeed)
                    description = string.format("%s\nYour speed has increased by %d.", description, info.extraSpeed)
                end
                if info.outfit then
                    if not player:hasOutfit(info.outfit[1], info.outfit[3]) or not player:hasOutfit(info.outfit[2], info.outfit[3]) then
                        player:addOutfitAddon(info.outfit[1], info.outfit[3])
                        player:addOutfitAddon(info.outfit[2], info.outfit[3])
                        description = string.format("%s\nYou now have got %s outfit.", description, Outfit(info.outfit[1]).name)
                    end
                end
                player:sendTextMessage(MESSAGE_INFO_DESCR, description)
            end
        end
    end
    return true
end
cAdvanceEvent:register()

local cLoginEvent = CreatureEvent("AdvanceRewardLogin")
function cLoginEvent.onLogin(player)
    player:registerEvent("AdvanceRewardByLvl")
    return true
end
cLoginEvent:register()

View attachment 54535
Speed isn't saved, once player logs out/dies, speed is lost.
 
Speed isn't saved, once player logs out/dies, speed is lost.
Thanks for your review, the problem is solved!
Post automatically merged:

Hello Sarah.
I need EXP online players bonus
5 - 19EXP +5%
20 - 49EXP +10%
50 - 99EXP +15%
100 - 249EXP +20%
250 - 399EXP +25%
400+EXP +30%
tfs 1.3
Hi @robert100

OPTION 1 (eventcallbacks):
open the file: data/scripts/eventcallbacks/player/default_onGainExperience.lua

look for this code: local ev = EventCallback
now above this code you are going to paste the following:
Lua:
local expOnlineBonus = {
    [{5, 19}] = 5,
    [{20, 49}] = 10,
    [{50, 99}] = 15,
    [{100, 249}] = 20,
    [{250, 399}] = 25,
    [{400}] = 30
}
table.sort(expOnlineBonus, function(a, b) return a > b end)

look for this code: return exp is most likely at the end of this file.
now above this code you are going to paste the following:
Lua:
    local players = #Game.getPlayers()
    for range, bonus in pairs(expOnlineBonus) do
        if players >= range[1] and (players <= (range[2] or math.huge)) then
            exp = exp * (1 + (bonus / 100))
            break
        end
    end

OPTION 2 (classic events):
open the file: data/events/scripts/player.lua
look for this code: function Player:onGainExperience(source, exp, rawExp) is most likely at the end of this file.
now above this code you are going to paste the following:
Lua:
local expOnlineBonus = {
    [{5, 19}] = 5,
    [{20, 49}] = 10,
    [{50, 99}] = 15,
    [{100, 249}] = 20,
    [{250, 399}] = 25,
    [{400}] = 30
}
table.sort(expOnlineBonus, function(a, b) return a > b end)
look for this code: return exp is most likely at the end of this file.
1612455844043.png
now above this code you are going to paste the following:
Lua:
    local players = #Game.getPlayers()
    for range, bonus in pairs(expOnlineBonus) do
        if players >= range[1] and (players <= (range[2] or math.huge)) then
            exp = exp * (1 + (bonus / 100))
            break
        end
    end

GIF 04-02-2021 12-25-25 p. m..gif
Post automatically merged:

Hello Sarah, good scripts you doing here ^^.
Can you make one for outfit and mounts bonuses? Each full outfit/mount obtained you gain some bonuses like +hp, +mana, +skills, they being in intervals: First mount/outfit: +1%hp, Second mount/outfit: +1%mp, third mount/outfit: +1skills (sword,axe,club,ml), Fourth mount/outfit: +1%hp and so on
Hi @jacqen

data/scripts/yourscriptname.lua
Lua:
local outfitBonus = {
    [137] = { -- Hunter
        addons = 3, -- Require Addon
        [370] = {
            hp = 1,
            mp = 1,
            skill = {CONDITION_PARAM_SKILL_AXE, 1}
        },
        [368] = {
            hp = 2,
            mp = 2,
            skill = {CONDITION_PARAM_SKILL_AXE, 2}
        }
    },
    [138] = { -- Mage
        addons = 3, -- Require Addon
        [368] = {
            hp = 1, -- in %
            mp = 1, -- in %
            skill = {CONDITION_PARAM_SKILL_SWORD, 1}
        }
    }
}

local ev = EventCallback
function ev.onChangeOutfit(creature, outfit)
    local currentOutfit = creature:getOutfit()
    local bonus = outfitBonus[currentOutfit.lookType]
    if bonus and currentOutfit.lookAddons >= bonus.addons then
        local mount = bonus[currentOutfit.lookMount]
        if mount then
            creature:removeCondition(CONDITION_ATTRIBUTES, CONDITIONID_COMBAT, 500 + currentOutfit.lookMount, true)
            creature:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
        end
    end
    local bonus = outfitBonus[outfit.lookType]
    if bonus and outfit.lookAddons >= bonus.addons then
        local mount = bonus[outfit.lookMount]
        if mount then
            local condition = Condition(CONDITION_ATTRIBUTES)
            condition:setParameter(CONDITION_PARAM_TICKS, -1)
            condition:setParameter(CONDITION_PARAM_SUBID, 500 + outfit.lookMount)
            if mount.hp then
                condition:setParameter(CONDITION_PARAM_STAT_MAXHITPOINTSPERCENT, 100 + mount.hp)
            end
            if mount.mp then
                condition:setParameter(CONDITION_PARAM_STAT_MAXMANAPOINTSPERCENT, 100 + mount.mp)
            end
            if mount.skill then
                condition:setParameter(mount.skill[1], mount.skill[2])
            end
            creature:addCondition(condition)
            creature:getPosition():sendMagicEffect(CONST_ME_MAGIC_GREEN)
        end
    end
    return true
end

Next I will show you a visual example of how it looks when you get the bonus and when you lose it due to lack of requirements
GIF 04-02-2021 01-10-49 p. m..gif

In the configuration table you can configure bonuses for each outfit, and each outfit can have its combination with a different mount, in such a way that each mount in conjunction with your outfit can give you different bonuses
 
Last edited:
Status
Not open for further replies.
Back
Top