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

Lua Xikini's Free Scripting Service TFS 1.4.2

Xikini

I whore myself out for likes
Senator
Premium User
Joined
Nov 17, 2010
Messages
6,800
Solutions
582
Reaction score
5,363
Request whatever you want, within reason.

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

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

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

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

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

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

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

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

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

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

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

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

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

Anyways!

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

Cheers,

Xikini
---------

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

 
Last edited by a moderator:
When I use any potion I get this error:
Code:
Lua Script Error: [Scripts Interface]
C:\TestOTVM\data\scripts\BossExtraDamage.lua:callback
C:\TestOTVM\data\scripts\BossExtraDamage.lua:20: attempt to index local 'attacker' (a nil value)
stack traceback:
        [C]: in function '__index'
        C:\TestOTVM\data\scripts\BossExtraDamage.lua:20: in function 'damageCalculator'
        C:\TestOTVM\data\scripts\BossExtraDamage.lua:35: in function <C:\TestOTVM\data\scripts\BossExtraDamage.lua:34>
        [C]: in function 'doTargetCombatHealth'
        data/actions/scripts/others/consumables/potions.lua:97: in function <data/actions/scripts/others/consumables/potions.lua:68>

Potion.lua line 68 and 97:
Code:
function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    if type(target) ~= "userdata" then
        return false
    end
------------
    if potion.health or potion.mana or potion.combat then
        if potion.health then
            doTargetCombatHealth(0, target, COMBAT_HEALING, potion.health[1], potion.health[2], CONST_ME_MAGIC_BLUE)
        end
Fixed over discord. Change is applied to thread.
 
Should be fixed. 👍
Post automatically merged:


Hey, I don't really understand what you're requesting here.

Are we only tracking the damage and hits of the fire dagger?
Does the fire dagger deal only fire damage? Or does it do a mix of fire and physical?

If it's mixed damage, is it only the fire damage we add 5% of?

Sorry, there's just 3-4 different ways to interpret your request and I want to do it correctly.
Post automatically merged:


I actually worked with damage maps recently, so I know how they work. :D
Ah sorry, let me try to be more clear. If a player attack an monster wielding the fire dagger and does a physical hit of 100 then add an additional 5% fire damage so in this case 5 fire damage. If a player does 349 physical damage it does an additional 17 fire damage.
 
@Xikini I'm looking for a script according to the title where the player with a configured level does not lose items, level, skills, NOTHING when he dies.

Revscript TFS 1.5 7.72 Downgrade Nekiro
 
Hi,
Anti MC scripts everywhere but there is one problem.
If someone gives a quick exit and logs in, the onLogin function won't see it and can still have more characters logged in than allowed.

Can you remedy this ?
Ideally the Admin account type and one IP address should be allowed to Max MC.
 
@Xikini I need help with this script. The script gives double and sometimes triple reward even though it is set differently in the script I don't know what is done wrong here. I've been trying to fix it for a few days and have no results. please help a lot.
TFS 1.5 NEKIRO 8.60 DOWNGRADE

Lua:
function onKill(creature, target)
    local monsterName = "Verminor"
    if target:getName() ~= monsterName then
        return true
    end

    local rewardedPlayers = {}

    for pid, _ in pairs(target:getDamageMap()) do
        if not rewardedPlayers[pid] then
            local attackerPlayer = Player(pid)
            if attackerPlayer then
                attackerPlayer:addItem(2160, 30)
                attackerPlayer:addLevel(2)
                creature:sendTextMessage(MESSAGE_INFO_DESCR, "Congratulations.")
                rewardedPlayers[pid] = true
            end
        end
    end
    return true
end
 
don't want to abuse requesting too many stuff, but i've seen many threads requesting skill stages. For example, from axe 10 to 50 have * 5 rate, from 50 to 70 *4, from 70 to 90 *3 and so on. This for all the skills: fist, axe, sword, club, fishing, shielding, etc. Any chance to add this to the queque? thanks a lot in advance! :)

edit---
I have another idea that I want to share, maybe it's intresting. Everytime a creature, let's use "Bandit" for the example, spawns on their normal spawn area. Would be possible to spawn it with a color randomization on their outfits? This way we can have Bandits with different colors. Also apply to other creatures such as Thief, Smuggler, Warlock, Amazons, or whatever monster that you would like to have with the system. Regards!
 
