• 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,835
Solutions
585
Reaction score
5,431
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:
Okay, so I disliked how incomplete the system was before.. so It's been updated.

And here's an example of what you can do with it, including the new functions.

View attachment 82368

Lua:
local function doStuff(creatureId, eventTimeline, originalSpeed)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
 
    local campfireLocation = Position(1002, 1006, 7)
 
    if eventTimeline == 0 then
        local nodeList = {
            {position = Position(1012, 1014, 7), nodeLooseness = 2},
            {position = Position(1017, 1010, 7), nodeLooseness = 1},
            {position = Position(1016, 1006, 7)},
            {position = Position(1015, 1006, 7)},
            {position = Position(1013, 1006, 6), changeElevation = true},
            {position = Position(1008, 1006, 6)},
            {position = Position(1006, 1006, 7), changeElevation = true},
            {position = Position(1001, 1006, 7)}
        }
        creature:startWalkCreatureAlongNodes(nodeList)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 1 then
        if creature:isWalkingCreatureAlongNodes() then
            if not originalSpeed and creature:getPosition():getDistance(Position(1017, 1012, 7)) <= 1 then
                creature:setPauseWalkCreatureAlongNodes(true, false)
                originalSpeed = 1 -- reusing this, cuz not being used yet
                addEvent(doStuff, getStepDuration(creature), creatureId, eventTimeline, originalSpeed)
                return
            elseif originalSpeed == 1 then
                creature:setDirection(DIRECTION_EAST)
                creature:say("Hello other me!")
                originalSpeed = 2
                addEvent(doStuff, 5000, creatureId, eventTimeline, originalSpeed)
                return
            elseif originalSpeed == 2 then
                creature:setPauseWalkCreatureAlongNodes(false)
                originalSpeed = 3
            end
            addEvent(doStuff, 500, creatureId, eventTimeline, originalSpeed)
            return
        end
        -- reached destination
        local speed = creature:getSpeed()
        creature:changeSpeed(-speed)
        originalSpeed = speed
        creature:setDirection(DIRECTION_EAST)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 2 then
        campfireLocation:sendMagicEffect(CONST_ME_POFF)
        Game.createItem(1421, 1, campfireLocation)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 3 then
        campfireLocation:sendMagicEffect(CONST_ME_POFF)
        local thing = Tile(campfireLocation):getItemById(1421)
        thing:transform(1422)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 4 then
        campfireLocation:sendMagicEffect(CONST_ME_FIREAREA)
        local thing = Tile(campfireLocation):getItemById(1422)
        thing:transform(1423)
        addEvent(doStuff, 10000, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 5 then
        campfireLocation:sendMagicEffect(CONST_ME_POFF)
        local thing = Tile(campfireLocation):getItemById(1423)
        thing:transform(1422)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 6 then
        campfireLocation:sendMagicEffect(CONST_ME_POFF)
        local thing = Tile(campfireLocation):getItemById(1422)
        thing:transform(1421)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 7 then
        campfireLocation:sendMagicEffect(CONST_ME_POFF)
        local thing = Tile(campfireLocation):getItemById(1421)
        thing:remove()
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 8 then
        local nodeList = {
            {position = Position(1001, 1016, 7)}
        }
        creature:changeSpeed(originalSpeed)
        creature:startWalkCreatureAlongNodes(nodeList)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 9 then
        if creature:isWalkingCreatureAlongNodes() then
            addEvent(doStuff, 500, creatureId, eventTimeline, originalSpeed)
            return
        end
        creature:teleportTo(Position(1000, 1017, 7), true)
        addEvent(doStuff, 200, creatureId, eventTimeline + 1, originalSpeed)
    elseif eventTimeline == 10 then
        local thing = Tile(Position(1000, 1017, 7)):getItemById(5500)
        thing:transform(5498)
        thing = Tile(Position(1001, 1017, 7)):getItemById(5501)
        thing:transform(5499)
        creature:getPosition():sendMagicEffect(CONST_ME_POFF)
        creature:remove()
    end    
end

local creature = 0

local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local target = Creature(creature)
    if not target then
        creature = Game.createNpc("bounty person", Position(1001, 1016, 7))
        if creature then
            creature = creature:getId()
            target = Creature(creature)
        end
    
        local thing = Tile(Position(1000, 1017, 7)):getItemById(5498)
        if thing then
            thing:transform(5500)
            thing = Tile(Position(1001, 1017, 7)):getItemById(5499)
            thing:transform(5501)
        end

        doStuff(target:getId(), 0)
    end
    return true
end

action:id(2173)
action:register()

They voice acting in the movie is really something exceptional... ah wait... What you have done with that script... or system I should say, is way beyond anyone would have expected, but I have already told you that...

I couldn't resist to try how it works, and there is really nothing that I would suggest regarding the quality or features. And I quit suggesting you another script ideas because after my suggestion you have spent more or less 22-24 hours (while streaming!) to create this system. Great work but god, slow down please! And have a nice day 🙃
 
They voice acting in the movie is really something exceptional... ah wait... What you have done with that script... or system I should say, is way beyond anyone would have expected, but I have already told you that...

I couldn't resist to try how it works, and there is really nothing that I would suggest regarding the quality or features. And I quit suggesting you another script ideas because after my suggestion you have spent more or less 22-24 hours (while streaming!) to create this system. Great work but god, slow down please! And have a nice day 🙃
The dinging you hear in the background is what I hear on stream everytime you guys send a message. xD

and yes, my voice acting career is just starting to blossom. 😊
 
Hi,
Need script talkactions for players.
1.) Player can check the same player maximum 3x for hours.
2.) Player get exhaust for talkctions 1 minute.
3.) If player use !checkbot PLAYERNAME - target player have 1 minutes to answer (code or something like this).
4.) If player target not answer (send text to first player (BOT Confirmed, you can kill him without frag).
5.) If player taget is bot, first player can kill him without frag.
6.) If target player target answer true, send message to first player (this is no bot).

*Player first can check target only is located at a maximum distance of 5 sqm.
And if this possibile, when player target not answer, player first have DMG X2.
 
The dinging you hear in the background is what I hear on stream everytime you guys send a message. xD

and yes, my voice acting career is just starting to blossom. 😊
Damn, those sounds must haunt you in the night, I guess it is more challenging to hear them for the whole day than scripting itself 😁

You got 10/10 from me for the voiceover, no more GIFs from now, you should record vidoes showing off your scripts!
 
Damn, those sounds must haunt you in the night, I guess it is more challenging to hear them for the whole day than scripting itself 😁

You got 10/10 from me for the voiceover, no more GIFs from now, you should record vidoes showing off your scripts!
I used to want to make about 20 scripts but I didn't know how to make them, now that the Xikini is here I can't think of any scripts to ask for.
 
Hi @Xikini

2156.png
Secret Red Gem adds extra +50 health points
2158.png
Secret Blue Gem adds extra +50 mana points

Players without VIP Access can use a maximum of 30 secret gems, while VIP Access players can use 50 secret gems.

Here is the table of available usages of secret gems (with VIP Access):

Available usages of secret gems:
Vocation:Max usages of Secret Red Gems:Max usages of Secret Blue Gems:
Sorcerer20 (+1000 health points)50 (+2500 mana points)
Druid20 (+1000 health points)50 (+2500 mana points)
Paladin25 (+1250 health points)35 (+1750 mana points)
Knight35 (+1750 health points)40 (+2000 mana points)

This is your decision which gems you will use to upgrade your character.

For example: Your character with vocation Sorcerer can have +2400 extra mana points, but you used 48 of 50 total available gems. It means you can add only +100 extra mana or health points depends on your choice.

You can check informations about used or total available gems by command !gems.
 
There's something very borked in the sources for creature:setMovementBlocked(true)
It doesn't seem to work correctly for monsters or npc's.

So, set npc walkinterval to 1500+ when walking npc's along a path.

