• 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 Xikini's Free Scripting Service TFS 1.4.2

  • Thread starter Thread starter Xikini
  • Start date Start date
Status
Not open for further replies.
X

Xikini

Guest
Request whatever you want, within reason.

Please do not request for things that require source editing or database queries.

------------------------------------
If I've reacted to your post, it means I've read it. 👍😍🤣😲🙁😡🤔😉

------------------------------------
Completed Requests

A boss that randomly creates effects on tiles, that when stepped on, gives the player increased damage/mitigation to that boss.
Kill monster and gain X% extra loot chance or Y% extra experience for Z minutes
A pack of 6 useful simple scripts.
-> (1) Simple quest npc
-> (2,3,4,5) use levers in specific order / stand with 4 players / use 4 objects / place items -> to open wall
-> (6) use lever to add/remove/replace objects
Wave type spell, with multiple effects
-> Same spell, but with default combat system
House market system. (owner places price on blackboard and object on the ground, other players buy with a lever)
Respawn System (closest anchor (like darks souls bonfire) / tavern / temple)
Vocation Death Protection (protect the noobs!)
Spell that shows area it will damage, before it strikes.
RAID SYSTEM - rebuilt in Lua, with some more features.
Modal Window - Teleport Item with saving/deleting of positions
Show top 3 Online Players (outfit, name, level) (as monsters, in set positions)
onLook function showing kill count of player.
Modal Window - Use Item -> choose reward.
Talkaction - !backpacks - to buy backpacks (or single items) anywhere. uses bank & current money on players
Quest/Event? Turn a bunch of objects with a monster, spawn portal.
Spawn Monsters, after they've all been killed, give global increased experience/loot in specific area's
Evolving Weapons - Kill X amount of specific creatures, evolve weapon and gain extra damage to those creatures.
Random Portals spawn at XX:XX time(s). (can exit 'off' portals, if you have the storage.)
Monster that adjusts speed based on target
Monster that increases damage output based on # of players nearby
Experience recovery Item. Die -> Use Item -> gain % of lost experience
Character Snapshot - Keeps track of all skills & level, for resetting later.
Fire Dagger - Physical Damage Melee Weapon, with % added damage
Players in specific level ranges don't lose skills/loot/experience, when they die.
Multiclient Limit Check - with admin account not being counted towards limit
Capacity Increasing Items
Upgradeable Protection Amulet - 10% to all elements
-> upgrade amulet, but for all items.
onKill - give reward to all players who dealt damage
-> example: give reward based on damage contribution
Quest Book - Record your quest progress into a book.
Stat System, using modal windows
Holy Tible (POI) - Require Item to use teleport tiles
Item Upgrade System
Skill Stages
-> individual stages for each skill type
-> talkaction to check rates (by @Extrodus)
Random Reward Item - gives different rewards based on vocation
Bounty Hunter System
NPC & Player Walk System (Follow Nodes to destination)
Health/Mana gain permanent - limited use items

------------------------------------
Support

If you have an issue with one of my scripts, I will attempt to help you, but not in this thread.
Make a thread in the support board.
Ensure to follow all rules of the support board.
Without all necessary information it's impossible to help you.

------------------------------------
I will only be scripting for TFS 1.4.2

Not TFS 1.1 / 1.2
Not OTServBR / OTX
and certainly not TFS 0.4

When requesting a script, don't ask for "this script I saw on super popular OT".

I don't care where the idea came from.
I don't want to see a video of the script in action.

Just describe what the script is supposed to do, and I'll try to make it.

Any script that I make in response to a request from this thread will be shared publicly, here, in this thread.

I'm not going to make anything in private, so post your request in this thread only.
Please, for the love of god, don't pm me asking to make a script.
I will actually add you to my ignore list if you do that.
--------------

Anyways!

Thanks for coming by and checking the thread out.
If you think there is a better way to script something, feel free to let me know.
I'm here to learn.

Cheers,

Xikini
---------

P.S.
I've been doing free scripting service's on/off for awhile.
And if you want to see the previous threads, go check them here.

 
Last edited by a moderator:
Hello Xikini, I need a script that I cannot implement
I tried a lot and did not succeed
What is required is a script that decodes currencies upon purchase
For example I have 3 custom Tokens////not money
Christmas token 6527///tic-tac-toe token 2638////Golden Token25377
Christmas token= 1//1tic-tac-toe token=100//1Golden Token=10000
When I go to buy anything from a token store, I want to defrost the frozen tokens so I don't have to manually unpack them
My Tokens store works with lever 1945,1946
17:48 You Dont Have 10000 Tokans or 100 tic-tac-toe tokens.
I have the Golden coin, but I have to break it so I can buy it
All I ask is that the currency be dismantled when you buy anything from Lever & with talkactions command
---------
Just as the attribute worth system works for Gold

cc&gn&gi //work fine with// attribute key="worth" // But for the money this works well in talkactions purchase orders
thank you in advance


 
Hello Xikini, I need a script that I cannot implement
I tried a lot and did not succeed
What is required is a script that decodes currencies upon purchase
For example I have 3 custom Tokens////not money
Christmas token 6527///tic-tac-toe token 2638////Golden Token25377
Christmas token= 1//1tic-tac-toe token=100//1Golden Token=10000
When I go to buy anything from a token store, I want to defrost the frozen tokens so I don't have to manually unpack them
My Tokens store works with lever 1945,1946
17:48 You Dont Have 10000 Tokans or 100 tic-tac-toe tokens.
I have the Golden coin, but I have to break it so I can buy it
All I ask is that the currency be dismantled when you buy anything from Lever & with talkactions command
---------
Just as the attribute worth system works for Gold

cc&gn&gi //work fine with// attribute key="worth" // But for the money this works well in talkactions purchase orders
thank you in advance
Untested.

I basically made it take from the lowest denomination possible, and give back change in the highest denomination possible.
I added return false/true.. for easier coding.. but I would suggest just making sure they have enough money first.
removeWealth will also 'give change' automatically.

LUA:
local cost = 15000

-- checking for wealth first..
if getTotalWealth(player) >= cost then
    removeWealth(player, cost)
else
    -- not enough wealth to purchase
end

--alternative, where you let the code check for us
if not removeWealth(player, cost) then
    -- not enough wealth to purchase
end
LUA:
local wealth_items = {
    {id = 25377, value = 10000},
    {id = 2638, value = 100},
    {id = 6527, value = 1}
}
table.sort(wealth_items, function(a, b) return a.value > b.value end)


local function getTotalWealth(player)
    local total = 0
    for _, item in ipairs(wealth_items) do
        total = total + (item.value * player:getItemCount(item.id))
    end
    return total
end

local function addWealth(player, amount)
    if amount <= 0 then
        return true
    end
    for _, item in ipairs(wealth_items) do
        local quantity_to_add = math.floor(amount / item.value)
        if quantity_to_add > 0 then
            player:addItem(item.id, quantity_to_add, true)
        end
        amount = amount - (quantity_to_add * item.value)
        if amount <= 0 then
            return true
        end
    end
    return false
end

local function removeWealth(player, amount)
    if getTotalWealth(player) < amount then
        return false
    end
  
    for i = #wealth_items, 1, -1 do
        local item = wealth_items[i]
        local quantity_to_remove = math.min(player:getItemCount(item.id), math.floor(amount / item.value))
        if quantity_to_remove > 0 then
            player:removeItem(item.id, quantity_to_remove)
        end
        amount = amount - (quantity_to_remove * item.value)
        if amount <= 0 then
            return true
        end
    end
  
    for i = #wealth_items, 1, -1 do
        local item = wealth_items[i]
        local itemAmount = player:getItemCount(item.id)
        local quantity_to_remove = 0
        if itemAmount > 0 then
            for n = 1, itemAmount do
                quantity_to_remove = quantity_to_remove + 1
                amount = amount - item.value
                if amount <= 0 then
                    player:removeItem(item.id, quantity_to_remove)
                    addWealth(player, -amount)
                    return true
                end
            end
            player:removeItem(item.id, itemAmount)
        end
    end
  
    return false