Last edited:
hello, i wanna request a anti afk script for excerise weapons, i doesn't have anti afk, so i get kicked after 15min even when training, the afk timer should start 15min after the training is done, Regards.
 
hello, i wanna request a anti afk script for excerise weapons, i doesn't have anti afk, so i get kicked after 15min even when training, the afk timer should start 15min after the training is done, Regards.
This would be better as a support thread.

player:resetIdleTime() is how you would accomplish this.

I assume there is an addEvent to check if the player has moved / to send the shoot animation while the training weapon is inUse.
Just add it there.

Since everybody asks I will ask for something. I already have upgrade system but what I would like to have is modal points system. I would to have bonuses per point and list to choose from examples: extra any skill +1, health points 1% mana points 1% critical damage 1% experience 1% and talk action to make it easier !points. I will have my own missions and quests to provide those points. I just want this function to retrive it from 'task_points' or 'coins' I will edit this after anyway.

ATTRIBUTE DESCRIPTION AND CONDITION can be used here.

So yeah this is my request and thanks for what you doing, I always enjoy looking at your scripts and they you present it. Well done!

I've looked at this request for awhile, and I'm just not interested in doing it, as-requested.
There's too many unanswered questions.


If you look here, you can see all the different buffs we can apply to a character.
But, they don't all 'mix' together properly.

So you'd have to go through and decide what you want added to the stats system.

That's also only the 'buffs'. So you'd also have to go through and list all additional stats you want..
like capacity / experience increase, et cetera.

as for all of this
I will have my own missions and quests to provide those points. I just want this function to retrive it from 'task_points' or 'coins' I will edit this after anyway.

ATTRIBUTE DESCRIPTION AND CONDITION can be used here

I would probably be just setting this as storage values?

1 storage for points accumulated
2nd storage for points spent

and then 1 storage per stat, to tell me how many points have been spent on that attribute?

---
This is such a large request. lmao

stat system alone, and then implementing it into modal windows

-----------------
Well anyways.

I've went through and updated the main post with pending requests.
 
don't want to abuse requesting too many stuff, but i've seen many threads requesting skill stages. For example, from axe 10 to 50 have * 5 rate, from 50 to 70 *4, from 70 to 90 *3 and so on. This for all the skills: fist, axe, sword, club, fishing, shielding, etc. Any chance to add this to the queque? thanks a lot in advance! :)

edit---
I have another idea that I want to share, maybe it's intresting. Everytime a creature, let's use "Bandit" for the example, spawns on their normal spawn area. Would be possible to spawn it with a color randomization on their outfits? This way we can have Bandits with different colors. Also apply to other creatures such as Thief, Smuggler, Warlock, Amazons, or whatever monster that you would like to have with the system. Regards!

Such a script already exists, I use it for NPCs ( so they change clothes every day) and Monsters (so they change head color on spawn)


--------

One catch, upon server restart, I believe it doesn't change outfits on the client screen unless the player walks or logs or walks on stairs etc, it's a really minor issue that is barely noticable. I doubt its a script problem since its like 15 lines of code
----------

It's a really neat feature btw, something so small has a lot of effect when you start noticing it.
You can enhance it if you have creatures that you have like an "outfit" that way you can have dragons with different shades of green or demons with different horn colors, you name it!
 
Yeah, explain it. lmao
all players join a room like this where they have the same speed and can't diagonal movement only south, north, east, west they use !bomb to place a bomb that exploud with 1x1 and kill every player in the explosion area, the green grass is destroyable using these explosions but not the black grass ones.when you exploud the green grass you find orbs below that gives speed, makes your explosion bigger or faster (it takes 3 seconds at the begin with 1x1 area) until 1 player left then he wins the event. you can't use haste spells, magic walls, rush woods or push players.
 

Attachments

Request 1: Adventurer Journal
An idea initially from Red Dead Redemption (2) as you progress through the story,
you can look back at your journal and see drawings and little scrabbles of what you did in the past.


ezgif-3-6b6461a912.gif


(QName) = Quest Name
(MName) = Mission Name
(MState) = Mission State

How would this work in Tibia?
You can use a Book and it will state all the completed mission states of a quest.
This way you can have a "physical" copy of your story in-game to add to your empty bookcase,
without the ability for others to overwrite them, and is somewhat more personalized.

With a "personalized" (onLook) with |playername| so that each book, even the same, are unique to a player.
5b0cc7f3a21d42dee743d761915abd29.png

