Advertisement
HR_Shaft

Best race lap script by aLTis for SAPP

Jan 16th, 2017
293
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.75 KB | None | 0 0
  1. --  Best race lap script by aLTis (altis94@gmail.com)
  2.  
  3. -- Change log
  4. --2016-07-30:
  5. --  Removed RALLY_GAMETYPES variable
  6. --  Modes on PC are now read correctly (thanks to Samuco)
  7. --2016-07-31:
  8. --  Added player_limit variable
  9. --  Fixed a glitch that didn't display time needed on any-order mode
  10. --2016-08-02
  11. --  Added player_limit_message_time variable
  12. --2016-10-07
  13. --  Added anti_death variable
  14.  
  15. --  Configuration
  16.    
  17.     --  If you want to edit messages just edit them in the script itself, I didn't add them to the config
  18.    
  19.     --  If server has this many players then the script will not record any laps anymore
  20.     player_limit = 6
  21.     --  Should players be announced if there's too many players
  22.     player_limit_message = true
  23.     --  Time after game start needed to send player_limit_messages messages (in seconds)
  24.     player_limit_message_time = 15
  25.    
  26.     --  Player's time will not be recorded if they warped during the lap
  27.     anti_warp = true
  28.     --  If player died during a lap then their time will not be recorded
  29.     anti_death = true
  30.    
  31.     -- Only driver can get records
  32.     driver_only = true
  33.    
  34.     --  Notify player by how much time he needed to beat current record
  35.     current_needed_message = true
  36.     --  Notify player by how much time he needed to beat all time record
  37.     all_time_needed_message = true
  38.     --  How many seconds does player's time have to be away in order to display above messages
  39.     time_needed_treshold = 20
  40.    
  41.     --  Admin level required to reset times
  42.     admin_level = 4
  43.     --  Command used to reset best times for all maps (must be lowercase)
  44.     reset_command = "reset_times"
  45.     --  Command that displays best times on all maps (must be lowercase)
  46.     display_command = "times"
  47.     --  Command that displays best any-order times on all maps (must be lowercase)
  48.     display_any_order_command = "times_any"
  49.     --  How long the times will be shown after entering the command (in seconds) (will show each page for this time)
  50.     display_time = 5
  51.     --  How many lines to display on the console at once?? (should be 20 or less)
  52.     page_size = 15
  53.     --  Number of decimal places to display
  54.     idp = 2
  55.    
  56.     --  Display best player on game over
  57.     display_most_records_on_game_over = false
  58.     --  Display best player on game over
  59.     display_current_record_on_game_over = true
  60.     --  Display best player on game over
  61.     display_all_time_record_on_game_over = false
  62.    
  63. --  End of configuration
  64.  
  65. api_version = "1.9.0.0"
  66.  
  67. best_current_lap = 32000--  In ticks
  68. best_lap_all_time = {}--    In ticks
  69. best_lap_all_time_any_order = {}--  In ticks
  70. current_name = nil--    Player name
  71. all_time_name = {}--    Player name
  72. all_time_name_any_order = {}--  Player name
  73. current_map = nil--     Map that the server is currently running
  74. race = false--          Is the gametype race
  75. previous_time = {}
  76. mode = 0--              0 = normal, 1 = any order, 2 = rally
  77. player_warps = {}--     0 = did not warp, 1 = warped
  78. game_started = false
  79.  
  80. function OnScriptLoad()
  81.     if (halo_type == "PC") then
  82.         gametype_base = 0x671340    
  83.     else
  84.         gametype_base = 0x5F5498    
  85.     end  
  86.     ReadFromFile()
  87.     register_callback(cb['EVENT_GAME_START'], "OnGameStart")
  88.     register_callback(cb['EVENT_GAME_END'], "OnGameEnd")
  89.     register_callback(cb['EVENT_JOIN'], "OnPlayerJoin")
  90.     register_callback(cb['EVENT_LEAVE'], "OnPlayerLeave")
  91.     register_callback(cb['EVENT_COMMAND'],"OnCommand")
  92.     if(anti_death) then
  93.         register_callback(cb['EVENT_DIE'], "OnPlayerDeath")
  94.     end
  95.     if(anti_warp) then
  96.         register_callback(cb['EVENT_WARP'],"OnWarp")
  97.     end
  98.    
  99.     CheckMapAndGametype(true)
  100.    
  101.     for i = 1,16 do--   Reset personal stats
  102.         previous_time[i] = 32000
  103.         player_warps[i] = 0
  104.     end
  105. end
  106.  
  107. function OnWarp(PlayerIndex)
  108.     player_warps[PlayerIndex] = 1
  109. end
  110.  
  111. function OnPlayerDeath(PlayerIndex)
  112.     player_warps[PlayerIndex] = 1
  113. end
  114.  
  115. function OnPlayerJoin(PlayerIndex)--    Inform player about the best time!
  116.     if(race) then
  117.         if(player_limit_message and game_started == false) then
  118.             if(tonumber(get_var(1, "$pn")) == player_limit) then
  119.                 say_all("There are too many players and lap times will not be recorded!")
  120.             end
  121.         end
  122.         if(mode == 0) then
  123.             if(all_time_name[current_map] ~= nil) then
  124.                 say(PlayerIndex, "All time lap record for this map by "..all_time_name[current_map].." is "..best_lap_all_time[current_map].." seconds!")
  125.             else
  126.                 say(PlayerIndex, "There is no lap record for this map yet!")
  127.             end
  128.         else
  129.             if(mode == 1) then
  130.                 if(all_time_name_any_order[current_map] ~= nil) then
  131.                     say(PlayerIndex, "All time any-order lap record for this map by "..all_time_name_any_order[current_map].." is "..best_lap_all_time_any_order[current_map].." seconds!")
  132.                 else
  133.                     say(PlayerIndex, "There is no any-order lap record for this map yet!")
  134.                 end
  135.             end
  136.         end
  137.     else
  138.         CheckMapAndGametype(false)
  139.     end
  140. end
  141.  
  142. function OnPlayerLeave()
  143.     if(player_limit_message and game_started == false) then
  144.         if(tonumber(get_var(1, "$pn")) == player_limit) then
  145.             say_all("Lap times are being recorded again!")
  146.         end
  147.     end
  148. end
  149.  
  150. function CheckMapAndGametype(NewGame)
  151.     if(get_var(1, "$gt") == "race") then--  Check if gametype is race
  152.         current_map = get_var(1, "$map")--  Set current map
  153.         if(NewGame == false and race == true) then
  154.             return false
  155.         end
  156.         race = true
  157.         register_callback(cb['EVENT_TICK'],"OnTick")
  158.            
  159.         safe_read(true)--    We don't want to crash the server if no map is loaded :P
  160.         if (halo_type == "PC") then
  161.             mode = read_byte(gametype_base + 0x7C - 32)
  162.         else
  163.             mode = read_byte(gametype_base + 0x7C)
  164.         end
  165.         safe_read(false)
  166.            
  167.         if(best_lap_all_time[current_map] == nil) then--    If current map doesn't have all time record then set it to a high value
  168.             best_lap_all_time[current_map] = 32000
  169.         end
  170.         if(best_lap_all_time_any_order[current_map] == nil) then--  If current map doesn't have all time record then set it to a high value
  171.             best_lap_all_time_any_order[current_map] = 32000
  172.         end
  173.            
  174.         if(NewGame) then
  175.             best_current_lap = 32000--  Reset current map record
  176.         end
  177.     else
  178.         race = false
  179.         unregister_callback(cb['EVENT_TICK'])
  180.     end
  181. end
  182.  
  183. function OnGameStart()
  184.     CheckMapAndGametype(true)
  185.     game_started = true
  186.     timer(1000*player_limit_message_time, "ResetGameStarted")
  187.    
  188.     for i = 1,16 do--   Reset personal stats
  189.         previous_time[i] = 32000
  190.     end
  191. end
  192.  
  193. function ResetGameStarted()
  194.     game_started = false
  195. end
  196.  
  197. function OnGameEnd()
  198.     for i = 1,16 do
  199.         player_warps[i] = 0
  200.     end
  201.     if(race == false or mode == 2) then
  202.         return false
  203.     end
  204.     timer(1000, "DisplayOnGameEnd")
  205. end
  206.  
  207. function DisplayOnGameEnd()
  208.     if(display_most_records_on_game_over and race) then
  209.         say_all("Player with most records is "..FindPlayerWithMostRecords().."!")
  210.     end
  211.     if(display_current_record_on_game_over)then
  212.         if(current_name ~= nil and best_current_lap ~= 32000) then
  213.             say_all("Current record for this map is "..best_current_lap.." seconds by "..current_name.."!")
  214.         end
  215.     end
  216.     if(display_all_time_record_on_game_over) then
  217.         if(mode == 0) then
  218.             if(all_time_name[current_map] ~= nil and best_lap_all_time[current_map] ~= 32000) then
  219.                 say_all("All time record for this map is "..best_lap_all_time[current_map].." seconds by "..all_time_name[current_map].."!")
  220.             end
  221.         else
  222.             if(all_time_name_any_order[current_map] ~= nil and best_lap_all_time_any_order[current_map] ~= 32000) then
  223.                 say_all("All time record for this map is "..best_lap_all_time_any_order[current_map].." seconds by "..all_time_name_any_order[current_map].."!")
  224.             end
  225.         end
  226.     end
  227. end
  228.  
  229. function OnTick()-- Check players best times and compare them to current and all time best laps
  230.     if(mode ~= 0 and mode ~= 1 or tonumber(get_var(1, "$pn")) > player_limit - 1) then
  231.         return false
  232.     end
  233.     for i=1,16 do
  234.         if(player_alive(i)) then
  235.             local player = get_player(i)
  236.             local player_address = get_dynamic_player(i)
  237.             local best_time = 32000
  238.             local seat = 0--    0 - driver or on foot, 1 - passenger or gunner
  239.            
  240.             if(driver_only) then--  Get vehicle seat
  241.                 local vehicle_objectid = read_dword(player_address + 0x11C)
  242.                 if(tonumber(vehicle_objectid) ~= 0xFFFFFFFF) then
  243.                     local vehicle = get_object_memory(tonumber(vehicle_objectid))
  244.                     local driver = read_dword(vehicle + 0x324)
  245.                     driver = get_object_memory(tonumber(driver))
  246.                     if(driver == player_address) then
  247.                         seat = 0
  248.                     else
  249.                         seat = 1
  250.                     end
  251.                 end
  252.             end
  253.                
  254.             best_time = read_word(player + 0xC4)--  Player's current best time
  255.             best_time = round(best_time/30)
  256.                
  257.             if(seat == 1) then
  258.                 previous_time[i] = best_time
  259.             end
  260.            
  261.             if(seat == 0 and previous_time[i] ~= best_time and player_warps[i] == 0) then
  262.                 if(best_time ~= 0 and best_time < best_current_lap) then
  263.                     best_current_lap = best_time
  264.                     current_name = get_var(i, "$name")
  265.                     say_all("New current record by "..current_name.."! "..best_time.." seconds")
  266.                    
  267.                     if(mode == 0) then
  268.                         if(best_current_lap < best_lap_all_time[current_map]) then
  269.                             best_lap_all_time[current_map] = best_current_lap
  270.                             all_time_name[current_map] = get_var(i, "$name")
  271.                             say_all("New all time record by "..all_time_name[current_map].."! "..best_time.." seconds")
  272.                             WriteToFile()
  273.                         else
  274.                             if(all_time_needed_message and best_time > 0 and best_time ~= 32000 and (best_time - best_lap_all_time[current_map]) < time_needed_treshold) then
  275.                                 say(i, "ALL time record is "..best_lap_all_time[current_map].." seconds and you had to be "..(best_time - best_lap_all_time[current_map]).." seconds faster to beat it!")
  276.                             end
  277.                         end
  278.                     else
  279.                         if(mode == 1) then
  280.                             if(best_current_lap < best_lap_all_time_any_order[current_map]) then
  281.                                 best_lap_all_time_any_order[current_map] = best_current_lap
  282.                                 all_time_name_any_order[current_map] = get_var(i, "$name")
  283.                                 say_all("New all time any-order record by "..all_time_name_any_order[current_map].."! "..best_time.." seconds")
  284.                                 WriteToFile()
  285.                             else
  286.                                 if(all_time_needed_message and best_time > 0 and best_time ~= 32000 and (best_time - best_lap_all_time_any_order[current_map]) < time_needed_treshold) then
  287.                                     say(i, "ALL time any-order record is "..best_lap_all_time_any_order[current_map].." seconds and you had to be "..(best_time - best_lap_all_time_any_order[current_map]).." seconds faster to beat it!")
  288.                                 end
  289.                             end
  290.                         end
  291.                     end
  292.                 else
  293.                     if(mode == 0 and best_time > 0) then
  294.                         if(current_name ~= get_var(i, "$name")) then
  295.                             if(current_needed_message and (best_time - best_current_lap) < time_needed_treshold) then
  296.                                 say(i, "Current record is "..best_current_lap.." seconds and you had to be "..(best_time - best_current_lap).." seconds faster to beat it!")
  297.                             end
  298.                         else
  299.                             if(all_time_needed_message  and (best_time - best_current_lap) < time_needed_treshold) then
  300.                                 say(i, "ALL time record is "..best_lap_all_time[current_map].." seconds and you had to be "..(best_time - best_lap_all_time[current_map]).." seconds faster to beat it!")  
  301.                             end
  302.                         end
  303.                     else
  304.                         if(mode == 1 and best_time > 0) then
  305.                             if(current_name ~= get_var(i, "$name")) then
  306.                                 if(current_needed_message and (best_time - best_current_lap) < time_needed_treshold) then
  307.                                     say(i, "Current record is "..best_current_lap.." seconds and you had to be "..(best_time - best_current_lap).." seconds faster to beat it!")
  308.                                 end
  309.                             else
  310.                                 if(all_time_needed_message and (best_time - best_lap_all_time_any_order[current_map]) < time_needed_treshold) then
  311.                                     say(i, "ALL time any-order record is "..best_lap_all_time_any_order[current_map].." seconds and you had to be "..(best_time - best_lap_all_time_any_order[current_map]).." seconds faster to beat it!")
  312.                                 end
  313.                             end
  314.                         end
  315.                     end
  316.                 end
  317.             end
  318.            
  319.             if(previous_time[i] ~= best_time and player_warps[i] == 1) then
  320.                 say(i, "Your time was not recorded because you were warping or died during this lap!")
  321.                 player_warps[i] = 0
  322.             end
  323.            
  324.             previous_time[i] = best_time
  325.         end
  326.     end
  327. end
  328.  
  329. function WriteToFile()
  330.     --write mode, map string, time number, player string
  331.     local savefile = io.open("sapp\\lap_records.txt", "w")
  332.    
  333.     for map,value in pairs(all_time_name) do
  334.         savefile:write(0, ",", map,",", best_lap_all_time[map],",", value..",\n")
  335.     end
  336.     for map,value in pairs(all_time_name_any_order) do
  337.         savefile:write(1, ",", map,",", best_lap_all_time_any_order[map],",", value..",\n")
  338.     end
  339.     savefile:close()
  340. end
  341.  
  342. function ReadFromFile()
  343.     --read the same info and put in the tables
  344.     local savefile = io.open("sapp\\lap_records.txt", "r")
  345.     local n = 0
  346.    
  347.     if(savefile ~= nil) then
  348.         local line = savefile:read("*line")
  349.         while(line ~= nil) do
  350.             local words = {}
  351.             for word in string.gmatch(line, "([^,]+)") do
  352.                 words[n] = word
  353.                
  354.                 if(n < 3) then
  355.                     n = n + 1
  356.                 else
  357.                     n = 0
  358.                 end
  359.             end
  360.        
  361.             if(tonumber(words[0]) == 0) then--if mode is normal or any-order
  362.                 best_lap_all_time[words[1]] = tonumber(words[2])
  363.                 all_time_name[words[1]] = words[3]
  364.             else
  365.                 best_lap_all_time_any_order[words[1]] = tonumber(words[2])
  366.                 all_time_name_any_order[words[1]] = words[3]
  367.             end
  368.            
  369.             line = savefile:read("*line")
  370.         end
  371.         savefile:close()
  372.     end
  373. end
  374.  
  375. function OnCommand(PlayerIndex,Command)
  376.     Command = string.lower(Command)
  377.     if(Command == display_command) then
  378.         DisplayBestTimes(PlayerIndex, display_time, 1)
  379.         return false
  380.     end
  381.     if(Command == display_any_order_command) then
  382.         DisplayBestAnyOrderTimes(PlayerIndex, display_time, 1)
  383.         return false
  384.     end
  385.     if(Command == reset_command) then
  386.         if(tonumber(get_var(PlayerIndex, "$lvl")) >= admin_level) then
  387.             ResetTimes(PlayerIndex)
  388.             return false
  389.         else
  390.             say(PlayerIndex, "You don't have the rights to reset times!")
  391.             return false
  392.         end
  393.     end
  394.     return true
  395. end
  396.  
  397. function FindPlayerWithMostRecords()
  398.     local best_player = nil--       name of the player who scored the most
  399.     local records = {} --       names and how many records they have
  400.    
  401.     for map,value in pairs(all_time_name) do
  402.         if(records[value] == nil) then
  403.             records[value] = 1
  404.         else
  405.             records[value] = records[value] + 1
  406.         end
  407.     end
  408.    
  409.     for map,value in pairs(all_time_name_any_order) do
  410.         if(records[value] == nil) then
  411.             records[value] = 1
  412.         else
  413.             records[value] = records[value] + 1
  414.         end
  415.     end
  416.    
  417.     for name,count in pairs(records) do
  418.         if(records[best_player] == nil or records[best_player] < records[name]) then
  419.             best_player = name
  420.         end
  421.     end
  422.    
  423.     return best_player
  424. end
  425.  
  426. function DisplayBestAnyOrderTimes(PlayerIndex, time_left, page)
  427.     page = tonumber(page)
  428.     local not_used = true
  429.     local record_count = 0
  430.    
  431.     ClearConsole(PlayerIndex)
  432.    
  433.     for map,value in pairs(all_time_name_any_order) do
  434.         if(not_used) then
  435.             if(page == 1) then
  436.                 rprint(PlayerIndex, "Player with most records is "..FindPlayerWithMostRecords().."!")
  437.             end
  438.             rprint(PlayerIndex, "Fastest any-order laps are:")
  439.             not_used = false
  440.         end
  441.        
  442.         record_count = record_count + 1
  443.        
  444.         if(record_count > page * page_size - page_size and record_count < page * page_size) then
  445.             rprint(PlayerIndex, "    "..map.." - "..best_lap_all_time_any_order[map].." seconds by "..value)
  446.         end
  447.     end
  448.    
  449.     if(not_used) then
  450.         rprint(PlayerIndex, "There are no records yet")
  451.     end
  452.    
  453.     local total_pages = math.floor(record_count/page_size) + 1
  454.     if(total_pages > 1) then
  455.         rprint(PlayerIndex, "Page "..page.."/"..total_pages)
  456.     end
  457.    
  458.     if(tonumber(time_left) > 0) then
  459.         timer(1000, "DisplayBestAnyOrderTimes", PlayerIndex, time_left - 1, page)
  460.     else
  461.         if(page < total_pages) then
  462.             timer(1000, "DisplayBestAnyOrderTimes", PlayerIndex, display_time, page + 1)
  463.         else
  464.             timer(1000, "ClearConsole", PlayerIndex)
  465.             return false
  466.         end
  467.     end
  468. end
  469.  
  470. function DisplayBestTimes(PlayerIndex, time_left, page)
  471.     page = tonumber(page)
  472.     local not_used = true
  473.     local record_count = 0
  474.    
  475.     ClearConsole(PlayerIndex)
  476.    
  477.     for map,value in pairs(all_time_name) do
  478.         if(not_used) then
  479.             if(page == 1) then
  480.                 rprint(PlayerIndex, "Player with most records is "..FindPlayerWithMostRecords().."!")
  481.             end
  482.             rprint(PlayerIndex, "Fastest normal laps are:")
  483.             not_used = false
  484.         end
  485.        
  486.         record_count = record_count + 1
  487.        
  488.         if(record_count > page * page_size - page_size and record_count < page * page_size) then
  489.             rprint(PlayerIndex, "    "..map.." - "..best_lap_all_time[map].." seconds by "..value)
  490.         end
  491.     end
  492.    
  493.     if(not_used) then
  494.         rprint(PlayerIndex, "There are no records yet")
  495.     end
  496.    
  497.     local total_pages = math.floor(record_count/page_size) + 1
  498.     if(total_pages > 1) then
  499.         rprint(PlayerIndex, "Page "..page.."/"..total_pages)
  500.     end
  501.    
  502.     if(tonumber(time_left) > 0) then
  503.         timer(1000, "DisplayBestTimes", PlayerIndex, time_left - 1, page)
  504.     else
  505.         if(page < total_pages) then
  506.             timer(1000, "DisplayBestTimes", PlayerIndex, display_time, page + 1)
  507.         else
  508.             timer(1000, "ClearConsole", PlayerIndex)
  509.             return false
  510.         end
  511.     end
  512. end
  513.  
  514. function ClearConsole(i)--  Clears player's console from any messages
  515.     for j=1,30 do
  516.         rprint(i," ")
  517.     end
  518. end
  519.  
  520. function ResetTimes(PlayerIndex)--  resets all times
  521.     local savefile = io.open("sapp\\lap_records.txt", "w")
  522.     savefile:write("")
  523.     savefile:close()
  524.    
  525.     best_lap_all_time = {}
  526.     best_lap_all_time_any_order = {}
  527.     all_time_name = {}
  528.     all_time_name_any_order = {}
  529.    
  530.     current_name = nil
  531.     best_current_lap = 32000
  532.     if(best_lap_all_time[current_map] == nil) then--    If current map doesn't have all time record then set it to a high value
  533.         table.insert(best_lap_all_time, {current_map, 32000})
  534.         best_lap_all_time[current_map] = 32000
  535.     end
  536.     if(best_lap_all_time_any_order[current_map] == nil) then--  If current map doesn't have all time record then set it to a high value
  537.         table.insert(best_lap_all_time_any_order, {current_map, 32000})
  538.         best_lap_all_time_any_order[current_map] = 32000
  539.     end
  540.    
  541.     say(PlayerIndex, "All times have been reset!")
  542. end
  543.  
  544. function round(num)
  545.   local mult = 10^(idp or 0)
  546.   return math.floor(num * mult + 0.5) / mult
  547. end
  548.  
  549. function OnScriptUnload()
  550. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement