• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Lua Xikini's Free Scripting Service TFS 1.4.2

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

Xikini

Guest
Request whatever you want, within reason.

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

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

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

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

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

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

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

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

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

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

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

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

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

Anyways!

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

Cheers,

Xikini
---------

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

 
Last edited by a moderator:
Anyone using this in their server?
Would be interested to see it in action.
dm me?
I want to implement this (when I have time) onto my project, when I made the first NPC (probably traveling merchant and shopkeepers) I will let you know!
 
I made it for generic physical damage, I think.
I say just use it as-is. lol

Its not working for my crossbow.

LUA:
local firecrossbow = 5390
local fire_percent = 10
local fire_damage = {}


local weapon = Weapon(WEAPON_DISTANCE)

local combat = Combat()
combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatParam(combat, COMBAT_PARAM_EFFECT, 28)
combat:setParameter(COMBAT_PARAM_BLOCKARMOR, true)
combat:setFormula(COMBAT_FORMULA_SKILL, 0, 0, 1, 0)

function onGetFormulaValues(player, skill, attack, factor)
    local min = 0
    local max = getMaxWeaponDamage(player:getLevel(), skill, (attack * GLOBAL_vocationMultipliers[player:getVocation():getId()].distDamage), factor)
    local damage = normal_random_range(min, max)
    fire_damage[player:getId()] = math.floor(((damage / 100) * fire_percent) + 0.5)
    local target = player:getTarget()
    damage, effect = target:calculateDamageAfterArmorandDefence(damage)
    target:getPosition():sendMagicEffect(effect)
    return -damage, -damage
end

combat:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")


local combat_fire = Combat()
combat_fire:setParameter(COMBAT_PARAM_TYPE, COMBAT_FIREDAMAGE)

function onGetFormulaValues(player, skill, attack, factor)
    local fireDamage = fire_damage[player:getId()]
    fire_damage[player:getId()] = nil
    return -fireDamage, -fireDamage
end

