• 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
Premium User
Joined
Nov 17, 2010
Messages
6,800
Solutions
582
Reaction score
5,363
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:
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?
not any monsters, it's a specific slow monster that I am luring on a tile to rotate it (only the tile in front of each Dangerous Apparatus and that monster can rotate it)
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 can keep rotating it as long as you're moving the monster on the tile till you think it's the correct direction.There's no diagonal ones, it's all to directions like south/north/east/west as in the screenshot, the strange machine is always looking to 1 direction (it's not rotate able)
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?
I didn't think of this, can we make this like an annihilator entrance with a lever but with more tiles (10 to 15) and also 1, 2, or 10 players can enter (no need to fill all tiles) then no one can enter until the ones inside have finished or 15 minutes passed and the team inside got kicked (all of them)
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?
It happens when the team inside gets kicked (all of them) now with the anni style and lever they all will have the same time, and it also happens as soon as the teleport disappears
....................................
thank you very much, tell me if you need more explanation
 
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.

How do you determine the remaining time?
Why would the user have the ability to reset the remaining time?
 
How do you determine the remaining time?
Why would the user have the ability to reset the remaining time?
I have reconsidered: it would be preferable for the player not to have the ability to reset the remaining time of the boss. Instead, I envision the player clicking on the item to prompt a modal window displaying the remaining time until the boss appears. Do you follow? Upon clicking, the player would ascertain the remaining time and await the boss's availability in a designated location. Subsequently, the player would proceed to confront the boss. This arrangement suffices. I require the boss check functionality to exhibit the boss's remaining time.
 
I have reconsidered: it would be preferable for the player not to have the ability to reset the remaining time of the boss. Instead, I envision the player clicking on the item to prompt a modal window displaying the remaining time until the boss appears. Do you follow? Upon clicking, the player would ascertain the remaining time and await the boss's availability in a designated location. Subsequently, the player would proceed to confront the boss. This arrangement suffices. I require the boss check functionality to exhibit the boss's remaining time.
That doesn't answer anything. lol

How do you determine the time that the boss appears?
How do you determine the remaining time?
 
To determine when the boss appears, I typically use a spawn system based on specific conditions, such as time elapsed since the boss's last appearance, player activities in nearby areas, or pre-programmed events in the game.
To determine the remaining time until the next boss appearance, I usually employ a countdown system that starts either after the boss is defeated or after a specific time period has elapsed since the last appearance. This system is continuously updated to reflect the remaining time until the next boss appearance.
 
To determine when the boss appears, I typically use a spawn system based on specific conditions, such as time elapsed since the boss's last appearance, player activities in nearby areas, or pre-programmed events in the game.
To determine the remaining time until the next boss appearance, I usually employ a countdown system that starts either after the boss is defeated or after a specific time period has elapsed since the last appearance. This system is continuously updated to reflect the remaining time until the next boss appearance.

You do see how this is a problem, right?

How do I access the time until the boss appears?
How do I access the remaining time?

What format are these times in?
 
Last edited:
Yes, that's what I wanted to see to know how much time is left for the boss to appear. The time format can be 24 hours, as my boss has various different schedules. One of them appears every 30 minutes, another every 2 hours, and another boss appears once a day.
 
Yes, that's what I wanted to see to know how much time is left for the boss to appear. The time format can be 24 hours, as my boss has various different schedules. One of them appears every 30 minutes, another every 2 hours, and another boss appears once a day.
I give up.
 
Per your request i'm not greedy!!!



------------------------

Request 1: Evolving Weapons

Lots of weapons can become legendary in name.
In the universe of Arda, many weapons are named after their deeds.
For example, the Goblin Cleaver was named for its slaying of many Goblins.
Which brings me to the idea of weapons that can evolve!


  1. The player obtains for example a sword. (should be configurable to set specific weapons to be able to evolve)​
  2. If the sword kills 1000 Goblins, it turns into Goblin Cleaver, giving extra damage to Goblins.​



- When the item has been traded, the count should still be on the weapon.
------------------------


Request 2: A Creature that adjusts its speed according to the current target
As I have different chase scenes in an open-world game, it is a bit painful to adjust the monster's speed to the player level,
especially on lower-level players, this is troublesome.

  1. A creature that can adjust its speed to the speed of its current target player.​
  2. If a player is level 1 it should have the speed of a level 2.​
  3. If a player is level 2, it should have the speed of a level 3.​
(might be too easy)
------------------------

Flying Kiss Flirting GIF by SpongeBob SquarePants
 
Last edited:
Sometimes Google, which translates for me, understands very poorly, and sometimes I write, and Google translates poorly into English as well. I apologize. I will try once more to explain it better and more clearly.

This is the Boss Checker, used to check if the boss is alive or dead, and also to display the time remaining until the next boss respawn. If a player chooses the boss "Troll", they will only monitor the Troll to know when the respawn is due or if the boss has already been defeated. If the player does not want to monitor the Troll for information, they can reset the boss and choose another, like the "Dark Cleric", to see if the respawn is imminent. The modal window will indicate if the boss has appeared. Then, the player can go and defeat the boss. It's as simple as that. Did you understand? If not, we can drop the subject. Thank you for your attention.

I have taken the teleport modal and modified it for Boss checking. I have made some progress, but I am uncertain about where to incorporate the boss information related to storage. Specifically, I am unsure about how to handle the situation when the boss is alive and the status indicates "active", prompting the player to proceed to the boss location and defeat it. I am seeking clarification on how this storage mechanism operates or if there is an alternative, more effective approach.

Lua:
local bossCheckerItemId = 39674

local config = {
    modalWindow = {
        id = 1000,
        title = "Boss Checker",
        message = "Choose a boss to check:",
        eventText = "ModalWindow_BossChecker",
        buttons = {
            {text = "Check Time"},
            {text = "Reset Time"},
            {text = "Cancel"},
        }
    },
    bossStorage = {
        [1] = {name = "Dark Cleric", storage = 1001, respawnTime = 1800},
        [2] = {name = "Morgaroth", storage = 1002, respawnTime = 2400},
        [3] = {name = "Troll", storage = 1003, respawnTime = 3600}
      
    }
}

local function createBossCheckerWindow(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)
        end
    end       

    for bossId, boss in ipairs(config.bossStorage) do
        modalWindow:addChoice(bossId, boss.name)
    end
    
    modalWindow:hasPriority()
    modalWindow:sendToPlayer(player)
end

local function showBossStatusModal(player, bossName, status, timeToRespawn)
    local modalWindow = ModalWindow(2000, "Boss Status", bossName .. " - Status: " .. status .. " - Respawn in: " .. timeToRespawn .. "s")
    modalWindow:setDefaultEscapeButton(101)

    local function onClose(buttonId)
        if buttonId == 100 then
            print("Closing Boss Status Modal")
        elseif buttonId == 101 then
            print("Returning to Boss Checker Window")
            addEvent(createBossCheckerWindow, 100, player:getId())
        end
    end
    
    modalWindow:addButton(100, "Close", onClose)
    modalWindow:addButton(102, "Back", onClose)
    
    modalWindow:sendToPlayer(player)
end


local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if item.itemid == bossCheckerItemId then
        createBossCheckerWindow(player:getId())
        return true
    end
    return false
end

action:id(bossCheckerItemId)
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 boss = config.bossStorage[choiceId]
        
        if buttonChoice == "Check Time" then
            local lastKilled = player:getStorageValue(boss.storage)
            local remainingTime = boss.respawnTime - (os.time() - lastKilled)
            local status = remainingTime > 0 and "Alive" or "Dead"
            local timeToRespawn = remainingTime > 0 and remainingTime or 0
            showBossStatusModal(player, boss.name, status, timeToRespawn)
            
        elseif buttonChoice == "Reset Time" then
            player:setStorageValue(boss.storage, -1)
        elseif buttonChoice == "Cancel" then
            return true
        end
        
        createBossCheckerWindow(player:getId())
        return true
    elseif modalWindowId == 2000 then
        if buttonId == 100 then
            createBossCheckerWindow(player:getId())
            return true
        elseif buttonId == 101 then
            addEvent(createBossCheckerWindow, 100, player:getId())
            return true
        end
    end
    return true
end


creatureEvent:register()
 
I would like a script, probably in creatureScript format, that increases monster's damage according to the number of players in a certain range of that monster's current position, for example 4SQM.
 
Since everybody asks I will ask for something. I already have upgrade system but what I would like to have is modal points system. I would to have bonuses per point and list to choose from examples: extra any skill +1, health points 1% mana points 1% critical damage 1% experience 1% and talk action to make it easier !points. I will have my own missions and quests to provide those points. I just want this function to retrive it from 'task_points' or 'coins' I will edit this after anyway.

ATTRIBUTE DESCRIPTION AND CONDITION can be used here.

So yeah this is my request and thanks for what you doing, I always enjoy looking at your scripts and they you present it. Well done!
 
Last edited:
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, 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

View attachment 81805

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

example of a raid config.
Lua:
{    raid = {
        name = "raidName",
        specificTimes = {
            -- "hh:mm:ss"
            "07:00:00", -- 7am
            "19:00:00"  -- 7pm
        },
        startDelay = 30,
        interval = 15,
        chance = 100,
        forceAfterAttempts = 20,
        cooldown = 120,
        forceNewRaidInstance = 1
    },  
    nonSpawnableAreas = {
        {from = Position(1004, 1013, 7), to = Position(1011, 1016, 7)}
    },
    waves = {
        { -- wave 1
            broadcast = {messageType = MESSAGE_STATUS_WARNING, text = "raidName is starting in 60 seconds."}
        },
        { -- wave 2
            broadcast = {messageType = MESSAGE_STATUS_WARNING, text = "Wave example with RANDOM monsters only"},
            randomMonsters = {
                {
                    amount = {min = 5, max = 20},
                    monsterList = {"rat", "cave rat", "troll"},
                    spawnAreas = {
                        {from = Position(1003, 1012, 7), to = Position(1012, 1017, 7)}
                    }
                },
                {
                    amount = {min = 20, max = 20},
                    monsterList = {"rotworm"},
                    spawnAreas = {
                        {from = Position(1003, 1012, 7), to = Position(1012, 1017, 7)},
                        {from = Position(1003, 1012, 7), to = Position(1012, 1017, 7)}
                    }
                },
            },
            nextWaveTimer = 10
        },
        { -- wave 3
            broadcast = {messageType = MESSAGE_STATUS_WARNING, text = "Wave example with STATIC monsters only"},
            staticMonsters = {
                {position = Position(1005, 1015, 7), name = "cyclops"},
                {position = Position(1006, 1015, 7), name = "dragon"}
            },
            nextWaveTimer = 10
        },
        { -- wave 4
            broadcast = {messageType = MESSAGE_STATUS_WARNING, text = "Wave example with both STATIC & RANDOM monsters"},
            staticMonsters = {
                {position = Position(1007, 1015, 7), name = "dragon lord"}
            },
            randomMonsters = {
                {
                    amount = {min = 20, max = 20},
                    monsterList = {"bug", "wolf", "bear"},
                    spawnAreas = {
                        {from = Position(1003, 1012, 7), to = Position(1012, 1017, 7)},
                        {from = Position(1003, 1012, 7), to = Position(1012, 1017, 7)}
                    }
                }
            },
            nextWaveTimer = 10
        },
        { -- wave 5
            broadcast = {messageType = MESSAGE_STATUS_WARNING, text = "Wave example Boss?"},
            staticMonsters = {
                {position = Position(1009, 1015, 7), name = "demon"}
            }
        }
    }
}

data/scripts/raidSystemInLua.lua
Lua:
-- Check the attachments. Code is too large to post.
I just had some time to check this. Man such a nice script, I just finished reading it and it is just perfect.
A little question, if I set forceAfterAttempts = -1 and chance = 10000, this means it will have a 100% of chance to occur at specificTimes?

ps. I haven't tested it too much but I will definitely post back the feedback asap. ^^

@Xikini I updated this post with a second request if it is possible. It is a really simple one based on this post:
I will just quote myself:

ralke said:
There's a chance that you could make a talkaction script to buy backpacks, in different colors? Something like: if you do !backpack without param, you receive default backpack. But if you add param like !backpack red, !backpack blue, !backpack beach, !backpack camouflage, you get the variations. It should have a configurable price --and name-- for each variation. Thanks in advance!
 
Last edited:
I just had some time to check this. Man such a nice script, I just finished reading it and it is just perfect.
A little question, if I set forceAfterAttempts = -1 and chance = 10000, this means it will have a 100% of chance to occur at specificTimes?

ps. I haven't tested it too much but I will definitely post back the feedback asap. ^^

@Xikini I updated this post with a second request if it is possible. It is a really simple one based on this post:
I will just quote myself:
both -1 and 1 would both force it to occur.

-1 would force raid, and keep any remaining monsters from last raid(s).
1 would force raid, and remove remaining monsters from last raid.
 
hi i am building an ot 1.4.2, futuristic and i would like a script for gift boxes. so when you open a gift box you got modalwindow with choises like.

1. boost exp.
2. xxx item,
3. xxx money.

thanks!
 
hi i am building an ot 1.4.2, futuristic and i would like a script for gift boxes. so when you open a gift box you got modalwindow with choises like.

1. boost exp.
2. xxx item,
3. xxx money.

thanks!
We basically built this exact same thing a few days ago.


For the experience boost, just make it an item that gives the experience boost.
Post automatically merged:

I just had some time to check this. Man such a nice script, I just finished reading it and it is just perfect.
A little question, if I set forceAfterAttempts = -1 and chance = 10000, this means it will have a 100% of chance to occur at specificTimes?

ps. I haven't tested it too much but I will definitely post back the feedback asap. ^^

@Xikini I updated this post with a second request if it is possible. It is a really simple one based on this post:
I will just quote myself:

bandicam2024-02-0509-36-42-890-ezgif.com-video-to-gif-converter.gif
Untitled.png
Finished it offline.
Kinda of hard to make a video for it xD

Made it take money from player and bank.

!backpack OR !backpack name
!backpack confirm -> confirms the purchase details
!backpack list

checks for money and inventory space / capacity

data/scripts/talkaction_backpacks.lua
Lua:
local backpacks = {
    ["brown"] = {itemId = 1988, price = 20},
    ["crown"] = {itemId = 10522, price = 10000}
}

-- END OF CONFIG

local playerConfirmation = {}

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

local talkaction = TalkAction("!backpack")

function talkaction.onSay(player, words, param, type)
   
    if param == "" then
        param = "brown" -- aka: default backpack
    end
   
    param = param:lower()
    local playerId = player:getId()
    local index = playerConfirmation[playerId]
    playerConfirmation[playerId] = nil   
   
    if param == "confirm" and index then
        if player:getTotalMoney() < backpacks[index].price then
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You do not have sufficient funds to purchase this item.")
            return false
        end
        local backpack = Game.createItem(backpacks[index].itemId, 1)
        if player:addItemEx(backpack, false) ~= RETURNVALUE_NOERROR then
            player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "You do not have sufficient room or capacity to receive this item.")
            return false
        end
        player:removeTotalMoney(backpacks[index].price)
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "You have purchased " .. getItemNameString(backpack) .. " for " .. backpacks[index].price .. " gold.")
        return false
    elseif param == "list" then
        local text = ""
        for k, v in pairs(backpacks) do
            if text ~= "" then
                text = text .. "\n"
            end
            text = text .. k .. " backpack - " .. v.price .. " gold"
        end
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Here is the list of backpacks.")
        player:showTextDialog(1988, "List of backpacks:\n\n" .. text)
        return false
    end
   
    index = backpacks[param]
   
    if not index then
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "There is no backpack named " .. param .. ".")
        return false
    end
   
    playerConfirmation[playerId] = param
    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Would you like to purchase a " .. param .. " backpack for " .. index.price .. " gold?")
    player:sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "To finalise the purchase use !backpack confirm")
    return false
