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

Items: World Exp Scroll / World Loot Scroll

Ciosny

Member
Joined
Aug 16, 2024
Messages
96
Reaction score
12
Hi !

I saw a few posts about it, but either TFS was different or it was based on clicking on an object on the map.

I want to create 2 scrolls:

1. World Exp Scroll (I created the item myself) with the function of giving +25% exp for 30 minutes.

The rule is simple, someone buys World Exp Scroll from the Item store, uses it and everyone on OTS has a +25% EXP bonus for 30 minutes.

Additionally:
  • Nobody can use the scroll wheel again when one is activated (information about blocking use)
  • Scroll disappears after use
  • After the scroll time ends, exp returns from 125% to 100%.

The second scroll is the loot scroll, which for 30 minutes gives +100% chance of loot but does not give 2x more loot (i.e. if a mob normally drops e.g. 100 gp, it will not suddenly start dropping 200, but if the chance of some item is 10% then when this scroll works, there will be a 20% chance of falling out)

Both scrolls are separate items

Probably simple for someone who knows, but I tried to change the object from the forum to scrolls for sale and it didn't work 😅

I have:
TFS 1.4.2
OTC800
Tibia 10.98
 
Good luck.
Let us know how it goes.
If I don't have this file default_onGainExpirience.lua (I don't have an events folder either, but it's probably the eventcallbacks folder in my case), should I create a new lua file called default_onGainExpirience.lua and paste these options there?

default_onDropLoot.lua i have in eventcallbacks > monster
 

Attachments

If I don't have this file default_onGainExpirience.lua (I don't have an events folder either, but it's probably the eventcallbacks folder in my case), should I create a new lua file called default_onGainExpirience.lua and paste these options there?


Events folder is in data folder
You don't need to create a default onGainExperience.lua :D
 
Events folder is in data folder
You don't need to create a default onGainExperience.lua :D
Yes, I have events in forgottenserver-1.4.2\data\events but both there and \scripts I do not have this default_onGainExpirience.lua 😅

If this is a stupid question, forgive me, because it may be easy for someone to do, and this is my first time doing this script😅
 

Attachments

If I don't have this file default_onGainExpirience.lua (I don't have an events folder either, but it's probably the eventcallbacks folder in my case), should I create a new lua file called default_onGainExpirience.lua and paste these options there?

default_onDropLoot.lua i have in eventcallbacks > monster
Ah, I had thought 1.4.2 already had those files in place.
As stated above by another user, you can find the events in data/events/scripts.

Yes, I have events in forgottenserver-1.4.2\data\events but both there and \scripts I do not have this default_onGainExpirience.lua 😅

If this is a stupid question, forgive me, because it may be easy for someone to do, and this is my first time doing this script😅

Player will contain the onGainExperience function.
Monster will contain the onDropLoot function.

You can freely modify the functions in here to add your intended functionality.
 
Take a look here, just to get some ideas on how the bonus XP and loot scripts work. It can help you reflect and modify them in your own way, depending on what you want for scripts like World Exp Scroll / World Loot Scroll, etc.

 
I will definitely check it as soon as I solve the problem with the market (it stopped working for me). I'll do one thing and move on to another. I will definitely answer this topic! :)

Thank you for your help
 
I tried to make 2 separate items ones as follows:

1 - only world exp scroll +25% exp for 30 min
2 - only world loot scroll +25% chance drop for 30 min

*Everyone on the server gets a bonus when someone fires and the information appears on the screen "Player xxx has scored +25% EXP for 30 minutes!"
*Only one exp and drop bonus can be activated at the same time. Only when the bonus ends can you activate another one
*At the bottom left (above the chat) there is an icon, e.g. "EXP" or "DROP", and when you point at it it shows how much time is left.

I already had the boost figured out, but then I messed something up and it completely crashed. :(

I threw it in the trash. Does anyone have an idea how to do this? :)
 
I threw it in the trash.
Throwing it in the trash was incorrect, imo.
As of now, your original question was answered.. so there's nothing further to help you with.