end
 
Untested.

I basically made it take from the lowest denomination possible, and give back change in the highest denomination possible.
I added return false/true.. for easier coding.. but I would suggest just making sure they have enough money first.
removeWealth will also 'give change' automatically.

LUA:
local cost = 15000

-- checking for wealth first..
if getTotalWealth(player) >= cost then
    removeWealth(player, cost)
else
    -- not enough wealth to purchase
end

--alternative, where you let the code check for us
if not removeWealth(player, cost) then
    -- not enough wealth to purchase
end
LUA:
local wealth_items = {
    {id = 25377, value = 10000},
    {id = 2638, value = 100},
    {id = 6527, value = 1}
}
table.sort(wealth_items, function(a, b) return a.value > b.value end)


local function getTotalWealth(player)
    local total = 0
    for _, item in ipairs(wealth_items) do
        total = total + (item.value * player:getItemCount(item.id))
    end
    return total
end

local function addWealth(player, amount)
    if amount <= 0 then
        return true
    end
    for _, item in ipairs(wealth_items) do
        local quantity_to_add = math.floor(amount / item.value)
        if quantity_to_add > 0 then
            player:addItem(item.id, quantity_to_add, true)
        end
        amount = amount - (quantity_to_add * item.value)
        if amount <= 0 then
            return true
        end
    end
    return false
end

local function removeWealth(player, amount)
    if getTotalWealth(player) < amount then
        return false
    end
 
    for i = #wealth_items, 1, -1 do
        local item = wealth_items[i]
        local quantity_to_remove = math.min(player:getItemCount(item.id), math.floor(amount / item.value))
        if quantity_to_remove > 0 then
            player:removeItem(item.id, quantity_to_remove)
        end
        amount = amount - (quantity_to_remove * item.value)
        if amount <= 0 then
            return true
        end
    end
 
    for i = #wealth_items, 1, -1 do
        local item = wealth_items[i]
        local itemAmount = player:getItemCount(item.id)
        local quantity_to_remove = 0
        if itemAmount > 0 then
            for n = 1, itemAmount do
                quantity_to_remove = quantity_to_remove + 1
                amount = amount - item.value
                if amount <= 0 then
                    player:removeItem(item.id, quantity_to_remove)
                    addWealth(player, -amount)
                    return true
                end
            end
            player:removeItem(item.id, itemAmount)
        end
    end
 
    return false
end
LUA:
function addWealth(player, amount)
function getTotalWealth(player)
function removeWealth(player, amount)
Just misses (local) local function getTotalWealth(player)
Now everything works fine Thank you ♥♥♥
 
Hi there @Xikini ^^ I have a little idea from a script you made a while ago.

There could be a chance to make some changes to it? I would like it to be a moveevent.
  • If you step-in, automatically start casting "exura" each 2 seconds
  • If you step-out, automatically stop the action
It is really important to have a check in case that player got disconnected by using exit, since my server kicks them automatically if it doesn't find the player ip. About the auto-eat function and the talkaction itself, can be deleted, what I really need is to trigger it with step event, and exact parameters (exura, 2 seconds).

Thanks in advance!
Regards :)
 
Hello Xikini! :)
Recently I heard that it is possible to somehow create a lua file for TFS 1.4.2 otcv8 where instead of using the schema for each item separately:

local listOfValuesByItemId = {
["34021"] = 1000001,
["36792"] = 100001,
["3043"] = 10001,
["3415"] = 1001,
["3003"] = 51
}

local function getColorForValue(value)
if value >= 1000000 then
return TextColors.yellow
elseif value >= 100000 then
return TextColors.purple
elseif value >= 10000 then
return TextColors.blue
elseif value >= 1000 then
return TextColors.green
elseif value >= 50 then
return TextColors.grey
end
return TextColors.white
end
(I had a different ID than above - for otcv8)

It is possible to somehow create a .lua that collects the prices of items and, based on them, assigns the colors of the displayed loot, e.g. Firesword - green, Boots of haste - red, etc.

I tried to implement this for me:
however, it didn't work unfortunately
 
Hi there @Xikini ^^ I have a little idea from a script you made a while ago.

There could be a chance to make some changes to it? I would like it to be a moveevent.
  • If you step-in, automatically start casting "exura" each 2 seconds
  • If you step-out, automatically stop the action
It is really important to have a check in case that player got disconnected by using exit, since my server kicks them automatically if it doesn't find the player ip. About the auto-eat function and the talkaction itself, can be deleted, what I really need is to trigger it with step event, and exact parameters (exura, 2 seconds).

Thanks in advance!
Regards :)
Unless someone adds it to the source, there is currently no way to force a spell to be cast.
Forcing the player to say the spell words doesn't trigger the spell.

Hello Xikini! :)
Recently I heard that it is possible to somehow create a lua file for TFS 1.4.2 otcv8 where instead of using the schema for each item separately:


(I had a different ID than above - for otcv8)

It is possible to somehow create a .lua that collects the prices of items and, based on them, assigns the colors of the displayed loot, e.g. Firesword - green, Boots of haste - red, etc.

I tried to implement this for me:
however, it didn't work unfortunately
I've never worked on client specific scripts.
I'd suggest trying again, and maybe opening a support thread if you still have a persisting issue.
 
Unless someone adds it to the source, there is currently no way to force a spell to be cast.
Forcing the player to say the spell words doesn't trigger the spell.


I've never worked on client specific scripts.
I'd suggest trying again, and maybe opening a support thread if you still have a persisting issue.
Thanks for the reply! How about making it use skill ticks instead of spell cast?
Like it's done here (didn't found it but there's a 1.X version too I think) Action - Exercise Dummy for TFS 0.4 :o (https://otland.net/threads/exercise-dummy-for-tfs-0-4-o.264807/#post-2559581)

So we "fake" it. The player gain skill ticks, that raises in the same way that would be a normal "training", calculating the magic level skill ticks based on player vocation (being sure that every vocation gain the skill tick that corresponds). And every time the player gain a skill tick, display some kind of effects that simulates player casting a spell (probably we could use creatureSay to look the same).

It would be also needed to make players unable to cast spells on the training square, to avoid a double magic level gaining while using ticks + spell casting, this way it increases as a constant.

Regards, ralke
 
Last edited:
Hello Xikini
I think this modal window would help a lot of servers:
A modal that when you step on a sqm, you choose whether to accept Grizzly Addams' tasks (something like that instead of going to ask him hi-join-yes, task, tarantula, yes).
That is, just step on a sqm and it gives you the tasks that the NPC gives you. I don't know if I explained myself...

 
Last edited:
This could be scripted a lot better, but I can't be fucked. lmao
Looks like ass, but it works.

View attachment 81944