end

talkaction:separator(" ")
talkaction: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

bandicam2024-02-0513-00-35-262-ezgif.com-video-to-gif-converter.gif

Untitled.png

data/scripts/Madusa_Request.lua
Lua:
local config = {
    actionId = 45036,
    rotateMonster = "cat",
    rotateItems = {7163, 7166, 7165, 7164}, -- needs to have 4 items (south, west, north, east)
    teleport = {
        duration = 120, -- seconds
        spawnPosition = Position(965, 1019, 7),
        destination = Position(1000, 1000, 7) -- reward area?
    },
    requiredRotatedItems = {
        {itemId = 7166, position = Position(973, 1008, 7)},
        {itemId = 7163, position = Position(967, 1008, 7)},
        {itemId = 7164, position = Position(967, 1014, 7)},
        {itemId = 7163, position = Position(972, 1014, 7)}, -- if all of these are correct items, then open portal
        {itemId = 7166, position = Position(972, 1018, 7)},
        {itemId = 7165, position = Position(962, 1018, 7)},
        {itemId = 7165, position = Position(962, 1009, 7)},
        {itemId = 7166, position = Position(962, 1004, 7)}
    },
    area = {
        from = Position(957, 1004, 7), -- the event area
        to = Position(973, 1019, 7)
    },
    lever = {
        left = 1945,
        right = 1946,
        playerArea = {
            from = Position(982, 1013, 7), -- area around lever
            to = Position(988, 1019, 7)
        },
        position = Position(985, 1016, 7),
        destination = Position(957, 1019, 7)
    },
    kickTimer = 900, -- seconds
    kickPosition = Position(1000, 1000, 7)
}