Monsters 'work' as well, but they try to run to nearby players, and make the path really glitchy looking.

In the gif below, I have 'testPath' enabled, so you can see where the npc is trying to walk.

function list
Lua:
-- for single position walking
-- pauseState = true/false
-- canMove = true/false -- if you creatures to move after pausing and before resuming
-- nodeLooseness = 0+ -- how close to destination creature needs to be, to consider the task finished
-- testPath = true/false/nil -- set to true if you want to see intended path, effects.
Creature:isWalkingCreatureTo()
Creature:stopWalkCreatureTo()
Creature:setPauseWalkCreatureTo(pauseState, canMove)
Creature:startWalkCreatureTo(position, nodeLooseness, testPath)


-- for complicated paths (aka nodes)

-- nodeList -- example..
-- changeElevation = true/false/nil -- set to true if going up/down stairs/holes/ladders/teleporting
--[[
nodeList = {
    {position = Position(1000, 1000, 7), changeElevation = true},
    {position = Position(1001, 1001, 7), nodeLooseness = 2},
    {position = Position(1002, 1002, 7)},
    {position = Position(1003, 1003, 7)}
}

]]--
Creature:isWalkingCreatureAlongNodes()
Creature:stopWalkCreatureAlongNodes()
Creature:setPauseWalkCreatureAlongNodes(pauseState, canMove)
Creature:startWalkCreatureAlongNodes(nodeList, testPath, nodeTimeoutDuration)

View attachment 82325
View attachment 82332
View attachment 82367

Yes, this is the longest script of your life, so that no source edits are required.
data/lib/core/xikiniCustomFunctions.lua
Lua:
-- check attached document

example usage, as shown in the 2nd gif
data/scripts/test.lua
Lua:
local creature = 0

local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local target = Creature(creature)
    if not target then
        creature = Game.createNpc("bounty person", player:getPosition())
        if creature then
            creature = creature:getId()
            target = Creature(creature)
        end
    end
    if target then
        local nodeList = {
            {position = Position(1001, 1006, 7)},
            {position = Position(1006, 1006, 7)},
            {position = Position(1008, 1006, 6), changeElevation = true},
            {position = Position(1013, 1006, 6)},
            {position = Position(1015, 1006, 7), changeElevation = true},
            {position = Position(1019, 1006, 7)},
        }
        walkCreatureAlongNodes(target:getId(), nodeList, true)
        -- walkCreatureAlongNodes(creatureId, nodeList, testPath, nodeLooseness, nodeTimeoutDuration, nodeDuration, nodeActive)
    end
    return true
end

action:id(2173)
action:register()
And more complicated example, as shown in the video.
Lua:
local function doStuff(creatureId, eventTimeline, originalSpeed)
    local creature = Creature(creatureId)
    if not creature then
        return
    end
   
    local campfireLocation = Position(1002, 1006, 7)
   
    if eventTimeline == 0 then
        local nodeList = {
            {position = Position(1012, 1014, 7), nodeLooseness = 2},
            {position = Position(1017, 1010, 7), nodeLooseness = 1},
            {position = Position(1016, 1006, 7)},
            {position = Position(1015, 1006, 7)},
            {position = Position(1013, 1006, 6), changeElevation = true},
            {position = Position(1008, 1006, 6)},
            {position = Position(1006, 1006, 7), changeElevation = true},
            {position = Position(1001, 1006, 7)}
        }
        creature:startWalkCreatureAlongNodes(nodeList)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 1 then
        if creature:isWalkingCreatureAlongNodes() then
            if not originalSpeed and creature:getPosition():getDistance(Position(1017, 1012, 7)) <= 1 then
                creature:setPauseWalkCreatureAlongNodes(true, false)
                originalSpeed = 1 -- reusing this, cuz not being used yet
                addEvent(doStuff, getStepDuration(creature), creatureId, eventTimeline, originalSpeed)
                return
            elseif originalSpeed == 1 then
                creature:setDirection(DIRECTION_EAST)
                creature:say("Hello other me!")
                originalSpeed = 2
                addEvent(doStuff, 5000, creatureId, eventTimeline, originalSpeed)
                return
            elseif originalSpeed == 2 then
                creature:setPauseWalkCreatureAlongNodes(false)
                originalSpeed = 3
            end
            addEvent(doStuff, 500, creatureId, eventTimeline, originalSpeed)
            return
        end
        -- reached destination
        local speed = creature:getSpeed()
        creature:changeSpeed(-speed)
        originalSpeed = speed
        creature:setDirection(DIRECTION_EAST)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 2 then
        campfireLocation:sendMagicEffect(CONST_ME_POFF)
        Game.createItem(1421, 1, campfireLocation)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 3 then
        campfireLocation:sendMagicEffect(CONST_ME_POFF)
        local thing = Tile(campfireLocation):getItemById(1421)
        thing:transform(1422)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 4 then
        campfireLocation:sendMagicEffect(CONST_ME_FIREAREA)
        local thing = Tile(campfireLocation):getItemById(1422)
        thing:transform(1423)
        addEvent(doStuff, 10000, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 5 then
        campfireLocation:sendMagicEffect(CONST_ME_POFF)
        local thing = Tile(campfireLocation):getItemById(1423)
        thing:transform(1422)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 6 then
        campfireLocation:sendMagicEffect(CONST_ME_POFF)
        local thing = Tile(campfireLocation):getItemById(1422)
        thing:transform(1421)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 7 then
        campfireLocation:sendMagicEffect(CONST_ME_POFF)
        local thing = Tile(campfireLocation):getItemById(1421)
        thing:remove()
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 8 then
        local nodeList = {
            {position = Position(1001, 1016, 7)}
        }
        creature:changeSpeed(originalSpeed)
        creature:startWalkCreatureAlongNodes(nodeList)
        addEvent(doStuff, 500, creatureId, eventTimeline + 1, originalSpeed)
        return
    elseif eventTimeline == 9 then
        if creature:isWalkingCreatureAlongNodes() then
            addEvent(doStuff, 500, creatureId, eventTimeline, originalSpeed)
            return
        end
        creature:teleportTo(Position(1000, 1017, 7), true)
        addEvent(doStuff, 200, creatureId, eventTimeline + 1, originalSpeed)
    elseif eventTimeline == 10 then
        local thing = Tile(Position(1000, 1017, 7)):getItemById(5500)
        thing:transform(5498)
        thing = Tile(Position(1001, 1017, 7)):getItemById(5501)
        thing:transform(5499)
        creature:getPosition():sendMagicEffect(CONST_ME_POFF)
        creature:remove()
    end       
end

local creature = 0

local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local target = Creature(creature)
    if not target then
        creature = Game.createNpc("bounty person", Position(1001, 1016, 7))
        if creature then
            creature = creature:getId()
            target = Creature(creature)
        end
       
        local thing = Tile(Position(1000, 1017, 7)):getItemById(5498)
        if thing then
            thing:transform(5500)
            thing = Tile(Position(1001, 1017, 7)):getItemById(5499)
            thing:transform(5501)
        end

        doStuff(target:getId(), 0)
    end
    return true
end

action:id(2173)
action:register()
THIS. IS. INCREDIBLE.

LOVE YOU XIKINI, Im gonna have so much fun creating new NPC's :)
 
As requested, can put every element up to 10%.

View attachment 82075

data/scripts/delikeramRequest.lua
Lua:
local amuletItemId = 2173
local maximumUpgradePercent = 10

local protectionItems = {
--    [1111] = {protectionType = "physical", percent = 0.5},
    [8303] = {protectionType = "energy", percent = 0.5},
--    [1111] = {protectionType = "earth", percent = 0.5},
--    [1111] = {protectionType = "fire", percent = 0.5},
    [8302] = {protectionType = "ice", percent = 0.5},
--    [1111] = {protectionType = "holy", percent = 0.5},
--    [1111] = {protectionType = "death", percent = 0.5}
}

-- END OF CONFIG

local protectionTypes = {
    ["physical"] = COMBAT_PHYSICALDAMAGE,
    ["energy"] = COMBAT_ENERGYDAMAGE,
    ["earth"] = COMBAT_EARTHDAMAGE,
    ["fire"] = COMBAT_FIREDAMAGE,
    ["ice"] = COMBAT_ICEDAMAGE,
    ["holy"] = COMBAT_HOLYDAMAGE,
    ["death"] = COMBAT_DEATHDAMAGE
}

local combatTypes = {
    [COMBAT_PHYSICALDAMAGE] = "physical",
    [COMBAT_ENERGYDAMAGE] = "energy",
    [COMBAT_EARTHDAMAGE] = "earth",
    [COMBAT_FIREDAMAGE] = "fire",
    [COMBAT_ICEDAMAGE] = "ice",
    [COMBAT_HOLYDAMAGE] = "holy",
    [COMBAT_DEATHDAMAGE] = "death"
}


local function setProtectionDescription(item)
    local text = ""
    local isMaxUpgraded = true
    local order = {"physical", "energy", "earth", "fire", "ice", "holy", "death"}
    for _, element in ipairs(order) do
        local attributeValue = item:getCustomAttribute(element) or 0
        if attributeValue > 0 then
            if text ~= "" then
                text = text .. ", "
            end
            text = text .. element .. " +" .. attributeValue .. "%"
        end
        if attributeValue ~= maximumUpgradePercent then
            isMaxUpgraded = false
        end
    end
    if isMaxUpgraded then
        text = "[Additional Protections: All Damage Types +" .. maximumUpgradePercent .. "%]"
    else
        text = "[Additional Protections: " .. text .. "]"
    end
    item:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, text)