data/scripts/onStepIn_snapshotCharacter.lua
LUA:
local config = {
    teleportIn = { -- snapshots character
        actionId = 45045,
        destination = Position(981, 1001, 7)
    },
    teleportOut = { -- resets character
        actionId = 45046,
        destination = Position(985, 1001, 7)
    },
    storageKeys = {
        level          = 45047,
        magic          = 45048,
        magicTries     = 45049,
        fist           = 45050,
        fistTries      = 45051,
        club           = 45052,
        clubTries      = 45053,
        sword          = 45054,
        swordTries     = 45055,
        axe            = 45056,
        axeTries       = 45057,
        distance       = 45058,
        distanceTries  = 45059,
        shielding      = 45060,
        shieldingTries = 45061,
        fishing        = 45062,
        fishingTries   = 45063,
    },
    setValue = {
        [{1, 5, 2, 6}] = { -- mages
            level     = 200,
            magic     = 65,
            fist      = 20,
            club      = 20,
            sword     = 20,
            axe       = 20,
            distance  = 20,
            shielding = 20,
            fishing   = 50
        },
        [{3, 7}] = { -- paladins
            level     = 200,
            magic     = 25,
            fist      = 25,
            club      = 25,
            sword     = 25,
            axe       = 25,
            distance  = 50,
            shielding = 25,
            fishing   = 50
        },
        [{4, 8}] = { -- knights
            level     = 200,
            magic     = 5,
            fist      = 50,
            club      = 50,
            sword     = 50,
            axe       = 50,
            distance  = 25,
            shielding = 50,
            fishing   = 70
        }
    }
}


local moveevent = MoveEvent()

function moveevent.onStepIn(creature, item, position, fromPosition)
    if not creature:isPlayer() then
        return true
    end
 
    local actionId = item:getActionId()
 
    if config.teleportIn.actionId == actionId then
        if creature:getStorageValue(config.storageKeys.level) ~= -1 then
            creature:sendTextMessage(MESSAGE_STATUS_SMALL, "This character already has a snapshot.")
            creature:teleportTo(fromPosition)
            return true
        end
 
        local vocationId = creature:getVocation():getId()
        for k, v in pairs(config.setValue) do
            if table.contains(k, vocationId) then
                creature:setStorageValue(config.storageKeys.level, creature:getExperience())
                creature:addLevel(v.level - creature:getLevel(), true)
         
                creature:setStorageValue(config.storageKeys.magic, creature:getMagicLevel())
                creature:setStorageValue(config.storageKeys.magicTries, creature:getManaSpent())
                creature:addMagicLevel(v.magic - creature:getMagicLevel())
         
                creature:setStorageValue(config.storageKeys.fist, creature:getSkillLevel(SKILL_FIST))
                creature:setStorageValue(config.storageKeys.fistTries, creature:getSkillTries(SKILL_FIST))
                creature:addSkillLevel(SKILL_FIST, v.fist - creature:getSkillLevel(SKILL_FIST))
         
                creature:setStorageValue(config.storageKeys.club, creature:getSkillLevel(SKILL_CLUB))
                creature:setStorageValue(config.storageKeys.clubTries, creature:getSkillTries(SKILL_CLUB))
                creature:addSkillLevel(SKILL_CLUB, v.club - creature:getSkillLevel(SKILL_CLUB))
         
                creature:setStorageValue(config.storageKeys.sword, creature:getSkillLevel(SKILL_SWORD))
                creature:setStorageValue(config.storageKeys.swordTries, creature:getSkillTries(SKILL_SWORD))
                creature:addSkillLevel(SKILL_SWORD, v.sword - creature:getSkillLevel(SKILL_SWORD))
         
                creature:setStorageValue(config.storageKeys.axe, creature:getSkillLevel(SKILL_AXE))
                creature:setStorageValue(config.storageKeys.axeTries, creature:getSkillTries(SKILL_AXE))
                creature:addSkillLevel(SKILL_AXE, v.axe - creature:getSkillLevel(SKILL_AXE))
         
                creature:setStorageValue(config.storageKeys.distance, creature:getSkillLevel(SKILL_DISTANCE))
                creature:setStorageValue(config.storageKeys.distanceTries, creature:getSkillTries(SKILL_DISTANCE))
                creature:addSkillLevel(SKILL_DISTANCE, v.distance - creature:getSkillLevel(SKILL_DISTANCE))
         
                creature:setStorageValue(config.storageKeys.shielding, creature:getSkillLevel(SKILL_SHIELD))
                creature:setStorageValue(config.storageKeys.shieldingTries, creature:getSkillTries(SKILL_SHIELD))
                creature:addSkillLevel(SKILL_SHIELD, v.shielding - creature:getSkillLevel(SKILL_SHIELD))
         
                creature:setStorageValue(config.storageKeys.fishing, creature:getSkillLevel(SKILL_FISHING))
                creature:setStorageValue(config.storageKeys.fishingTries, creature:getSkillTries(SKILL_FISHING))
                creature:addSkillLevel(SKILL_FISHING, v.fishing - creature:getSkillLevel(SKILL_FISHING))
         
                creature:sendTextMessage(MESSAGE_STATUS_SMALL, "Character has received a snapshot.")
                creature:teleportTo(config.teleportIn.destination)
                return true
            end
        end
 
        creature:sendTextMessage(MESSAGE_STATUS_SMALL, "Vocation snapshot information unable to be gathered. Contact Admin.") -- table not setup with this vocation
        creature:teleportTo(fromPosition)
        return true
 
    else
        if creature:getStorageValue(config.storageKeys.level) == -1 then
            creature:sendTextMessage(MESSAGE_STATUS_SMALL, "This character does not have a snapshot.")
            creature:teleportTo(fromPosition)
            return true
        end
 
        local experienceAmount = creature:getStorageValue(config.storageKeys.level) - creature:getExperience()
        creature:setStorageValue(config.storageKeys.level, -1)
        if experienceAmount > 0 then
            creature:addExperience(experienceAmount)
        else
            experienceAmount = experienceAmount * -1
            creature:removeExperience(experienceAmount)
        end
 
        local magicLevel = creature:getStorageValue(config.storageKeys.magic) - creature:getMagicLevel()
        creature:addMagicLevel(magicLevel)
 
        local manaSpentAmount = creature:getStorageValue(config.storageKeys.magicTries) - creature:getManaSpent()
        creature:setStorageValue(config.storageKeys.magicTries, -1)
        if manaSpentAmount > 0 then
            creature:addManaSpent(manaSpentAmount)
        else
            manaSpentAmount = manaSpentAmount * -1
            creature:removeManaSpent(manaSpentAmount)
        end
 
        local fistingLevel = creature:getStorageValue(config.storageKeys.fist) - creature:getSkillLevel(SKILL_FIST)
        creature:addSkillLevel(SKILL_FIST, fistingLevel)
 
        local fistTriesAmount = creature:getStorageValue(config.storageKeys.fistTries) - creature:getSkillTries(SKILL_FIST)
        creature:setStorageValue(config.storageKeys.fistTries, -1)
        if fistTriesAmount > 0 then
            creature:addSkillTries(SKILL_FIST, fistTriesAmount)
        else
            fistTriesAmount = fistTriesAmount * -1
            creature:removeSkillTries(SKILL_FIST, fistTriesAmount)
        end
 
        local clubingLevel = creature:getStorageValue(config.storageKeys.club) - creature:getSkillLevel(SKILL_CLUB)
        creature:addSkillLevel(SKILL_CLUB, clubingLevel)
 
        local clubTriesAmount = creature:getStorageValue(config.storageKeys.clubTries) - creature:getSkillTries(SKILL_CLUB)
        creature:setStorageValue(config.storageKeys.clubTries, -1)
        if clubTriesAmount > 0 then
            creature:addSkillTries(SKILL_CLUB, clubTriesAmount)
        else
            clubTriesAmount = clubTriesAmount * -1
            creature:removeSkillTries(SKILL_CLUB, clubTriesAmount)
        end
 
        local swordingLevel = creature:getStorageValue(config.storageKeys.sword) - creature:getSkillLevel(SKILL_SWORD)
        creature:addSkillLevel(SKILL_SWORD, swordingLevel)
 
        local swordTriesAmount = creature:getStorageValue(config.storageKeys.swordTries) - creature:getSkillTries(SKILL_SWORD)
        creature:setStorageValue(config.storageKeys.swordTries, -1)
        if swordTriesAmount > 0 then
            creature:addSkillTries(SKILL_SWORD, swordTriesAmount)
        else
            swordTriesAmount = swordTriesAmount * -1
            creature:removeSkillTries(SKILL_SWORD, swordTriesAmount)
        end
 
        local axeingLevel = creature:getStorageValue(config.storageKeys.axe) - creature:getSkillLevel(SKILL_AXE)
        creature:addSkillLevel(SKILL_AXE, axeingLevel)
 
        local axeTriesAmount = creature:getStorageValue(config.storageKeys.axeTries) - creature:getSkillTries(SKILL_AXE)
        creature:setStorageValue(config.storageKeys.axeTries, -1)
        if axeTriesAmount > 0 then
            creature:addSkillTries(SKILL_AXE, axeTriesAmount)
        else
            axeTriesAmount = axeTriesAmount * -1
            creature:removeSkillTries(SKILL_AXE, axeTriesAmount)
        end
 
        local distanceLevel = creature:getStorageValue(config.storageKeys.distance) - creature:getSkillLevel(SKILL_DISTANCE)
        creature:addSkillLevel(SKILL_DISTANCE, distanceLevel)
 
        local distanceTriesAmount = creature:getStorageValue(config.storageKeys.distanceTries) - creature:getSkillTries(SKILL_DISTANCE)
        creature:setStorageValue(config.storageKeys.distanceTries, -1)
        if distanceTriesAmount > 0 then
            creature:addSkillTries(SKILL_DISTANCE, distanceTriesAmount)
        else
            distanceTriesAmount = distanceTriesAmount * -1
            creature:removeSkillTries(SKILL_DISTANCE, distanceTriesAmount)
        end
 
        local shieldingLevel = creature:getStorageValue(config.storageKeys.shielding) - creature:getSkillLevel(SKILL_SHIELD)
        creature:addSkillLevel(SKILL_SHIELD, shieldingLevel)
 
        local shieldingTriesAmount = creature:getStorageValue(config.storageKeys.shieldingTries) - creature:getSkillTries(SKILL_SHIELD)
        creature:setStorageValue(config.storageKeys.shieldingTries, -1)
        if shieldingTriesAmount > 0 then
            creature:addSkillTries(SKILL_SHIELD, shieldingTriesAmount)
        else
            shieldingTriesAmount = shieldingTriesAmount * -1
            creature:removeSkillTries(SKILL_SHIELD, shieldingTriesAmount)
        end
 
        local fishingLevel = creature:getStorageValue(config.storageKeys.fishing) - creature:getSkillLevel(SKILL_FISHING)
        creature:addSkillLevel(SKILL_FISHING, fishingLevel)
 
        local fishingTriesAmount = creature:getStorageValue(config.storageKeys.fishingTries) - creature:getSkillTries(SKILL_FISHING)
        creature:setStorageValue(config.storageKeys.fishingTries, -1)
        if fishingTriesAmount > 0 then
            creature:addSkillTries(SKILL_FISHING, fishingTriesAmount)
        else
            fishingTriesAmount = fishingTriesAmount * -1
            creature:removeSkillTries(SKILL_FISHING, fishingTriesAmount)
        end
 
        creature:teleportTo(config.teleportOut.destination)
        return true
    end
 
 
    return true
