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

TalkAction [TFS 1.0] Local highscores

hodleo

Formerly cbrm -Crypto enthusiast, Retired scripter
Staff member
Global Moderator
Joined
Jan 6, 2009
Messages
6,598
Solutions
3
Reaction score
955
Location
Caribbean Sea
E4GsaUhs.png
I made this talkaction since I didn't see any ingame highscore scripts for tfs 1.0 yet. It loads the top 30 ranked players on experience, magic and skill levels into global storages when server starts up and it gets updated each 3 hours by default. This script takes advantage of the new global storage management, in order to avoid requesting data from the database each time a player uses this command. The optional storage highscore is disabled by default.

Changelog
08/03/14 Improvements on the creaturescript; event registration moved to talkaction.
08/01/14 Initial release

/globalevents/globalevents.xml
Code:
<globalevent type="startup" name="Highscore" script="highscores.lua"/>
<globalevent interval="10800000" name="Highscores" script="highscores.lua"/>
/globalevents/scripts/highscores.lua
Code:
--[[
    ....:::::::::::::::::::::....
     Local Highscores for TFS 1.0
     by cbrm(CyberM/cybermaster)
     otland.net
    \:::::::::::::::::::::::::::/
]]

local QueryList = {
    ['Level'] = {'`name`, `level` AS `score` FROM `players`', 'ORDER BY `experience` DESC'},
    ['Magic Level'] = {'`name`, `maglevel` AS `score` FROM `players`', 'ORDER BY `maglevel` DESC, `manaspent` DESC'},
    --['Storage'] = {'`players`.`name` AS `name`, `value` AS `score` FROM `player_storage` LEFT JOIN `players` ON `player_storage`.`player_id` = `players`.`id`', 'AND `key` = 1550 ORDER BY `value` DESC'}
}

for i, skill in ipairs({'fist','club','sword','axe','dist','shielding','fishing'}) do
    local index = (skill == 'dist' and 'Distance' or skill:gsub('^%l',string.upper)) .. (i < 6 and ' Fighting' or '')
    QueryList[index] = {'`name`, `skill_' .. skill .. '` AS `score` FROM `players`','ORDER BY `skill_' .. skill .. '` DESC, `skill_' .. skill .. '_tries` DESC'}
end

function updateHighscores()
    for skill, query in pairs(QueryList) do
        local t, Query = {}, db.storeQuery('SELECT ' .. query[1] .. ' WHERE `deletion` = 0 AND `group_id` < 3 ' .. query[2] .. ' LIMIT 30;')
        if Query ~= false then
            repeat
                table.insert(t, {result.getDataString(Query, 'name'), result.getDataInt(Query, 'score')})
            until not result.next(Query)
            result.free(Query)
            setGlobalStorageValue(skill, t)
        end
    end
    setGlobalStorageValue('highscores', os.time())
end

function onStartup()
    updateHighscores()
end

function onThink(interval)
    updateHighscores()
    return true
end
/creaturescripts/creaturescripts.xml
Code:
<event type="modalwindow" name="Highscores" script="highscores.lua"/>
/creaturescripts/scripts/highscores.lua
Code:
--[[
    ....:::::::::::::::::::::....
     Local Highscores for TFS 1.0
     by cbrm(CyberM/cybermaster)
     otland.net
    \:::::::::::::::::::::::::::/
]]

SkillWindow = {
    [1337] = 'Local highscores at ' .. getConfigInfo('serverName'),
    [1338] = 'Level',               [1339] = 'Magic Level',         [1340] = 'Shielding',
    [1341] = 'Distance Fighting',   [1342] = 'Sword Fighting',      [1343] = 'Club Fighting',
    [1344] = 'Axe Fighting',        [1345] = 'Fist Fighting',       [1346] = 'Fishing',
    --[1347] = 'Storage'
}

highscores = ModalWindow(1337, SkillWindow[1337], 'Choose a category:')
for i, skill in ipairs({'Level','Magic','Shielding','Distance','Sword','Club','Axe','Fist','Fishing'}) do
    highscores:addChoice(i, skill)
end
--highscores:addChoice(10, 'Storage')
highscores:addButton(1, 'Show')
highscores:addButton(2, 'Close')
highscores:addButton(3, 'Info')
highscores:setDefaultEnterButton(1)
highscores:setDefaultEscapeButton(2)
highscores:setPriority(true)