If you need further support, you should post your code, so people can see and help with your latest issue.
 
Throwing it in the trash was incorrect, imo.
As of now, your original question was answered.. so there's nothing further to help you with.

If you need further support, you should post your code, so people can see and help with your latest issue.

The scripts I had for TFS 1.4.2 (themselves assigned to items for now):

World Exp +25% for 30 min:

local config = {
itemId = 26385,
boostTime = 30 * 60, -- duration in seconds (30 minutes)
boostStorage = 480665, -- unique key to store boost activity status
boostExpPercent = 25, -- % experience bonus
textBoostHasEnded = "The World Bonus exp has ended.",
textAlreadyActive = "You cannot do this now because the experience bonus is already active.",
effectOn = CONST_ME_MAGIC_BLUE, -- effect upon activation
effectOff = CONST_ME_POFF -- effect on failed attempt
}

local function endBoost()
if Game.getStorageValue(config.boostStorage) == 1 then
Game.setExperienceStage(1) -- Restore normal experience after the boost ends
Game.setStorageValue(config.boostStorage, -1) -- Reset the storage value
Game.broadcastMessage(config.textBoostHasEnded, MESSAGE_STATUS_WARNING)
end
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
-- Check if the boost is already active
if Game.getStorageValue(config.boostStorage) == 1 then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, config.textAlreadyActive)
player:getPosition():sendMagicEffect(config.effectOff)
return true
end

-- Set the boost end time and activate the boost
Game.setStorageValue(config.boostStorage, 1)
Game.setExperienceStage(config.boostExpPercent / 100 + 1)

-- Broadcast message about the boost activation
local message = string.format("Player %s has activated the World Bonus exp +25%% for 30 minutes", player:getName())
Game.broadcastMessage(message, MESSAGE_STATUS_WARNING)

-- Send visual effect
player:getPosition():sendMagicEffect(config.effectOn)

-- Remove the item after use
item:remove(1)

-- Schedule the boost to end after the specified duration
addEvent(endBoost, config.boostTime * 1000)

return true
end

World loot +25% for 30 min:
(25% I mean that if an item has a drop chance of 10%, with the 25% bonus it has 12.5% (10% of the total + 25% of these 10%)



local config = {
itemId = 26386,
boostTime = 30 * 60, -- duration in seconds (30 minutes)
boostStorage = 480666, -- unique key to store boost activity status
boostLootPercent = 25, -- % loot bonus
textBoostHasEnded = "The World Loot bonus has ended.",
textAlreadyActive = "You cannot do this now because the loot bonus is already active.",
effectOn = CONST_ME_MAGIC_GREEN, -- effect upon activation
effectOff = CONST_ME_POFF -- effect on failed attempt
}

local function endBoost()
if Game.getStorageValue(config.boostStorage) == 1 then
Game.setLootRate(1) -- Restore normal loot rate after the boost ends
Game.setStorageValue(config.boostStorage, -1) -- Reset the storage value
Game.broadcastMessage(config.textBoostHasEnded, MESSAGE_STATUS_WARNING)
end
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
-- Check if the boost is already active
if Game.getStorageValue(config.boostStorage) == 1 then
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, config.textAlreadyActive)
player:getPosition():sendMagicEffect(config.effectOff)
return true
end

-- Set the boost end time and activate the loot boost
Game.setStorageValue(config.boostStorage, 1)
Game.setLootRate(1 + config.boostLootPercent / 100)

-- Broadcast message about the boost activation
local message = string.format("Player %s has activated the World Loot bonus +25%% for 30 minutes", player:getName())
Game.broadcastMessage(message, MESSAGE_STATUS_WARNING)

-- Send visual effect
player:getPosition():sendMagicEffect(config.effectOn)

-- Remove the item after use
item:remove(1)

-- Schedule the boost to end after the specified duration
addEvent(endBoost, config.boostTime * 1000)

return true
end
 
You're not parsing any information to your addEvent function endBoost and then you ask for your addEvent to use information it does not know.

