• 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

Xikini

I whore myself out for likes
Senator
Joined
Nov 17, 2010
Messages
6,931
Solutions
589
Reaction score
5,590
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:
I have seen a lot of scripts that raise the critical attribute.
But none that adds a weapon such an attribute that doesn't have it.

Could you write such a script for TFS 1.4.2?

E.g. use an item on a weapon, then it will add a critical hit chance and an item description +% on critical hit.
TFS 1.4.2 already has critical strike as attribute you just need an action that adds critical to the item.
enum SpecialSkills_t {
SPECIALSKILL_CRITICALHITCHANCE,
SPECIALSKILL_CRITICALHITAMOUNT,
SPECIALSKILL_LIFELEECHCHANCE,
SPECIALSKILL_LIFELEECHAMOUNT,
SPECIALSKILL_MANALEECHCHANCE,
SPECIALSKILL_MANALEECHAMOUNT,
hope it helps
 
Hi @Xikini. So good to see you back on this! Here's my request ^^

An alternative for raid system, entirely based on revscriptsys. What I need is to spawn a list of creatures (example firstlist = demon, skeleton, troll, then secondlist = deer, rabbit, rat), with a desired number (from 1 to 50 creatures for example), inside the area x to y (frompos, topos), and turnable z (true if you wan't to spawn creatures on upper floors or lower floors, false if you want to spawn only at z: 7) and start every "x" hours/minutes/etc.

What is really important is to check if the raid has been already excequted inside the coordinates, to avoid possible crashes. So this ideas comes to my mind.

a) Create specific monsters for the raid, so it checks inside the area for the monstername (a.k.a Rat2, Demon2, or RatEvent, DemonEvent). This way the check can differ from normal monsters (ex. if there's a rat inside rat raid area). and delete them all if a new wave of the raid is going to start.

b) It really needs a method to spawn monsters in good positions, far from traps, this is really challenging so I don't think this going to be solved really quick. I asked to zbisu's Nimbus bot to see how can a monster be spawned far from walls, it sent me something like this:

LUA:
local function isPositionValid(position)
    -- Check if the position is far from traps, closed spaces, and walls
    -- Implement your logic here to determine if the position is valid
    -- You can use functions like Tile.isWalkable, Tile.getTopUseThing, etc.
    -- to check for traps, closed spaces, and walls
    return true -- Return true if the position is valid, false otherwise
end

local function getRandomValidPosition()
    local maxAttempts = 100 -- Maximum number of attempts to find a valid position
    local position = nil

    for i = 1, maxAttempts do
        -- Generate a random position
        position = Position(math.random(100, 200), math.random(100, 200), 7)

        -- Check if the position is valid
        if isPositionValid(position) then
            return position -- Return the valid position
        end
    end

    return nil -- Return nil if a valid position couldn't be found
end

local function spawnMonster()
    local monsterName = "Monster" -- Replace with the name of the monster you want to spawn
    local position = getRandomValidPosition()