a809d7f8ef0b8a833a1035084c4a2760.png

With some imagination, you could add anything, not only quests to these books.
For example we can create a bestiary out of this script or tell some more about locations discovered.
This could even take over Quest Tracker altogether and make it so players have to read their book to see how further to proceed.

------------
How does the book gets updated?
The book must be "writing itself" according to the mission states by the owner
but it would be weird if that happens if the book is not on the player at all,
we also want the ability to choose if we want to update the book at all.
- If the owner of the book uses a Quill on a book, the book gets updated.
- If the owner of the book just uses the book, it just gets read.

205f1a09b40e3fbc81ed1c360b7ea503.png


- We can set specific books for each quest, so for example:
Red Tome will be used for Quest 1, Green Tome for Quest 2

OR
- Some sort of pages? Each page is a Quest, so essentially you fill one book with many pages.


The question I'm still having, how do we even set which quest the book shows haha


------------------
In Short~
Perhaps we could use a Desk(Any platform) as a base to use to state a Quest for a book if that makes it easier to script
  • Player puts book on platform.
  • Player uses Quill on the book and states Quest Name; the book gets personalized and Quest and Mission States are pulled and written in the book.
(Perhaps these steps can be skipped but I was thinking of the market system and blackboard configuration and perhaps that can be used the same 🤔 )

- From here on out, wherever the player is, the owner of the book can use Quill on the book to refresh the Mission States.
(Note: Players are not allowed to write in this book like you normally can just type in any book as this will be considered a special book)
a88269e3ac34aba938cb96f99a5d3fcc.png


the lord of the rings GIF
Scared Cringe GIF by O&O, Inc
Craft Beer Sourbeer GIF by Vault City Brewing

 
Last edited:
This would be better as a support thread.

player:resetIdleTime() is how you would accomplish this.

I assume there is an addEvent to check if the player has moved / to send the shoot animation while the training weapon is inUse.
Just add it there.



I've looked at this request for awhile, and I'm just not interested in doing it, as-requested.
There's too many unanswered questions.


If you look here, you can see all the different buffs we can apply to a character.
But, they don't all 'mix' together properly.

So you'd have to go through and decide what you want added to the stats system.

That's also only the 'buffs'. So you'd also have to go through and list all additional stats you want..
like capacity / experience increase, et cetera.

as for all of this


I would probably be just setting this as storage values?

1 storage for points accumulated
2nd storage for points spent

and then 1 storage per stat, to tell me how many points have been spent on that attribute?

---
This is such a large request. lmao

stat system alone, and then implementing it into modal windows

-----------------
Well anyways.

I've went through and updated the main post with pending requests.





Yes this is the way forward: "1 storage for points accumulated
2nd storage for points spent

and then 1 storage per stat, to tell me how many points have been spent on that attribute?"

If modal is to complicated task to do this maybe we can use .
!stats with menu in OnLook text instead of Modal to make it easier?
!stats reset, !stats add,magic !stats remove,magic

Adding or removal of stats will remove 1 point at the time. If this is to much I understand. ;)

Is this possible list of stats?