Also when your computer processes a script, it starts at the top and go down,
in this case you run an addEvent of a function which it hasn't read yet.

Either your find this information helpfull or your need someone who knows how to script to do it for you.
 
Incomplete answer.. because I don't have your server files.. which appear to be different then a standard 1.4.2, for whatever reason.

Below is the script for the items, to give the global boost..
Ideally, you'd rename it and turn it into a global table and have it load from data/lib/core

Then you can loop through the table when checking the storages in expGain and dropLoot functions.
LUA:
-- example of what you'd throw into the experience function
for k, v in pairs(config) do
    if v.boostExpPercent > 0 then
        if Game.getStorageValue(v.boostStorage) >= os.time() then
            local percentIncrease = 1 + (v.boostExpPercent / 100)
            exp = exp * percentIncrease
        end
    end
end

-- example of dropLoot, but you'd need to loop through like above.. to calculate the entire loot multiplier
LUA:
local boostedLootMultiplier = player and player:getStorageValue(GLOBAL_BonusLootorExperience.loot) > os.time() and 1 + (GLOBAL_BonusLootorExperience.lootBoost / 100) or 1
.
.
if monsterLoot[i].chance then
    monsterLoot[i].chance = math.min(monsterLoot[i].chance * boostedLootMultiplier, MAX_LOOTCHANCE)
end

-- the script for items
LUA:
local config = {
--  [itemid]
    [26386] = {
        boostTime = 30 * 60, -- duration in seconds (30 minutes)
        boostStorage = 480666, -- unique key to store boost activity status
        boostExpPercent = 0, -- % experience bonus
        boostLootPercent = 25, -- % loot bonus
        effectOn = CONST_ME_MAGIC_GREEN, -- effect upon activation
        effectOff = CONST_ME_POFF -- effect on failed attempt
    },
    [26385] = {
        boostTime = 30 * 60,   -- all 3 of the items in config can be active same time
        boostStorage = 480665,
        boostExpPercent = 25,
        boostLootPercent = 0,
        effectOn = CONST_ME_MAGIC_BLUE,
        effectOff = CONST_ME_POFF
    },
    [11111] = {
        boostTime = 30 * 60,
        boostStorage = 11111, -- magical third item that
        boostExpPercent = 25, -- can have both loot & exp bonus
        boostLootPercent = 25,
        effectOn = CONST_ME_MAGIC_BLUE,
        effectOff = CONST_ME_POFF
    }
}

local function notifyBoostEnd(message)
    Game.broadcastMessage("The " .. message .. " has ended.", MESSAGE_STATUS_WARNING)
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local index = config[item:getId()]
    if not index then
        print("Something wrong in actions.xml or table. ItemId " .. item:getId() .. " not found in table.")
        return true
    end
    
    local message = ""
    if index.boostExpPercent > 0 then
        message = message .. "Exp"
    end
    if index.boostLootPercent > 0 then
        if message ~= "" then
            message = message .. " & "
        end
        message = message .. "Loot"
    end
    message = message .. "World " .. message .. " Bonus (+" .. index.boostExpPercent .. "%)"
    
    local currentTime = os.time()
    local globalStorage = Game.getStorageValue(index.boostStorage)
    
    if globalStorage and globalStorage > currentTime then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You cannot do this now because the " .. message .. " is already active.")
        player:getPosition():sendMagicEffect(config.effectOff)
        return true
    end
    
    local broadcastMessage = player:getName() .. " has activated the " .. message .. " for " .. (index.boostTime / 60) .. " minutes!"    
    Game.broadcastMessage(broadcastMessage, MESSAGE_STATUS_WARNING)
    player:getPosition():sendMagicEffect(config.effectOn)
    Game.setStorageValue(index.boostStorage, os.time() + index.boostTime)
    item:remove(1)
    
    addEvent(notifyBoostEnd, index.boostTime * 1000, message)
    return true
end

Anyway, good luck.
Xikini
 
Back
Top