    if position then
        -- Spawn the monster at the valid position
        Game.createMonster(monsterName, position)
    else
        print("Couldn't find a valid position to spawn the monster.")
    end
end

-- Call the spawnMonster function to spawn the monster
spawnMonster()

No idea if this is going to be a good starting point. Anyways, I guess I have attached the most important stuff, i'm sure that you will get a much better idea than me once you think it as code. Thanks in advance!

PS. If it is possible too, would like to request a talkaction to trigger the raid. That works along with the other parameters such as time, if is running or not, etc.

To be clear, this is a fully functioning raid system built in Lua.
Short video to showcase, and description of the talkaction, but all the normal features of the default raid system should be there.

talkaction sets a custom time for a raid to start.
!executeRaid raidName, time, forceNewRaidInstance

usage
-> !executeRaid -- will tell you all the raid names in the server, and some instructions on how to use the command

-> !executeRaid raidName -- will start the raid immediately
-> !executeRaid raidName, cancel -- will cancel currently running raid, and remove all previously spawned monsters
-> !executeRaid raidName, check -- will tell you information about a specific raid. (active / if all monsters dead)
-> !executeRaid raidName, nil, true -- will start the raid immediately & remove all previous raid monsters (of that specific raid)
-> !executeRaid raidName, nil, false -- will start the raid immediately & use default settings for that raid (remove or don't remove monsters)
-> !executeRaid raidName, 07:00:00 -- will start the raid at 7am (assuming the server stays online that long)

-> !executeRaid raidName, list -- will give a list of all Custom Scheduled raid events for that specific raid
-> !executeRaid raidName, 07:00:00, remove -- will remove a custom scheduled raid event for that specific raid

---
And there is also 'raid items' that are consumable, for players to force specific raids to spawn.

bandicam2024-02-0202-16-47-550-ezgif.com-video-to-gif-converter(1).gif

data/lib/core/core.lua -- add
LUA:
data/lib/core/xikiniCustomFunctions.lua
data/lib/core/xikiniCustomFunctions.lua -- add
LUA:
MONSTER_STORAGE = MONSTER_STORAGE or {}

function Monster.setStorageValue(self, key, value)
    local cid = self:getId()
    local storageMap = MONSTER_STORAGE[cid]
    if not storageMap then
        MONSTER_STORAGE[cid] = {[key] = value}
    else
        storageMap[key] = value
    end
end

function Monster.getStorageValue(self, key)
    local storageMap = MONSTER_STORAGE[self:getId()]
    if storageMap then
        return storageMap[key] or -1
    end
    return -1
end

data/scripts/raidSystemInLua.lua
LUA:
-- Check the attachments. Code is too large to post.
 

Attachments

Last edited:
TFS 1.4.2 already has critical strike as attribute you just need an action that adds critical to the item.
enum SpecialSkills_t {
SPECIALSKILL_CRITICALHITCHANCE,
SPECIALSKILL_CRITICALHITAMOUNT,
SPECIALSKILL_LIFELEECHCHANCE,
SPECIALSKILL_LIFELEECHAMOUNT,
SPECIALSKILL_MANALEECHCHANCE,
SPECIALSKILL_MANALEECHAMOUNT,
hope it helps
I addressed another issue with him and it appears he didn't test it, or perhaps didn't register it in movements.xml to make certain critical functioning occur. Just adding our items and making the description appear is not enough; in fact, it needs to be registered in movements.xml. Additionally, I provided a script via weapons.xml that would also trigger critical right and work fine. I don't understand what this guy is thinking, haha.
 
I addressed another issue with him and it appears he didn't test it, or perhaps didn't register it in movements.xml to make certain critical functioning occur. Just adding our items and making the description appear is not enough; in fact, it needs to be registered in movements.xml. Additionally, I provided a script via weapons.xml that would also trigger critical right and work fine. I don't understand what this guy is thinking, haha.

I tested by adding this to each weapon in items.xml and ok it works, but when I initially want the weapon to be 0% (i.e. standard) then it doesn't work.
I would like to add something like imbuments.
Only in 10.98.

That is, there were scripts , which increased the critical chance from 1% to 10%, for example.
But if the item had 0% it did not add 10% + description.
It simply did not work, it did not want to give a new attribute, it was only possible to change it.
 
I tested by adding this to each weapon in items.xml and ok it works, but when I initially want the weapon to be 0% (i.e. standard) then it doesn't work.
I would like to add something like imbuments.
Only in 10.98.

That is, there were scripts , which increased the critical chance from 1% to 10%, for example.
But if the item had 0% it did not add 10% + description.
It simply did not work, it did not want to give a new attribute, it was only possible to change it.
Now I comprehend your intentions. Why didn't you furnish more elaborate details to enhance clarity? The summary you provided was rather concise, rendering it challenging to grasp. If I understand correctly, in the standard system, clicking on the item yields a 0.1% increase and triggers a critical reaction. Subsequently, clicking on the item again escalates the percentage to 0.2%, and eventually up to 0.10%. Indeed, there are scripts and systems circulating across certain networks.
 
I would like to request assistance with another matter. I have attempted to create a script but was unable to finalize it due to my limited expertise, particularly in modal window implementation. I kindly ask for your assistance in reviewing and rectifying any deficiencies in the script. Allow me to provide an explanation of how this system operates. The Teleport-Pos feature enables the saving of up to three coordinates, which can then be accessed from different locations. Upon clicking the Teleport-Pos item, a modal window for Teleport Coordinates will appear, facilitating the saving of multiple positions. Unlike standard teleportation methods, this feature ensures reliability and does not compromise the integrity of the coordinates. Additionally, manual removal of coordinates is possible should the need arise for replacement. Upon successfully saving a coordinate, a confirmation message will indicate 'positions saved'. To utilize the saved positions, simply select the desired one and click 'go'. This functionality streamlines the process of navigating to previously saved locations. I would greatly appreciate any assistance you can provide in this matter.


Upon using the item, a modal window appears, but it does not save the coordinates. There may be something missing, I'm not sure
LUA:
local BUTTON_SAVE = 100
local BUTTON_TELEPORT = 101
local BUTTON_CANCEL = 102

local TELEPORT_STORAGE = 54646
local KEY_PREFIX = "TeleportPos_"
local MAX_POSITIONS = 3

function createTeleportModal(player)
    local modal = ModalWindow(100, "Teleport-Pos", "Choose a position to teleport:")
    modal:addButton(BUTTON_SAVE, "Save")
    modal:addButton(BUTTON_TELEPORT, "Teleport")
    modal:addButton(BUTTON_CANCEL, "Cancel")

    for i = 1, MAX_POSITIONS do
        local coordinates = getSavedCoordinates(player, i)
        if coordinates then
            modal:addChoice(i, "Position " .. i .. ": (" .. coordinates.x .. ", " .. coordinates.y .. ", " .. coordinates.z .. ")")
        end
    end

    modal:setDefaultEnterButton(BUTTON_TELEPORT)
    modal:setDefaultEscapeButton(BUTTON_CANCEL)

    modal:sendToPlayer(player)
end

local tpModal = CreatureEvent("Teleport-Pos")

function tpModal.onModalWindow(player, modalWindowId, buttonId, choiceId)
    if modalWindowId == 100 then
        if buttonId == BUTTON_SAVE then
            local x, y, z = player:getPosition().x, player:getPosition().y, player:getPosition().z
            if saveCoordinates(player, choiceId, {x = x, y = y, z = z}) then
                player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Position saved successfully!")
            else
                player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Failed to save the position.")
            end
        elseif buttonId == BUTTON_TELEPORT then
            local coordinates = getSavedCoordinates(player, choiceId)
            if coordinates then
                tpBack(player, nil, nil, nil, nil)
            else
                player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Position not found.")
            end
        elseif buttonId == BUTTON_CANCEL then
            player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Action canceled.")
        end
    end
end

tpModal:register()

local tp = Action()


function tp.onUse(player, item, fromPosition, itemEx, toPosition, isHotkey)
    createTeleportModal(player)
    return true
end


function saveCoordinates(player, index, coordinates)
    if index > 0 and index <= MAX_POSITIONS then
        player:setStorageValue(TELEPORT_STORAGE, KEY_PREFIX .. index .. "_x", coordinates.x)
        player:setStorageValue(TELEPORT_STORAGE, KEY_PREFIX .. index .. "_y", coordinates.y)
        player:setStorageValue(TELEPORT_STORAGE, KEY_PREFIX .. index .. "_z", coordinates.z)
        return true
    end
    return false
end


function getSavedCoordinates(player, index)
    if index > 0 and index <= MAX_POSITIONS then
        local x = player:getStorageValue(TELEPORT_STORAGE, KEY_PREFIX .. index .. "_x")
        local y = player:getStorageValue(TELEPORT_STORAGE, KEY_PREFIX .. index .. "_y")
        local z = player:getStorageValue(TELEPORT_STORAGE, KEY_PREFIX .. index .. "_z")
        if x ~= nil and y ~= nil and z ~= nil then
            return {x = x, y = y, z = z}
        end
    end
    return nil
end

tp:id(39557)
tp:register()

bandicam2024-02-0306-02-26-126-ezgif.com-video-to-gif-converter.gif

data/lib/core/core.lua -- add
LUA:
dofile('data/lib/core/xikiniCustomFunctions.lua')
data/lib/core/xikiniCustomFunctions.lua -- add
LUA:
--[[ quick reference of events

    CREATURE_EVENT_NONE
    CREATURE_EVENT_LOGIN
    CREATURE_EVENT_LOGOUT
    CREATURE_EVENT_THINK
    CREATURE_EVENT_PREPAREDEATH
    CREATURE_EVENT_DEATH
    CREATURE_EVENT_KILL
    CREATURE_EVENT_ADVANCE
    CREATURE_EVENT_MODALWINDOW
    CREATURE_EVENT_TEXTEDIT
    CREATURE_EVENT_HEALTHCHANGE
    CREATURE_EVENT_MANACHANGE
    CREATURE_EVENT_EXTENDED_OPCODE
]]--

function Player:hasEvent(type, name)
    for k, v in pairs(self:getEvents(type)) do
        if v == name then
            return true
        end
    end
    return false
end

data/scripts/onUse_RemoveSaveTeleport.lua
LUA:
local teleportItemId = 11134

local config = {
    modalWindow = {
        id = 1000,
        title = "Teleport-Pos",
        message = "Choose a position to teleport",
        eventText = "ModalWindow_RemoveSaveTeleport",
        buttons = {
            {text = "Remove"},
            {text = "Save"},
            {text = "Teleport", defaultEnterButton = true},
            {text = "Cancel", defaultEscapeButton = true},
        }
    },
    teleport = {
        {45026, 45027, 45028}, -- these are storageKeys
        {45029, 45030, 45031}, 
        {45032, 45033, 45034}  -- add as many as you want. just make sure all the storages are unused, and unique
    }
}

local function createTeleportWindow(playerId)
    local player = Player(playerId)
    if not player then
        return
    end

    if player:hasEvent(CREATURE_EVENT_MODALWINDOW, config.modalWindow.eventText) then
        player:unregisterEvent(config.modalWindow.eventText)
    end
    player:registerEvent(config.modalWindow.eventText)
    
    local modalWindow = ModalWindow(config.modalWindow.id, config.modalWindow.title, config.modalWindow.message)
    
    for id, button in ipairs(config.modalWindow.buttons) do
        modalWindow:addButton(id, button.text)
        if button.defaultEscapeButton then
            modalWindow:setDefaultEscapeButton(id)
        elseif button.defaultEnterButton then
            modalWindow:setDefaultEnterButton(id)
        end
    end        

    for id, v in ipairs(config.teleport) do
        local x = player:getStorageValue(v[1])
        local y = player:getStorageValue(v[2])
        local z = player:getStorageValue(v[3])
        local text = x ~= -1 and string.format("Position(%s, %s, %s)", x, y, z) or "No position saved."
        modalWindow:addChoice(id, text)
    end
    
    modalWindow:hasPriority()
    modalWindow:sendToPlayer(player)
end


local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    createTeleportWindow(player:getId())
    return true
end

action:id(teleportItemId)
action:register()


local creatureevent = CreatureEvent(config.modalWindow.eventText)

function creatureevent.onModalWindow(player, modalWindowId, buttonId, choiceId)
    player:unregisterEvent(config.modalWindow.eventText)
    
    if modalWindowId == config.modalWindow.id then
        local buttonChoice = config.modalWindow.buttons[buttonId].text
        
        if buttonChoice == "Teleport" then
            local x = player:getStorageValue(config.teleport[choiceId][1])
            local y = player:getStorageValue(config.teleport[choiceId][2])
            local z = player:getStorageValue(config.teleport[choiceId][3])
            if x ~= -1 then
                local position = Position(x, y, z)
                player:teleportTo(position)
                position:sendMagicEffect(CONST_ME_TELEPORT)
            end
        elseif buttonChoice == "Save" then
            local playerPosition = player:getPosition()
            player:setStorageValue(config.teleport[choiceId][1], playerPosition.x)
            player:setStorageValue(config.teleport[choiceId][2], playerPosition.y)
            player:setStorageValue(config.teleport[choiceId][3], playerPosition.z)
            
        elseif buttonChoice == "Remove" then
            player:setStorageValue(config.teleport[choiceId][1], -1)
            player:setStorageValue(config.teleport[choiceId][2], -1)
            player:setStorageValue(config.teleport[choiceId][3], -1)
        else
            -- "Cancel" button
            return true
        end
        
        addEvent(createTeleportWindow, 0, player:getId())
    end
    return true
end

creatureevent:register()
Post automatically merged:

Script regarding players in guilds.

If a player is in a guild and beats someone who has another guild - he doesn't get a frag.
If he kills someone from his guild, he has a frag.
Of course, if someone from a guild kills players without a guild and vice versa, he also gets a frag.
Unfortunately I've learned that all 'frag' information is stored in the database, with no default functions to manipulate it.

So, this falls under database queries and will not be scripted.
 
Last edited:
Hello, I need help with a script. It would be like a raid. a rift that opens in a hunt and spawns boosted creatures in random positions. After players kill all creatures, other creatures in that area gain a boost in XP and loot for a certain time.
 
View attachment 81824

data/lib/core/core.lua -- add
LUA:
dofile('data/lib/core/xikiniCustomFunctions.lua')
data/lib/core/xikiniCustomFunctions.lua -- add
LUA:
--[[ quick reference of events

    CREATURE_EVENT_NONE
    CREATURE_EVENT_LOGIN
    CREATURE_EVENT_LOGOUT
    CREATURE_EVENT_THINK
    CREATURE_EVENT_PREPAREDEATH
    CREATURE_EVENT_DEATH
    CREATURE_EVENT_KILL
    CREATURE_EVENT_ADVANCE
    CREATURE_EVENT_MODALWINDOW
    CREATURE_EVENT_TEXTEDIT
    CREATURE_EVENT_HEALTHCHANGE
    CREATURE_EVENT_MANACHANGE
    CREATURE_EVENT_EXTENDED_OPCODE
]]--

function Player:hasEvent(type, name)
    for k, v in pairs(self:getEvents(type)) do
        if v == name then
            return true
        end
    end
    return false
end

data/scripts/onUse_RemoveSaveTeleport.lua
LUA:
local teleportItemId = 11134

local config = {
    modalWindow = {
        id = 1000,
        title = "Teleport-Pos",
        message = "Choose a position to teleport",
        eventText = "ModalWindow_RemoveSaveTeleport",
        buttons = {
            {text = "Remove"},
            {text = "Save"},
            {text = "Teleport", defaultEnterButton = true},
            {text = "Cancel", defaultEscapeButton = true},
        }
    },
    teleport = {
        {45026, 45027, 45028}, -- these are storageKeys
        {45029, 45030, 45031},
        {45032, 45033, 45034}  -- add as many as you want. just make sure all the storages are unused, and unique
    }
}

local function createTeleportWindow(playerId)
    local player = Player(playerId)
    if not player then
        return
    end

    if player:hasEvent(CREATURE_EVENT_MODALWINDOW, config.modalWindow.eventText) then
        player:unregisterEvent(config.modalWindow.eventText)
    end
    player:registerEvent(config.modalWindow.eventText)
   
    local modalWindow = ModalWindow(config.modalWindow.id, config.modalWindow.title, config.modalWindow.message)
   
    for id, button in ipairs(config.modalWindow.buttons) do
        modalWindow:addButton(id, button.text)
        if button.defaultEscapeButton then
            modalWindow:setDefaultEscapeButton(id)
        elseif button.defaultEnterButton then
            modalWindow:setDefaultEnterButton(id)
        end
    end       

    for id, v in ipairs(config.teleport) do
        local x = player:getStorageValue(v[1])
        local y = player:getStorageValue(v[2])
        local z = player:getStorageValue(v[3])
        local text = x ~= -1 and string.format("Position(%s, %s, %s)", x, y, z) or "No position saved."
        modalWindow:addChoice(id, text)
    end
   
    modalWindow:hasPriority()
    modalWindow:sendToPlayer(player)
end


local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    createTeleportWindow(player:getId())
    return true
end

action:id(teleportItemId)
action:register()


local creatureevent = CreatureEvent(config.modalWindow.eventText)

function creatureevent.onModalWindow(player, modalWindowId, buttonId, choiceId)
    player:unregisterEvent(config.modalWindow.eventText)
   
    if modalWindowId == config.modalWindow.id then
        local buttonChoice = config.modalWindow.buttons[buttonId].text
       
        if buttonChoice == "Teleport" then
            local x = player:getStorageValue(config.teleport[choiceId][1])
            local y = player:getStorageValue(config.teleport[choiceId][2])
            local z = player:getStorageValue(config.teleport[choiceId][3])
            if x ~= -1 then
                local position = Position(x, y, z)
                player:teleportTo(position)
                position:sendMagicEffect(CONST_ME_TELEPORT)
            end
        elseif buttonChoice == "Save" then
            local playerPosition = player:getPosition()
            player:setStorageValue(config.teleport[choiceId][1], playerPosition.x)
            player:setStorageValue(config.teleport[choiceId][2], playerPosition.y)
            player:setStorageValue(config.teleport[choiceId][3], playerPosition.z)
           
        elseif buttonChoice == "Remove" then
            player:setStorageValue(config.teleport[choiceId][1], -1)
            player:setStorageValue(config.teleport[choiceId][2], -1)
            player:setStorageValue(config.teleport[choiceId][3], -1)
        else
            -- "Cancel" button
            return true
        end
       
        addEvent(createTeleportWindow, 0, player:getId())
    end
    return true
end

creatureevent:register()
Post automatically merged:


Unfortunately I've learned that all 'frag' information is stored in the database, with no default functions to manipulate it.

So, this falls under database queries and will not be scripted.
Thank you very much for completing the script that I tested and approved. It works GREAT. I wasn't aware that I needed to add "data/lib/core"; I will study more about that. Thank you very much. The script is top-notch and fantastic!
 
Hello thanks and for your time!

[Script Request]
A script that will show top 3 players clones, name, outfit and level as a monster?

Players name [LvL: 999]

Thank you!

Video shows it updating every 1 second, but in live server I recommend updating every 5+ minutes.

bandicam2024-02-0308-01-07-711-ezgif.com-video-to-gif-converter.gif

data/scripts/showTopOnlinePlayers.lua
LUA:
local checkInterval = 1 -- seconds (recommend like 5+ minutes inbetween checks. getting all online players is a fairly expensive operation.)

local topPlayers = {
    {playerId = 0, monsterId = 0, position = Position(998, 1003, 7)},  -- only edit the position of where the monster will spawn
    {playerId = 0, monsterId = 0, position = Position(1000, 1002, 7)},
    {playerId = 0, monsterId = 0, position = Position(1002, 1003, 7)}  -- if you want to show more then 3 players, just keep adding more into the table.
}


local function setMonsterDefaultSettings(monster)
    monster:rename("Top Player [LvL: ??]", "a top online placeholder creature")
    local outfit = monster:getOutfit()
    outfit.lookType = 0
    outfit.lookTypeEx = 2110
    monster:setOutfit(outfit)
end

local function createTopScoreMonster(index)
    local monster = Game.createMonster("deer", topPlayers[index].position, false, true)
    monster:setDropLoot(false)
    topPlayers[index].monsterId = monster:getId()
    setMonsterDefaultSettings(monster)
    return monster
end


local globalevent = GlobalEvent("onThink_showTopOnlinePlayers")

function globalevent.onThink(interval)
    local onlinePlayers = Game.getPlayers()
   
    local players = {}
    local seenIds = {}
   
    for k, v in ipairs(topPlayers) do
        local player = Player(v.playerId)
        if player and not seenIds[v.playerId] then
            players[#players + 1] = {level = player:getLevel(), id = v.playerId}
            seenIds[v.playerId] = true
        else
            v.playerId = 0
        end
    end   
    for _, player in pairs(onlinePlayers) do
        local playerId = player:getId()
        if not seenIds[playerId] and not player:getGroup():getAccess() then
            players[#players + 1] = {level = player:getLevel(), id = playerId}
            seenIds[playerId] = true
        end
    end
    table.sort(players, function(a, b) return a.level > b.level    end)
   
    for k, v in ipairs(topPlayers) do
        local monster = Monster(v.monsterId)
        if players[k] then
            v.playerId = players[k].id
            local player = Player(v.playerId)
           
            if not monster then
                monster = createTopScoreMonster(k)
            end
           
            local newName = string.format("%s [LvL: %s]", player:getName(), players[k].level)
            monster:rename(newName, "the current #" .. k .. " online player " .. newName)
            local outfit = player:getOutfit()
            monster:setOutfit(outfit)
        else
            if monster then
                setMonsterDefaultSettings(monster)
            end
        end
    end
    return true
end

globalevent:interval(checkInterval * 1000)
globalevent:register()


local globalevent = GlobalEvent("onStartup_showTopOnlinePlayers")

function globalevent.onStartup()
    for k, v in pairs(topPlayers) do
        createTopScoreMonster(k)
    end
    return true
end

globalevent:register()
Post automatically merged:

Hi,
I would need a code that will show in the onLook function how many kills a person has (since the beginning of his game on the server).

Additionally, I have an old frag system (3 kills to RS).
I would like it to:

1.) If a player who has a guild, kills a person from another guild he will not receive any frag.
2.) If a person having a guild kills a player from his guild he will receive a frag.
3.) If a person without a guild kills a person who has a guild and vice versa, also receives a fraga.

In summary, if a person participates in a guild and kills a person from another guild, he does not receive a frage.
Statistical kills must be counted normally, but are not penalized with a frag.

So as explained earlier, I cannot stop a frag from occurring, but I can definitely count how many frags a person has done. (since the script was installed.)
Video shows killing same guild killing, but the script checks for players in different guilds as you wanted. Just a mistake when filming.

bandicam2024-02-0308-30-02-782online-video-cutter.com-ezgif.com-video-to-gif-converter.gif

data/scripts/eventcallbacks/player/default_onLook.lua
under
LUA:
    local description = "You see " .. thing:getDescription(distance)
add
LUA:
    if thing:isPlayer() then
        local frags = math.max(thing:getStorageValue(FRAG_STORAGE_KEY), 0)
        description = string.format("%s %s have %s frags.", description, self == thing and "You" or "They", frags)
    end

data/scripts/eventcallbacks/player/default_onLookInBattleList.lua
under
LUA:
    local description = "You see " .. creature:getDescription(distance)
add
LUA:
    if creature:isPlayer() then
        local frags = math.max(creature:getStorageValue(FRAG_STORAGE_KEY), 0)
        description = string.format("%s %s have %s frags.", description, self == thing and "You" or "They", frags)
    end

data/scripts/fragCounter_onLook_onKill.lua
LUA:
FRAG_STORAGE_KEY = 45035

local creatureevent = CreatureEvent("onKill_FragCounter")

function creatureevent.onKill(creature, target)
    if target:isPlayer() then
        local giveFrag = true
     
        local targetGuild = target:getGuild()
        local creatureGuild = creature:getGuild()
        if targetGuild and creatureGuild then
            if creatureGuild:getId() ~= targetGuild:getId() then
                giveFrag = false
            end
        end     
     
        if giveFrag then
            local frags = math.max(creature:getStorageValue(FRAG_STORAGE_KEY), 0)
            creature:setStorageValue(FRAG_STORAGE_KEY, frags + 1)
        end
    end
    return true
end

creatureevent:register()



local creatureevent = CreatureEvent("onLogin_FragCounter")

function creatureevent.onLogin(player)
    player:registerEvent("onKill_FragCounter")
    return true
end

creatureevent:register()
Post automatically merged:

Can you make a script where 1 monster to rotate the Dangerous Apparatus onStep on tiles next to it, to face next direction till we make it reposition correct, until it all face the Strange Machine. You have to reposition all the Dangerous Apparatus in 15 minutes or you get kicked of the room. After repositioning all the Dangerous Apparatus then a tp open for 2 min to next mission.After 15 minutes all Dangerous Apparatus shuffle directions again when all players kicked or failed.
thank you In advance

latest

So many questions..

1 monster to rotate the Dangerous Apparatus onStep on tiles next to it
If a monster is running around and rotating these things.. how would it ever find all the correct directions?

to face next direction till we make it reposition correct, until it all face the Strange Machine.
Does this mean you can't over-rotate?
How would I determine what 'face the Strange machine' is on a diagonal?

You have to reposition all the Dangerous Apparatus in 15 minutes or you get kicked of the room.
How do I know when the players entered the room?
If players enter in staggered intervals.. first person enters, then another person 7 minutes later, do I still kick both players out? or just the first person?

After 15 minutes all Dangerous Apparatus shuffle directions again when all players kicked or failed.
Or only when players are kicked? Is it shuffled when each person is kicked, or only if no players remain in the room? Does it happen after the teleport appears and disappears?

I really need a better explanation here. xD
Post automatically merged:

Hi there, I have a request if its possible to make.

Info:
  • TFS 1.4.2
  • Client 10.98

When a player reaches a certain lvl they will receive an item (this system is already in place). This item they can right-click to open a list of items. They can only choose ONE out of these items. When they have chosen the item they want (confirm button) , the chosen item will be added to the players backpack, and maybe a text will be displayed with the name of the item they choose. Then the item they right-clicked on will be deleted.
There would also need to be a cancel button where the item they right-clicked (the original reward) is not deleted, and can be opened at a later point.

It would also be a great feature if the player could click on any of the items in the list and press a "Details" button to get more info about the items before making their choice.

------------------------------------
I've tried editing an already existing crafting script where a lot of this is already possible, but I don't need it to be a "crafting-script" per say where you need ingredients etc.. And the script I tried to edit also doesn't show any information about the item, only the name and the ingredients it takes to craft it.

Hopefully this is a challenge you are up for and doesn't prove impossible :D

Ask me if anything is unclear.


- Erik

bandicam2024-02-0310-45-01-916-ezgif.com-video-to-gif-converter.gif

data/scripts/onUse_chooseItemReward.lua
LUA:
local rewardBagItemId = 1950

local config = {
    modalWindow = {
        id = 1001, -- needs to be unique number?
        title = "Reward Bag",
        message = "Choose a reward from the list!",
        eventText = "ModalWindow_Reward_Bag",
        buttons = {
            {text = "Choose", defaultEnterButton = true},
            {text = "Cancel", defaultEscapeButton = true},
        }
    },
    rewards = {
        {itemId = 2160, amount = 1},
        {itemId = 2160, amount = 3}, -- add as many as you want.
        {itemId = 2160, amount = 10}
    }
}

-- END OF CONFIG

local usedItems = {
--    [playerId] = item
}

local function getItemNameString(item)
    return item:getNameDescription(item:getSubType(), true)
end

local function createRewardBagWindow(playerId)
    local player = Player(playerId)
    if not player then
        return
    end

    if player:hasEvent(CREATURE_EVENT_MODALWINDOW, config.modalWindow.eventText) then
        player:unregisterEvent(config.modalWindow.eventText)
    end
    player:registerEvent(config.modalWindow.eventText)
  
    local modalWindow = ModalWindow(config.modalWindow.id, config.modalWindow.title, config.modalWindow.message)
  
    for id, button in ipairs(config.modalWindow.buttons) do
        modalWindow:addButton(id, button.text)
        if button.defaultEscapeButton then
            modalWindow:setDefaultEscapeButton(id)
        elseif button.defaultEnterButton then
            modalWindow:setDefaultEnterButton(id)
        end
    end      

    for id, v in ipairs(config.rewards) do
        local item = Game.createItem(v.itemId, v.amount)
        local text = getItemNameString(item)
        modalWindow:addChoice(id, text)
    end
  
    modalWindow:hasPriority()
    modalWindow:sendToPlayer(player)
end


local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local _player = Player(item:getTopParent())
    if not _player then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag must be in your inventory to be used.")
        player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
        return true
    end
    usedItems[player:getId()] = item
    createRewardBagWindow(player:getId())
    return true
end

action:id(rewardBagItemId)
action:register()


local creatureevent = CreatureEvent(config.modalWindow.eventText)

function creatureevent.onModalWindow(player, modalWindowId, buttonId, choiceId)
    player:unregisterEvent(config.modalWindow.eventText)
  
    if modalWindowId == config.modalWindow.id then
        local buttonChoice = config.modalWindow.buttons[buttonId].text
        local playerId = player:getId()
      
        if buttonChoice == "Choose" then
            local usedItem = usedItems[playerId]
            if not usedItem or not Item(usedItem.uid) then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag no longer exists.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                usedItems[playerId] = nil
                return true
            end
            local _player = Player(usedItem:getTopParent())
            if not _player or _player:getId() ~= playerId then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag must be in your inventory to be used.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                usedItems[playerId] = nil
                return true
            end
            local item = Game.createItem(config.rewards[choiceId].itemId, config.rewards[choiceId].amount)
            if not player:addItemEx(item, false) then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "You do not have the room or capacity to receive this item.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                usedItems[playerId] = nil
                return true
            end
            player:say("You received " .. getItemNameString(item), TALKTYPE_MONSTER_SAY, nil, player)
            player:getPosition():sendMagicEffect(CONST_ME_HEARTS)
            usedItem:remove(1)
            usedItems[playerId] = nil
        else
            -- "Cancel" button
            usedItems[playerId] = nil
            return true
        end
      
    end
    return true
end

creatureevent:register()
Post automatically merged:

hey man,

i am wondering if you could make a rev script with this function:

there is an amulet (xxxx) id, when you use (x) id item on this amulet it gains stats.

there should be 6 diffrent stones 1 for each element (fire, earth, ice, energy, death and holy) each stone should give 0.5% if thats possible else 1% stats to this amulet stacking up to max 10% protection.

if rev script isnt possible then other things could work aswell.

thx in advance! :)
I have seen a lot of scripts that raise the critical attribute.
But none that adds a weapon such an attribute that doesn't have it.

Could you write such a script for TFS 1.4.2?

E.g. use an item on a weapon, then it will add a critical hit chance and an item description +% on critical hit.

Unfortunately as of right now, this appears to be impossible.
There does not seem to be a way to apply this directly to the items.

I can grab the information about the items.. but can't apply it in any manner.

Example
LUA:
    local itemabilities = ItemType(11355):getAbilities()
  