end

moveevent:aid(config.teleportIn.actionId, config.teleportOut.actionId)
moveevent:register()

Feb 8, 2024
Sneaky Diller said:
this is script works very well. I forgot to say can we add custom eq too?

Dec 2, 2024
Sneaky Diller said:
Hello can you do this? if you have free time
LUA:
-- this will send all the players equipped items to their mailbox
for slot = 1, 10 do
    local equipmentItem = creature:getSlotItem(slot)
    if equipmentItem then
        local clonedItem = equipmentItem:clone()
        creature:getInbox():addItemEx(clonedItem, INDEX_WHEREEVER, FLAG_NOLIMIT)
        equipmentItem:remove()
    end
end

-- then you give the player whatever other gear you want.
-- there is no way to 'store' the items you give, for later removal, so ensure that you're okay with the player getting free items
-- or force them into an area, where it's impossible to take the items with them when they leave, and delete everything off of their character when you revert them to regular stats
-- the players will still need to go to their mailbox and manually re-equip all their old gear afterwords
LUA:
-- place it directly above this line
creature:sendTextMessage(MESSAGE_STATUS_SMALL, "Character has received a snapshot.")
Post automatically merged:

Thanks for the reply! How about making it use skill ticks instead of spell cast?
Yeah, you could definitely simulate a spell.
It would be also needed to make players unable to cast spells on the training square, to avoid a double magic level gaining while using ticks + spell casting, this way it increases as a constant.
Probably not required, since we'd be removing the mana required for the training spell.
If the player is manually casting spells, then they won't reach the 'mana threshold' for the training spell to be cast.

Let me know if you still need it, and I'll make it.
 
Last edited by a moderator:
Hello @Xikini I'm trying to fix the CTF event that was made by @Itutorial I manged to fix some parts but there is a problem that allies can kill each others and tried to find a way to stop that but coudnlt do that here is the script I know it would be alot to ask but just I got that out of my hands





The Lib script is the download attachment

The revscript
LUA:
---CTF STATUS TRACKING DONT TOUCH --
CTF_STATUS = 0
CTF_PLAYERS_QUEUE = {}
CTF_GREEN_TEAM_PLAYERS = {}
CTF_RED_TEAM_PLAYERS = {}
CTF_GREEN_SCORE = 0
CTF_RED_SCORE = 0
CTF_GREEN_FLAG_HOLDER = nil
CTF_RED_FLAG_HOLDER = nil
CTF_PLAYER_OUTFITS = {}

------------------------------------
 
-------------------- CTF MAIN CONFIG --------------------------
CTF_GREEN_FLAGID = 1437 -- Flag itemID of green team
CTF_RED_FLAGID = 1435 -- Flag itemId of red team
CTF_GREEN_CAPTURE_TILE_ID = 426 -- Itemid of tile to capture enemy flag
CTF_RED_CAPTURE_TILE_ID = 426 -- Itemid of tile to capture enemy flag
CTF_ACTIONID = 5675 -- Action id for flags and capture tiles
CTF_REMOVE_GATES_TIME = 1 -- Walls that block players from running around CTF right away. 2 minutes
CTF_WIN_SCORE = 1 -- How many times the flag is captured before the team automatically wins.
 
CTF_AREA = { -- Make sure all tiles in the area in included in this. Its used to reset the field --
    min = Position(2207, 608, 7), -- Set to top left tile of CTF area --
    max = Position(2339, 750, 7) -- Set to bottom right tile of CTF area --
}
 
CTF_GREEN_FLAG_POSITION = Position(2227, 634, 7) -- Set to position that flag starts at
CTF_RED_FLAG_POSITION = Position(2301, 692, 7) -- Set to position that flag starts at
CTF_GREEN_CAPTURE_TILE_POS = Position(2229, 635, 7) -- Tile player walks on to capture enemy flag
CTF_RED_CAPTURE_TILE_POS = Position(2299, 693, 7) -- Tile player walks on to capture enemy flag
 
CTF_GATES = { -- These will be removed when its time for players to run around in CTF. They should block exits/entrances --
    [1] = {itemid = 3766, pos = Position(2256, 672, 7)},
    [2] = {itemid = 3766, pos = Position(2265, 672, 7)},
    [3] = {itemid = 3766, pos = Position(2270, 672, 7)},
    [4] = {itemid = 3766, pos = Position(2243, 686, 7)}

}
 