end

local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not target:isItem() then
        player:getPosition():sendMagicEffect(CONST_ME_POFF)
        return true
    end
    if target:getId() ~= amuletItemId then
        target:getPosition():sendMagicEffect(CONST_ME_POFF)
        return true
    end
  
    local itemId = item:getId()
    local attributeValue = target:getCustomAttribute(protectionItems[itemId].protectionType) or 0
  
    if attributeValue >= maximumUpgradePercent then
        target:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
        return true
    end
  
    target:setCustomAttribute(protectionItems[itemId].protectionType, math.min(attributeValue + protectionItems[itemId].percent, maximumUpgradePercent))
    target:getPosition():sendMagicEffect(CONST_ME_MAGIC_GREEN)
    setProtectionDescription(target)
    item:remove(1)
    return true
end

for itemId, _ in pairs(protectionItems) do
    action:id(itemId)
end
action:register()


local function damageCalculator(player, primaryDamage, primaryType, secondaryDamage, secondaryType)
    local slotItem = player:getSlotItem(CONST_SLOT_NECKLACE)
    if slotItem then
        if combatTypes[primaryType] then
            local reductionPecent = slotItem:getCustomAttribute(combatTypes[primaryType]) or 0
            if reductionPecent > 0 then
                primaryDamage = primaryDamage - (primaryDamage * (reductionPecent / 100))
            end
        end
        if combatTypes[secondaryType] then
            local reductionPecent = slotItem:getCustomAttribute(combatTypes[secondaryType]) or 0
            if reductionPecent > 0 then
                secondaryDamage = secondaryDamage - (secondaryDamage * (reductionPecent / 100))
            end
        end
    end
    return primaryDamage, secondaryDamage
end


local healthChange = CreatureEvent("onHealthChange_protectionAmulet")

function healthChange.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    primaryDamage, secondaryDamage = damageCalculator(creature, primaryDamage, primaryType, secondaryDamage, secondaryType)
    return primaryDamage, primaryType, secondaryDamage, secondaryType
end

healthChange:register()


local manaChange = CreatureEvent("onManaChange_protectionAmulet")

function manaChange.onManaChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
    primaryDamage, secondaryDamage = damageCalculator(creature, primaryDamage, primaryType, secondaryDamage, secondaryType)
    return primaryDamage, primaryType, secondaryDamage, secondaryType
end

manaChange:register()


local creatureevent = CreatureEvent("example")

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

creatureevent:register()
@Xikini
I was looking at this system and it looks interesting, I was wondering if I could make a modification and add "Dodge" as a custom attribute, that is, you can add Dodge to the equipment, thus having 25% Dodge in each part of the equipment, by achieving 100% if you have the equipment with 25% each. (Helmet, Armor, Legs, Boots).

I have seen what this Dodge system is, but as storage for the character.

Well, what I'm trying to do is replace this player system (storages) with a Dodge equipment system.

You can also implement a Critical attribute, the same as the Dodge but the higher the percentage, the more damage it does and the more frequently it comes out.

EDIT: If there is the possibility of also adding a reflect attribute as well, it will work like the dodge but the reflect makes it reflect the damage / if the player gives it a hit of 200, it would reflect 50% which would be 100 damage to the opponent. If the player receives 5 hits, would he get a reflect perhaps? hmm I don't know, you can do it your way.So it would be Dodge/Critical and Reflect. Thank you!

The time and dedication is appreciated.
 
Last edited:
Here are some Quest & Boss Mechanics that would be fun and interesting to have in the community and could be used in many different ways:



QUEST MECHANICS:

Outfit:
- An item (closet, for example) that onClick changes your Outfit for certain amount of time.

- NPC's react to outfit (if you have normal outfit, they wont let you cross the door/dont talk to you, if you have "Camuflated Outfit exclusive for the quest (could be from the mechanic above) then they let you cross the door/do talk to you.

- Npc reacts to spell. For example, a Warrior has "Berserker Spell", and the NPC is a coward, so when a player activates Berserker spell in front of him, the NPC run away and come back to it's original position after 3 minutes.

- Find "Quest buff" that is applied differently to each vocation and lasts until quest is finished. For example, there is an item in the quest that holds the buff. When a warrior clik on it, gives him +10 Attack, when a Sorcerer click on it, gives him +5 Magic lvl. Same could be with any other skill, like speed or distance or atributes like elements resistence and others.



BOSS MECHANICS:


- CINEMATIC INTRO TO BOSS:
When 4 characters have entered into the room (Paladin, Knight, Sorcerer and Druid), all characters are teleported to specific position and freeze (can't move, attack or talk on chat). Douring this time the BOSS does the cinematic intro (walk into the screen, talk and make some magic effect. Here's a place to be creative, include other NPC's into the cinematic to have a conversation, etc..)

* Could here be added automatic text dialogues from the player's characters itself?? :O



- ROOM FIGHTING MECHANICS:

1. There is a room in the boss chamber's that spawn monsters in waves, such as in RAID event you did. But there are 2 columns/pilars near this door. If players during battle bring the Boss close to that colums/pilars and the boss hit them with an specific spell (let's say "Exori"), after 3 hits, the column will break. When both columns are broken by the boss attacks, stones fall into the door and so monster waves cannot go trough the door and attack you.


2. In the Boss chamber there are 4 weapons (Magic tool, balista,...). When the fight starts, the boss have like a magic armor spell on with 90% damage reduction, but the boss summons other monsters, and this monsters drop directly into the ground (no need to open the corpses) the balista/magic tool missiles. This missiles look like floating in the map. The players have to step into the missile position (when this happens, the missile is floating over the characters head) and walk with the missile into the magic tool/balista charging position(behind). When balista is charged, the 4 players have to stay into "Balista Charging position" at the same time and they shoots 3 missiles automaticly to the boss. This missiles do not cause damage to the boss but break the armor, so players now can cause 80% damage instead of only 10% for a certain amount of time (15-30 seconds).


Thank you so much @Xikini !!! :D
 
Changing spell colldown (attack) when player attack player (mouser target)

etc. If player attack monsters have default spell colldown but Its attack player all attack spells have colldowns 2s.
Might be possible?
Have to look into it.