function string.diff(diff) --by Colandus and fixed by Cykotitan
    local format = {
        {'day', diff / 60 / 60 / 24},
        {'hour', diff / 60 / 60 % 24},
        {'minute', diff / 60 % 60},
        {'second', diff % 60}
    }

    local out = {}
    for k, t in ipairs(format) do
        local v = math.floor(t[2])
        if(v > 0) then
            table.insert(out, (k < #format and (#out > 0 and ', ' or '') or ' and ') .. v .. ' ' .. t[1] .. (v ~= 1 and 's' or ''))
        end
    end
    local ret = table.concat(out)
    if ret:len() < 16 and ret:find('second') then
        local a, b = ret:find(' and ')
        ret = ret:sub(b+1)
    end
    return ret
end

function string.abbr(first, final, limit)
    local str = first .. final
    if str:len() > limit then
        str = first:sub(1, limit-(final:len())) .. final
    end
    return str
end

function sendSkillWindow(cid, windowId)
    local highscore = ModalWindow(windowId, 'Ranking for ' .. SkillWindow[windowId], 'Scroll down for entire list')
    for rank, score in ipairs(getGlobalStorageValue(SkillWindow[windowId])) do
        highscore:addChoice(rank, string.abbr(rank .. '. ' .. score[1], '... ' .. score[2], 30))
    end
    highscore:addButton(1, 'Back')
    highscore:addButton(2, 'Close')
    highscore:addButton(3, 'Info')
    highscore:setDefaultEscapeButton(2)
    highscore:setPriority(true)
    highscore:sendToPlayer(cid)
end

function onModalWindow(cid, modalWindowId, buttonId, choiceId)

    if not SkillWindow[modalWindowId] then
        return
    end

    if buttonId == 3 then
        doPlayerPopupFYI(cid, 'Local highscores were last updated ' .. string.diff(os.time()-getGlobalStorageValue('highscores')) .. ' ago.')
    elseif buttonId == 1 then
        if modalWindowId == 1337 then
            sendSkillWindow(cid, 1337+choiceId)
        else
            highscores:sendToPlayer(cid)
        end
        return
    end

    return unregisterCreatureEvent(cid, 'Highscores')
end
/talkactions/talkactions.xml
Code:
<talkaction words="!highscores" script="highscores.lua" />
/talkactions/scripts/highscores.lua
Code:
function onSay(cid, words, param)
       registerCreatureEvent(cid, 'Highscores')
       highscores:sendToPlayer(cid)
       return false
end
 
great =) do you accept suggestions? if yes, I suggest an option to look by vocations =P
 
I could fork one if I receive more requests
 
Nicely done, but you still use table.insert? :p
 
Found what I did wrong. Silly mistake, I registered the even on login for no apparent reason, works perfectly now, only one thing that is very weird in my opinion, I started useing this and it works but then I started getting errors for the "task" system from evo rpg, problem with using getCreatureStorage instead of getPlayerStorageValue, but still very odd that it shows up from using your code NOT the task window....
 
Last edited:
Well done, using it on my Projects.

Kind Regards,
Eldin.
 
Please tell us more about your error @Soba20
What does your logg say?

The script is working fine so unless you have an old TFS version and not the latest TFS 1.0, it should work.

Kind Regards,
Eldin.
 
It is a great script but I think it needs to be updated to work with TFS 1.1 series
 
It is a great script but I think it needs to be updated to work with TFS 1.1 series
data/creaturescripts/highscores.lua
Code:
--[[
    ....:::::::::::::::::::::....
     Local Highscores for TFS 1.0
     by cbrm(CyberM/cybermaster)
     otland.net
    \:::::::::::::::::::::::::::/
]]

SkillWindow = {
    [1337] = 'Local highscores at ServerName',
    [1338] = 'Level',               [1339] = 'Magic Level',         [1340] = 'Shielding',
    [1341] = 'Distance Fighting',   [1342] = 'Sword Fighting',      [1343] = 'Club Fighting',
    [1344] = 'Axe Fighting',        [1345] = 'Fist Fighting',       [1346] = 'Fishing',
    --[1347] = 'Storage'
}

highscores = ModalWindow(1337, SkillWindow[1337], 'Choose a category:')
for i, skill in ipairs({'Level','Magic','Shielding','Distance','Sword','Club','Axe','Fist','Fishing'}) do
    highscores:addChoice(i, skill)
end
--highscores:addChoice(10, 'Storage')
highscores:addButton(1, 'Show')
highscores:addButton(2, 'Close')
highscores:addButton(3, 'Info')
highscores:setDefaultEnterButton(1)
highscores:setDefaultEscapeButton(2)
highscores:setPriority(true)

function string.diff(diff) --by Colandus and fixed by Cykotitan
    local format = {
        {'day', diff / 60 / 60 / 24},
        {'hour', diff / 60 / 60 % 24},
        {'minute', diff / 60 % 60},
        {'second', diff % 60}
    }

    local out = {}
    for k, t in ipairs(format) do
        local v = math.floor(t[2])
        if(v > 0) then
            table.insert(out, (k < #format and (#out > 0 and ', ' or '') or ' and ') .. v .. ' ' .. t[1] .. (v ~= 1 and 's' or ''))
        end
    end
    local ret = table.concat(out)
    if ret:len() < 16 and ret:find('second') then
        local a, b = ret:find(' and ')
        ret = ret:sub(b+1)
    end
    return ret
end

function string.abbr(first, final, limit)
    local str = first .. final
    if str:len() > limit then
        str = first:sub(1, limit-(final:len())) .. final
    end
    return str
end

function sendSkillWindow(cid, windowId)
    local highscore = ModalWindow(windowId, 'Ranking for ' .. SkillWindow[windowId], 'Scroll down for entire list')
    for rank, score in ipairs(Game.getStorageValue(SkillWindow[windowId])) do
        highscore:addChoice(rank, string.abbr(rank .. '. ' .. score[1], '... ' .. score[2], 30))
    end
    highscore:addButton(1, 'Back')
    highscore:addButton(2, 'Close')
    highscore:addButton(3, 'Info')
    highscore:setDefaultEscapeButton(2)
    highscore:setPriority(true)
    highscore:sendToPlayer(cid)
end

function onModalWindow(cid, modalWindowId, buttonId, choiceId)

    if not SkillWindow[modalWindowId] then
        return
    end

    if buttonId == 3 then
        Player(cid):popupFYI('Local highscores were last updated ' .. string.diff(os.time()-Game.getStorageValue('highscores')) .. ' ago.')
    elseif buttonId == 1 then
        if modalWindowId == 1337 then
            sendSkillWindow(cid, 1337+choiceId)
        else
            highscores:sendToPlayer(cid)
        end
        return
    end

    return Player(cid):unregisterEvent('Highscores')
end

data/talkactions/highscores.lua
Code:
function onSay(player, words, param)
       player:registerEvent('Highscores')
       highscores:sendToPlayer(player)
       return false
end

data/globalevents/highscores.lua
Code:
--[[
    ....:::::::::::::::::::::....
     Local Highscores for TFS 1.0
     by cbrm(CyberM/cybermaster)
     otland.net
    \:::::::::::::::::::::::::::/
]]

local QueryList = {
    ['Level'] = {'`name`, `level` AS `score` FROM `players`', 'ORDER BY `experience` DESC'},
    ['Magic Level'] = {'`name`, `maglevel` AS `score` FROM `players`', 'ORDER BY `maglevel` DESC, `manaspent` DESC'},
    --['Storage'] = {'`players`.`name` AS `name`, `value` AS `score` FROM `player_storage` LEFT JOIN `players` ON `player_storage`.`player_id` = `players`.`id`', 'AND `key` = 1550 ORDER BY `value` DESC'}
}

for i, skill in ipairs({'fist','club','sword','axe','dist','shielding','fishing'}) do
    local index = (skill == 'dist' and 'Distance' or skill:gsub('^%l',string.upper)) .. (i < 6 and ' Fighting' or '')
    QueryList[index] = {'`name`, `skill_' .. skill .. '` AS `score` FROM `players`','ORDER BY `skill_' .. skill .. '` DESC, `skill_' .. skill .. '_tries` DESC'}
end

function updateHighscores()
    for skill, query in pairs(QueryList) do
        local t, Query = {}, db.storeQuery('SELECT ' .. query[1] .. ' WHERE `deletion` = 0 AND `group_id` < 3 ' .. query[2] .. ' LIMIT 30;')
        if Query ~= false then
            repeat
                table.insert(t, {result.getDataString(Query, 'name'), result.getDataInt(Query, 'score')})
            until not result.next(Query)
            result.free(Query)
            Game.setStorageValue(skill, t)
        end
    end
    Game.setStorageValue('highscores', os.time())
end

function onStartup()
    updateHighscores()
end

function onThink(interval)
    updateHighscores()
    return true
end
 
Back
Top