CTF_TIME_LIMIT = 30 -- End CTF automatically after 30 minutes
CTF_RESTART_TIME = 360 -- Start CTF again after 60 minutes
CTF_CHECK_QUEUE = 1 -- Check CTF queue after 5 minutes
CTF_MIN_PLAYERS = 2 -- How many players must be queued for CTF to start.
CTF_LEVEL_REQ = 100 -- What level do you need to enter CTF.
 
CTF_GREEN_TEAM_START_POSITIONS = {min = Position(2233, 633, 7), max = Position(2240, 638, 7)} -- Green team players are teleported in this area
CTF_RED_TEAM_START_POSITIONS = {min = Position(2304, 696, 7), max = Position(2311, 703, 7)} -- Red team players are teleported in this area
 
 
CTF_RESPAWN_POSITIONS = { -- Multiple respawn points randomly selected for each team. Nice "unique" thing to have.
    GREEN_TEAM = {
        [1] = {min = Position(2233, 633, 7), max = Position(2240, 638, 7)},
        [2] = {min = Position(2233, 633, 7), max = Position(2240, 638, 7)},
        [3] = {min = Position(2233, 633, 7), max = Position(2240, 638, 7)}
    },
    RED_TEAM = {
        [1] = {min = Position(2304, 696, 7), max = Position(2311, 703, 7)},
        [2] = {min = Position(2304, 696, 7), max = Position(2311, 703, 7)},
        [3] = {min = Position(2304, 696, 7), max = Position(2311, 703, 7)}
    }
}
 
CTF_WINNER_MESSAGE = "Your team has won capture the flag!"
CTF_LOSER_MESSAGE = "Your team has lost capture the flag!"
CTF_TIE_MESSAGE = "Both teams have tied."
CTF_MSG_FLAG_RETRUNED_GREEN = "The green teams flag has been recovered by the green team."
CTF_MSG_FLAG_RETRUNED_RED = "The red teams flag has been recovered by the green red."
CTF_MSG_FLAG_CAPTURED_GREEN = "The green team has captured the red teams flag!"
CTF_MSG_FLAG_CAPTURED_RED = "The red team has captured the green teams flag!"
 
CTF_TELEPORT_POSITION = Position(1000, 1000, 7) -- Where players teleport after CTF is over.
 
CTF_GIVE_ITEM_REWARDS = true -- Set to false for no item rewards.
CTF_REWARD_TIE = true -- Gives rewards to all players if they tie.
 
CTF_ITEMREWARDS = { -- Rewards are given to whole team.
    [1] = {itemid = 2160, count = 5, randomAmount = true}, -- Random amount will be 1-count
    [2] = {itemid = 2157, count = 1, randomAmount = false} -- Random amount will be 1-count
}
 
CTF_GREEN_OUTFIT = { -- TEAM OUTFITS =D as requested
    MALE = {legs = 82, head = 82, feet = 82, body = 82,},
    FEMALE = {legs = 82, head = 82, feet = 82, body = 82}
}
 
CTF_RED_OUTFIT = {
    MALE = {legs = 94, head = 94, feet = 94, body = 94},
    FEMALE = {legs = 94, head = 94, feet = 94, body = 94}
}
 
 
---------------------------------------------------------------
 
---------- FUNCTIONS ------------
function isGreenTeam(playerName)
    for i = 1, #CTF_GREEN_TEAM_PLAYERS do
        if CTF_GREEN_TEAM_PLAYERS[i] == playerName then
            return true
        end
    end
    return false
end
 
function isRedTeam(playerName)
    for i = 1, #CTF_RED_TEAM_PLAYERS do
        if CTF_RED_TEAM_PLAYERS[i] == playerName then
            return true
        end
    end
    return false
end
 
function broadcastToCTFPlayers(msg)
    -- Broadcast to green team players
    for i = 1, #CTF_GREEN_TEAM_PLAYERS do
        local player = Player(CTF_GREEN_TEAM_PLAYERS[i])
       
        if player then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, msg)  -- Changed to white style
        end
    end
   
    -- Broadcast to red team players
    for i = 1, #CTF_RED_TEAM_PLAYERS do
        local player = Player(CTF_RED_TEAM_PLAYERS[i])
       
        if player then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, msg)  -- Changed to white style
        end
    end
end

 
function checkCTFPlayers()
    for i = 1, #CTF_PLAYERS_QUEUE do
        local player = Player(CTF_PLAYERS_QUEUE)
 
        if player and player:hasCondition(CONDITION_ISINFIGHT) then
            CTF_PLAYERS_QUEUE[i] = nil
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You are in combat and cannot enter capture the flag. You have been removed from the queue.")
        end
    end
 
    if #CTF_PLAYERS_QUEUE < CTF_MIN_PLAYERS then
        Game.broadcastMessage("There are not enough players for CTF to start. CTF will try again in 30 minutes. You do not need to requeue.", 1)
        addEvent(restartCTF, 30 * 60 * 1000)
    else
        startCTF()
    end
end
 
function restartCTF()
    CTF_STATUS = 0
end
 
function startCTF()
    for i = 1, #CTF_PLAYERS_QUEUE do
        if #CTF_GREEN_TEAM_PLAYERS > #CTF_RED_TEAM_PLAYERS then
            CTF_RED_TEAM_PLAYERS[#CTF_RED_TEAM_PLAYERS + 1] = CTF_PLAYERS_QUEUE[i]
        else
            CTF_GREEN_TEAM_PLAYERS[#CTF_GREEN_TEAM_PLAYERS + 1] = CTF_PLAYERS_QUEUE[i]
        end
    end
 
    CTF_PLAYERS_QUEUE = {}
 
    -- Store original outfits before the event starts
for i = 1, #CTF_GREEN_TEAM_PLAYERS do
    local player = Player(CTF_GREEN_TEAM_PLAYERS[i])
   
    if player then
        -- Store the player's original outfit
        CTF_PLAYER_OUTFITS[player:getName()] = player:getOutfit()
       
        -- Set the new outfit for the green team
        local newOutfit = player:getOutfit()
        if player:getSex() == 0 then
            newOutfit.lookLegs = CTF_GREEN_OUTFIT.FEMALE.legs
            newOutfit.lookHead = CTF_GREEN_OUTFIT.FEMALE.head
            newOutfit.lookFeet = CTF_GREEN_OUTFIT.FEMALE.feet
            newOutfit.lookBody = CTF_GREEN_OUTFIT.FEMALE.body
        else
            newOutfit.lookLegs = CTF_GREEN_OUTFIT.MALE.legs
            newOutfit.lookHead = CTF_GREEN_OUTFIT.MALE.head
            newOutfit.lookFeet = CTF_GREEN_OUTFIT.MALE.feet
            newOutfit.lookBody = CTF_GREEN_OUTFIT.MALE.body
        end
        Creature(player):setOutfit(newOutfit)
       
        -- Teleport and message
        player:teleportTo(Position(math.random(CTF_GREEN_TEAM_START_POSITIONS.min.x, CTF_GREEN_TEAM_START_POSITIONS.max.x), math.random(CTF_GREEN_TEAM_START_POSITIONS.min.y, CTF_GREEN_TEAM_START_POSITIONS.max.y), math.random(CTF_GREEN_TEAM_START_POSITIONS.min.z, CTF_GREEN_TEAM_START_POSITIONS.max.z)))
        player:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "Welcome to CTF,You have been placed in the GREEN team, Gates will open in 2 minutes")
    end
end

for i = 1, #CTF_RED_TEAM_PLAYERS do
    local player = Player(CTF_RED_TEAM_PLAYERS[i])
   
    if player then
        -- Store the player's original outfit
        CTF_PLAYER_OUTFITS[player:getName()] = player:getOutfit()
       
        -- Set the new outfit for the red team
        local newOutfit = player:getOutfit()
        if player:getSex() == 0 then
            newOutfit.lookLegs = CTF_RED_OUTFIT.FEMALE.legs
            newOutfit.lookHead = CTF_RED_OUTFIT.FEMALE.head
            newOutfit.lookFeet = CTF_RED_OUTFIT.FEMALE.feet
            newOutfit.lookBody = CTF_RED_OUTFIT.FEMALE.body
        else
            newOutfit.lookLegs = CTF_RED_OUTFIT.MALE.legs
            newOutfit.lookHead = CTF_RED_OUTFIT.MALE.head
            newOutfit.lookFeet = CTF_RED_OUTFIT.MALE.feet
            newOutfit.lookBody = CTF_RED_OUTFIT.MALE.body
        end
        Creature(player):setOutfit(newOutfit)
       
        -- Teleport and message
        player:teleportTo(Position(math.random(CTF_RED_TEAM_START_POSITIONS.min.x, CTF_RED_TEAM_START_POSITIONS.max.x), math.random(CTF_RED_TEAM_START_POSITIONS.min.y, CTF_RED_TEAM_START_POSITIONS.max.y), math.random(CTF_RED_TEAM_START_POSITIONS.min.z, CTF_RED_TEAM_START_POSITIONS.max.z)))
        player:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "Welcome to CTF,You have been placed in the RED team,Gates will open in 2 minutes")
    end