Since you make such clean and handsome scripts, could you also add like physical and elemental damage?
That and capacity increase it 2 additions that would be dope in this script!

/Thanks in advance, Erna.
There is already systems out there to do this.

Requesting a more unique loot stats for all weapons, and equipment but not to complicated with attributes and such.

Weapons can have a boost of max +3 in atk and defense.

Armors/legs/shield can have a max boost of +2

helmets/boots/amulets/rings can have a max boost of +1 def

Lets use the katana as an example, common stats are atk:16 def: 12 so with the more unique loot stats I mean you are able to loot katanas with the max stats of +3 of the regular stats so the max would be atk:19 def: 15 but can be anything in between. Same with for example studded armor: 5 max can be armor: 7.

And no fancy names like common, rare and legendary just
Same thing as above.. there are systems out there.
Just remove the common/rare/legendary descriptions, and you're already golden.

Just a little question, using slot = "backpack, ammo" will work? Because backpacks can be equiped (generally) on ammo and backpack slots. Just tested it as this:
View attachment 82364
but it only triggers the ammo slot in this case. There's also a test that must be done in case that both slots get enabled, just a little tip check if equip and deequip events with the two avaible slots for the same item can cause addition of infinite capacity. Regards!

You have to change how it registers them.
so change slot = "backpack" to slot = {"backpack", "ammo"}

Then down below when it's registering the item for a slot, you'd loop through this table and grab all the slots.

And the item equips and de-equips.. and rechecks all the items you're wearing.. so there's no way for it to cause infinite capacity.

If for some reason it is causing that.. you could turn it into an addEvent with timer of 0, so it happens 1 ms after the item equip/deequip is finished.

-----

And I've updated the main post with all the new Pending Requests.
 
View attachment 82272

data/scripts/bountyHunterSystem.lua
Lua:
GLOBAL_BOUNTY_INFO = {
    redSkullBounty = 10000,
    bountyStorage = 45084,
    bountyPayoutStorage = 45086,
    bountyStartTimeStorage = 45088,
    bountyBuyoffDelay = 24 * 60 * 60,
    skullStorage = 45085,
    bountyActionId = 45087 -- put actionId on items you want (onLook function, for telling about bounties)
}


function getBountyStartTime(player)
    return player:getStorageValue(GLOBAL_BOUNTY_INFO.bountyStartTimeStorage)
end

function getBountyPayout(player)
    local bountyAmount = player:getStorageValue(GLOBAL_BOUNTY_INFO.bountyPayoutStorage)
    bountyAmount = bountyAmount > 0 and bountyAmount or 0
    return bountyAmount
end

function getBounty(player)
    local bountyAmount = player:getStorageValue(GLOBAL_BOUNTY_INFO.bountyStorage)
    bountyAmount = bountyAmount > 0 and bountyAmount or 0
    return bountyAmount
end

function changeBounty(player, amount)
    local bountyAmount = getBounty(player) + amount
    player:setStorageValue(GLOBAL_BOUNTY_INFO.bountyStorage, bountyAmount)
    player:sendTextMessage(MESSAGE_STATUS_WARNING, "Your bounty has been " .. (amount > 0 and "increased" or "decreased") .. " to " .. bountyAmount .. ".")
    if amount > 0 and getBountyStartTime(player) == -1 then
        player:setStorageValue(GLOBAL_BOUNTY_INFO.bountyStartTimeStorage, os.time())
    end
end

local function checkPreviousSkull(playerId, currentSkull)
    local player = Player(playerId)
    if not player then
        return
    end
    if player:getSkull() ~= SKULL_RED then
        return
    end
    local previousSkull = currentSkull and currentSkull or player:getStorageValue(GLOBAL_BOUNTY_INFO.skullStorage)
    if previousSkull == SKULL_RED then
        return
    end
    changeBounty(player, GLOBAL_BOUNTY_INFO.redSkullBounty)
    player:setStorageValue(GLOBAL_BOUNTY_INFO.bountyStartTimeStorage, os.time())
end


local creatureevent = CreatureEvent("onKill_BountySystem")

function creatureevent.onKill(creature, target)
    if not target:isPlayer() then
        return true
    end
    local bountyAmount = getBounty(target)
    if bountyAmount > 0 then
        local damageMap = {}
        local playerCount = 0
        for creatureId, damage in pairs(target:getDamageMap()) do
            local _creature = Creature(creatureId)
            if _creature then
                local master = _creature:getMaster()
                if master and master:isPlayer() then
                    _creature = master
                end
                if _creature:isPlayer() then
                    local playerId = _creature:getId()
                    damageMap[playerId] = (damageMap[playerId] or 0) + damage.total
                    playerCount = playerCount + 1
                end
            end
        end
        local payout = math.ceil(bountyAmount / playerCount)
        for playerId, _ in pairs(damageMap) do
            local player = Player(playerId)
            if player then
                local bountyPayout = getBountyPayout(player) + payout
                player:setStorageValue(GLOBAL_BOUNTY_INFO.bountyPayoutStorage, bountyPayout)
                player:sendTextMessage(MESSAGE_STATUS_WARNING, "Bounty Receieved: " .. payout)
            end
        end
        target:say("BOUNTIED PLAYER!\n" .. bountyAmount, TALKTYPE_MONSTER_SAY, false, nil, target:getPosition())
        target:setStorageValue(GLOBAL_BOUNTY_INFO.bountyStorage, 0)
        target:setStorageValue(GLOBAL_BOUNTY_INFO.bountyStartTimeStorage, -1)
    end
    addEvent(checkPreviousSkull, 0, creature:getId(), creature:getSkull())
    return true
end

creatureevent:register()


local creatureevent = CreatureEvent("onLogin_BountySystem")

function creatureevent.onLogin(player)
    addEvent(checkPreviousSkull, 0, player:getId())
    player:registerEvent("onKill_BountySystem")
    return true
end

creatureevent:register()


local creatureevent = CreatureEvent("onLogout_BountySystem")

function creatureevent.onLogout(player)
    player:setStorageValue(GLOBAL_BOUNTY_INFO.skullStorage, player:getSkull())
    return true
end

creatureevent:register()



local ec = EventCallback

