• 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!

Add Player 3% Mana per sec needed

Hashirama479

World of Ninja
Joined
Dec 19, 2016
Messages
536
Solutions
6
Reaction score
74
Yo I need a script which gives players 3% mana per sec and it should work forever also its shouldnt be like using a item = getting mana it should always heal doenst matter if you log off or what ever haha xD ( sorry if the script alredy exists but cant find it.... )
 
@Znote
are you sure $onlinecreatures[$cid] is not short solution for looping trough table and returning the requested value?

I'm very bad at coding terms, I was trying to find in google how the tables are stored in memory and what happens if values is requested by key, found no good results.

Players are declared as unordered_map, so the complexity is O(1) in the best case and O(N) in the worst.
 
@EvulMastah PHP array handling is awesome. :D

And it completely spoils me, so now I suck at any other programming language because of crappy array and list logic.
 
Players are declared as unordered_map, so the complexity is O(1) in the best case and O(N) in the worst.
I mean in code in general not in TFS.

what does O(1) even mean?
I want to know how the request is handled in low level code.
How much they are different when in high level you do specific request or randomly loop rough table to find the specific value.

Because I think its not much different, its just in high level code we have made it comfortable for ourselves to get table values, because we do it practically ALL THE TIME

to put it simply.
what does the low level code too with table when it reads a line of code and finds "." symbol

table.key
___^
 
I mean in code in general not in TFS.

what does O(1) even mean?
I want to know how the request is handled in low level code.
How much they are different when in high level you do specific request or randomly loop rough table to find the specific value.

Because I think its not much different, its just in high level code we have made it comfortable for ourselves to get table values, because we do it practically ALL THE TIME

to put it simply.
what does the low level code too with table when it reads a line of code and finds "." symbol

table.key
___^
https://en.wikipedia.org/wiki/Big_O_notation
the . symbol is short for [' '] (string keys in tables)
accessing table information gets the value inside of the memory address the table is stored at (someone correct me if im wrong)
 
I mean in code in general not in TFS.

what does O(1) even mean?
I want to know how the request is handled in low level code.
How much they are different when in high level you do specific request or randomly loop rough table to find the specific value.

Because I think its not much different, its just in high level code we have made it comfortable for ourselves to get table values, because we do it practically ALL THE TIME

to put it simply.
what does the low level code too with table when it reads a line of code and finds "." symbol

table.key
___^
Associative arrays (maps): https://en.wikipedia.org/wiki/Hash_table
Arrays: https://en.wikipedia.org/wiki/Array_data_structure

Lua table uses a combination of both to optmize it.
You can read about it here: https://www.lua.org/doc/jucs05.pdf (Section 4)
 
Good reads! Now the @EvulMastah sentence makes more sense too

So I guess requesting value by key can be faster than looping trough table and finding the value.
Depending on how the table structure is written and what method the source applies.

Is that the method how to loop trough table decided in source or depends how the table is written?

Maybe the answer is written on the wiki (only read about Big O Notations and Hast Tables atm)
 
Last edited:
You maybe think Game.getPlayers() is huge issue because it creates and returns entire online playerlist.
Constructing Player(playerID) is actually means it loops trough all online players and compares if the the given parameter exist in the playerlist, before it returns the correct player userdata.

Hence with 500 people online, you tap into the playerlist 500 times.
where with globalevent you simply return the entire playerlist once regadless of online player amount.
But not only that, if someone logs out within 1 sec, you still going to try to fetch the player with addEvent, so a little addition there too.

Ok so Player(playerID) is idd faster than looping trough entire list and comparing the active playerID's to find a match.
But even still at some point as the player amount increases the globalEvent is going to be still better solution for that case.
 
Actually as someone said, let's stop pretending like we know what is going on in the engine. I cannot tell whether filling the event stack with 500 events all the time is slower or faster than calling for a players table each second. I don't think you can either. So leave that alone or call in someone who might know.