-- END OF CONFIG

local event_players = {}
local event_kickPlayers = -1

local function rotateItem(item, rotateRandomDirection)
    local itemId = item:getId()
    if rotateRandomDirection then
        itemId = config.rotateItems[math.random(#config.rotateItems)]
    else
        for i = 1, #config.rotateItems do
            if config.rotateItems[i] == itemId then
                if i == 4 then
                    i = 0
                end
                itemId = config.rotateItems[i + 1]
                break
            end
        end
    end
    item:transform(itemId)
end

local function randomRotateAllItemsInArea(from, to)
    for x = from.x, to.x do
        for y = from.y, to.y do
            for z = from.z, to.z do
                local position = Position(x, y, z)
                local tile = Tile(position)
                if tile then
                    for _, itemId in pairs(config.rotateItems) do
                        local rotatableItem = tile:getItemById(itemId)
                        if rotatableItem then
                            rotateItem(rotatableItem, true)
                            break
                        end
                    end
                end
            end
        end
    end
end

local function isAllObjectsRotatedCorrectly()
    for k, v in pairs(config.requiredRotatedItems) do
        if not Tile(v.position):getItemById(v.itemId) then
            return false
        end
    end
    return true
end

local function createTimedPortal(position, destination, timer, portalSpawned)
    if not portalSpawned then
        local teleport = Game.createItem(1387, 1, position)
        teleport:setDestination(destination)
        teleport:setActionId(config.actionId)
        portalSpawned = true
    end
    local portal = Tile(position):getItemById(1387)
    if portal then
        if timer % 5 == 0 and timer ~= 0 then
            for _, creature in pairs(Game.getPlayers()) do
                creature:say(timer, TALKTYPE_MONSTER_SAY, false, nil, position)
                break
            end
        end
        if timer > 0 then
            addEvent(createTimedPortal, 1000, position, destination, timer - 1, portalSpawned)
            return
        end
        portal:remove()
    end
end

local function kickEventPlayers()
    for k, v in pairs(event_players) do
        local player = Player(k)
        if player then
            player:teleportTo(config.kickPosition)
        end
    end
end

local function resetEvent(forceStop)
    if forceStop then
        kickEventPlayers()
        event_players = {}
    end
    
    if next(event_players) == nil then
        if event_kickPlayers ~= -1 then
            stopEvent(event_kickPlayers)
        end
        event_kickPlayers = -1
    end    
    
    local portal = Tile(config.teleport.spawnPosition):getItemById(1387)
    if portal then
        portal:remove()
    end
    
    randomRotateAllItemsInArea(config.area.from, config.area.to)
    
    local lever = Tile(config.lever.position):getItemById(config.lever.right)
    if lever then
        lever:transform(config.lever.left)
    end
end

local function sendMessageToEventPlayers(message, messageType)   
    for _player, _ in pairs(event_players) do
        local player = Player(_player)
        if player then
            player:sendTextMessage(messageType, message)
        end
    end
end


local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if item:getId() == config.lever.right then
       
        return
    end
    item:transform(config.lever.right)
   
    -- get all players, teleport, and register
    local spectators = Game.getSpectators(item:getPosition(), false, true)
    for i = 1, #spectators do
        local spectator = spectators[i]
        if spectator:getPosition():isInRange(config.lever.playerArea.from, config.lever.playerArea.to) then
            spectator:teleportTo(config.lever.destination)
            event_players[spectator:getId()] = 0
        end
    end
   
    event_kickPlayers = addEvent(resetEvent, config.kickTimer * 1000, true)
    return true
end

action:aid(config.actionId)
action:register()


local moveevent = MoveEvent()

function moveevent.onStepIn(creature, item, position, fromPosition)
    local itemId = item:getId()
    if itemId == config.lever.left or itemId == config.lever.right then
        return true
    end       

    if itemId == 1387 then
        if not creature:isPlayer() then
            return true
        end
        event_players[creature:getId()] = nil
        if next(event_players) == nil then
            resetEvent()
        end
        return true
    end

    if not creature:isMonster() then
        return true
    end
   
    local monsterName = creature:getName():lower()
    if config.rotateMonster:lower() ~= monsterName then
        return true
    end
   
    if Tile(config.teleport.spawnPosition):getItemById(1387) then
        return true
    end

    for direction = 0, 3 do
        local checkPosition = Position(position)
        checkPosition:getNextPosition(direction)
        local tile = Tile(checkPosition)
        if tile then
            for _, itemId in pairs(config.rotateItems) do
                local rotatableItem = tile:getItemById(itemId)
                if rotatableItem then
                    rotateItem(rotatableItem)
                    break
                end
            end
        end
    end
   
    if not isAllObjectsRotatedCorrectly() then
        return true
    end
   

    createTimedPortal(config.teleport.spawnPosition, config.teleport.destination, config.teleport.duration)
    addEvent(randomRotateAllItemsInArea, config.teleport.duration * 1000, config.area.from, config.area.to)
    sendMessageToEventPlayers("The portal has been activated!\nGo through it quickly!", MESSAGE_INFO_DESCR)
    return true
end

moveevent:aid(config.actionId)
moveevent:register()


local creatureevent = CreatureEvent("onLogin_MadusaRequest")

function creatureevent.onLogin(player)
    if player:getPosition():isInRange(config.area.from, config.area.to) then
        player:teleportTo(config.kickPosition)
    end
    return true
end

creatureevent:register()



local globalevent = GlobalEvent("onStartUp_MadusaRequest")

function globalevent.onStartup()
    randomRotateAllItemsInArea(config.area.from, config.area.to)
    return true
end

globalevent:register()
 
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.

bandicam2024-02-0514-39-17-972-ezgif.com-video-to-gif-converter.gif

in data\scripts\eventcallbacks\monster\default_onDropLoot.lua
replace the entire code with this
Lua:
local ec = EventCallback

ec.onDropLoot = function(self, corpse)
    if configManager.getNumber(configKeys.RATE_LOOT) == 0 then
        return
    end

    local player = Player(corpse:getCorpseOwner())
    local mType = self:getType()
    if not player or player:getStamina() > 840 then
        local boostedLootMultiplier = 1
        local corpsePosition = corpse:getPosition()
        if Game.getStorageValue(GLOBAL_BonusLootandExperience.globalStorage) > os.time() then
            for k, v in pairs(GLOBAL_BonusLootandExperience.areas) do
                if corpsePosition:isInRange(v.from, v.to) then
                    boostedLootMultiplier = 1 + (GLOBAL_BonusLootandExperience.lootBoost / 100)
                    break
                end
            end
        end
        local monsterLoot = mType:getLoot()
        for i = 1, #monsterLoot do
            if monsterLoot[i].chance then
                monsterLoot[i].chance = math.min(monsterLoot[i].chance * boostedLootMultiplier, MAX_LOOTCHANCE)
            end
            local item = corpse:createLootItem(monsterLoot[i])
            if not item then
                print('[Warning] DropLoot:', 'Could not add loot item to corpse.')
            end
        end

        if player then
            local text = ("Loot of %s: %s"):format(mType:getNameDescription(), corpse:getContentDescription())
            local party = player:getParty()
            if party then
                party:broadcastPartyLoot(text)
            else
                player:sendTextMessage(MESSAGE_LOOT, text)
            end
        end
    else
        local text = ("Loot of %s: nothing (due to low stamina)"):format(mType:getNameDescription())
        local party = player:getParty()
        if party then
            party:broadcastPartyLoot(text)
        else
            player:sendTextMessage(MESSAGE_LOOT, text)
        end
    end
end

ec:register()


data/scripts/spawnMonsters_whenAllKilledGiveBonusLootandExperience.lua
Lua:
GLOBAL_BonusLootandExperience = {
    globalStorage = 45037,
    experienceBoost = 100, -- percent
    lootBoost = 100, -- percent
    areas = {
        {from = Position(936, 1006, 7), to = Position(947, 1017, 7)},
        --{from = Position(1000, 1000, 7), to = Position(1000, 1000, 7)}
    },
    
    endTime = 0 -- don't modify
}

local config = {
    rift = {
        itemId = 1387, -- any portal item
        duration = 120,
        spawnPosition = Position(988, 995, 7),
        destination = Position(941, 1007, 7)
    },
    monsters = {
        {name = "rotworm", position = Position(940, 1010, 7)},
        {name = "troll", position = Position(943, 1010, 7)}
    },
    riftRewardTimer = 30 -- minutes (how long the bonus loot and experience lasts)
}

-- END OF CONFIG

local riftMonsters = {}

local function createTimedRift(position, destination, timer, riftId, riftSpawned)
    if not riftSpawned then
        local rift = Game.createItem(riftId, 1, position)
        rift:setDestination(destination)
        riftSpawned = true
    end
    local rift = Tile(position):getItemById(riftId)
    if rift then
        if timer % 5 == 0 and timer ~= 0 then
            for _, creature in pairs(Game.getPlayers()) do
                creature:say(timer, TALKTYPE_MONSTER_SAY, false, nil, position)
                break
            end
        end
        if timer > 0 then
            addEvent(createTimedRift, 1000, position, destination, timer - 1, riftId, riftSpawned)
            return
        end
        rift:remove()
    end
end

local function spawnRift()
    for k, v in pairs(config.monsters) do
        print(v.name, v.position.x, v.position.y)
        local monster = Game.createMonster(v.name, v.position, true, true)
        if monster then
            riftMonsters[monster:getId()] = 0
            monster:registerEvent("onDeath_riftMonsters")
        end
    end
    createTimedRift(config.rift.spawnPosition, config.rift.destination, config.rift.duration, config.rift.itemId)
end

local function riftReward()
    Game.setStorageValue(GLOBAL_BonusLootandExperience.globalStorage, os.time() + (config.riftRewardTimer * 60))
    Game.broadcastMessage(string.format("All rift monsters were killed! Monsters in specific areas now give %s%% increased experience and %s%% increased loot!", GLOBAL_BonusLootandExperience.experienceBoost, GLOBAL_BonusLootandExperience.lootBoost))
end


local creatureevent = CreatureEvent("onDeath_riftMonsters")

function creatureevent.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
    riftMonsters[creature:getId()] = nil
    if next(riftMonsters) == nil then
        riftReward()
    end
    return true
end

creatureevent:register()


local globalevent = GlobalEvent("onStartUp_riftMonsters")

function globalevent.onStartup()
    Game.setStorageValue(GLOBAL_BonusLootandExperience.globalStorage, 0)
    return true
end

globalevent:register()


local ec = EventCallback

ec.onGainExperience = function(self, source, exp, rawExp)
    if not source:isMonster() then
        return exp
    end
    if Game.getStorageValue(GLOBAL_BonusLootandExperience.globalStorage) > os.time() then
        local percent = 1 + (GLOBAL_BonusLootandExperience.experienceBoost / 100)
        exp = exp * percent
        print("bonus experience working?")
    end
    return exp
end

ec:register()



local action = Action()

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

action:id(2173)
action:register()
 
Per your request i'm not greedy!!!



------------------------

Request 1: Evolving Weapons

Lots of weapons can become legendary in name.
In the universe of Arda, many weapons are named after their deeds.
For example, the Goblin Cleaver was named for its slaying of many Goblins.
Which brings me to the idea of weapons that can evolve!


  1. The player obtains for example a sword. (should be configurable to set specific weapons to be able to evolve)​
  2. If the sword kills 1000 Goblins, it turns into Goblin Cleaver, giving extra damage to Goblins.​



- When the item has been traded, the count should still be on the weapon.
------------------------


Request 2: A Creature that adjusts its speed according to the current target
As I have different chase scenes in an open-world game, it is a bit painful to adjust the monster's speed to the player level,
especially on lower-level players, this is troublesome.

  1. A creature that can adjust its speed to the speed of its current target player.​
  2. If a player is level 1 it should have the speed of a level 2.​
  3. If a player is level 2, it should have the speed of a level 3.​
(might be too easy)
------------------------

Flying Kiss Flirting GIF by SpongeBob SquarePants

ezgif.com-animated-gif-maker.gif

data/script/evolvingWeapons.lua
Lua:
local evolvingWeapons = {
    [2376] = {
        ["Gobblin' These Nuts"] = {
            evolve = {
                killsRequired = 20,
                newDescription = "With your wanton cravings out of whack, you gobble up all the nuts and deal increased damage.",
                monsters = {
                    ["goblin lord"] = {value = 20},
                    ["goblin"] = {value = 1},
                    ["goblin assassin"] = {value = 1}
                }
            },
            bonuses = {
                increasedDamagePercent = 100,
                affectedMonsters = {"goblin", "goblin assassin"}
            }
        },
        ["Dragon Poker"] = {
            evolve = {
                killsRequired = 20,
                newDescription = "Poking dragons bum for increased damage. :D",
                monsters = {
                    ["demodras"] = {value = 20},
                    ["dragon"] = {value = 1},
                    ["dragon lord"] = {value = 2}
                }
            },
            bonuses = {
                increasedDamagePercent = 100,
                affectedMonsters = {"dragon", "dragon lord"}
            }
        }       
    }
}

-- END OF CONFIG

local affectedMonsters = {}

for itemId, weapons in pairs(evolvingWeapons) do
    for weaponName, weaponDetails in pairs(weapons) do
        -- recreate monster table with lowercase letters
        local newMonsters = {}
        for monsterName, monsterDetails in pairs(weaponDetails.evolve.monsters) do
            newMonsters[monsterName:lower()] = monsterDetails
        end
        weaponDetails.evolve.monsters = newMonsters
        -- update all affected monster with lowercase letters
        if weaponDetails.bonuses and weaponDetails.bonuses.affectedMonsters then
            for i, monsterName in ipairs(weaponDetails.bonuses.affectedMonsters) do
                weaponDetails.bonuses.affectedMonsters[i] = monsterName:lower()
                affectedMonsters[weaponDetails.bonuses.affectedMonsters[i]] = 0
            end
        end
    end
end

local function sendDelayedMessage(creatureId, message)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
    creature:sendTextMessage(MESSAGE_INFO_DESCR, message)
end


local creatureevent = CreatureEvent("onKill_evolvingWeapons")

function creatureevent.onKill(creature, target)
    if not target:isMonster() then
        return true
    end
   
    local weapon = creature:getSlotItem(CONST_SLOT_LEFT)
    if not weapon then
        return true
    end
   
    if weapon:getCustomAttribute("EVOLVED_WEAPON") then
        return true
    end
   
    local index = evolvingWeapons[weapon:getId()]
    if not index then
        return true
    end
   
    local monsterName = target:getName():lower()   
    local evolveEvents = {
        -- {evolveName = "", totalKills = 0}
    }
   
    for k, v in pairs(index) do
        local totalKills = weapon:getCustomAttribute(k)
        totalKills = totalKills and totalKills or 0
        if v.evolve.monsters[monsterName] then
            totalKills = totalKills + v.evolve.monsters[monsterName].value
            weapon:setCustomAttribute(k, totalKills)
        end
        if totalKills >= v.evolve.killsRequired then
            evolveEvents[#evolveEvents + 1] = {evolveName = k, totalKills = totalKills}
        end
    end
   
    table.sort(evolveEvents, function(a, b) return a.totalKills > b.totalKills end)
   
    if not evolveEvents[1] or evolveEvents[2] and evolveEvents[1].totalKills == evolveEvents[2].totalKills then
        return true
    end
   
    for k, _ in pairs(index) do
        if weapon:getCustomAttribute(k) then
            weapon:removeCustomAttribute(k)
        end
    end
   
    local itemName = ItemType(weapon:getId()):getName()
    local text = string.format("Your %s evolved into %s!", itemName, evolveEvents[1].evolveName)
    addEvent(sendDelayedMessage, 0, creature:getId(), text)
    weapon:setAttribute(ITEM_ATTRIBUTE_NAME, evolveEvents[1].evolveName)
    weapon:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, index[evolveEvents[1].evolveName].evolve.newDescription)
    weapon:setCustomAttribute("EVOLVED_WEAPON", evolveEvents[1].evolveName)
    return true
end

creatureevent:register()


local creatureevent = CreatureEvent("onLogin_evolvingWeapons")

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

creatureevent:register()



local creatureevent = CreatureEvent("onHealthChange_evolvingWeapons")

function creatureevent.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    if not isPlayer(attacker) then
        return primaryDamage, primaryType, secondaryDamage, secondaryType
    end
   
    local weapon = attacker:getSlotItem(CONST_SLOT_LEFT)
    if not weapon then
        return primaryDamage, primaryType, secondaryDamage, secondaryType
    end
   
    local evolvedWeapon = weapon:getCustomAttribute("EVOLVED_WEAPON")
    if not evolvedWeapon then
        return primaryDamage, primaryType, secondaryDamage, secondaryType
    end
   
    local index = evolvingWeapons[weapon:getId()][evolvedWeapon].bonuses
    if not table.contains(index.affectedMonsters, creature:getName():lower()) then
        return primaryDamage, primaryType, secondaryDamage, secondaryType
    end
   
    primaryDamage = primaryDamage * ((index.increasedDamagePercent + 100) / 100)
    secondaryDamage = secondaryDamage * ((index.increasedDamagePercent + 100) / 100)
    return primaryDamage, primaryType, secondaryDamage, secondaryType
end

creatureevent:register()



local eventCallback = EventCallback

function eventCallback.onSpawn(creature, position, startup, artificial)
    if affectedMonsters[creature:getName():lower()] then
        creature:registerEvent("onHealthChange_evolvingWeapons")
    end
    return true
end

eventCallback:register(-666)
 
Last edited:
Xikini,
I tried to make it myself but to no avail.

So here goes:

I have 10 different teleports in different places.
I would like it to always at 24:00, change access randomly.
E.g..
Teleport 1/2/3
Teleport 2/3/5
Teleport 4/2/1

In addition, if the player has the necessary storage (for each teleport different, then regardless of whether the teleport is open he will be able to use it.
I hope you understood.

It would also be extra if, for example, it would be possible to use an item that shows in the text of the book what teleports are active at a given time.
 
Back
Top