{"life increase", 100},
{"mana increase", 100,
{"magic", 1},
{"melee", 1}, -- sword/axe/club
{"distance", 1},
{"shield", 1},
{"critical hit chance", 1},
{"critical hit damage", 1},
{"life leech chance", 1},
{"life leech amount", 1},
{"mana leech chance", 1},
{"mana leech amount", 1},
 
Last edited:
Ah sorry, let me try to be more clear. If a player attack an monster wielding the fire dagger and does a physical hit of 100 then add an additional 5% fire damage so in this case 5 fire damage. If a player does 349 physical damage it does an additional 17 fire damage.

So, I went into way too much detail for this, cuz I wanted it to be fairly accurate. xD

bandicam2024-02-1107-03-57-686-ezgif.com-video-to-gif-converter.gif

data/scripts/fireDagger.lua
Lua:
local fireDaggerId = 2418
local fire_percent = 5
local fire_damage = {}


local weapon = Weapon(WEAPON_SWORD)

local combat = Combat()
combat:setParameter(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)

function onGetFormulaValues(player, skill, attack, factor)
    local min = 0
    local max = getMaxWeaponDamage(player:getLevel(), skill, (attack * GLOBAL_vocationMultipliers[player:getVocation():getId()].meleeDamage), 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(fireDaggerId)
weapon:register()

data/lib/core/core.lua -- add
Lua:
dofile('data/lib/core/xikiniCustomFunctions.lua')
data/lib/core/xikiniCustomFunctions.lua -- add
Lua:
-- Xikini's Shitty™ Weapon Handling for Physical Melee Weapons

function parseVocationFormulas(xmlContent)
    local vocations = {}

    local pattern = "<vocation%s+id=\"(.-)\".-<formula%s+meleeDamage=\"(.-)\"%s+distDamage=\"(.-)\"%s+defense=\"(.-)\"%s+armor=\"(.-)\"%s*/>"
    
    for id, meleeDamage, distDamage, defense, armor in xmlContent:gmatch(pattern) do
        vocations[tonumber(id)] = {
            meleeDamage = meleeDamage,
            distDamage = distDamage,
            defense = defense,
            armor = armor
        }
    end

    return vocations
end

-- Function to read the XML content from a file
function readXmlFile(filePath)
    local file = io.open(filePath, "r")
    if not file then
        error("Cannot open file: " .. filePath)
        return nil
    end
    local content = file:read("*all")
    file:close()
    return content
end

local filePath = "data/XML/vocations.xml"
local xmlContent = readXmlFile(filePath)
GLOBAL_vocationMultipliers = parseVocationFormulas(xmlContent)


weaponTypesToSkillType = {
    [WEAPON_SWORD] = SKILL_SWORD,
    [WEAPON_CLUB] = SKILL_CLUB,
    [WEAPON_AXE] = SKILL_AXE
}


function Creature.getDefense(self)
    -- shield and melee weapon
    local defense = 0
 
    if self:isMonster() then
        defense = self:getType():defense()
     
    elseif self:isPlayer() then
        -- if no weapon or shield do fist fighting
        local defenseSkill = self:getSkillLevel(SKILL_FIST)
        local defenseValue = 7;
     
        local weapon = self:getSlotItem(CONST_SLOT_LEFT)
        local weaponDefense = 0
        local weaponExtraDefense = 0
     
        local shield = self:getSlotItem(CONST_SLOT_RIGHT)
        local shieldDefense = 0
 
        if weapon then
            local weaponItemType = ItemType(weapon:getId())
         
            if weapon:hasAttribute(ITEM_ATTRIBUTE_DEFENSE) then
                weaponDefense = weapon:getAttribute(ITEM_ATTRIBUTE_DEFENSE)
            else
                weaponDefense = weaponItemType:getDefense()
            end
            if weapon:hasAttribute(ITEM_ATTRIBUTE_EXTRADEFENSE) then
                weaponExtraDefense = weapon:getAttribute(ITEM_ATTRIBUTE_EXTRADEFENSE)
            else
                weaponExtraDefense = weaponItemType:getExtraDefense()
            end
         
            defenseValue = weaponDefense + weaponExtraDefense
            local skillType = weaponTypesToSkillType[weaponItemType:getWeaponType()]
            defenseSkill = skillType and self:getSkillLevel(skillType) or 0
        end
 
        if shield then
            local shieldItemType = ItemType(shield:getId())
         
            if shield:hasAttribute(ITEM_ATTRIBUTE_DEFENSE) then
                shieldDefense = shield:getAttribute(ITEM_ATTRIBUTE_DEFENSE)
            else
                shieldDefense = shieldItemType:getDefense()
            end
     
            defenseValue = weapon and shieldDefense + weaponExtraDefense or shieldDefense
            defenseSkill = self:getSkillLevel(SKILL_SHIELD)
        end
     
        if defenseSkill == 0 then
            if self:getFightMode() == FIGHTMODE_DEFENSE then
                return 2
            else
                return 1
            end
        end
     
        defense = (defenseSkill / 4. + 2.23) * defenseValue * 0.15 * GLOBAL_vocationMultipliers[self:getVocation():getId()].defense
    end
 
    return defense
end

function Creature.getArmor(self)
    local armor = 0
 
    if self:isMonster() then
        armor = self:getType():armor()

    elseif self:isPlayer() then
        -- loop through equipment, finding armor and adding together
        for slotItem = 1, 10 do
            if slotItem ~= CONST_SLOT_LEFT and slotItem ~= CONST_SLOT_RIGHT then
                local item = self:getSlotItem(slotItem)
                if item then
                    if item:hasAttribute(ITEM_ATTRIBUTE_ARMOR) then
                        armor = armor + item:getAttribute(ITEM_ATTRIBUTE_ARMOR)
                    else
                        armor = armor + ItemType(item:getId()):getArmor()
                    end
                end
            end
        end
 
    end
 
    return armor
end

function Creature.calculateDamageAfterArmorandDefence(self, damage)
    local effect = CONST_ME_NONE
    local checkArmor = true
   
    local defense = self:getDefense()
    damage = damage - (math.random(defense / 2, defense))
    if damage <= 0 then
        damage = 0
        checkArmor = false
        effect = CONST_ME_POFF
    end

    if checkArmor then
        local armor = math.max(self:getArmor(), 1)
        damage = damage - (math.random(armor / 2, armor - (armor % 2 + 1)))
        if damage <= 0 then
            damage = 0
            effect = CONST_ME_BLOCKHIT
        end
    end
   
    return math.floor(damage + 0.5), effect
end

function normal_random(mean, std_dev)
    local u1 = math.random()
    local u2 = math.random()
    local z0 = math.sqrt(-2.0 * math.log(u1)) * math.cos(2.0 * math.pi * u2)
    -- Use z0 for the normal random number (z1 would be the second number, not used here)
    return z0 * std_dev + mean
end

-- Function to generate a random integer within a range based on a normal distribution
function normal_random_range(minNumber, maxNumber)
    local mean = 0.5
    local std_dev = 0.25
    local v
    repeat
        v = normal_random(mean, std_dev)
    until v >= 0.0 and v <= 1.0

    local a, b = math.min(minNumber, maxNumber), math.max(minNumber, maxNumber)
    return math.floor(a + (b - a) * v + 0.5) -- Using floor(x + 0.5) to round to the nearest integer
end

function getMaxWeaponDamage(playerLevel, skillLevel, attackValue, attackFactor)
    return math.ceil((playerLevel / 5) + (((((skillLevel / 4.) + 1) * (attackValue / 3.)) * 1.03) / attackFactor))
end
 
Last edited:
@Xikini I'm looking for a script according to the title where the player with a configured level does not lose items, level, skills, NOTHING when he dies.

Revscript TFS 1.5 7.72 Downgrade Nekiro

No video, cuz.. I mean. xD

dat/events/events.xml -- make sure this is enabled
Lua:
<event class="Player" method="onLoseExperience" enabled="1" />
data/creaturescripts/scripts/droploot.lua -- replace with my code.
Lua:
function onDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
    if player:hasFlag(PlayerFlag_NotGenerateLoot) or player:getVocation():getId() == VOCATION_NONE then
        return true
    end
   
    local protectedPlayer = false
    local level = player:getLevel()
    for k, v in pairs(GLOBAL_protectedPlayerRanges) do
        if level <= k[2] and level >= k[1] then
            if not v.dropLoot then
                protectedPlayer = true
            end
            break
        end
    end

    if not protectedPlayer then
        local amulet = player:getSlotItem(CONST_SLOT_NECKLACE)
        local isRedOrBlack = table.contains({SKULL_RED, SKULL_BLACK}, player:getSkull())
        if amulet and amulet.itemid == ITEM_AMULETOFLOSS and not isRedOrBlack then
            local isPlayer = false
            if killer then
                if killer:isPlayer() then
                    isPlayer = true
                else
                    local master = killer:getMaster()
                    if master and master:isPlayer() then
                        isPlayer = true
                    end
                end
            end
   
            if not isPlayer or not player:hasBlessing(6) then
                player:removeItem(ITEM_AMULETOFLOSS, 1, -1, false)
            end
        else
            for i = CONST_SLOT_HEAD, CONST_SLOT_AMMO do
                local item = player:getSlotItem(i)
                local lossPercent = player:getLossPercent()
                if item then
                    if isRedOrBlack or math.random(item:isContainer() and 100 or 1000) <= lossPercent then
                        if (isRedOrBlack or lossPercent ~= 0) and not item:moveTo(corpse) then
                            item:remove()
                        end
                    end
                end
            end
        end
    end

    if not player:getSlotItem(CONST_SLOT_BACKPACK) then
        player:addItem(ITEM_BAG, 1, false, CONST_SLOT_BACKPACK)
    end
    return true
end

data/scripts/player_protectionRanges.lua
Lua:
GLOBAL_protectedPlayerRanges = {
    [{0, 24}] = {dropLoot = false, loseSkills = false, loseExperience = false},
    [{25, 49}] = {dropLoot = true, loseSkills = false, loseExperience = false},
    [{50, 100}] = {dropLoot = true, loseSkills = false, loseExperience = true}
}

local creatureevent = CreatureEvent("onPrepareDeath_playerLosesNothing")

function creatureevent.onPrepareDeath(creature, killer)
    local level = creature:getLevel()
    for k, v in pairs(GLOBAL_protectedPlayerRanges) do
        if level <= k[2] and level >= k[1] then
            if not v.dropLoot then
                creature:setDropLoot(false)
            end
            if not v.loseSkills then
                creature:setSkillLoss(false)
            end
        end
    end
    return true
end

creatureevent:register()


local creatureevent = CreatureEvent("onLogin_playerLosesNothing")

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

creatureevent:register()


local ec = EventCallback

ec.onLoseExperience = function(self, exp)
    local level = self:getLevel()
    for k, v in pairs(GLOBAL_protectedPlayerRanges) do
        if level <= k[2] and level >= k[1] then
            if not v.loseExperience then
                exp = 0
            end
            break
        end
    end
    return exp
end

ec:register()
 
Last edited:
Hi,
Anti MC scripts everywhere but there is one problem.
If someone gives a quick exit and logs in, the onLogin function won't see it and can still have more characters logged in than allowed.

Can you remedy this ?
Ideally the Admin account type and one IP address should be allowed to Max MC.

Credits to @Evil Hero for the network message function.

bandicam2024-02-1109-23-09-289-ezgif.com-video-to-gif-converter.gif

data/scripts/multiclientLimiter.lua
Lua:
local multiclient_limit = 3
local countGMTowardsLimit = false

-- END OF CONFIG

GLOBAL_PLAYER_IPS = GLOBAL_PLAYER_IPS or {
--    [ip_string] = {{playerId}, {playerId}}
}

local function pruneIp(ip, logout)
    if GLOBAL_PLAYER_IPS[ip] then
        for i = #GLOBAL_PLAYER_IPS[ip], 1, -1 do
            local player = Player(GLOBAL_PLAYER_IPS[ip][i])
            if not player then
                GLOBAL_PLAYER_IPS[ip][i] = nil
            end
        end
        if logout and #GLOBAL_PLAYER_IPS[ip] == 0 then
            GLOBAL_PLAYER_IPS[ip] = nil
        end
    end
end

local function pruneIpList(ipList)
    pruneIp(ipList[1], true)
    ipList[1] = nil
    if #ipList > 0 then
        addEvent(pruneIpList, 0, ipList)
    end
end

local function removePlayer(playerId)
    local player = Player(playerId)
    if not player then
        return
    end
    player:remove()
end

local function multiclientLimitReached(player)
    local nm = NetworkMessage()
    nm:addByte(0x14)
    nm:addString("Multiclient limit reached. Unable to login.")
    nm:sendToPlayer(player)
    nm:delete()
end


local creatureevent = CreatureEvent("onLogin_multiClientLimiter")

function creatureevent.onLogin(player)
    if player:getGroup():getAccess() and not countGMTowardsLimit then
        return true
    end
    local ip = player:getIp()
    if not GLOBAL_PLAYER_IPS[ip] then
        GLOBAL_PLAYER_IPS[ip] = {}
    end
    pruneIp(ip)
    if #GLOBAL_PLAYER_IPS[ip] >= math.min(multiclient_limit, 4) then
        multiclientLimitReached(player)
        addEvent(removePlayer, 0, player:getId())
        return true
    end
    GLOBAL_PLAYER_IPS[ip][#GLOBAL_PLAYER_IPS[ip] + 1] = player:getId()
    return true
end

creatureevent:register()


local creatureevent = CreatureEvent("onLogout_multiClientLimiter")

function creatureevent.onLogout(player)
    local ip = player:getIp()
    pruneIp(ip, true)
    return true
end

creatureevent:register()


local globalevent = GlobalEvent("onThink_multiClientLimiter")

function globalevent.onThink()
    local ipList = {}
    for ip, _ in pairs(GLOBAL_PLAYER_IPS) do
        ipList[#ipList + 1] = ip
    end
    pruneIpList(ipList)
    return true
end

globalevent:interval(1800000)
globalevent:register()
 
Back
Top