Aside from that, it's very obvious creaturescripts is the fastest approach. Our previous discussion was not about what is faster, but rather how much faster?
I can't confirm without tests but I believe a loop would be better approach here as the overhead of addEvent could be greater than calling doPlayerAddMana directly.
500 events of doPlayerAddMana would still be unnoticeable. But, if we assumed they are 500 events of a bigger function I'd say @Znote implementation would smooth out things but in the cost of reducing the overall performance (Would still be better tho, IMO).
The PHP code is able to find the correct creature object because cid is a reference to where the object is in the array. So you do not need to loop through the array to find which element match cid.
Probably goes back to what Colandus said, speculations as to what happens in the backend.
For instance, if cid value is used as a key in an online list array, you don't have to traverse it.

PHP sample:
PHP:
$onlinecreatures = array(
    0 => array(
        'getName' => 'Znote',
        'isPlayer' => true,
        'getMana' => 60,
        'getMaxMana' => 100,
    ),
    1 => array(
        'getName' => 'Colandus',
        'isPlayer' => true,
        'getMana' => 120,
        'getMaxMana' => 120,
    ),
    2 => array(
        'getName' => 'Whiteevo',
        'isPlayer' => true,
        'getMana' => 90,
        'getMaxMana' => 110,
    ),
    3 => array(
        'getName' => 'Orc Berserker',
        'isPlayer' => false,
        'getMana' => 100,
        'getMaxMana' => 100,
    )
);

$cid = 2; // Cid represent index/key of online/active creature list.

$player = $onlinecreatures[$cid]; // local player = Player(cid)
echo $player['getName']; // player:getName()
The PHP code is able to find the correct creature object because cid is a reference to where the object is in the array. So you do not need to loop through the array to find which element match cid.
This exmaple doesn't make any sense. Anyway, in Lua it's almost the same when you are using a method registered in player's table, you cast the returned value to an address block which points to the object(TFS 1.x).
@EvulMastah PHP array handling is awesome. :D
I agree about PHP arrays, but, Lua tables just as awesome ;)

If I were to implement it myself I'd go with creatureevent approach as it seems the most appropriate event for such a case.
Code:
local mpGainPercent = 3
function onThink(cid, interval)
    local mana = getCreatureMana(cid)
    local maxMana = getCreatureMaxMana(cid)
    if mana ~= maxMana then
        doCreatureAddMana(cid, math.min(maxMana-mana, mpGainPercent * (maxMana/100)))
    end
end
Assuming the default creature event check is happening once every second. If you have a higher value and still looking for efficiency
Code:
local mpGainPercent = 3
players = {}
if not eventId then
    local function addMana()
        for cid in pairs(players) do
            local mana = getCreatureMana(cid)
            local maxMana = getCreatureMaxMana(cid)
            if mana ~= maxMana then
                doCreatureAddMana(cid, math.min(maxMana-mana, mpGainPercent * (maxMana/100)))
            end
        end
        eventId = addEvent(addMana, 1000)
    end
    addMana()
end

function onLogin(cid, interval)
    players[cid] = true
end

function onLogout(cid)
    if players[cid] then
        players[cid] = nil
    end
    return true
end
And, if you have a low value for creature event check
Code:
local mpGainPercent = 3
local thinkInterval = 1000
players = {}
function onThink(cid, interval)
    local time = players[cid]
    if not time then
        players[cid] = interval
    else
        if time >= thinkInterval then
            local mana = getCreatureMana(cid)
            local maxMana = getCreatureMaxMana(cid)
            if mana ~= maxMana then
                doCreatureAddMana(cid, math.min(maxMana-mana, maxMana * (mpGainPercent/100)))
            end
            time = 0
        end
        players[cid] = time + interval
    end
end

function onLogout(cid)
    if players[cid] then
        players[cid] = nil
    end
    return true