end

-- When the event ends, restore the original outfits
function restoreOriginalOutfits()
    for playerName, originalOutfit in pairs(CTF_PLAYER_OUTFITS) do
        local player = Player(playerName)
       
        if player then
            -- Restore the original outfit
            Creature(player):setOutfit(originalOutfit)
           
            -- Optionally, teleport the player back to their original position
            -- You could store their initial position earlier if needed
        end
    end
end

 
    CTF_STATUS = 2
    Game.broadcastMessage("Capture the flag is now closed. Good luck to the participants.", 1)
    addEvent(removeGates, CTF_REMOVE_GATES_TIME * 60 * 1000)
    addEvent(stopCTF, CTF_TIME_LIMIT * 60 * 1000)
end
 
function removeGates()
    for i = 1, #CTF_GATES do
        local position = CTF_GATES[i].pos
        local tile = Tile(position)
        if tile and tile:getItemById(CTF_GATES[i].itemid) then
            tile:getItemById(CTF_GATES[i].itemid):remove()
        end
    end
 
    for i = 1, #CTF_GREEN_TEAM_PLAYERS do
        local player = Player(CTF_GREEN_TEAM_PLAYERS[i])
 
        if player then
            player:sendTextMessage(MESSAGE_STATUS_WARNING, "Gates has been removed, GO CAPTURE THE RED FLAG")

        end
    end
 
    for i = 1, #CTF_RED_TEAM_PLAYERS do
        local player = Player(CTF_RED_TEAM_PLAYERS[i])
 
        if player then
            player:sendTextMessage(MESSAGE_STATUS_WARNING, "Gates has been removed, GO CAPTURE THE GREEN FLAG")
        end
    end
end
 
function stopCTF()
    CTF_STATUS = -1
   
    if CTF_GREEN_SCORE == CTF_RED_SCORE then
        -- Broadcast a tie message to the entire server
        Game.broadcastMessage("The Capture the Flag event has ended in a tie! Both teams played well!", MESSAGE_STATUS_WARNING)
       
        -- Handle tie situation for Green team players
        for i = 1, #CTF_GREEN_TEAM_PLAYERS do
            local player = Player(CTF_GREEN_TEAM_PLAYERS[i])
            if player then
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, CTF_TIE_MESSAGE)
                Creature(player):setOutfit(CTF_PLAYER_OUTFITS[player:getName()])
               
                if CTF_GIVE_ITEM_REWARDS and CTF_REWARD_TIE then
                    for i = 1, #CTF_ITEMREWARDS do
                        if CTF_ITEMREWARDS[i].randomAmount then
                            player:addItem(CTF_ITEMREWARDS[i].itemid, math.random(CTF_ITEMREWARDS[i].count))
                        else
                            player:addItem(CTF_ITEMREWARDS[i].itemid, CTF_ITEMREWARDS[i].count)
                        end
                    end
                end
                player:teleportTo(CTF_TELEPORT_POSITION)
            end
        end
       
        -- Handle tie situation for Red team players
        for i = 1, #CTF_RED_TEAM_PLAYERS do
            local player = Player(CTF_RED_TEAM_PLAYERS[i])
            if player then
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, CTF_TIE_MESSAGE)
                Creature(player):setOutfit(CTF_PLAYER_OUTFITS[player:getName()])
               
                if CTF_GIVE_ITEM_REWARDS and CTF_REWARD_TIE then
                    for i = 1, #CTF_ITEMREWARDS do
                        if CTF_ITEMREWARDS[i].randomAmount then
                            player:addItem(CTF_ITEMREWARDS[i].itemid, math.random(CTF_ITEMREWARDS[i].count))
                        else
                            player:addItem(CTF_ITEMREWARDS[i].itemid, CTF_ITEMREWARDS[i].count)
                        end
                    end
                end
                player:teleportTo(CTF_TELEPORT_POSITION)
            end
        end
       
    elseif CTF_GREEN_SCORE > CTF_RED_SCORE then
        -- Broadcast Green team win to the server
        Game.broadcastMessage("Green team has won the Capture the Flag event!", MESSAGE_STATUS_WARNING)
       
        -- Handle Green team victory for players
        for i = 1, #CTF_GREEN_TEAM_PLAYERS do
            local player = Player(CTF_GREEN_TEAM_PLAYERS[i])
            if player then
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, CTF_WINNER_MESSAGE)
                Creature(player):setOutfit(CTF_PLAYER_OUTFITS[player:getName()])
               
                if CTF_GIVE_ITEM_REWARDS and CTF_REWARD_TIE then
                    for i = 1, #CTF_ITEMREWARDS do
                        if CTF_ITEMREWARDS[i].randomAmount then
                            player:addItem(CTF_ITEMREWARDS[i].itemid, math.random(CTF_ITEMREWARDS[i].count))
                        else
                            player:addItem(CTF_ITEMREWARDS[i].itemid, CTF_ITEMREWARDS[i].count)
                        end
                    end
                end
                player:teleportTo(CTF_TELEPORT_POSITION)
            end
        end
       
        -- Handle Red team defeat for players
        for i = 1, #CTF_RED_TEAM_PLAYERS do
            local player = Player(CTF_RED_TEAM_PLAYERS[i])
            if player then
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, CTF_LOSER_MESSAGE)
                player:teleportTo(CTF_TELEPORT_POSITION)
                Creature(player):setOutfit(CTF_PLAYER_OUTFITS[player:getName()])
            end
        end
       
    else
        -- Broadcast Red team win to the server
        Game.broadcastMessage("Red team has won the Capture the Flag event!", MESSAGE_STATUS_WARNING)
       
        -- Handle Red team victory for players
        for i = 1, #CTF_RED_TEAM_PLAYERS do
            local player = Player(CTF_RED_TEAM_PLAYERS[i])
            if player then
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, CTF_WINNER_MESSAGE)
                Creature(player):setOutfit(CTF_PLAYER_OUTFITS[player:getName()])
               
                if CTF_GIVE_ITEM_REWARDS and CTF_REWARD_TIE then
                    for i = 1, #CTF_ITEMREWARDS do
                        if CTF_ITEMREWARDS[i].randomAmount then
                            player:addItem(CTF_ITEMREWARDS[i].itemid, math.random(CTF_ITEMREWARDS[i].count))
                        else
                            player:addItem(CTF_ITEMREWARDS[i].itemid, CTF_ITEMREWARDS[i].count)
                        end
                    end
                end
                player:teleportTo(CTF_TELEPORT_POSITION)
            end
        end
       
        -- Handle Green team defeat for players
        for i = 1, #CTF_GREEN_TEAM_PLAYERS do
            local player = Player(CTF_GREEN_TEAM_PLAYERS[i])
            if player then
                player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, CTF_LOSER_MESSAGE)
                player:teleportTo(CTF_TELEPORT_POSITION)
                Creature(player):setOutfit(CTF_PLAYER_OUTFITS[player:getName()])
            end
        end
    end


    CTF_GREEN_TEAM_PLAYERS = {}
    CTF_RED_TEAM_PLAYERS = {}
    CTF_PLAYER_OUTFITS = {}
    CTF_GREEN_SCORE = 0
    CTF_RED_SCORE = 0
    CTF_GREEN_FLAG_HOLDER = nil
    CTF_RED_FLAG_HOLDER = nil
 
    if not Tile(CTF_GREEN_FLAG_POSITION):getItemById(CTF_GREEN_FLAGID) then
        local flag = Game.createItem(CTF_GREEN_FLAGID, 1, CTF_GREEN_FLAG_POSITION)
        flag:setAttribute('aid', CTF_ACTIONID)
    end
 
    if not Tile(CTF_RED_FLAG_POSITION):getItemById(CTF_RED_FLAGID) then
        local flag = Game.createItem(CTF_RED_FLAGID, 1, CTF_RED_FLAG_POSITION)
        flag:setAttribute('aid', CTF_ACTIONID)
    end
 
    for x = CTF_AREA.min.x, CTF_AREA.max.x do
        x = x
        for y = CTF_AREA.min.y, CTF_AREA.max.y do
            y = y
            for z = CTF_AREA.min.z, CTF_AREA.max.z do
                local position = Position(x, y, z)
                local tile = Tile(position)
 
                if tile then
                    if tile:getItemById(CTF_GREEN_FLAGID) and position ~= CTF_GREEN_FLAG_POSITION then
                        tile:getItemById(CTF_GREEN_FLAGID):remove()
                    elseif tile:getItemById(CTF_RED_FLAGID) and position ~= CTF_RED_FLAG_POSITION then
                        tile:getItemById(CTF_RED_FLAGID):remove()
                    end
                end
            end
        end
    end
 
    for i = 1, #CTF_GATES do
        if Tile(CTF_GATES[i].pos) and not Tile(CTF_GATES[i].pos):getItemById(CTF_GATES[i].itemid) then
            Game.createItem(CTF_GATES[i].itemid, 1, CTF_GATES[i].pos)
        end
    end
 
    addEvent(restartCTF, CTF_RESTART_TIME * 60 * 1000)
