Top 5 highscores getting a effect

Discussion in 'Requests' started by AngeLOT, Aug 9, 2018.

  1. AngeLOT

    AngeLOT Active Member

    Joined:
    Dec 14, 2017
    Messages:
    353
    Likes Received:
    49
    Best Answers:
    2
    Hey Otland, would like to request a script since I cant find it anywhere :/

    The script is simple:
    If you are top 1-5 of highscore, u getting always a effect like every 2 sec and thats all xD
     
    Last edited: Aug 10, 2018
  2. Best Answer:
    Post #7 by Xikini, Aug 12, 2018
  3. AngeLOT

    AngeLOT Active Member

    Joined:
    Dec 14, 2017
    Messages:
    353
    Likes Received:
    49
    Best Answers:
    2
  4. Xikini

    Xikini I whore myself out for likes

    Joined:
    Nov 17, 2010
    Messages:
    3,688
    Likes Received:
    1,902
    Best Answers:
    94
    Server version?
    What classifies them as high scoring?
     
  5. AngeLOT

    AngeLOT Active Member

    Joined:
    Dec 14, 2017
    Messages:
    353
    Likes Received:
    49
    Best Answers:
    2
    Sorry totally forgot to write my tfs version.. im using tfs 0.4

    Their level ^^
     
  6. Xikini

    Xikini I whore myself out for likes

    Joined:
    Nov 17, 2010
    Messages:
    3,688
    Likes Received:
    1,902
    Best Answers:
    94
    I'm not good with databases unfortunately.
    I could script it to work with the 5 highest level players currently logged in, if you want.
     
    AngeLOT likes this.
  7. AngeLOT

    AngeLOT Active Member

    Joined:
    Dec 14, 2017
    Messages:
    353
    Likes Received:
    49
    Best Answers:
    2
    Ye could work aswell :p
     
  8. Xikini

    Xikini I whore myself out for likes

    Joined:
    Nov 17, 2010
    Messages:
    3,688
    Likes Received:
    1,902
    Best Answers:
    94
    Best Answer
    Tested on 0.3.7
    (If there are multiple people with the same 'highscore' they will all get the animation for that highscore tier.)
    Code (Lua):
    1. Example..?
    2. Levels of players on server == 10, 10, 9, 8, 8, 8, 8, 7, 6, 5, 4, 3, 1
    3.  
    4. Players 10, 10 -> "first place"
    5. Player 9 -> "second place"
    6. Players 8, 8, 8, 8 -> "third place"
    7. Player 7 -> "fourth place"
    8. Player 6 -> "fifth place"
    9.  
    10. Players 5, 4, 3, 1 -> Get no effect.
    I think interval on 0.4 is in seconds instead of milliseconds.
    If I'm wrong, change interval to 2000.
    Code (XML):
    1. <globalevent name="highscore_animation" interval="2" event="script" value="highscore_animation.lua"/>
    Code (Lua):
    1. local config = { -- player with high scores get these effects, based on their ranking
    2.     [1] = CONST_ME_HEARTS, -- first place
    3.     [2] = CONST_ME_CRAPS,
    4.     [3] = CONST_ME_FIREWORK_BLUE,
    5.     [4] = CONST_ME_FIREWORK_YELLOW,
    6.     [5] = CONST_ME_FIREWORK_RED   -- fifth place
    7. }
    8.  
    9. local function compare(a, b)
    10.     return a[1] > b[1]
    11. end
    12.  
    13. local function send_effect(cid, rank)
    14.     doSendMagicEffect(getCreaturePosition(cid), config[rank])
    15. end
    16.  
    17. function onThink(cid, interval, lastExecution)
    18.     local player_data, temp1, temp2 = {}, 0, 1
    19.     for _, pid in ipairs(getPlayersOnline()) do
    20.         player_data[#player_data + 1] = {getPlayerLevel(pid), pid}
    21.     end
    22.     table.sort(player_data, compare)
    23.     for i = 1, #player_data do
    24.         if temp1 == 0 or temp1 == player_data[i][1] then
    25.             addEvent(send_effect, 0, player_data[i][2], temp2)
    26.         elseif temp2 < 5 then
    27.             addEvent(send_effect, 0, player_data[i][2], temp2 + 1)
    28.             temp2 = temp2 + 1
    29.         else
    30.             break
    31.         end
    32.         temp1 = player_data[i][1]
    33.     end
    34.     return true
    35. end
     
  9. AngeLOT

    AngeLOT Active Member

    Joined:
    Dec 14, 2017
    Messages:
    353
    Likes Received:
    49
    Best Answers:
    2
    Thanks you really much! <3
     
    Xikini likes this.
  10. 4drik

    4drik Active Member

    Joined:
    Jun 30, 2014
    Messages:
    146
    Likes Received:
    71
    Best Answers:
    0
    I think that the list of players should be done in login, logout and level advance functions.
    Not in onThink.
     
  11. AngeLOT

    AngeLOT Active Member

    Joined:
    Dec 14, 2017
    Messages:
    353
    Likes Received:
    49
    Best Answers:
    2
    Can I ask why?
     
  12. Xikini

    Xikini I whore myself out for likes

    Joined:
    Nov 17, 2010
    Messages:
    3,688
    Likes Received:
    1,902
    Best Answers:
    94
    So that you don't need to re-create the list of players constantly, which will reduce overhead. (time it takes for your computer to do the calculations)
    in pre tfs 1.0x servers each section (actions/globalevents/creatureevents/et cetera) is localised, and cannot share tables with each other. (trust me, I've tried)

    The only way to change it like you propose is to use storage values, and then use onThink to send the animations to the players with the correct storage values.
    Honestly, it's probably the better solution, just a bit more time consuming to create initially..
    But that's assuming a few things.

    Counter-point 1, this is assuming players are not being assholes.
    Example: Logging in & out constantly.

    Counter-point 2, this is assuming the server is a low-rate exploration server.
    Example: Highrate server, where player levels are constantly changing.
    Example: War-based server, where player levels are changing constantly, and players are dying, which causes a logout and login as well as an advance function to trigger.

    Those are the bigger examples, but there are some smaller things you could look at as well.

    When these above events are happening, the overhead to the server would be huge, especially if you multiply the amount of players online doing the same 'destructive' behaviour.

    For these reasons, I believe it's best to have a consistent triggering of the event, instead of low and high spikes of activity.

    ------------------------------
    As for my script, if you are not worried about getting the most up-to-date information, we could change it to update the player highscores every 5 minutes, for example, to reduce the amount of overhead the script causes.

    (So it checks for first to fifth place once per 5 minutes, and then sends the animations to the players for a full 5 minutes, before checking for player highscores again.)

    (Note: If a highscoring player logs out or dies inbetween the 5 minute checks, they will no longer have the effect, until the next 5 minute check.)

    So, same as before.
    5 * 60 = 300 seconds
    But, if it counts in milliseconds, use 300 * 1000 = 300000
    Code (XML):
    1. <globalevent name="highscore_animation" interval="300" event="script" value="highscore_animation.lua"/>
    Code (Lua):
    1.  
    2. local config = { -- player with high scores get these effects, based on their ranking
    3.     [1] = CONST_ME_HEARTS, -- first place
    4.     [2] = CONST_ME_CRAPS,
    5.     [3] = CONST_ME_FIREWORK_BLUE,
    6.     [4] = CONST_ME_FIREWORK_YELLOW,
    7.     [5] = CONST_ME_FIREWORK_RED   -- fifth place
    8. }
    9.  
    10. local function compare(a, b)
    11.     return a[1] > b[1]
    12. end
    13.  
    14. local function send_effect(cid, rank, amount)
    15.     if not isPlayer(cid) then
    16.         return true
    17.     end
    18.     doSendMagicEffect(getCreaturePosition(cid), config[rank])
    19.     if amount > 0 then
    20.         addEvent(send_effect, 2000, cid, rank, amount - 1)
    21.     end
    22. end
    23.  
    24. function onThink(cid, interval, lastExecution)
    25.     local player_data, temp1, temp2 = {}, 0, 1
    26.     for _, pid in ipairs(getPlayersOnline()) do
    27.         player_data[#player_data + 1] = {getPlayerLevel(pid), pid}
    28.     end
    29.     table.sort(player_data, compare)
    30.     for i = 1, #player_data do
    31.         if temp1 == 0 or temp1 == player_data[i][1] then
    32.             addEvent(send_effect, 0, player_data[i][2], temp2, 150)
    33.         elseif temp2 < 5 then
    34.             addEvent(send_effect, 0, player_data[i][2], temp2 + 1, 150)
    35.             temp2 = temp2 + 1
    36.         else
    37.             break
    38.         end
    39.         temp1 = player_data[i][1]
    40.     end
    41.     return true
    42. end
     
    4drik likes this.
  13. 4drik

    4drik Active Member

    Joined:
    Jun 30, 2014
    Messages:
    146
    Likes Received:
    71
    Best Answers:
    0
    I never used TFS but since I can do it on YurOTS, it's all the more on such a powerful engine as TFS.
    There is no situation in which the code in previous posts would be better.
    So your counter-points are rather a false guess, but of course, your solution is faster to write.

    As if someone wanted to write it better.
    In game.h declare:
    Code (C++):
    1. std::list<Player*> topPlayers;
    Then compare players in functions:
    Code (C++):
    1. void Game::addPlayer(Player* player)
    2. void Game::removePlayer(Player* player)
    3. bool CreatureEvents::playerAdvance(Player* player, skills_t skill, uint32_t oldLevel,
    4. uint32_t newLevel)
    5.  
    In the last function, exclude here:
    Code (C++):
    1.  
    2. if (skill == SKILL_LEVEL){
    3. ...
    4. }
    5.  
    Add top 5 to topPlayers list:
    Code (C++):
    1.  
    2. for(int i = 0; i <= 4; i++ )
    3. topPlayers.push_back(table[i]);
    4.  
    In a function:
    Code (C++):
    1. void Player::onThink(uint32_t interval)
    Check if the player is in the list:
    Code (C++):
    1. if(std::find(topPlayers.begin(), topPlayers.end(), this) != topPlayers.end()){
    2. ...
    3. }
    Send the effect.

    #Down:
    You're right, I did not specify in the previous post.
     
    Last edited: Aug 12, 2018
    Xikini likes this.
  14. Xikini

    Xikini I whore myself out for likes

    Joined:
    Nov 17, 2010
    Messages:
    3,688
    Likes Received:
    1,902
    Best Answers:
    94
    Sorry, yes, if you code it into the source it's going to be faster.
    I had assumed you meant via lua scripts, not via source.

    Just a small rebuttal;
    It's not a 'false guess', that if 1 player decides to log in and out repeatedly, it would trigger both the login and logout functions repeatedly, which would make it check more often then every 2 seconds. (and if there is 20-30 people doing this..? Or after a server save when 70 people try to log in right away?)

    Unless I'm mistaken in what your trying to tell me. :/
     
    Last edited: Aug 12, 2018
  15. tetra20

    tetra20 DD

    Joined:
    Jan 17, 2009
    Messages:
    1,306
    Likes Received:
    293
    Best Answers:
    3
    The first lua code xikini pasted is actually fine for lua(maybe?),It has an order of O(Nlogn) where n is the number of players,which wouldn't lag even if you repeated it every 2 seconds with 10000 players online(probably?)

    In my own opinion,if you are seeking better time and less memory,this'd probably be done in source with std::set

    1-when a player logs in,insert both his {level,id} into set
    2-when the player logout,erase both his {level,id} from the set

    Both operations above are O(logn),and each 2 seconds,as the set is already sorted by itself,you'd only have to check the last 5 positions in the set as they have the highest 5 players,with their ids

    That's O(logn) time,O(n) memory

    to achieve an O(1) memory,you can do the following..
    1-when a player logs in,insert both his {level,id} into set
    2-while the set size is greater than 5,erase the smallest element(beginning of set)
    3-when the player logout,erase both his {level,id} from the set
     
  16. Xikini

    Xikini I whore myself out for likes

    Joined:
    Nov 17, 2010
    Messages:
    3,688
    Likes Received:
    1,902
    Best Answers:
    94
    You gotta account for many people having the same level though.
    If 18 people all have level 10, and level 10 is the highest level on the server, you gotta give them all the effect, not just the first 5 to login.
    This was the harder part of the script, tbh.
     
    tetra20 likes this.
  17. tetra20

    tetra20 DD

    Joined:
    Jan 17, 2009
    Messages:
    1,306
    Likes Received:
    293
    Best Answers:
    3
    Back to O(logn) time and O(n) memory
    1-when a player logs in,insert both his {level,id} into set
    2-when the player logout,erase both his {level,id} from the set
    now you have best players Added in the list,just iterate in the following way
    two variables highestLevelFound = 0,timesFound = 0;
    once you encounter a new highestLevelFound,increase the timesFound by 1,if the timesFound reaches 6,break for example

    {10,10,10,9,8,8,7,6,5}
    those are the iterations
    1-Set highestLevelFound to 10,timesFound = 1,and send effect to player
    2-highestLevelFound is already equal to the second player,so just send effect to player
    3-highestLevelFound is already equal to the third player,so just send effect to player
    4-set HighestLevelFound to 9,timesFound = 2,and send effect to player
    5-set highestLevelFound to 8,timesFound = 3,and send effect to player
    6-highestLevelfound already equal to 8,just send effect to player
    7-set highestLevelFound to 7,timesFound = 4,and send effect to player
    8-set highestLevelFound to 6,timesFound = 5,and send effect to player
    9-set highestLevelFound to 5,timesFound = 6,Break

    The worst case here is O(n) where n is number of players,but this will rarely happen,there isn't that much people with same level?
    Best case is O(1) <-- which will mostly happen

    This is just another way to do it,but all the ways are fine,your way is actually good enough and forgive my long post
     
    Xikini likes this.

Share This Page

Loading...