    for k, v in pairs(itemabilities) do
        print(k, v)
    end
    print("------")
    for k, v in pairs(itemabilities.absorbPercent) do
        print(k, v)
    end
outputs
Code:
manaGain        0
manaTicks       0
statsPercent    table: 0x18a61bf8
speed   0
conditionSuppressions   0
invisible       false
fieldAbsorbPercent      table: 0x18ba9bb0
specialSkills   table: 0x18ba9a98
elementDamage   0
conditionImmunities     0
absorbPercent   table: 0x18ba9c08
skills  table: 0x18a61cb0
regeneration    false
healthGain      0
stats   table: 0x18a61b68
manaShield      false
elementType     0
healthTicks     0
------
2       10
5       0
12      0
11      0
4       0
10      0
9       0
8       0
3       -10
7       0
1       0
6       0
 
Last edited:
Video shows it updating every 1 second, but in live server I recommend updating every 5+ minutes.

View attachment 81831

data/scripts/showTopOnlinePlayers.lua
LUA:
local checkInterval = 1 -- seconds (recommend like 5+ minutes inbetween checks. getting all online players is a fairly expensive operation.)

local topPlayers = {
    {playerId = 0, monsterId = 0, position = Position(998, 1003, 7)},  -- only edit the position of where the monster will spawn
    {playerId = 0, monsterId = 0, position = Position(1000, 1002, 7)},
    {playerId = 0, monsterId = 0, position = Position(1002, 1003, 7)}  -- if you want to show more then 3 players, just keep adding more into the table.
}


local function setMonsterDefaultSettings(monster)
    monster:rename("Top Player [LvL: ??]", "a top online placeholder creature")
    local outfit = monster:getOutfit()
    outfit.lookType = 0
    outfit.lookTypeEx = 2110
    monster:setOutfit(outfit)
end

local function createTopScoreMonster(index)
    local monster = Game.createMonster("rotworm", topPlayers[index].position, false, true)
    topPlayers[index].monsterId = monster:getId()
    setMonsterDefaultSettings(monster)
    return monster
end


local globalevent = GlobalEvent("onThink_showTopOnlinePlayers")

function globalevent.onThink(interval)
    local onlinePlayers = Game.getPlayers()
  