ec.onLook = function(self, thing, position, distance, description)  
    if thing:isItem() and thing:getActionId() == GLOBAL_BOUNTY_INFO.bountyActionId then
        local bounties = {}
        for _, player in ipairs(Game.getPlayers()) do
            local bounty = getBounty(player)
            if bounty > 0 then
                bounties[#bounties + 1] = {bounty = bounty, playerName = player:getName()}
            end
        end
        table.sort(bounties, function(a,b)
            return a.bounty > b.bounty
        end)
        description = "You see a list of available bounties."
        if distance > 1 then
            for i = 1, #bounties do
                if i <= 3 then
                    description = description .. "\n" .. bounties[i].playerName .. " " .. bounties[i].bounty
                else
                    description = description .. "\n\n(I could see more bounties if I moved closer)"
                end
                if description ~= "You see a list of available bounties." then
                    description = "\n" .. description
                else
                    description = description  .. "\n\nNobody has a bounty."
                end
            end
        else
            local text = ""
            for i = 1, #bounties do
                if text ~= "" then
                    text = text .. "\n"
                end
                text = text .. bounties[i].playerName .. " " .. bounties[i].bounty
            end
            if text == "" then
                text = text  .. "\n\nNobody has a bounty."
            end
            self:showTextDialog(thing:getId(), "List of available bounties\n\n" .. text)
        end
    end
    return description
end

ec:register(1)

data/npc/Bounty Person.xml
XML:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Bounty Person" script="bountyperson.lua" walkinterval="2000" floorchange="0">
    <health now="100" max="100" />
    <look type="139" head="20" body="39" legs="45" feet="7" addons="0" />
</npc>
data/npc/scripts/bountyperson.lua
Lua:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

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

local bounty = {}
local minimumBounty = 500

local function greetCallback(cid)
    local player = Player(cid)
    npcHandler.topic[cid] = 0
    bounty[cid] = {bountyType = "", bountyAmount = 0, bountyTarget = ""}
    return true
end

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

    local player = Player(cid)
   
    if msgcontains(msg, "bounty") then
        npcHandler:say("Are you wanting to {add} a bounty or {buyoff} or {check} a bounty? Or are you wanting to {collect} your received bounties?", cid)
        npcHandler.topic[cid] = 1
       
    elseif npcHandler.topic[cid] == 1 then
        if not (msgcontains(msg, "buyoff") or msgcontains(msg, "add") or msgcontains(msg, "check") or msgcontains(msg, "collect")) then
            npcHandler:say("Maybe another time, then.", cid)
            npcHandler.topic[cid] = 0
            return true
        end
       
        if msgcontains(msg, "collect") then
            local uncollectedBounty = getBountyPayout(player)
            if uncollectedBounty < 1 then
                npcHandler:say("You do not have any uncollected bounties at this time.", cid)
                npcHandler.topic[cid] = 0
                return true
            end
            npcHandler:say("You currently have " .. uncollectedBounty .. " of uncollected bounty. Would you like to collect it now?", cid)
            npcHandler.topic[cid] = 5
            return true
        end
       
        bounty[cid].bountyType = msgcontains(msg, "add") and "add" or msgcontains(msg, "buyoff") and "buyoff" or "check"
        npcHandler:say("Who do you want to " .. bounty[cid].bountyType .. " a bounty for?", cid)
        npcHandler.topic[cid] = 2
       
    elseif npcHandler.topic[cid] == 2 then
        local bountyPlayer = Player(msg)
        if not bountyPlayer then
            npcHandler:say("The player (" .. msg .. ") is offline, or does not exist.", cid)
            return true
        end
       
        bounty[cid].bountyTarget = bountyPlayer:getName()
        local bountyAmount = getBounty(bountyPlayer)
       
        if bounty[cid].bountyType == "check" then
            npcHandler:say(bounty[cid].bountyTarget .. " has a bounty of " .. bountyAmount .. ".", cid)
            bounty[cid] = {bountyType = "", bountyAmount = 0, bountyTarget = ""}
            npcHandler.topic[cid] = 0
            return true
        end
       
        if bounty[cid].bountyType == "buyoff" and bountyAmount < 1 then
            npcHandler:say("The player (" .. bounty[cid].bountyTarget .. ") has no bounty to buyoff.", cid)
            bounty[cid] = {bountyType = "", bountyAmount = 0, bountyTarget = ""}
            npcHandler.topic[cid] = 0
            return true
        end
       
        if bounty[cid].bountyType == "buyoff" and getBountyStartTime(player) + GLOBAL_BOUNTY_INFO.bountyBuyoffDelay > os.time() then
            npcHandler:say("The player (" .. bounty[cid].bountyTarget .. ")'s bounty is too recent and unable to be bought off.", cid)
            bounty[cid] = {bountyType = "", bountyAmount = 0, bountyTarget = ""}
            npcHandler.topic[cid] = 0
            return true
        end
       
        npcHandler:say("How much bounty would you like to " .. (bounty[cid].bountyType == "add" and "add to" or "buyoff from") .. " " .. bounty[cid].bountyTarget .. "? They currently have a bounty of " .. bountyAmount .. ".", cid)
        npcHandler.topic[cid] = 3
       
    elseif npcHandler.topic[cid] == 3 then
        local bountyPlayer = Player(bounty[cid].bountyTarget)
        if not bountyPlayer then
            npcHandler:say("The player (" .. bounty[cid].bountyTarget .. ") has went offline. Unable to continue with transaction.", cid)
            bounty[cid] = {bountyType = "", bountyAmount = 0, bountyTarget = ""}
            npcHandler.topic[cid] = 0
            return true
        end
       
        local amount = tonumber(msg)
        if not amount or amount ~= math.floor(amount) or amount < 1 then
            npcHandler:say("That is not a valid number.", cid)
            return true
        elseif bounty[cid].bountyType == "add" and amount < minimumBounty then
            npcHandler:say("Minimum bounty that can be added is " .. minimumBounty .. ".", cid)
            return true
        end
       
        if bounty[cid].bountyType == "buyoff" and amount > getBounty(bountyPlayer) then
            amount = getBounty(bountyPlayer)
        end
        bounty[cid].bountyAmount = amount
        npcHandler:say("To confirm, you would you like to " .. (bounty[cid].bountyType == "add" and "add " .. bounty[cid].bountyAmount .. " to" or "buyoff " .. bounty[cid].bountyAmount .. " from") .. " " .. bounty[cid].bountyTarget .. "'s bounty amount?", cid)
        npcHandler.topic[cid] = 4
       
    elseif npcHandler.topic[cid] == 4 then
        if not msgcontains(msg, "yes") then
            npcHandler:say("Maybe another time, then.", cid)
            bounty[cid] = {bountyType = "", bountyAmount = 0, bountyTarget = ""}
            npcHandler.topic[cid] = 0
            return true
        end
   
        local bountyPlayer = Player(bounty[cid].bountyTarget)
        if not bountyPlayer then
            npcHandler:say("The player (" .. bounty[cid].bountyTarget .. ") has went offline. Unable to continue with transaction.", cid)
            bounty[cid] = {bountyType = "", bountyAmount = 0, bountyTarget = ""}
            npcHandler.topic[cid] = 0
            return true
        end
       
       
        local bountyAmount = getBounty(bountyPlayer)
        if bounty[cid].bountyType == "buyoff" and bountyAmount == 0 then
            npcHandler:say("The player (" .. bounty[cid].bountyTarget .. ") no longer has a bounty to buyoff.", cid)
            bounty[cid] = {bountyType = "", bountyAmount = 0, bountyTarget = ""}
            npcHandler.topic[cid] = 0
            return true
        end
       
        local amount = bounty[cid].bountyAmount
        if bounty[cid].bountyType == "buyoff" and amount > bountyAmount then
            amount = bountyAmount
        end
        bounty[cid].bountyAmount = amount
       
        if player:getTotalMoney() < bounty[cid].bountyAmount then
            npcHandler:say("You do not have the required currency available for this transaction.", cid)
            bounty[cid] = {bountyType = "", bountyAmount = 0, bountyTarget = ""}
            npcHandler.topic[cid] = 0
            return true
        end
       
        player:removeTotalMoney(bounty[cid].bountyAmount)
        if bounty[cid].bountyType == "add" then
            bountyAmount = bountyAmount + bounty[cid].bountyAmount
            changeBounty(bountyPlayer, amount)
        else
            bountyAmount = bountyAmount - bounty[cid].bountyAmount
            changeBounty(bountyPlayer, -amount)
            if bountyAmount == 0 then
                bountyPlayer:setStorageValue(GLOBAL_BOUNTY_INFO.bountyStartTimeStorage, -1)
            end
        end
       
       
        npcHandler:say("Transaction successful. " .. bounty[cid].bountyTarget .. "'s bounty is now " .. bountyAmount .. ".", cid)
        bounty[cid] = {bountyType = "", bountyAmount = 0, bountyTarget = ""}
        npcHandler.topic[cid] = 0
       
    elseif npcHandler.topic[cid] == 5 then
        if not msgcontains(msg, "yes") then
            npcHandler:say("Maybe another time, then.", cid)
            npcHandler.topic[cid] = 0
            return true
        end
       
        local uncollectedBounty = getBountyPayout(player)
        player:setBankBalance(player:getBankBalance() + uncollectedBounty)
        player:setStorageValue(GLOBAL_BOUNTY_INFO.bountyPayoutStorage, 0)
        npcHandler:say(uncollectedBounty .. " in accumulated bounties has been sent to your bank.", cid)
        npcHandler.topic[cid] = 0       

    end
    return true
end

local function onAddFocus(cid)

end

local function onReleaseFocus(cid)

end

npcHandler:setCallback(CALLBACK_ONADDFOCUS, onAddFocus)
npcHandler:setCallback(CALLBACK_ONRELEASEFOCUS, onReleaseFocus)

npcHandler:setCallback(CALLBACK_GREET, greetCallback)
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())
Damn sadly not using revscript :o insane release
 