combat_fire:setCallback(CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")


function weapon.onUseWeapon(player, variant)
    if player:getSkull() == SKULL_BLACK then
        return false
    end

    combat:execute(player, variant)
    combat_fire:execute(player, variant)
    return true
end

weapon:id(firecrossbow)
weapon:register()


It is working for lets say an fire spear, but its not working for bows/crossbows.
 
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()
Would it be possible to do it the other way around or almost the same? instead of protection I would like to increase the damage, regardless of the item, that is: using the upgrade stone on any weapon/wand would increase its damage by x% for each stone used... please and thank you xD
 
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.


Lua Script Error: [Scripts Interface]
C:\Users\Martin\Downloads\ProjectoKabo\Server Baiak-Kabo\baiakthunder-master\data\scripts\Burning Heart.lua
data/lib/compat/compat.lua:124: bad argument #1 to 'rawset' (table expected, got userdata)
stack traceback:
[C]: at 0x7ff7a73d3890
[C]: in function 'rawset'
data/lib/compat/compat.lua:124: in function '__newindex'
...-Kabo\baiakthunder-master\data\scripts\Burning Heart.lua:3: in main chunk
Burning Heart.lua [error]
 
To be clear, this is a fully functioning raid system built in Lua.
Short video to showcase, and description of the talkaction, but all the normal features of the default raid system should be there.

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

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

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

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

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

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

data/scripts/raidSystemInLua.lua
LUA:
-- Check the attachments. Code is too large to post.
amazing! <3
 
Can you help me edit one of your scripts?
 
Hey @Xikini
I need revscript with:
1. Quest chest but with storage for chest and storage from other system +1.
Example:

Storage chest 1000
Storage from other system: value.examle2000 + 1


2. Block use potions or runes or both {configurable} in area fromPos xyz toPos xyz.

3. Disable visible level from chat if group >= 3.
Idk where i can change it, revscript or c++?
 
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.
Help me with this script. It worked well for me in 1.5 860, and when I upgraded dat/spr to 13.21, the commands no longer worked and this error appears in the client.
Code:
ERROR: ProtocolGame parse message exception (244 bytes, 225 unread, last opcode is 0x96 (150), prev opcode is 0xffffffff (-1)): InputMessage eof reached
Packet has been saved to packet.log, you can use it to find what was wrong. (Protocol: 860)
!gems
Thanks in advance
Post automatically merged:

fixed
LUA:
player:showTextDialog(1979, text)
 
@Xikini

I've tested out a traveling merchant and it worked as perfectly as I would think.
To get the perfect results though make sure the nodes are a maximum of 8 tiles apart, this way the NPC won't teleport.

If you have a merchant that travels over 1000 tiles (like mine) be prepared to make a lot of nodes (just use AI to fill it in)
For now it works perfectly to walk around the map in a circle, setting up shop in a few places, some tiles like the Lush Grass are a bit wonky but perhaps I should play with NPC walkinterval a bit, it is now at 2000, might make it 2500.

Tiles like dirt and grass the NPC walks very naturally, exactly what I wanted!
--------

I will try a roaming creature next, although what likely is going to happen is that it will auto target players, which will cause it to run from it's node track, thus teleport after disengaging the player 🤔
 
Last edited:
@Xikini

I've tested out a traveling merchant and it worked as perfectly as I would think.
To get the perfect results though make sure the nodes are a maximum of 8 tiles apart, this way the NPC won't teleport.

If you have a merchant that travels over 1000 tiles (like mine) be prepared to make a lot of nodes (just use AI to fill it in)
For now it works perfectly to walk around the map in a circle, setting up shop in a few places, some tiles like the Lush Grass are a bit wonky but perhaps I should play with NPC walkinterval a bit, it is now at 2000, might make it 2500.

Tiles like dirt and grass the NPC walks very naturally, exactly what I wanted!
--------

I will try a roaming creature next, although what likely is going to happen is that it will auto target players, which will cause it to run from it's node track, thus teleport after disengaging the player 🤔
Yeah, I don't recommend doing it with monsters, unless you have some script constantly checking if the creature has a target, then disable the node walking... might work.

And yeah, I only did the tiles I had access to in 10.98
Any newer tiles probably won't work correctly.
Would have to calculate their speeds, and add to the list.
 
Hi xikini!

There was a very interesting script for trade vip days in the past.

It was a talkaction that sends the command !tradevip playername, premiumdays then a trade window opens between the player and the target (without a modal window).

About the trade window, will be nice if select item ID 2329 as the "premium days" item.

1726317532949.webp

If trade is accepted, remove player premium days to add to the target.


Could you help the community with a script like this?
 

Attachments

  • 1726317385373.webp
    1726317385373.webp
    412 bytes · Views: 2 · VirusTotal
Last edited:
Hi xikini!

There was a very interesting script for trade vip days in the past.

It was a talkaction that sends the command !tradevip playername, premiumdays then a trade window opens between the player and the target (without a modal window).

About the trade window, will be nice if select item ID 2329 as the "premium days" item.

View attachment 87083

If trade is accepted, remove player premium days to add to the target.


Could you help the community with a script like this?

Funny enough, I searched high and low, and can't find a way to initiate the trade request via script.
There doesn't appear to be a way to do this currently in tfs 1.0+

I mean.. maybe there is some weird way to form a network message.. that initiates the trade?
But that's beyond my knowledge.
 
Funny enough, I searched high and low, and can't find a way to initiate the trade request via script.
There doesn't appear to be a way to do this currently in tfs 1.0+

I mean.. maybe there is some weird way to form a network message.. that initiates the trade?
But that's beyond my knowledge.
I've searched and found one guy thought a talkaction like me (Link here) and he uses doStartTrade(cid, creature, doPlayerAddItem(cid, config.itemid, 1)) as a function to make this works. That means my idea need source modification..

Do you think can be done with modal windows?
 
I've searched and found one guy thought a talkaction like me (Link here) and he uses doStartTrade(cid, creature, doPlayerAddItem(cid, config.itemid, 1)) as a function to make this works. That means my idea need source modification..

Do you think can be done with modal windows?

What you could do is:

!transerVip 2
you receive a item with 2 days vip and 2 days vip will be removed from your account and that item you can trade or drop or what ever you want as example
 
Hello, I would like a script (action) that, when the item is clicked, it disappears and gives the player some other items. Also, if possible, add days of premium account directly to the player’s account who used the item.

All necessary checks must be included: check if the player has the capacity and slots in the backpack to receive the item. If not, the item should not be usable, and an error message should be displayed.

If possible, the items should go to the appropriate location in the inventory (if there’s nothing equipped in the inventory slot corresponding to the item).

The idea is to create some boxes, and when the player buys the box and uses it, they receive the full set that could have been bought in the shop item by item.

Thanks
 
Hello, I would like a script (action) that, when the item is clicked, it disappears and gives the player some other items. Also, if possible, add days of premium account directly to the player’s account who used the item.

All necessary checks must be included: check if the player has the capacity and slots in the backpack to receive the item. If not, the item should not be usable, and an error message should be displayed.

If possible, the items should go to the appropriate location in the inventory (if there’s nothing equipped in the inventory slot corresponding to the item).

The idea is to create some boxes, and when the player buys the box and uses it, they receive the full set that could have been bought in the shop item by item.

Thanks

Install this.
Then use this.
LUA:
local itemBoxId = 1111

local reward = {
--  {itemId, amount}
    {1111, 1},
    {2222, 1},
    {3333, 1}
}

local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not player:giveItems(reward) then
        return false
    end
    item:remove(1)
    return true
end

action:id(itemBoxId)
action:register()
 
Install this.
Then use this.
LUA:
local itemBoxId = 1111

local reward = {
--  {itemId, amount}
    {1111, 1},
    {2222, 1},
    {3333, 1}
}

local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not player:giveItems(reward) then
        return false
    end
    item:remove(1)
    return true
end

action:id(itemBoxId)
action:register()
giveItems a nil value - Line 14

Is it possible to enhance the code to deliver directly to the player's account: outfits, addons, mounts, and premium account?
 
giveItems a nil value - Line 14

Is it possible to enhance the code to deliver directly to the player's account: outfits, addons, mounts, and premium account?

giveItems can only be a nil value if you failed to install it. (or forgot to restart the server after installing?)

LUA:
local itemBoxId = 1111

local rewards = {
    items = {
    --  {itemId, amount}
        {1111, 1},
        {2222, 1},
        {3333, 1}
    },
    outfits = {
        {outfitId = 136, gender = 0}, -- male = 1, female = 0, both = 2 (if you want to give it to the player, even if they can't wear it)
        {outfitId = 128, gender = 1}
    },
    addons = {
        {outfitId = 136, addon = 3, gender = 0}, -- 1 = first addon, 2 = second addon, 3 = both 1 & 2.
        {outfitId = 128, addon = 3, gender = 1},
    },
    mounts = {
        {mountId = 1}
    },
    premium = 7 -- days
}

local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not player:giveItems(rewards.items) then
        return false
    end
    item:remove(1)
  
    local playerGender = player:getSex()
  
    for k, v in pairs(rewards.outfits) do
        if v.gender == 2 or v.gender == playerGender then
            player:addOutfit(v.outfitId)
        end
    end
  
    for k, v in pairs(rewards.addons) do
        if v.gender == 2 or v.gender == playerGender then
            player:addOutfitAddon(v.outfitId, v.addon)
        end
    end
  
    for k, v in pairs(rewards.mounts) do
        player:addMount(v.mountId)
    end
  
    if rewards.premium > 0 then
        player:addPremiumTime(rewards.premium * 86400)
    end
    return true
end

action:id(itemBoxId)
action:register()
 
giveItems can only be a nil value if you failed to install it. (or forgot to restart the server after installing?)

LUA:
local itemBoxId = 1111

local rewards = {
    items = {
    --  {itemId, amount}
        {1111, 1},
        {2222, 1},
        {3333, 1}
    },
    outfits = {
        {outfitId = 136, gender = 0}, -- male = 1, female = 0, both = 2 (if you want to give it to the player, even if they can't wear it)
        {outfitId = 128, gender = 1}
    },
    addons = {
        {outfitId = 136, addon = 3, gender = 0}, -- 1 = first addon, 2 = second addon, 3 = both 1 & 2.
        {outfitId = 128, addon = 3, gender = 1},
    },
    mounts = {
        {mountId = 1}
    },
    premium = 7 -- days
}

local action = Action()

function action.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if not player:giveItems(rewards.items) then
        return false
    end
    item:remove(1)
 
    local playerGender = player:getSex()
 
    for k, v in pairs(rewards.outfits) do
        if v.gender == 2 or v.gender == playerGender then
            player:addOutfit(v.outfitId)
        end
    end
 
    for k, v in pairs(rewards.addons) do
        if v.gender == 2 or v.gender == playerGender then
            player:addOutfitAddon(v.outfitId, v.addon)
        end
    end
 
    for k, v in pairs(rewards.mounts) do
        player:addMount(v.mountId)
    end
 
    if rewards.premium > 0 then
        player:addPremiumTime(rewards.premium * 86400)
    end
    return true
end

action:id(itemBoxId)
action:register()

It worked perfectly, thank you.

Now, if possible, I would like to change my NPC that buys items from players. In this case, if the player doesn't have item 4444, the NPC should buy the items for half the price listed. But if the player has the item, the NPC should buy for the full price on the list. (The player only needs to be carrying the item, it doesn't need to be equipped or anything like that)

Code:
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 shopModule = ShopModule:new()
npcHandler:addModule(shopModule)

shopModule:addSellableItem({'golden legs'}, 2470, 30000, 'golden legs')
shopModule:addSellableItem({'demon legs'}, 2495, 50000, 'demon legs')
shopModule:addSellableItem({'boots of haste'}, 2195, 30000, 'boots of haste')
shopModule:addSellableItem({'steel boots'}, 2645, 30000, 'steel boots')
shopModule:addSellableItem({'demon shield'}, 2520, 30000, 'demon shield')
shopModule:addSellableItem({'mastermind shield'}, 2514, 50000, 'mastermind shield')

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())
 
It worked perfectly, thank you.

Now, if possible, I would like to change my NPC that buys items from players. In this case, if the player doesn't have item 4444, the NPC should buy the items for half the price listed. But if the player has the item, the NPC should buy for the full price on the list. (The player only needs to be carrying the item, it doesn't need to be equipped or anything like that)