    local players = {}
    local seenIds = {}
  
    for k, v in ipairs(topPlayers) do
        local player = Player(v.playerId)
        if player and not seenIds[v.playerId] then
            players[#players + 1] = {level = player:getLevel(), id = v.playerId}
            seenIds[v.playerId] = true
        else
            v.playerId = 0
        end
    end  
    for _, player in pairs(onlinePlayers) do
        local playerId = player:getId()
        if not seenIds[playerId] and not player:getGroup():getAccess() then
            players[#players + 1] = {level = player:getLevel(), id = playerId}
            seenIds[playerId] = true
        end
    end
    table.sort(players, function(a, b) return a.level > b.level    end)
  
    for k, v in ipairs(topPlayers) do
        local monster = Monster(v.monsterId)
        if players[k] then
            v.playerId = players[k].id
            local player = Player(v.playerId)
          
            if not monster then
                monster = createTopScoreMonster(k)
            end
          
            local newName = string.format("%s [LvL: %s]", player:getName(), players[k].level)
            monster:rename(newName, "the current #" .. k .. " online player " .. newName)
            local outfit = player:getOutfit()
            monster:setOutfit(outfit)
        else
            if monster then
                setMonsterDefaultSettings(monster)
            end
        end
    end
    return true
end

globalevent:interval(checkInterval * 1000)
globalevent:register()


local globalevent = GlobalEvent("onStartup_showTopOnlinePlayers")

function globalevent.onStartup()
    for k, v in pairs(topPlayers) do
        createTopScoreMonster(k)
    end
    return true
end

globalevent:register()
Post automatically merged:



So as explained earlier, I cannot stop a frag from occurring, but I can definitely count how many frags a person has done. (since the script was installed.)
Video shows killing same guild killing, but the script checks for players in different guilds as you wanted. Just a mistake when filming.

View attachment 81832

data/scripts/eventcallbacks/player/default_onLook.lua
under
LUA:
    local description = "You see " .. thing:getDescription(distance)
add
LUA:
    if thing:isPlayer() then
        local frags = math.max(thing:getStorageValue(FRAG_STORAGE_KEY), 0)
        description = string.format("%s %s have %s frags.", description, self == thing and "You" or "They", frags)
    end

data/scripts/eventcallbacks/player/default_onLookInBattleList.lua
under
LUA:
    local description = "You see " .. creature:getDescription(distance)
add
LUA:
    if creature:isPlayer() then
        local frags = math.max(creature:getStorageValue(FRAG_STORAGE_KEY), 0)
        description = string.format("%s %s have %s frags.", description, self == thing and "You" or "They", frags)
    end

data/scripts/fragCounter_onLook_onKill.lua
LUA:
FRAG_STORAGE_KEY = 45035

local creatureevent = CreatureEvent("onKill_FragCounter")

function creatureevent.onKill(creature, target)
    if target:isPlayer() then
        local giveFrag = true
      
        local targetGuild = target:getGuild()
        local creatureGuild = creature:getGuild()
        if targetGuild and creatureGuild then
            if creatureGuild:getId() ~= targetGuild:getId() then
                giveFrag = false
            end
        end      
      
        if giveFrag then
            local frags = math.max(creature:getStorageValue(FRAG_STORAGE_KEY), 0)
            creature:setStorageValue(FRAG_STORAGE_KEY, frags + 1)
        end
    end
    return true
end

creatureevent:register()



local creatureevent = CreatureEvent("onLogin_FragCounter")

function creatureevent.onLogin(player)
    player:registerEvent("onKill_FragCounter")
    return true
end

creatureevent:register()
Post automatically merged:



So many questions..

1 monster to rotate the Dangerous Apparatus onStep on tiles next to it
If a monster is running around and rotating these things.. how would it ever find all the correct directions?

to face next direction till we make it reposition correct, until it all face the Strange Machine.
Does this mean you can't over-rotate?
How would I determine what 'face the Strange machine' is on a diagonal?

You have to reposition all the Dangerous Apparatus in 15 minutes or you get kicked of the room.
How do I know when the players entered the room?
If players enter in staggered intervals.. first person enters, then another person 7 minutes later, do I still kick both players out? or just the first person?

After 15 minutes all Dangerous Apparatus shuffle directions again when all players kicked or failed.
Or only when players are kicked? Is it shuffled when each person is kicked, or only if no players remain in the room? Does it happen after the teleport appears and disappears?

I really need a better explanation here. xD
Post automatically merged:



View attachment 81833

data/scripts/onUse_chooseItemReward.lua
LUA:
local rewardBagItemId = 1950

local config = {
    modalWindow = {
        id = 1001, -- needs to be unique number?
        title = "Reward Bag",
        message = "Choose a reward from the list!",
        eventText = "ModalWindow_Reward_Bag",
        buttons = {
            {text = "Choose", defaultEnterButton = true},
            {text = "Cancel", defaultEscapeButton = true},
        }
    },
    rewards = {
        {itemId = 2160, amount = 1},
        {itemId = 2160, amount = 3}, -- add as many as you want.
        {itemId = 2160, amount = 10}
    }
}

-- END OF CONFIG

local usedItems = {
--    [playerId] = item
}

local function getItemNameString(item)
    return item:getNameDescription(item:getSubType(), true)
end

local function createRewardBagWindow(playerId)
    local player = Player(playerId)
    if not player then
        return
    end

    if player:hasEvent(CREATURE_EVENT_MODALWINDOW, config.modalWindow.eventText) then
        player:unregisterEvent(config.modalWindow.eventText)
    end
    player:registerEvent(config.modalWindow.eventText)
   
    local modalWindow = ModalWindow(config.modalWindow.id, config.modalWindow.title, config.modalWindow.message)
   
    for id, button in ipairs(config.modalWindow.buttons) do
        modalWindow:addButton(id, button.text)
        if button.defaultEscapeButton then
            modalWindow:setDefaultEscapeButton(id)
        elseif button.defaultEnterButton then
            modalWindow:setDefaultEnterButton(id)
        end
    end       

    for id, v in ipairs(config.rewards) do
        local item = Game.createItem(v.itemId, v.amount)
        local text = getItemNameString(item)
        modalWindow:addChoice(id, text)
    end
   
    modalWindow:hasPriority()
    modalWindow:sendToPlayer(player)
end


local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local _player = Player(item:getTopParent())
    if not _player then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag must be in your inventory to be used.")
        player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
        return true
    end
    usedItems[player:getId()] = item
    createRewardBagWindow(player:getId())
    return true
end

action:id(rewardBagItemId)
action:register()


local creatureevent = CreatureEvent(config.modalWindow.eventText)

function creatureevent.onModalWindow(player, modalWindowId, buttonId, choiceId)
    player:unregisterEvent(config.modalWindow.eventText)
   
    if modalWindowId == config.modalWindow.id then
        local buttonChoice = config.modalWindow.buttons[buttonId].text
        local playerId = player:getId()
       
        if buttonChoice == "Choose" then
            local usedItem = usedItems[playerId]
            if not usedItem then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag no longer exists.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                usedItems[playerId] = nil
                return true
            end
            local _player = Player(usedItem:getTopParent())
            if not _player or _player:getId() ~= playerId then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag must be in your inventory to be used.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                usedItems[playerId] = nil
                return true
            end
            local item = Game.createItem(config.rewards[choiceId].itemId, config.rewards[choiceId].amount)
            if not player:addItemEx(item, false) then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "You do not have the room or capacity to receive this item.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                usedItems[playerId] = nil
                return true
            end
            player:say("You received " .. getItemNameString(item), TALKTYPE_MONSTER_SAY, nil, player)
            player:getPosition():sendMagicEffect(CONST_ME_HEARTS)
            usedItem:remove(1)
            usedItems[playerId] = nil
        else
            -- "Cancel" button
            usedItems[playerId] = nil
            return true
        end
       
    end
    return true
end

creatureevent:register()
Post automatically merged:




Unfortunately as of right now, this appears to be impossible.
There does not seem to be a way to apply this directly to the items.

I can grab the information about the items.. but can't apply it in any manner.

Example
LUA:
    local itemabilities = ItemType(11355):getAbilities()
   
    for k, v in pairs(itemabilities) do
        print(k, v)
    end
    print("------")
    for k, v in pairs(itemabilities.absorbPercent) do
        print(k, v)
    end
outputs
Code:
manaGain        0
manaTicks       0
statsPercent    table: 0x18a61bf8
speed   0
conditionSuppressions   0
invisible       false
fieldAbsorbPercent      table: 0x18ba9bb0
specialSkills   table: 0x18ba9a98
elementDamage   0
conditionImmunities     0
absorbPercent   table: 0x18ba9c08
skills  table: 0x18a61cb0
regeneration    false
healthGain      0
stats   table: 0x18a61b68
manaShield      false
elementType     0
healthTicks     0
------
2       10
5       0
12      0
11      0
4       0
10      0
9       0
8       0
3       -10
7       0
1       0
6       0


I found something like this and it actually works after entering the codes into TFS 1.4.2.
CreatureEvent - [TFS 1.3] updated Slot System (https://otland.net/threads/tfs-1-3-updated-slot-system.267624/)
The problem is that you can only delete after slots, that is, if someone has imbuing:
[crit] [crit%] [mlvl] then with the code then you can delete for example number 2, that is crit%.

If you could modify this code so that you could delete attributes by name, it would be a thing of beauty that could make further development of this for TFS 1.4.2.

LUA:
local it = player:addItem(2125, 1)
it:setMaxSockets(3)
it:addStat("HP", "+2%")
it:addStat("Sword", "+2")
it:removeStat(2) -- removes sword buff

it:removeStat(2) -- removes sword buff -
Possible modification something like: it:removeStat("Sword") ?
With this, I think you can even develop this into a time imbuing only for version 10.98.
 
I found something like this and it actually works after entering the codes into TFS 1.4.2.
CreatureEvent - [TFS 1.3] updated Slot System (https://otland.net/threads/tfs-1-3-updated-slot-system.267624/)
The problem is that you can only delete after slots, that is, if someone has imbuing:
[crit] [crit%] [mlvl] then with the code then you can delete for example number 2, that is crit%.

If you could modify this code so that you could delete attributes by name, it would be a thing of beauty that could make further development of this for TFS 1.4.2.

LUA:
local it = player:addItem(2125, 1)
it:setMaxSockets(3)
it:addStat("HP", "+2%")
it:addStat("Sword", "+2")
it:removeStat(2) -- removes sword buff

it:removeStat(2) -- removes sword buff - Possible modification something like: it:removeStat("Sword") ?
With this, I think you can even develop this into a time imbuing only for version 10.98.
Yeah, I've done exactly that in the past, except it was for base items, not upgrading.


But this is not the same as applying it directly to the item, which as far as I can tell is impossible.
 
Yeah, I've done exactly that in the past, except it was for base items, not upgrading.


But this is not the same as applying it directly to the item, which as far as I can tell is impossible.

I think we misunderstood in the post asking for this script.
I will try to explain it as best and simply as I can.
I would like to have something like imbuing:

That is, if the player selects from the modal window (or simply has the needed items in the backpack) uses IDXXXX e.g. on Royal Axe and gets imbuing: crit + crit% , additionally has a description after clicking on Royal Axe e.g. :
Slot: Crit 5%
Slot: Crit +10

I know it can be insanely difficult to do it in time, but maybe, for example, add 1000 charges to Royal Axe, after this thousand removes the added bonuses from the machine.

The best option is to make it work similarly to imbuing on the globe, if you can't then on these charges, only that instead of this whole window in the new versions, you poke a small modal window, or just use some item on the weapon.
 
But this is not the same as applying it directly to the item, which as far as I can tell is impossible.
Of course it's possible. Just take advantage of and adapt the functions from zbizu to the revscripts, all right, and then you can use modal craft as a base or it can be actions when clicking and giving attributes like critical hit, mana leech, and other things I've already done... It took me about 40 hours to finish. It's not easy because I'm learning TFS 1.x. I'll leave the links that need to have functions for simple attributes to work.


Watch the video I made showing modal craft similar to imbuing... What did I do? I simply took the functions from zbizu and put them in the craft modal... It recognized it instantly and worked well.

what I just using here was:
LUA:
it:setMaxSockets(3) ----This line 'setMaxSockets' will determine how many attributes you want; if you put 1, it will have only 1 attribute. In this case, 3 means you can upgrade the item up to a maximum of 3 attributes. If you want 5, it will go up to 5.
it:addStat("HP") --This 'addStat' line needs to be added to the modal craft or clicking the stone to apply it to the item like imbuing or upgrading.
it:removeStat(2) -- removes sword buff This 'removeStat' line is used to remove attributes like imbuing or upgrading. You can either click the stone to remove the item or use it as an add event to remove attributes directly from the item.

item:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, description) -You already know how to give the item a look with this line.

My imbuing system is not ready yet. I'm still developing it.
 
Of course it's possible. Just take advantage of and adapt the functions from zbizu to the revscripts, all right, and then you can use modal craft as a base or it can be actions when clicking and giving attributes like critical hit, mana leech, and other things I've already done... It took me about 40 hours to finish. It's not easy because I'm learning TFS 1.x. I'll leave the links that need to have functions for simple attributes to work.


Watch the video I made showing modal craft similar to imbuing... What did I do? I simply took the functions from zbizu and put them in the craft modal... It recognized it instantly and worked well.

what I just using here was:
LUA:
it:setMaxSockets(3) ----This line 'setMaxSockets' will determine how many attributes you want; if you put 1, it will have only 1 attribute. In this case, 3 means you can upgrade the item up to a maximum of 3 attributes. If you want 5, it will go up to 5.
it:addStat("HP") --This 'addStat' line needs to be added to the modal craft or clicking the stone to apply it to the item like imbuing or upgrading.
it:removeStat(2) -- removes sword buff This 'removeStat' line is used to remove attributes like imbuing or upgrading. You can either click the stone to remove the item or use it as an add event to remove attributes directly from the item.

item:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, description) -You already know how to give the item a look with this line.

My imbuing system is not ready yet. I'm still developing it.

Wow, something beautiful.
The only problem is , I am not a programmer and I would agonize over this for months.
That's why I want to use Xikini's help and free service.

Still the only problem is that these stats are not temporary but forever added to the weapon.
 
Wow, something beautiful.
The only problem is , I am not a programmer and I would agonize over this for months.
That's why I want to use Xikini's help and free service.

Still the only problem is that these stats are not temporary but forever added to the weapon.
I have two systems: one for temporary status and another for permanent status. If the player wants only a temporary effect, they go to a different machine for upgrading the item. If the player wants a permanent status, they use another machine. I've created seven different machines, each for permanent attributes, temporary attributes, normal skills, and even elemental damages.
 
Of course it's possible. Just take advantage of and adapt the functions from zbizu to the revscripts, all right, and then you can use modal craft as a base or it can be actions when clicking and giving attributes like critical hit, mana leech, and other things I've already done... It took me about 40 hours to finish. It's not easy because I'm learning TFS 1.x. I'll leave the links that need to have functions for simple attributes to work.


Watch the video I made showing modal craft similar to imbuing... What did I do? I simply took the functions from zbizu and put them in the craft modal... It recognized it instantly and worked well.

what I just using here was:
LUA:
it:setMaxSockets(3) ----This line 'setMaxSockets' will determine how many attributes you want; if you put 1, it will have only 1 attribute. In this case, 3 means you can upgrade the item up to a maximum of 3 attributes. If you want 5, it will go up to 5.
it:addStat("HP") --This 'addStat' line needs to be added to the modal craft or clicking the stone to apply it to the item like imbuing or upgrading.
it:removeStat(2) -- removes sword buff This 'removeStat' line is used to remove attributes like imbuing or upgrading. You can either click the stone to remove the item or use it as an add event to remove attributes directly from the item.

item:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, description) -You already know how to give the item a look with this line.

My imbuing system is not ready yet. I'm still developing it.
Wow, something beautiful.
The only problem is , I am not a programmer and I would agonize over this for months.
That's why I want to use Xikini's help and free service.

Still the only problem is that these stats are not temporary but forever added to the weapon.
I have two systems: one for temporary status and another for permanent status. If the player wants only a temporary effect, they go to a different machine for upgrading the item. If the player wants a permanent status, they use another machine. I've created seven different machines, each for permanent attributes, temporary attributes, normal skills, and even elemental damages.

I don't know how more clear I can be.

These systems are applying a buff to the character.
They are not applying the stat to the item itself.

Without source edits, his original request is impossible.
 
I don't know how more clear I can be.

These systems are applying a buff to the character.
They are not applying the stat to the item itself.

Without source edits, his original request is impossible.
Ok, I understand.
But they work in such a way that if the player has an item put on an item that has been upgraded then he gets a bonus, if the item is in the backpack then as you can see this bonus is not there.
So using os.time it would be possible to impose a bonus on a character for a certain period of time?

The system that Mateus Robeerto presented in his video is, for me, equivalent to what I would like to get.
Post automatically merged:

Video shows it updating every 1 second, but in live server I recommend updating every 5+ minutes.

View attachment 81831

data/scripts/showTopOnlinePlayers.lua
LUA:
local checkInterval = 1 -- seconds (recommend like 5+ minutes inbetween checks. getting all online players is a fairly expensive operation.)

local topPlayers = {
    {playerId = 0, monsterId = 0, position = Position(998, 1003, 7)},  -- only edit the position of where the monster will spawn
    {playerId = 0, monsterId = 0, position = Position(1000, 1002, 7)},
    {playerId = 0, monsterId = 0, position = Position(1002, 1003, 7)}  -- if you want to show more then 3 players, just keep adding more into the table.
}


local function setMonsterDefaultSettings(monster)
    monster:rename("Top Player [LvL: ??]", "a top online placeholder creature")
    local outfit = monster:getOutfit()
    outfit.lookType = 0
    outfit.lookTypeEx = 2110
    monster:setOutfit(outfit)
end

local function createTopScoreMonster(index)
    local monster = Game.createMonster("rotworm", topPlayers[index].position, false, true)
    topPlayers[index].monsterId = monster:getId()
    setMonsterDefaultSettings(monster)
    return monster
end


local globalevent = GlobalEvent("onThink_showTopOnlinePlayers")

function globalevent.onThink(interval)
    local onlinePlayers = Game.getPlayers()
 
    local players = {}
    local seenIds = {}
 
    for k, v in ipairs(topPlayers) do
        local player = Player(v.playerId)
        if player and not seenIds[v.playerId] then
            players[#players + 1] = {level = player:getLevel(), id = v.playerId}
            seenIds[v.playerId] = true
        else
            v.playerId = 0
        end
    end 
    for _, player in pairs(onlinePlayers) do
        local playerId = player:getId()
        if not seenIds[playerId] and not player:getGroup():getAccess() then
            players[#players + 1] = {level = player:getLevel(), id = playerId}
            seenIds[playerId] = true
        end
    end
    table.sort(players, function(a, b) return a.level > b.level    end)
 
    for k, v in ipairs(topPlayers) do
        local monster = Monster(v.monsterId)
        if players[k] then
            v.playerId = players[k].id
            local player = Player(v.playerId)
         
            if not monster then
                monster = createTopScoreMonster(k)
            end
         
            local newName = string.format("%s [LvL: %s]", player:getName(), players[k].level)
            monster:rename(newName, "the current #" .. k .. " online player " .. newName)
            local outfit = player:getOutfit()
            monster:setOutfit(outfit)
        else
            if monster then
                setMonsterDefaultSettings(monster)
            end
        end
    end
    return true
end

globalevent:interval(checkInterval * 1000)
globalevent:register()


local globalevent = GlobalEvent("onStartup_showTopOnlinePlayers")

function globalevent.onStartup()
    for k, v in pairs(topPlayers) do
        createTopScoreMonster(k)
    end
    return true
end

globalevent:register()
Post automatically merged:



So as explained earlier, I cannot stop a frag from occurring, but I can definitely count how many frags a person has done. (since the script was installed.)
Video shows killing same guild killing, but the script checks for players in different guilds as you wanted. Just a mistake when filming.

View attachment 81832

data/scripts/eventcallbacks/player/default_onLook.lua
under
LUA:
    local description = "You see " .. thing:getDescription(distance)
add
LUA:
    if thing:isPlayer() then
        local frags = math.max(thing:getStorageValue(FRAG_STORAGE_KEY), 0)
        description = string.format("%s %s have %s frags.", description, self == thing and "You" or "They", frags)
    end

data/scripts/eventcallbacks/player/default_onLookInBattleList.lua
under
LUA:
    local description = "You see " .. creature:getDescription(distance)
add
LUA:
    if creature:isPlayer() then
        local frags = math.max(creature:getStorageValue(FRAG_STORAGE_KEY), 0)
        description = string.format("%s %s have %s frags.", description, self == thing and "You" or "They", frags)
    end

data/scripts/fragCounter_onLook_onKill.lua
LUA:
FRAG_STORAGE_KEY = 45035

local creatureevent = CreatureEvent("onKill_FragCounter")

function creatureevent.onKill(creature, target)
    if target:isPlayer() then
        local giveFrag = true
     
        local targetGuild = target:getGuild()
        local creatureGuild = creature:getGuild()
        if targetGuild and creatureGuild then
            if creatureGuild:getId() ~= targetGuild:getId() then
                giveFrag = false
            end
        end     
     
        if giveFrag then
            local frags = math.max(creature:getStorageValue(FRAG_STORAGE_KEY), 0)
            creature:setStorageValue(FRAG_STORAGE_KEY, frags + 1)
        end
    end
    return true
end

creatureevent:register()



local creatureevent = CreatureEvent("onLogin_FragCounter")

function creatureevent.onLogin(player)
    player:registerEvent("onKill_FragCounter")
    return true
end

creatureevent:register()
Post automatically merged:



So many questions..

1 monster to rotate the Dangerous Apparatus onStep on tiles next to it
If a monster is running around and rotating these things.. how would it ever find all the correct directions?

to face next direction till we make it reposition correct, until it all face the Strange Machine.
Does this mean you can't over-rotate?
How would I determine what 'face the Strange machine' is on a diagonal?

You have to reposition all the Dangerous Apparatus in 15 minutes or you get kicked of the room.
How do I know when the players entered the room?
If players enter in staggered intervals.. first person enters, then another person 7 minutes later, do I still kick both players out? or just the first person?

After 15 minutes all Dangerous Apparatus shuffle directions again when all players kicked or failed.
Or only when players are kicked? Is it shuffled when each person is kicked, or only if no players remain in the room? Does it happen after the teleport appears and disappears?

I really need a better explanation here. xD
Post automatically merged:



View attachment 81833

data/scripts/onUse_chooseItemReward.lua
LUA:
local rewardBagItemId = 1950

local config = {
    modalWindow = {
        id = 1001, -- needs to be unique number?
        title = "Reward Bag",
        message = "Choose a reward from the list!",
        eventText = "ModalWindow_Reward_Bag",
        buttons = {
            {text = "Choose", defaultEnterButton = true},
            {text = "Cancel", defaultEscapeButton = true},
        }
    },
    rewards = {
        {itemId = 2160, amount = 1},
        {itemId = 2160, amount = 3}, -- add as many as you want.
        {itemId = 2160, amount = 10}
    }
}

-- END OF CONFIG

local usedItems = {
--    [playerId] = item
}

local function getItemNameString(item)
    return item:getNameDescription(item:getSubType(), true)
end

local function createRewardBagWindow(playerId)
    local player = Player(playerId)
    if not player then
        return
    end

    if player:hasEvent(CREATURE_EVENT_MODALWINDOW, config.modalWindow.eventText) then
        player:unregisterEvent(config.modalWindow.eventText)
    end
    player:registerEvent(config.modalWindow.eventText)
  
    local modalWindow = ModalWindow(config.modalWindow.id, config.modalWindow.title, config.modalWindow.message)
  
    for id, button in ipairs(config.modalWindow.buttons) do
        modalWindow:addButton(id, button.text)
        if button.defaultEscapeButton then
            modalWindow:setDefaultEscapeButton(id)
        elseif button.defaultEnterButton then
            modalWindow:setDefaultEnterButton(id)
        end
    end      

    for id, v in ipairs(config.rewards) do
        local item = Game.createItem(v.itemId, v.amount)
        local text = getItemNameString(item)
        modalWindow:addChoice(id, text)
    end
  
    modalWindow:hasPriority()
    modalWindow:sendToPlayer(player)
end


local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local _player = Player(item:getTopParent())
    if not _player then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag must be in your inventory to be used.")
        player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
        return true
    end
    usedItems[player:getId()] = item
    createRewardBagWindow(player:getId())
    return true
end

action:id(rewardBagItemId)
action:register()


local creatureevent = CreatureEvent(config.modalWindow.eventText)

function creatureevent.onModalWindow(player, modalWindowId, buttonId, choiceId)
    player:unregisterEvent(config.modalWindow.eventText)
  
    if modalWindowId == config.modalWindow.id then
        local buttonChoice = config.modalWindow.buttons[buttonId].text
        local playerId = player:getId()
      
        if buttonChoice == "Choose" then
            local usedItem = usedItems[playerId]
            if not usedItem then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag no longer exists.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                usedItems[playerId] = nil
                return true
            end
            local _player = Player(usedItem:getTopParent())
            if not _player or _player:getId() ~= playerId then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "Reward bag must be in your inventory to be used.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                usedItems[playerId] = nil
                return true
            end
            local item = Game.createItem(config.rewards[choiceId].itemId, config.rewards[choiceId].amount)
            if not player:addItemEx(item, false) then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "You do not have the room or capacity to receive this item.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                usedItems[playerId] = nil
                return true
            end
            player:say("You received " .. getItemNameString(item), TALKTYPE_MONSTER_SAY, nil, player)
            player:getPosition():sendMagicEffect(CONST_ME_HEARTS)
            usedItem:remove(1)
            usedItems[playerId] = nil
        else
            -- "Cancel" button
            usedItems[playerId] = nil
            return true
        end
      
    end
    return true
end

creatureevent:register()
Post automatically merged:




Unfortunately as of right now, this appears to be impossible.
There does not seem to be a way to apply this directly to the items.

I can grab the information about the items.. but can't apply it in any manner.

Example
LUA:
    local itemabilities = ItemType(11355):getAbilities()
  
    for k, v in pairs(itemabilities) do
        print(k, v)
    end
    print("------")
    for k, v in pairs(itemabilities.absorbPercent) do
        print(k, v)
    end
outputs
Code:
manaGain        0
manaTicks       0
statsPercent    table: 0x18a61bf8
speed   0
conditionSuppressions   0
invisible       false
fieldAbsorbPercent      table: 0x18ba9bb0
specialSkills   table: 0x18ba9a98
elementDamage   0
conditionImmunities     0
absorbPercent   table: 0x18ba9c08
skills  table: 0x18a61cb0
regeneration    false
healthGain      0
stats   table: 0x18a61b68
manaShield      false
elementType     0
healthTicks     0
------
2       10
5       0
12      0
11      0
4       0
10      0
9       0
8       0
3       -10
7       0
1       0
6       0

It is possible to show clones of the best characters, but only those who are online, just all of them?
That is, the TOP 3 on the server?
In addition, clones can be killed like rotworms if they are outside the PZ zone - I don't know if this is not a mistake.
 
Last edited:
Yet another request, and this will mark the final addition to my OT project. I am in need of a script that facilitates a specific functionality: upon clicking an item, a modal window should prompt the user to verify whether they intend to utilize the Boss-Checker feature. This feature serves the purpose of either checking the remaining time of a boss or completely resetting it. Additionally, it should provide the option to individually check the remaining time of each boss or reset them as needed.

Following the user's selection, a page displaying a list of monsters will appear. In this modal window, the user can easily identify which monsters possess bosses. For instance, if the user chooses 'Morgaroth', they would then simply select the respective monster and click 'Ok'. If the intention is to check the time, the remaining duration will be displayed accordingly. Conversely, if the user opts to reset, the timer will be reset, making it available for subsequent use.
 
Ok, I understand.
But they work in such a way that if the player has an item put on an item that has been upgraded then he gets a bonus, if the item is in the backpack then as you can see this bonus is not there.
So using os.time it would be possible to impose a bonus on a character for a certain period of time?

The system that Mateus Robeerto presented in his video is, for me, equivalent to what I would like to get.
Post automatically merged:



It is possible to show clones of the best characters, but only those who are online, just all of them?
That is, the TOP 3 on the server?
In addition, clones can be killed like rotworms if they are outside the PZ zone - I don't know if this is not a mistake.
No wonder why they can be killed when these are actual MONSTERS, you don't need to be a programmer to understand a code ! :D


Good Job @Xikini !!!
 
Back
Top