Could you create this script for me please
dodge critical system onlook to player
thank you In advance
If you say it from the post at RevScripts - I need a Dodge&Critical system (https://otland.net/threads/i-need-a-dodge-critical-system.288013/#post-2745062)

Just place this in default_onLook or in the onLook event:
Lua:
-- Look Dodge & Critical --
if thing:isPlayer() and not thing:getGroup():getAccess() then
    local dodgeStorage = STORAGEVALUE_DODGE
    local criticalDodge = STORAGEVALUE_CRITICAL
    local dodgeAmount, criticalAmount = thing:getStorageValue(dodgeStorage), thing:getStorageValue(criticalDodge)
    description = description .. '\nDodge: [' ..dodgeAmount..'] and ' .. 'Critical: ['..criticalAmount..'].'
end
 
Hi @Xikini

2156.png
Secret Red Gem adds extra +50 health points
2158.png
Secret Blue Gem adds extra +50 mana points

Players without VIP Access can use a maximum of 30 secret gems, while VIP Access players can use 50 secret gems.

Here is the table of available usages of secret gems (with VIP Access):

Available usages of secret gems:
Vocation:Max usages of Secret Red Gems:Max usages of Secret Blue Gems:
Sorcerer20 (+1000 health points)50 (+2500 mana points)
Druid20 (+1000 health points)50 (+2500 mana points)
Paladin25 (+1250 health points)35 (+1750 mana points)
Knight35 (+1750 health points)40 (+2000 mana points)

This is your decision which gems you will use to upgrade your character.

For example: Your character with vocation Sorcerer can have +2400 extra mana points, but you used 48 of 50 total available gems. It means you can add only +100 extra mana or health points depends on your choice.

You can check informations about used or total available gems by command !gems.

bandicam2024-02-2310-38-48-351-ezgif.com-video-to-gif-converter.gif

data/script/Forkz_Request.lua
Lua:
local config = {
    totalGemUses = {limit = 30, vipLimitIncrease = 20},
    totalGemStorageKey = 45089,
    gems = {
        [2156] = {
            vocations = {
                [{1, 5}] = {gemLimit = 20}, -- limit is for this gem specifically
                [{2, 6}] = {gemLimit = 20},
                [{3, 7}] = {gemLimit = 25},
                [{4, 8}] = {gemLimit = 35}
            },
            gemStorageKey = 45090,
            health = 50,
            effect = CONST_ME_MAGIC_RED
        },
        [2158] = {
            vocations = {
                [{1, 5}] = {gemLimit = 50}, -- sorc
                [{2, 6}] = {gemLimit = 50}, -- druid
                [{3, 7}] = {gemLimit = 35}, -- pally
                [{4, 8}] = {gemLimit = 40}  -- knight
            },
            gemStorageKey = 45091,
            mana = 50,
            effect = CONST_ME_MAGIC_BLUE
        },
        
        --[2154] = {
        --    vocations = {
        --        [{1, 5}] = {gemLimit = ??},
        --        [{2, 6}] = {gemLimit = ??},
        --        [{3, 7}] = {gemLimit = ??},
        --        [{4, 8}] = {gemLimit = ??}
        --    },
        --    gemStorageKey = 45092,
        --    health = 25, -- could have both hp and mana in 1 gem
        --    mana = 25,
        --  effect = CONST_ME_MAGIC_GREEN
        --},
    }
}



local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    -- local vipStatus = player:isVip() -- returns true/false?
    local vipStatus = true
    
    local totalGemUses = config.totalGemUses.limit + (vipStatus and config.totalGemUses.vipLimitIncrease or 0)
    local currentTotalGemUses = math.max(player:getStorageValue(config.totalGemStorageKey), 0)
    
    if currentTotalGemUses >= totalGemUses then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, "Secret Gem total limit reached.")
        player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
        return true
    end
    
    local gemIndex = config.gems[item:getId()]
    local currentGemUses = math.max(player:getStorageValue(gemIndex.gemStorageKey), 0)
    local vocationId = player:getVocation():getId()
    
    for k, v in pairs(gemIndex.vocations) do
        if table.contains(k, vocationId) then
            if currentGemUses >= v.gemLimit then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "Specific Gem vocation limit reached.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                return true
            end
            break
        end
    end
    
    player:setStorageValue(config.totalGemStorageKey, currentTotalGemUses + 1)
    player:setStorageValue(gemIndex.gemStorageKey, currentGemUses + 1)
    
    if gemIndex.health then
        player:say("+" .. gemIndex.health .. " health!")
        player:setMaxHealth(player:getMaxHealth() + gemIndex.health)
        player:getPosition():sendMagicEffect(gemIndex.effect)
    end
    if gemIndex.mana then
        player:say("+" .. gemIndex.mana .. " mana!")
        player:setMaxMana(player:getMaxMana() + gemIndex.mana)
        player:getPosition():sendMagicEffect(gemIndex.effect)
    end
    
    item:remove(1)
    player:save()
    return true
end

for itemId, _ in pairs(config.gems) do
    action:id(itemId)
end
action:register()


local talkaction = TalkAction("!gems")

function talkaction.onSay(player, words, param, type)
    local text = ""
    local healthGained = 0
    local manaGained = 0
     
    local vocation = player:getVocation()
    local vocationId = vocation:getId()
    
    local gemInfo = ""
    for itemId, info in pairs(config.gems) do
        if gemInfo ~= "" then
            gemInfo = gemInfo .. "\n\n"
        end
        gemInfo = gemInfo .. ItemType(itemId):getName():upper() .. "\n    "
        for k, v in pairs(info.vocations) do
            if table.contains(k, vocationId) then
                gemInfo = gemInfo .. vocation:getName() .. " Limit: " .. v.gemLimit .. "\n    "
                break
            end
        end
        local currentGemUses = math.max(player:getStorageValue(info.gemStorageKey), 0)
        gemInfo = gemInfo .. "Used: " .. currentGemUses .. "\n    "
        gemInfo = gemInfo .. "Gives:"
        if info.health then
            gemInfo = gemInfo .. "\n        Health: " .. info.health
            healthGained = healthGained + (info.health * currentGemUses)
        end
        if info.mana then
            gemInfo = gemInfo .. "\n        Mana: " .. info.mana
            manaGained = manaGained + (info.mana * currentGemUses)
        end
    end
    
    text = "Gem Information\n\nTotal Gained\n    Health: " .. healthGained .. "\n    Mana: " .. manaGained
    text = text .. "\n\nGlobal Gem Limits\n    Non-Vip: " .. config.totalGemUses.limit .. "\n    Vip: " .. (config.totalGemUses.limit + config.totalGemUses.vipLimitIncrease) .. "\n    Used: " .. math.max(player:getStorageValue(config.totalGemStorageKey), 0)
    text = text .. "\n\n" .. gemInfo
        
    player:showTextDialog(2177, text)
    return false
end

talkaction:separator(" ")
talkaction:register()
Post automatically merged:

Changing spell colldown (attack) when player attack player (mouser target)

etc. If player attack monsters have default spell colldown but Its attack player all attack spells have colldowns 2s.
Gave it a try. Can only check if the player has used a spell. Cannot modify the cooldown.
Only way this is possible, is if you manually add cooldowns for spells inside of their files, and add/remove/check/change them that way.
 
Last edited:
View attachment 82403