Code:
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 shopModule = ShopModule:new()
npcHandler:addModule(shopModule)

shopModule:addSellableItem({'golden legs'}, 2470, 30000, 'golden legs')
shopModule:addSellableItem({'demon legs'}, 2495, 50000, 'demon legs')
shopModule:addSellableItem({'boots of haste'}, 2195, 30000, 'boots of haste')
shopModule:addSellableItem({'steel boots'}, 2645, 30000, 'steel boots')
shopModule:addSellableItem({'demon shield'}, 2520, 30000, 'demon shield')
shopModule:addSellableItem({'mastermind shield'}, 2514, 50000, 'mastermind shield')

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())

Base npc from here.

Modified, for your request.

Doubles sell price, if player is holding the special item.
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 specialTradeItem = 4444

local tradeList = {
    {id = 2470, buy = 0, sell = 15000, name = "golden legs"},
    {id = 2495, buy = 0, sell = 25000, name = "demon legs"},
    {id = 2195, buy = 0, sell = 15000, name = "boots of haste"},
    {id = 2645, buy = 0, sell = 15000, name = "steel boots"},
    {id = 2520, buy = 0, sell = 15000, name = "demon shield"},
    {id = 2514, buy = 0, sell = 25000, name = "mastermind shield"}
}

local function getTradeItems(t)
    local list, obj = {}
    for i = 1, #t do
        obj = t[i]
        list[obj.id] = {id = obj.id, buy = obj.buy, sell = obj.sell, name = ItemType(obj.id):getName():lower()}
    end
    return list