end
As you can see, the code is getting complex when the event doesn't occur once every second. So, in this case I'd go with GlobalEvent approach as it's just as efficient as the others (in real world scenario).
GlobalEvent Script
Code:
local mpGainPercent = 3
function onThink(interval)
    for _, cid in ipairs(getPlayersOnline()) do
        local mana = getCreatureMana(cid)
        local maxMana = getCreatureMaxMana(cid)
        if mana ~= maxMana then
            doCreatureAddMana(cid, math.min(maxMana-mana, mpGainPercent*(maxMana/100)))
        end
    end
    return true
end
Btw @Colandus getPlayersOnline returns a list of cids, getOnlinePlayers returns a list of player names. I know it's confusing :p
 
I can't confirm without tests but I believe a loop would be better approach here as the overhead of addEvent could be greater than calling doPlayerAddMana directly.
500 events of doPlayerAddMana would still be unnoticeable. But, if we assumed they are 500 events of a bigger function I'd say @Znote implementation would smooth out things but in the cost of reducing the overall performance (Would still be better tho, IMO).

What? addEvent will use doPlayerAddMana the same way as any other approach.

Btw @Colandus getPlayersOnline returns a list of cids, getOnlinePlayers returns a list of player names. I know it's confusing :p

Not in 1.x apparently, which I used to test with.
 
What? addEvent will use doPlayerAddMana the same way as any other approach.
I meant, the overhead that comes with addEvent such as the function call itself, locking/unlocking before moving the task to the dispatcher thread, checking whether the event has stopped or not, etc.
Not in 1.x apparently, which I used to test with.
Ah, right.
 
@andu Hey I need help with ur script its working as supposed but you forgot to add exhastion time! xD can you add a exhastion time of 1 sec? so it adds every sec the mana? :p
Lua:
-- Creaturescripts.xml: <event type="think" name="Healing" script="healing.lua"/>
-- login.lua: registerCreatureEvent(cid, "Healing")
-- for more ask andu @ otland.net

local config = {
    useTfsVersion1 = "no", -- use "yes" for tfs 1.0+ and otx 2.0+. For old tfs, and other engines use "no".
    inCombat = {
        healthPercent = 0.0,    -- % of max health
        manaPercent = 1.0    -- % of max mana
    },
    outOfCombat = {
        healthPercent = 0.0,    -- % of max health
        manaPercent = 1.0    -- % of max mana
    },
    energyGain = 10        -- melee/tank etc (in my server players what have exactly 100 mana are melee/tanks)
}

if config.useTfsVersion1 == "yes" then
    function hasCondition(cid, condition)
        local c = Creature(cid)
        return c ~= nil and c:getCondition(condition, CONDITIONID_DEFAULT) or false
    end
end

function onThink(cid, interval)
    if isPlayer(cid) == true then
        local hp, mp = 0, 0
        if hasCondition(cid, CONDITION_INFIGHT) == true then
            hp = config.inCombat.healthPercent
            mp = config.inCombat.manaPercent
        else
            hp = config.outOfCombat.healthPercent
            mp = config.outOfCombat.manaPercent
        end

        local hpheal, mpheal = getCreatureMaxHealth(cid)*(hp/100), getPlayerMaxMana(cid) * (mp / 100)

        if hpheal >= 1 and getCreatureHealth(cid) < getCreatureMaxHealth(cid) then
            doCreatureAddHealth(cid, hpheal)
        end
        if getPlayerMana(cid) < getPlayerMaxMana(cid) then
            if getPlayerMaxMana(cid) > 100 then
                if mpheal >= 1 then
                    doPlayerAddMana(cid, mpheal)
                --    doSendMagicEffect(getThingPos(cid), CONST_ME_MAGIC_BLUE)
                end
            else
                doPlayerAddMana(cid, config.energyGain)    -- energy
            end
        end
    end
    return true
end
 
Last edited by a moderator:
Back
Top