end
 

Attachments

Hello @Xikini I'm trying to fix the CTF event that was made by @Itutorial I manged to fix some parts but there is a problem that allies can kill each others and tried to find a way to stop that but coudnlt do that here is the script I know it would be alot to ask but just I got that out of my hands





The Lib script is the download attachment

The revscript
Ask in the his thread, or open a support thread.
This is not the correct place for this.
 
Can I still make requests? That's great!


I'll take a chance and make a request. There are certainly similar systems out there, but none that are really functional...


I’d like a system where every 2 hours, a monster is randomly selected, starting a general hunt across the server. The player who kills the most of that monster becomes the winner and receives a reward in money, an item, or experience.


I’ve been trying to find or create such a system for a long time and never managed to do it. It would be amazing if you could help...


In addition to this, another great system would be a simplified "raid" where you could set it up so that at certain times every day, specific bosses spawn. And in this same script, I’d like to configure multiple bosses for different times. For example, at 2 PM, Orshabaal spawns, and at 4 PM, Ferumbras spawns...
I saw that you already made a raid system, but it's random... is there a way to set it for specific times?


Thank you very much, and I think what you do is incredibly important for the community.


Thanks!
 
Last edited:
Can I still make requests? That's great!
:)

In addition to this, another great system would be a simplified "raid" where you could set it up so that at certain times every day, specific bosses spawn. And in this same script, I’d like to configure multiple bosses for different times. For example, at 2 PM, Orshabaal spawns, and at 4 PM, Ferumbras spawns...
I saw that you already made a raid system, but it's random... is there a way to set it for specific times?
Yep. Set chance to 0, to disable random raid
and then just configure specific time as needed.
2pm -> "14:00:00"
4pm -> "16:00:00"

I’d like a system where every 2 hours, a monster is randomly selected, starting a general hunt across the server. The player who kills the most of that monster becomes the winner and receives a reward in money, an item, or experience.
For this, we'd need to send mail to the player, regardless of online status.
Probably like this, with the hacky mailbox method.

Everything else beyond that would be using onSpawn for every monster in the server, to give them an onDeath trigger, and a global table to hold information about the current event.

Let me know if that works for you, and I'll whip something up.
 
Yeah, you could definitely simulate a spell.

Probably not required, since we'd be removing the mana required for the training spell.
If the player is manually casting spells, then they won't reach the 'mana threshold' for the training spell to be cast.

Let me know if you still need it, and I'll make it.
Would be amazing to have something like it. I really think this is a really good way to balance knight/paladin training vs. sorcerer/druids training; unless you have a tasker running it is literally impossible to train them. Thanks in advance bro, really appreciate it!
 
I’d like a system where every 2 hours, a monster is randomly selected, starting a general hunt across the server. The player who kills the most of that monster becomes the winner and receives a reward in money, an item, or experience.
But, here is a really really simple version of it
LUA:
local raids = {
    {"14:00", "Orshabaal", Position(1000, 1000, 7), "Orshabaal has appeared!"},
    {"16:00", "Ferumbras", Position(1000, 1000, 7), "leave blank for no spawn message."}
}

for i = 1, #raids do
    
    local raidIndex = i

    local globalevent = GlobalEvent("onTime_SimpleBossSpawner_" .. raidIndex)
    
    function globalevent.onTime(interval)
        if raids[raidIndex][4] ~= "" then
            broadcastMessage(raids[raidIndex][4], MESSAGE_STATUS_DEFAULT)
        end
        Game.createMonster(raids[raidIndex][2], raids[raidIndex][3], false, true, CONST_ME_TELEPORT)
        return true
    end
    
    globalevent:time(raids[raidIndex][1])
    globalevent:register()
    
end

Would be amazing to have something like it. I really think this is a really good way to balance knight/paladin training vs. sorcerer/druids training; unless you have a tasker running it is literally impossible to train them. Thanks in advance bro, really appreciate it!

Untested.
LUA:
local tileActionId = 45001
local training = {
    --["character name"] = randomValue
}

-- casts if at 90% mana, removing 10% of total mana
local function castFakeSpell(player)
    local maxMana = player:getMaxMana()
    local currentMana = player:getMana()
    
    if ((maxMana / 100) * 90) <= currentMana then -- if 90% mana threshold reached
        local ten_percent = math.floor(((maxMana / 100) * 90) - ((maxMana / 100) * 80))
        player:addMana(-ten_percent, false)
        player:addManaSpent(ten_percent)
        player:say("Mana Training Spell Name", TALKTYPE_MONSTER_SAY)
        player:getPosition():sendMagicEffect(CONST_ME_MAGIC_BLUE)
    end
end

local function trainPlayer(playerId, lastExecution, playerName)
    local player = Player(playerId)
    if not training[playerName] or not player then
        training[playerName] = nil
        return
    end
    if lastExecution ~= training[playerName] then
        return
    end
    
    castFakeSpell(player)    
    lastExecution = lastExecution < 1000000 and lastExecution + 1 or 1
    addEvent(trainPlayer, 1000, playerId, lastExecution, playerName)
end

local function stopTraining(playerName, lastExecution)
    if not training[playerName] then
        return
    end

    if training[playerName] == lastExecution then
        training[playerName] = nil
    end