data/script/Forkz_Request.lua
Lua:
local config = {
    totalGemUses = {limit = 30, vipLimitIncrease = 20},
    totalGemStorageKey = 45089,
    gems = {
        [2156] = {
            vocations = {
                [{1, 5}] = {gemLimit = 20}, -- limit is for this gem specifically
                [{2, 6}] = {gemLimit = 20},
                [{3, 7}] = {gemLimit = 25},
                [{4, 8}] = {gemLimit = 35}
            },
            gemStorageKey = 45090,
            health = 50,
            effect = CONST_ME_MAGIC_RED
        },
        [2158] = {
            vocations = {
                [{1, 5}] = {gemLimit = 50}, -- sorc
                [{2, 6}] = {gemLimit = 50}, -- druid
                [{3, 7}] = {gemLimit = 35}, -- pally
                [{4, 8}] = {gemLimit = 40}  -- knight
            },
            gemStorageKey = 45091,
            mana = 50,
            effect = CONST_ME_MAGIC_BLUE
        },
       
        --[2154] = {
        --    vocations = {
        --        [{1, 5}] = {gemLimit = ??},
        --        [{2, 6}] = {gemLimit = ??},
        --        [{3, 7}] = {gemLimit = ??},
        --        [{4, 8}] = {gemLimit = ??}
        --    },
        --    gemStorageKey = 45092,
        --    health = 25, -- could have both hp and mana in 1 gem
        --    mana = 25,
        --  effect = CONST_ME_MAGIC_GREEN
        --},
    }
}



local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    -- local vipStatus = player:isVip() -- returns true/false?
    local vipStatus = true
   
    local totalGemUses = config.totalGemUses.limit + (vipStatus and config.totalGemUses.vipLimitIncrease or 0)
    local currentTotalGemUses = math.max(player:getStorageValue(config.totalGemStorageKey), 0)
   
    if currentTotalGemUses >= totalGemUses then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, "Secret Gem total limit reached.")
        player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
        return true
    end
   
    local gemIndex = config.gems[item:getId()]
    local currentGemUses = math.max(player:getStorageValue(gemIndex.gemStorageKey), 0)
    local vocationId = player:getVocation():getId()
   
    for k, v in pairs(gemIndex.vocations) do
        if table.contains(k, vocationId) then
            if currentGemUses >= v.gemLimit then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "Specific Gem vocation limit reached.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                return true
            end
            break
        end
    end
   
    player:setStorageValue(config.totalGemStorageKey, currentTotalGemUses + 1)
    player:setStorageValue(gemIndex.gemStorageKey, currentGemUses + 1)
   
    if gemIndex.health then
        player:say("+" .. gemIndex.health .. " health!")
        player:setMaxHealth(player:getMaxHealth() + gemIndex.health)
        player:getPosition():sendMagicEffect(gemIndex.effect)
    end
    if gemIndex.mana then
        player:say("+" .. gemIndex.mana .. " mana!")
        player:setMaxMana(player:getMaxMana() + gemIndex.mana)
        player:getPosition():sendMagicEffect(gemIndex.effect)
    end
   
    item:remove(1)
    player:save()
    return true
end

for itemId, _ in pairs(config.gems) do
    action:id(itemId)
end
action:register()


local talkaction = TalkAction("!gems")

function talkaction.onSay(player, words, param, type)
    local text = ""
    local healthGained = 0
    local manaGained = 0
    
    local vocation = player:getVocation()
    local vocationId = vocation:getId()
   
    local gemInfo = ""
    for itemId, info in pairs(config.gems) do
        if gemInfo ~= "" then
            gemInfo = gemInfo .. "\n\n"
        end
        gemInfo = gemInfo .. ItemType(itemId):getName():upper() .. "\n    "
        for k, v in pairs(info.vocations) do
            if table.contains(k, vocationId) then
                gemInfo = gemInfo .. vocation:getName() .. " Limit: " .. v.gemLimit .. "\n    "
                break
            end
        end
        local currentGemUses = math.max(player:getStorageValue(info.gemStorageKey), 0)
        gemInfo = gemInfo .. "Used: " .. currentGemUses .. "\n    "
        gemInfo = gemInfo .. "Gives:"
        if info.health then
            gemInfo = gemInfo .. "\n        Health: " .. info.health
            healthGained = healthGained + (info.health * currentGemUses)
        end
        if info.mana then
            gemInfo = gemInfo .. "\n        Mana: " .. info.mana
            manaGained = manaGained + (info.mana * currentGemUses)
        end
    end
   
    text = "Gem Information\n\nTotal Gained\n    Health: " .. healthGained .. "\n    Mana: " .. manaGained
    text = text .. "\n\nGlobal Gem Limits\n    Non-Vip: " .. config.totalGemUses.limit .. "\n    Vip: " .. (config.totalGemUses.limit + config.totalGemUses.vipLimitIncrease) .. "\n    Used: " .. math.max(player:getStorageValue(config.totalGemStorageKey), 0)
    text = text .. "\n\n" .. gemInfo
       
    player:showTextDialog(2177, text)
    return false
end

talkaction:separator(" ")
talkaction:register()
Post automatically merged:


Gave it a try. Can only check if the player has used a spell. Cannot modify the cooldown.
Only way this is possible, is if you manually add cooldowns for spells inside of their files, and add/remove/check/change them that way.
Ok...
Can you try write for me anti-bot talkactions.

VVVVVVV
And if this possibile, when player target not answer, player first have DMG X2.
 
View attachment 82403

data/script/Forkz_Request.lua
Lua:
local config = {
    totalGemUses = {limit = 30, vipLimitIncrease = 20},
    totalGemStorageKey = 45089,
    gems = {
        [2156] = {
            vocations = {
                [{1, 5}] = {gemLimit = 20}, -- limit is for this gem specifically
                [{2, 6}] = {gemLimit = 20},
                [{3, 7}] = {gemLimit = 25},
                [{4, 8}] = {gemLimit = 35}
            },
            gemStorageKey = 45090,
            health = 50,
            effect = CONST_ME_MAGIC_RED
        },
        [2158] = {
            vocations = {
                [{1, 5}] = {gemLimit = 50}, -- sorc
                [{2, 6}] = {gemLimit = 50}, -- druid
                [{3, 7}] = {gemLimit = 35}, -- pally
                [{4, 8}] = {gemLimit = 40}  -- knight
            },
            gemStorageKey = 45091,
            mana = 50,
            effect = CONST_ME_MAGIC_BLUE
        },
       
        --[2154] = {
        --    vocations = {
        --        [{1, 5}] = {gemLimit = ??},
        --        [{2, 6}] = {gemLimit = ??},
        --        [{3, 7}] = {gemLimit = ??},
        --        [{4, 8}] = {gemLimit = ??}
        --    },
        --    gemStorageKey = 45092,
        --    health = 25, -- could have both hp and mana in 1 gem
        --    mana = 25,
        --  effect = CONST_ME_MAGIC_GREEN
        --},
    }
}



local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    -- local vipStatus = player:isVip() -- returns true/false?
    local vipStatus = true
   
    local totalGemUses = config.totalGemUses.limit + (vipStatus and config.totalGemUses.vipLimitIncrease or 0)
    local currentTotalGemUses = math.max(player:getStorageValue(config.totalGemStorageKey), 0)
   
    if currentTotalGemUses >= totalGemUses then
        player:sendTextMessage(MESSAGE_STATUS_SMALL, "Secret Gem total limit reached.")
        player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
        return true
    end
   
    local gemIndex = config.gems[item:getId()]
    local currentGemUses = math.max(player:getStorageValue(gemIndex.gemStorageKey), 0)
    local vocationId = player:getVocation():getId()
   
    for k, v in pairs(gemIndex.vocations) do
        if table.contains(k, vocationId) then
            if currentGemUses >= v.gemLimit then
                player:sendTextMessage(MESSAGE_STATUS_SMALL, "Specific Gem vocation limit reached.")
                player:getPosition():sendMagicEffect(CONST_ME_POFF, player)
                return true
            end
            break
        end
    end
   
    player:setStorageValue(config.totalGemStorageKey, currentTotalGemUses + 1)
    player:setStorageValue(gemIndex.gemStorageKey, currentGemUses + 1)
   
    if gemIndex.health then
        player:say("+" .. gemIndex.health .. " health!")
        player:setMaxHealth(player:getMaxHealth() + gemIndex.health)
        player:getPosition():sendMagicEffect(gemIndex.effect)
    end
    if gemIndex.mana then
        player:say("+" .. gemIndex.mana .. " mana!")
        player:setMaxMana(player:getMaxMana() + gemIndex.mana)
        player:getPosition():sendMagicEffect(gemIndex.effect)
    end
   
    item:remove(1)
    player:save()
    return true