end

local function joinTables(old, new, mergeSameItems)
    for k, v in pairs(new) do
        if mergeSameItems then
            local found = false
            for _k, _v in pairs(old) do
                if v.id == _v.id then
                    found = true
                    if v.buy < _v.buy then
                        _v.buy = v.buy
                    end
                    if v.sell > _v.sell then
                        _v.sell = v.sell
                    end
                    break
                end
            end
            if not found then
                old[#old + 1] = v
            end
        else
            old[#old + 1] = v
        end
    end
    return old
end

local shopInfo = {
    --[cid] = "last known trade message"
}

local function createTradeInformation(cid, newMessage)
    if newMessage then
        shopInfo[cid] = newMessage
    end
    local lastKnownMessage = shopInfo[cid]
    local tradeItems = {}
   
    if not lastKnownMessage then
        return tradeItems
    end
   
    if lastKnownMessage == "regularTrade" then
        tradeItems = getTradeItems(tradeList)       
    end   
    return tradeItems
end

local function onBuy(player, itemid, subType, amount, ignoreCap, inBackpacks)
    local cid = player:getId()
    local shopInfo = createTradeInformation(cid)
    if not shopInfo[itemid] then
        return player:sendTextMessage(MESSAGE_INFO_DESCR, "No item selected?")
    end
   
    if not ignoreCap and player:getFreeCapacity() < ItemType(itemid):getWeight(amount) then
        return player:sendTextMessage(MESSAGE_INFO_DESCR, "You don't have enough capacity.")
    end
   
    local totalMoney = amount * shopInfo[itemid].buy
    if player:getTotalMoney() < totalMoney then   
        return player:sendTextMessage(MESSAGE_INFO_DESCR, "You don't have enough money.")
    end
   
    player:removeTotalMoney(totalMoney)
    player:addItem(itemid, amount, true)
    return player:sendTextMessage(MESSAGE_INFO_DESCR, "Bought " .. amount .. "x " .. shopInfo[itemid].name .. " for " .. totalMoney .. " gold coins.")
end

local function onSell(player, itemid, subType, amount, ignoreCap, inBackpacks)
    local cid = player:getId()
    local shopInfo = createTradeInformation(cid)
    if not shopInfo[itemid] then
        return player:sendTextMessage(MESSAGE_INFO_DESCR, "No item selected?")
    end
   
    local hasSpecialItem = false
    local totalMoney = amount * shopInfo[itemid].sell
    if player:getItemCount(specialTradeItem) > 0 then
        totalMoney = totalMoney * 2
        hasSpecialItem = true
    end
  
    player:removeItem(itemid, amount)   
    player:addMoney(totalMoney)
    return player:sendTextMessage(MESSAGE_INFO_DESCR, "Sold " .. amount .. "x " .. shopInfo[itemid].name .. " for " .. totalMoney .. " gold coins." .. (hasSpecialItem and " (2x sell price)" or ""))
end

local function greetCallback(cid)
    local player = Player(cid)
    -- npcHandler:setMessage(MESSAGE_GREET, 'Welcome back old chap. What brings you here this time?')
    return true
end

local function creatureSayCallback(cid, type, msg)
    if not npcHandler:isFocused(cid) then return false end
   
    local player = Player(cid)
   
    if msgcontains("trade", msg) then
        local tradeItems = createTradeInformation(cid, "regularTrade")
        openShopWindow(cid, tradeItems, onBuy, onSell)
        npcHandler:say("If you have {valuable object} in your possession when selling items to me, I'll double the price!", cid)
       
    end   
    return true
end


-- npcHandler:setMessage(MESSAGE_FAREWELL, 'Happy hunting, old chap!')
npcHandler:setCallback(CALLBACK_GREET, greetCallback)
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())
 
Status
Not open for further replies.
Back
Top