end


local moveevent = MoveEvent()

function moveevent.onStepIn(creature, item, position, fromPosition)
    if not creature:isPlayer() then
        return true
    end
    local playerName = creature:getName():lower()
    local rand = training[playerName] and training[playerName] - 5 or math.random(1000000)
    training[playerName] = rand
    trainPlayer(creature:getId(), rand, playerName)
    return true
end

moveevent:aid(tileActionId)
moveevent:register()


local moveevent = MoveEvent()

function moveevent.onStepOut(creature, item, position, fromPosition)
    if not creature:isPlayer() then
        return true
    end
    
    local playerName = creature:getName():lower()
    if training[playerName] then
        addEvent(stopTraining, 0, playerName, training[playerName])
    end
    return true
end

moveevent:aid(tileActionId)
moveevent:register()
 
:)


Yep. Set chance to 0, to disable random raid
and then just configure specific time as needed.
2pm -> "14:00:00"
4pm -> "16:00:00"


For this, we'd need to send mail to the player, regardless of online status.
Probably like this, with the hacky mailbox method.

Everything else beyond that would be using onSpawn for every monster in the server, to give them an onDeath trigger, and a global table to hold information about the current event.

Let me know if that works for you, and I'll whip something up.


I think it would work well like this... Can you make something like this? Example:


"The hunting event has started! The player who manages to kill the highest number of "random creature" within 30 minutes will be the winner of the event! Hurry up!"


After 30 minutes, a global message appears informing everyone that the event has ended, the winner was player X, and the next event will start in 1 hour and 30 minutes.



And about the boss system, it looks amazing, I'll test it out! <3
 
I think it would work well like this... Can you make something like this? Example:


"The hunting event has started! The player who manages to kill the highest number of "random creature" within 30 minutes will be the winner of the event! Hurry up!"


After 30 minutes, a global message appears informing everyone that the event has ended, the winner was player X, and the next event will start in 1 hour and 30 minutes.



And about the boss system, it looks amazing, I'll test it out! <3

"The hunting event has started! The player who manages to kill the highest number of rat's within 30 minutes will be the winner of the event! Hurry up!"
"Xikini has taken the lead in the hunting event with 1 rat kills!"
"Bee King has taken the lead in the hunting event with 7 rat kills!"
"Xikini has taken the lead in the hunting event with 19 rat kills!"
"The hunting event has ended! Congratulations to the winner Xikini with 44 rat kills!"
"The next hunting event starts in 90 minutes."

^ example of how the event might go.

Untested.
LUA:
local config = {
    startupDelay = 5, -- minutes until first hunting event
    eventDuration = 30, -- minutes
    eventCooldown = 90, -- minutes
    creatureList = { -- will pull 1 random creature from this list to be hunted.
        "rat", "cave rat", "troll", "rotworm",
        "cyclops", "dragon", "dragon lord",
        "demon", "deer", "rabbit"
    },
    rewards = {
        {itemId = 1111, amount = 1}, -- player is parcelled 1 random thing from this list
        {itemId = 1111, amount = 1},
        {itemId = 1111, amount = 1}
    },
    mailboxPosition = Position(1000, 1000, 7)
}

-- don't edit below here

local event = {
    active = false,
    lastExecuted = 0,
    targetCreature = "",
    leader = {name = "", count = 0},
    playerInfo = {
        --[playerName] = killCount
    }
}

local function sendReward(playerName)
    local parcel = Game.createItem(ITEM_PARCEL, 1)
    local label = Game.createItem(2599, 1)
    local mailbox = Tile(config.mailboxPosition):getItemByType(ITEM_TYPE_MAILBOX)
    if mailbox == nil then
        print("No mailbox found at location. " .. playerName .. " did not recieve a reward for the hunting event due to this issue.")
        return true
    end
    doSetItemText(label.uid, playerName)
    local randReward = config.rewards[math.random(#config.rewards)]
    parcel:addItem(randReward.itemId, randReward.amount)
    parcel:addItemEx(label)
    mailbox:addItemEx(parcel)
end

local function startEvent()
    event.lastExecuted = currentTime
    event.active = true
    event.targetCreature = config.creatureList[math.random(#config.creatureList)]
    broadcastMessage("The hunting event has started! The player who manages to kill the highest number of " .. event.targetCreature .. "'s within " .. config.eventDuration .. " minutes will be the winner of the event! Hurry up!", MESSAGE_STATUS_DEFAULT)
end

local function endEvent()
    local message = "\nThe next hunting event will begin in " .. config.eventCooldown .. " minutes."
    if event.leader.name == "" then
        message = "The hunting event has ended with no participants." .. message
    else
        message = "The hunting event has ended! Congratulations to the winner " .. event.leader.name .. " with " .. event.leader.count .. " " ..  event.targetCreature .. " kills!" .. message
        sendReward(event.leader.name)
    end
    broadcastMessage(message, MESSAGE_STATUS_DEFAULT)
    event.active = false
    event.lastExecuted = currentTime
    event.targetCreature = ""
    event.leader = {name = "", count = 0}
    event.playerInfo = {}
end


local globalevent = GlobalEvent("onThink_HuntingEvent")

function globalevent.onThink()
    local currentTime = os.time()
    
    if event.lastExecuted == 0 then
        event.lastExecuted = currentTime - (config.eventCooldown * 60) + (config.startupDelay * 60)
    end
    
    -- Check if the event should start
    if not event.active and (currentTime - event.lastExecuted) >= (config.eventCooldown * 60) then
        startEvent()
    end
    
    -- Checks is the event should end
    if event.active and event.lastExecuted + (config.eventDuration * 60) < currentTime then
        endEvent()
    end    
    return true
end

globalevent:interval(1000) -- Check every second
globalevent:register()


local creatureevent = CreatureEvent("onDeath_HuntingEvent")

function creatureevent.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
    if event.active and creature:getName():lower() == event.targetCreature then
        if killer then
            if killer:getMaster() then
                killer = killer:getMaster()
            end
            if killer:isPlayer() then
                local name = killer:getName()
                event.playerInfo[name] = (event.playerInfo[name] or 0) + 1
                
                if event.leader.count < event.playerInfo[name] then
                    local newLeader = event.leader.name ~= name
                    event.leader.name = name
                    event.leader.count = event.playerInfo[name]
                    if newLeader then
                        broadcastMessage(event.leader.name .. " has taken the lead in the hunting event with " .. event.leader.count .. " " ..  event.targetCreature .. " kills!", MESSAGE_STATUS_DEFAULT)
                    end
                end
            end
        end
    end
    return true
end

creatureevent:register()


local eventCallback = EventCallback

function eventCallback.onSpawn(creature, position, startup, artificial)
    if table.contains(config.creatureList, creature:getName():lower()) then
        creature:registerEvent("onDeath_HuntingEvent")
    end
    return true
end

eventCallback:register(-666)
 
Could you replace the mailbox with maybe delivering a bag directly to the player or sending it to the Depot? My server doesn't have a mailbox. :(
 
Last edited:
Could you replace the mailbox with maybe delivering a bag directly to the player or sending it to the Depot? My server doesn't have a mailbox. :(
There's no other way to give an offline player an item.
So, no.

And how does your server not have a mailbox?
The parcel system has existed since forever.
There shouldn't be a single server that doesn't have the function.
 
And how does your server not have a mailbox?
Nekiro removed the mailbox from the source in this TFS 1.5, and they need to reimplement the code for the mailbox system to work again in the source. I think it’s a good idea to use the function local depotChest = player:getDepotChest(townId, true) to store items for the player if they are offline. Then, when the player logs in, the system can send the items and display a success message.

@Bee King Or you can implement the mailbox system in your source; here it is...
 
Status
Not open for further replies.
Back
Top