end

for itemId, _ in pairs(config.gems) do
    action:id(itemId)
end
action:register()


local talkaction = TalkAction("!gems")

function talkaction.onSay(player, words, param, type)
    local text = ""
    local healthGained = 0
    local manaGained = 0
    
    local vocation = player:getVocation()
    local vocationId = vocation:getId()
   
    local gemInfo = ""
    for itemId, info in pairs(config.gems) do
        if gemInfo ~= "" then
            gemInfo = gemInfo .. "\n\n"
        end
        gemInfo = gemInfo .. ItemType(itemId):getName():upper() .. "\n    "
        for k, v in pairs(info.vocations) do
            if table.contains(k, vocationId) then
                gemInfo = gemInfo .. vocation:getName() .. " Limit: " .. v.gemLimit .. "\n    "
                break
            end
        end
        local currentGemUses = math.max(player:getStorageValue(info.gemStorageKey), 0)
        gemInfo = gemInfo .. "Used: " .. currentGemUses .. "\n    "
        gemInfo = gemInfo .. "Gives:"
        if info.health then
            gemInfo = gemInfo .. "\n        Health: " .. info.health
            healthGained = healthGained + (info.health * currentGemUses)
        end
        if info.mana then
            gemInfo = gemInfo .. "\n        Mana: " .. info.mana
            manaGained = manaGained + (info.mana * currentGemUses)
        end
    end
   
    text = "Gem Information\n\nTotal Gained\n    Health: " .. healthGained .. "\n    Mana: " .. manaGained
    text = text .. "\n\nGlobal Gem Limits\n    Non-Vip: " .. config.totalGemUses.limit .. "\n    Vip: " .. (config.totalGemUses.limit + config.totalGemUses.vipLimitIncrease) .. "\n    Used: " .. math.max(player:getStorageValue(config.totalGemStorageKey), 0)
    text = text .. "\n\n" .. gemInfo
       
    player:showTextDialog(2177, text)
    return false
end

talkaction:separator(" ")
talkaction:register()
Post automatically merged:


Gave it a try. Can only check if the player has used a spell. Cannot modify the cooldown.
Only way this is possible, is if you manually add cooldowns for spells inside of their files, and add/remove/check/change them that way.
Very good, if I want to change the VIP system to premium, how do I do it?
 
hey @Xikini how about remaking marriage system in .lua? It used to have mysql insertions, but I think this can be done in .lua nowdays.

I will quote tibiawiki:
To get married, you will first need to prepare items such as wedding rings and outfits. The full list is:

Then
Both persons must engage in a conversation with a priest (may or may not be the same priest) simultaneously.

In order to start the ceremony, both players must give their marriage items to the NPC:
Player 1 & 2: hi
Priest: Welcome in the name of the gods, pilgrim Player 1!
Player 1 & 2: marriage
Priest: Before we can start the marriage ceremony, each of you need to hand me a blank wedding ring and a box with a wedding outfit. Player 1/Player 2, do you have these items with you and are you willing to give them to me now?
Player 1 & 2: yes
Priest: Thank you. I'll give them back to you when the time is right. Please make sure that BOTH of you have handed me your items before we start the ceremony.

After both players give their items, now the ceremony can start:
Player 1: ceremony
Priest: Do you wish me to initiate the marriage ceremony now?
Player 1: yes
Priest: In the name of the Gods of Benevolence, I ask you, Player 1: are both of you ready and eager to be bound in marriage?
Player 1: yes
Priest: A moment of silence please... I hereby invoke the eternal powers who watch over our souls and lives. Please repeat after me: May the gods bless us!
Player 1: may the gods bless us
Priest: I ask thee, Player 1, what is the name of the person your heart belongs to?
Player 1: Player 2
Priest: Player 1, are you sure of your love to Player 2 and wish to bind your souls together for eternity?
Player 1: yes
Priest: So by the powers of the Gods, your soul is now bound to your beloved. Player 2, now step forward and tell me if your heart belongs to Player 1 too.

Now have your fiancee speak to her, saying the following:
Player 2: My heart belongs to Player 1
Lynda: Lynda: I ask thee, Player 2, will you honour your beloved Player 1 and will you stay at each other's side even through the darkest as well as lightest hours of life?
Player 2: yes
Priest: By the powers of the Gods your souls are now bound together for eternity. As a symbol of your love, receive your engraved wedding rings and festive clothes. ...
Priest: May the Gods watch with grace over your future life as a married couple. Go now and celebrate your honeymoon on the peaceful island of Meluna!

There's also a second NPC, a drunken priest that let you divorce.
Player: Hi
Druken Priest: G...greetings <hicks>. What can I <hicks> do for you?
Player:: Divorce
Druken Priest: <hicks> What, a divorce? Do you yearn for the joys of singledom? <hicks> I know it well, my marriage was a battleground... but less of that. Are you unhappily married?
Player: yes
Druken Priest: Really? I feel your p... pain, friend. <hicks> Not that I have a special connection to the Gods or anything <hicks> - but I can fix you up with a d... divorce, if that's what you want. <hicks> Do you?
Player: yes
Druken Priest: Hm. You see, uh... I would do it for free, but <hicks> I could in fact use some cash. Do me a favour and 'donate' 5000 gold coins so I can buy some, uhm... bibles. Then I'll do the rest. <hicks> What do you say?
Player: yes
Druken Priest: No p... problem. And no turning back now! But, just to be certain, <hicks> - are you sure that you want to free yourself from the misery of being tied to the good-for-nothing person you married in a moment of madness?
Player: yes
Brewster: Ehem. <hicks> By the Gods and b... beer and blah blah blah... let this unhappy and mistaken marriage come to an end. All b... <burp> bonds be broken and so on. Thanks for the beer - I mean bible money. <hicks> Don't make the same mistake again!

He will only grant you a divorce if you have 5,000 gold.
If you do not have 5,000 gold pieces Brewster will say:
Druken Priest: Damn, I bet <hicks> your cheating spouse took all of your money <hicks> from you. You're as poor as a church mouse. <hicks>

More information about the system based on the otland post I attached before:
Items: Players who get married receive a Wedding ring with your names and wedding date.

ID of rings:
  1. 10510 for broken weeding ring (i think this one will be challenging because you need to check if player is married so the ring can stay as engraved weeding ring, or something like that)
  2. 10502 for engraved weeding ring (you can see on description who is married to who)
  3. 2121 weeding ring (the 2 ones that are needed to start all this)
  4. 10503 weeding outfit box
1708862186402.png

While the couple is married, they are allowed to use "Newly Wed Outfits". If they divorse, they loose the outfits. No gender is needed for marriage, just two players. Maybe just to add more stuff into it, don't allow players to marry again if they divorce 3 times.

Look: the look shows who is married
w9R0p.png


Combat: The player can not attack your patner
commands:
/marriage info - shows a window in the price of marriage/divorce and the minimum level to get married.
/marriage status - shows who is married and the wedding date

It's a really big system. I hope you like the idea, regards! :)
 
Back
Top