Advertisement
Guest User

toptimes

a guest
Feb 16th, 2012
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.30 KB | None | 0 0
  1. --
  2. -- toptimes_client.lua
  3. --
  4.  
  5. CToptimes = {}
  6. CToptimes.__index = CToptimes
  7. CToptimes.instances = {}
  8. g_Settings = {}
  9.  
  10. ---------------------------------------------------------------------------
  11. -- Client
  12. -- Handle events from Race
  13. --
  14. -- This is the 'interface' from Race
  15. --
  16. ---------------------------------------------------------------------------
  17.  
  18. addEventHandler('onClientResourceStart', g_ResRoot,
  19. function()
  20. triggerServerEvent('onLoadedAtClient_tt', g_Me)
  21. end
  22. )
  23.  
  24. addEvent('onClientMapStarting', true)
  25. addEventHandler('onClientMapStarting', getRootElement(),
  26. function(mapinfo)
  27. outputDebug( 'TOPTIMES', 'onClientMapStarting' )
  28. if g_CToptimes then
  29. g_CToptimes:onMapStarting(mapinfo)
  30. end
  31. end
  32. )
  33.  
  34. addEvent('onClientMapStopping', true)
  35. addEventHandler('onClientMapStopping', getRootElement(),
  36. function()
  37. outputDebug( 'TOPTIMES', 'onClientMapStopping' )
  38. if g_CToptimes then
  39. g_CToptimes:onMapStopping()
  40. end
  41. end
  42. )
  43.  
  44. addEvent('onClientPlayerFinish', true)
  45. addEventHandler('onClientPlayerFinish', getRootElement(),
  46. function()
  47. outputDebug( 'TOPTIMES', 'onClientPlayerFinish' )
  48. if g_CToptimes then
  49. g_CToptimes:doAutoShow()
  50. end
  51. end
  52. )
  53.  
  54. addEvent('onClientSetMapName', true)
  55. addEventHandler('onClientSetMapName', getRootElement(),
  56. function(manName)
  57. if g_CToptimes then
  58. g_CToptimes:setWindowTitle(manName)
  59. end
  60. end
  61. )
  62.  
  63.  
  64. function updateSettings(settings, playeradmin)
  65. outputDebug( 'TOPTIMES', 'updateSettings' )
  66. if g_CToptimes then
  67. if settings and settings.gui_x and settings.gui_y then
  68. g_CToptimes:setWindowPosition( settings.gui_x, settings.gui_y )
  69. g_CToptimes.startshow = settings.startshow
  70. end
  71. -- If admin changed this setting manually, then show the table to him
  72. if playeradmin == getLocalPlayer() then
  73. g_CToptimes:doToggleToptimes(true)
  74. end
  75. end
  76. end
  77.  
  78.  
  79. ---------------------------------------------------------------------------
  80. --
  81. -- CToptimes:create()
  82. --
  83. --
  84. --
  85. ---------------------------------------------------------------------------
  86. function CToptimes:create()
  87. outputDebug ( 'TOPTIMES', 'CToptimes:create' )
  88. local id = #CToptimes.instances + 1
  89. CToptimes.instances[id] = setmetatable(
  90. {
  91. id = id,
  92. bManualShow = false, -- via key press
  93. bAutoShow = false, -- when player finished
  94. bGettingUpdates = false, -- server should send us updates to the toptimes
  95. listStatus = 'Empty', -- 'Empty', 'Loading' or 'Full'
  96. gui = {}, -- all gui items
  97. lastSeconds = 0,
  98. targetFade = 0,
  99. currentFade = 0,
  100. autoOffTimer = Timer:create(),
  101.  
  102. hasTimes = false
  103. },
  104. self
  105. )
  106.  
  107. CToptimes.instances[id]:postCreate()
  108. return CToptimes.instances[id]
  109. end
  110.  
  111.  
  112. ---------------------------------------------------------------------------
  113. --
  114. -- CToptimes:destroy()
  115. --
  116. --
  117. --
  118. ---------------------------------------------------------------------------
  119. function CToptimes:destroy()
  120. self:setHotKey(nil)
  121. self:closeWindow()
  122. self.autoOffTimer:destroy()
  123. CToptimes.instances[self.id] = nil
  124. self.id = 0
  125. end
  126.  
  127.  
  128. ---------------------------------------------------------------------------
  129. --
  130. -- CToptimes:postCreate()
  131. --
  132. --
  133. --
  134. ---------------------------------------------------------------------------
  135. function CToptimes:postCreate()
  136. self:openWindow()
  137. self:setWindowPosition( 0.7, 0.02 )
  138. self:setHotKey('F5')
  139. end
  140.  
  141.  
  142. ---------------------------------------------------------------------------
  143. --
  144. -- CToptimes:openWindow()
  145. --
  146. --
  147. --
  148. ---------------------------------------------------------------------------
  149. function CToptimes:openWindow ()
  150. if self.gui['container'] then
  151. return
  152. end
  153.  
  154. self.size = {}
  155. self.size.x = 400-120
  156. self.size.y = 46 + 15 * 10
  157.  
  158. local sizeX = self.size.x
  159. local sizeY = self.size.y
  160.  
  161. -- windowbg is the root gui element.
  162. -- windowbg holds the backround image, to which the required alpha is applied
  163. self.gui['windowbg'] = guiCreateStaticImage(100, 100, sizeX, sizeY, 'img/timepassedbg.png', false, nil)
  164. guiSetAlpha(self.gui['windowbg'], 0.4)
  165. guiSetVisible( self.gui['windowbg'], false )
  166.  
  167. -- windowbg as parent:
  168.  
  169.  
  170. self.gui['container'] = guiCreateStaticImage(0,0.1,1,1, 'img/blank.png', true, self.gui['windowbg'])
  171. guiSetProperty ( self.gui['container'], 'InheritsAlpha', 'false' )
  172.  
  173. -- container as parent:
  174.  
  175. self.gui['bar'] = guiCreateStaticImage(0, 0, sizeX, 18, 'img/timepassedbg.png', false, self.gui['container'])
  176. guiSetAlpha(self.gui['bar'], 0.4)
  177.  
  178. self.gui['title0'] = guiCreateLabel(0, 0, sizeX, 30, 'Hunter times', false, self.gui['windowbg'] )
  179. guiLabelSetHorizontalAlign ( self.gui['title0'], 'center' )
  180. guiSetFont(self.gui['title0'], 'default-bold-small')
  181. guiLabelSetColor ( self.gui['title0'],255,26,00)
  182.  
  183. self.gui['title'] = guiCreateLabel(0, 1, sizeX, 30, '', false, self.gui['container'] )
  184. guiLabelSetHorizontalAlign ( self.gui['title'], 'center' )
  185. guiSetFont(self.gui['title'], 'default-bold-small')
  186. guiLabelSetColor ( self.gui['title'], 255, 2, 5, 255 )
  187.  
  188.  
  189. self.gui['header'] = guiCreateLabel(19, 21, sizeX-30, 15, 'Pos Time Name', false, self.gui['container'] )
  190. guiSetFont(self.gui['header'], 'default-small')
  191. guiLabelSetColor ( self.gui['header'], 0, 0, 150 )
  192.  
  193. self.gui['headerul'] = guiCreateLabel(0, 21, sizeX, 15, string.rep('_', 38), false, self.gui['container'] )
  194. guiLabelSetHorizontalAlign ( self.gui['headerul'], 'center' )
  195. guiLabelSetColor ( self.gui['headerul'], 255, 192, 252 )
  196.  
  197. self.gui['paneLoading'] = guiCreateStaticImage(0,0,1,1, 'img/blank.png', true, self.gui['container'])
  198.  
  199. -- paneLoading as parent:
  200.  
  201. self.gui['busy'] = guiCreateLabel(sizeX/4, 38, sizeX/2, 15, 'Please wait', false, self.gui['paneLoading'] )
  202. self.gui['busy2'] = guiCreateLabel(sizeX/4, 53, sizeX/2, 15, 'until next map', false, self.gui['paneLoading'] )
  203. guiLabelSetHorizontalAlign ( self.gui['busy'], 'center' )
  204. guiLabelSetHorizontalAlign ( self.gui['busy2'], 'center' )
  205. guiSetFont(self.gui['busy'], 'default-bold-small')
  206. guiSetFont(self.gui['busy2'], 'default-bold-small')
  207.  
  208. self.gui['paneTimes'] = guiCreateStaticImage(0,0,1,1, 'img/blank.png', true, self.gui['container'])
  209.  
  210. -- paneTimes as parent:
  211.  
  212. -- All the labels in the time list
  213. self.gui['listTimes'] = {}
  214. self:updateLabelCount(12)
  215.  
  216. end
  217.  
  218.  
  219. ---------------------------------------------------------------------------
  220. --
  221. -- CToptimes:closeWindow()
  222. --
  223. --
  224. --
  225. ---------------------------------------------------------------------------
  226. function CToptimes:closeWindow ()
  227. destroyElement( self.gui['windowbg'] )
  228. self.gui = {}
  229. end
  230.  
  231.  
  232. ---------------------------------------------------------------------------
  233. --
  234. -- CToptimes:setWindowPosition()
  235. --
  236. --
  237. --
  238. ---------------------------------------------------------------------------
  239. function CToptimes:setWindowPosition ( gui_x, gui_y )
  240. if self.gui['windowbg'] then
  241. local screenWidth, screenHeight = guiGetScreenSize()
  242. local posX = screenWidth/2 + 63 + ( screenWidth * (gui_x - 0.56) )
  243. local posY = 14 + ( screenHeight * (gui_y - 0.02) )
  244.  
  245. local posXCurve = { {0, 0}, {0.7, screenWidth/2 + 63}, {1, screenWidth - self.size.x} }
  246. local posYCurve = { {0, 0}, {0.02, 14}, {1, screenHeight - self.size.y} }
  247. -- 1280 0-1000
  248. -- 0.0 = 1280/2 - 140 = 0
  249. -- 0.5 = 1280/2 - 140 = 500
  250. -- 0.7 = 1280/2 - 140 = 500 = 703
  251. -- 1.0 = 1280 - 280 = 1000
  252. -- 1024
  253. posX = math.evalCurve( posXCurve, gui_x )
  254. posY = math.evalCurve( posYCurve, gui_y )
  255. guiSetPosition( self.gui['windowbg'], posX, posY, false )
  256. end
  257. end
  258.  
  259.  
  260. ---------------------------------------------------------------------------
  261. --
  262. -- CToptimes:setWindowTitle()
  263. --
  264. --
  265. --
  266. ---------------------------------------------------------------------------
  267. function CToptimes:setWindowTitle( mapName )
  268. if self.gui['title'] then
  269. -- Set the title
  270. guiSetText ( self.gui['title'], mapName )
  271. -- Hide the 'until next map' message
  272. guiSetVisible (self.gui['busy2'], false)
  273. end
  274. end
  275.  
  276.  
  277. ---------------------------------------------------------------------------
  278. --
  279. -- CToptimes:setHotKey()
  280. --
  281. --
  282. --
  283. ---------------------------------------------------------------------------
  284. function CToptimes:setHotKey ( hotkey )
  285. if self.hotkey then
  286. unbindKey ( self.hotkey, 'down', "showtimes" )
  287. end
  288. if hotkey and self.hotkey and hotkey ~= self.hotkey then
  289. outputConsole( "Race Toptimes hotkey is now '" .. tostring(hotkey) .. "'" )
  290. end
  291. self.hotkey = hotkey
  292. if self.hotkey then
  293. bindKey ( self.hotkey, 'down', "showtimes" )
  294. end
  295. end
  296.  
  297.  
  298. ---------------------------------------------------------------------------
  299. --
  300. -- CToptimes:onMapStarting()
  301. --
  302. --
  303. --
  304. ---------------------------------------------------------------------------
  305.  
  306. function string.findIgnoreCase(haystack,needle)
  307. return string.find(string.lower(haystack),string.lower(needle),1,true)
  308. end
  309.  
  310.  
  311. function CToptimes:onMapStarting(mapinfo)
  312.  
  313. self.bAutoShow = false
  314. self.bGettingUpdates = false -- Updates are automatically cleared on the server at the start of a new map,
  315. self.listStatus = 'Empty'
  316. self.clientRevision = -1
  317. self:updateShow()
  318. self:setWindowTitle( mapinfo.name )
  319.  
  320. self.hasTimes = false
  321.  
  322. -- table.dump(mapinfo)
  323.  
  324. -- if self.startshow then
  325. if mapinfo.name and string.findIgnoreCase(mapinfo.name,"[DM]") then
  326. for _,e in pairs(getElementsByType("racepickup") or {}) do
  327. local t = getElementData(e,"type")
  328.  
  329. if t and t == "vehiclechange" then
  330. local v = getElementData(e,"vehicle")
  331.  
  332. if v and tonumber(v) == 425 then
  333. self.hasTimes = true
  334. break
  335. end
  336. end
  337. end
  338. end
  339.  
  340. if self.hasTimes then
  341. self:doToggleToptimes( true )
  342. end
  343. end
  344.  
  345.  
  346. ---------------------------------------------------------------------------
  347. --
  348. -- CToptimes:onMapStopping()
  349. --
  350. --
  351. --
  352. ---------------------------------------------------------------------------
  353. function CToptimes:onMapStopping()
  354.  
  355. self.bAutoShow = false
  356. self.bGettingUpdates = false -- Updates are automatically cleared on the server at the start of a new map,
  357. self.listStatus = 'Empty'
  358. self.clientRevision = -1
  359. self:doToggleToptimes(false)
  360. self:setWindowTitle( '' )
  361.  
  362. end
  363.  
  364.  
  365. ---------------------------------------------------------------------------
  366. --
  367. -- CToptimes:doAutoShow()
  368. --
  369. --
  370. --
  371. ---------------------------------------------------------------------------
  372. function CToptimes:doAutoShow()
  373. self.bAutoShow = true
  374. self:updateShow()
  375. end
  376.  
  377.  
  378. ---------------------------------------------------------------------------
  379. --
  380. -- CToptimes:updateShow()
  381. --
  382. --
  383. --
  384. ---------------------------------------------------------------------------
  385. function CToptimes:updateShow()
  386.  
  387. local bShowAny = self.bAutoShow or self.bManualShow
  388. self:enableToptimeUpdatesFromServer( bShowAny )
  389.  
  390. --outputDebug( 'TOPTIMES', 'updateShow bAutoShow:'..tostring(self.bAutoShow)..' bManualShow:'..tostring(self.bManualShow)..' listStatus:'..self.listStatus )
  391. if not bShowAny then
  392. self.targetFade = 0
  393. elseif not self.bManualShow and self.listStatus ~= 'Full' then
  394. -- No change
  395. else
  396. local bShowLoading = self.listStatus=='Loading'
  397. local bShowTimes = self.listStatus=='Full'
  398.  
  399. self.targetFade = 1
  400. guiSetVisible (self.gui['paneLoading'], bShowLoading)
  401. guiSetVisible (self.gui['paneTimes'], bShowTimes)
  402. end
  403. end
  404.  
  405.  
  406. ---------------------------------------------------------------------------
  407. --
  408. -- CToptimes:enableUpdatesFromServer()
  409. --
  410. --
  411. --
  412. ---------------------------------------------------------------------------
  413. function CToptimes:enableToptimeUpdatesFromServer( bOn )
  414. if bOn ~= self.bGettingUpdates then
  415. self.bGettingUpdates = bOn
  416. triggerServerEvent('onClientRequestToptimesUpdates', g_Me, bOn, self.clientRevision )
  417. end
  418. if self.bGettingUpdates and self.listStatus == 'Empty' then
  419. self.listStatus = 'Loading'
  420. end
  421. end
  422.  
  423.  
  424. ---------------------------------------------------------------------------
  425. --
  426. -- CToptimes:updateLabelCount()
  427. --
  428. --
  429. --
  430. ---------------------------------------------------------------------------
  431. function CToptimes:updateLabelCount(numLines)
  432.  
  433. local sizeX = self.size.x
  434. local sizeY = self.size.y
  435.  
  436. local parentGui = self.gui['paneTimes']
  437. local t = self.gui['listTimes']
  438.  
  439. -- Expand/shrink the list
  440. while #t < numLines do
  441. local y = #t
  442. local x = #t<9 and 20 or 13
  443. local label = guiCreateLabel(x, 38+15*y, sizeX-x-10, 15, '', false, parentGui )
  444. guiSetFont(label, 'default-bold-small')
  445. table.insert( t, label )
  446. end
  447.  
  448. while #t > numLines do
  449. local last = table.popLast(t)
  450. destroyElement( last )
  451. end
  452.  
  453. end
  454.  
  455.  
  456. ---------------------------------------------------------------------------
  457. --
  458. -- CToptimes:doOnServerSentToptimes()
  459. --
  460. --
  461. --
  462. ---------------------------------------------------------------------------
  463. function CToptimes:doOnServerSentToptimes( data, serverRevision, playerPosition )
  464. outputDebug( 'TOPTIMES', 'CToptimes:doOnServerSentToptimes ' .. tostring(#data) )
  465.  
  466. -- Calc number lines to use and height of window
  467. local numLines = math.clamp( 0, #data, 50 )
  468. self.size.y = 15 + 46 + 15 * numLines
  469.  
  470. -- Set height of window
  471. local sizeX = self.size.x
  472. local sizeY = self.size.y
  473. guiSetSize( self.gui['windowbg'], sizeX, sizeY, false )
  474.  
  475. -- Make listTimes contains the correct number of labels
  476. self:updateLabelCount(numLines)
  477.  
  478. -- Update the list items
  479. for i=1,numLines do
  480.  
  481. local timeText = data[i].timeText
  482. if timeText:sub(1,1) == '0' then
  483. timeText = ' ' .. timeText:sub(2)
  484. end
  485. local line = string.format( '%d. %s %s', i, timeText, data[i].playerName )
  486. guiSetText ( self.gui['listTimes'][i], line )
  487.  
  488. if i == playerPosition then
  489. guiLabelSetColor ( self.gui['listTimes'][i], 0, 255, 255 )
  490. else
  491. guiLabelSetColor ( self.gui['listTimes'][i], 255, 255, 255 )
  492. end
  493.  
  494. end
  495.  
  496. -- Debug
  497. if _DEBUG_CHECK then
  498. outputDebug( 'TOPTIMES', 'toptimes', string.format('crev:%s srev:%s', tostring(self.clientRevision), tostring(serverRevision) ) )
  499. if self.clientRevision == serverRevision then
  500. outputDebug( 'TOPTIMES', 'Already have this revision' )
  501. end
  502. end
  503.  
  504. -- Update status
  505. self.clientRevision = serverRevision
  506. self.listStatus = 'Full'
  507. self:updateShow()
  508. end
  509.  
  510.  
  511. function onServerSentToptimes( data, serverRevision, playerPosition )
  512. g_CToptimes:doOnServerSentToptimes( data, serverRevision, playerPosition )
  513. end
  514.  
  515. ---------------------------------------------------------------------------
  516. --
  517. -- CToptimes:doOnClientRender
  518. --
  519. --
  520. --
  521. ---------------------------------------------------------------------------
  522. function CToptimes:doOnClientRender()
  523. -- Early out test
  524. if self.targetFade == self.currentFade then
  525. return
  526. end
  527.  
  528. -- Calc delta seconds since last call
  529. local currentSeconds = getTickCount() / 1000
  530. local deltaSeconds = currentSeconds - self.lastSeconds
  531. self.lastSeconds = currentSeconds
  532.  
  533.  
  534.  
  535. deltaSeconds = math.clamp( 0, deltaSeconds, 1/25 )
  536.  
  537. -- Calc max fade change for this call
  538. local fadeSpeed = self.targetFade < self.currentFade and 2 or 6
  539. local maxChange = deltaSeconds * fadeSpeed
  540.  
  541. -- Update current fade
  542. local dif = self.targetFade - self.currentFade
  543. dif = math.clamp( -maxChange, dif, maxChange )
  544. self.currentFade = self.currentFade + dif
  545.  
  546. -- Apply
  547. guiSetAlpha( self.gui['windowbg'], self.currentFade * 0.4 )
  548. guiSetAlpha( self.gui['container'], self.currentFade)
  549. guiSetVisible( self.gui['windowbg'], self.currentFade > 0 )
  550. end
  551.  
  552.  
  553. addEventHandler ( 'onClientRender', getRootElement(),
  554. function(...)
  555. if g_CToptimes then
  556. g_CToptimes:doOnClientRender(...)
  557. end
  558. end
  559. )
  560.  
  561.  
  562. ---------------------------------------------------------------------------
  563. --
  564. -- CToptimes:doToggleToptimes()
  565. --
  566. --
  567. --
  568. ---------------------------------------------------------------------------
  569. function CToptimes:doToggleToptimes( bOn )
  570.  
  571. -- Kill any auto off timer
  572. self.autoOffTimer:killTimer()
  573.  
  574. -- Set bManualShow from bOn, or toggle if nil
  575. if bOn ~= nil then
  576. self.bManualShow = bOn
  577. else
  578. self.bManualShow = not self.bManualShow
  579. end
  580.  
  581. if self.bManualShow and not self.hasTimes then
  582. self.bManualShow = false
  583. end
  584.  
  585. -- Set auto off timer if switching on
  586. if self.bManualShow then
  587.  
  588. self.autoOffTimer:setTimer( function() self:doToggleToptimes(false) end, 10000, 1 )
  589.  
  590. end
  591.  
  592. self:updateShow()
  593.  
  594. end
  595.  
  596.  
  597. ---------------------------------------------------------------------------
  598. --
  599. -- Commands and binds
  600. --
  601. --
  602. --
  603. ---------------------------------------------------------------------------
  604.  
  605. function onHotKey()
  606. if g_CToptimes then
  607. g_CToptimes:doToggleToptimes()
  608. end
  609. end
  610. addCommandHandler ( "showtimes", onHotKey )
  611.  
  612. addCommandHandler('doF5',
  613. function(player,command,...)
  614. outputDebugString('doF5')
  615. if g_CToptimes then
  616. g_CToptimes:doToggleToptimes()
  617. end
  618. end
  619. )
  620. ---------------------------------------------------------------------------
  621.  
  622.  
  623. function guiCreateColorLabel(ax, ay, bx, by,str, parent, bool)
  624. local pat = "(.-)#(%x%x%x%x%x%x)"
  625. local s, e, cap, col = str:find(pat, 1)
  626. local last = 1
  627. local labels = {}
  628. while s do
  629. if cap == "" and col then r,g,b = tonumber("0x"..col:sub(1, 2)), tonumber("0x"..col:sub(3, 4)), tonumber("0x"..col:sub(5, 6)) end
  630. if (s ~= 1) or cap ~= "" then
  631. local w = dxGetTextWidth(cap)
  632. lbl = guiCreateLabel(ax, ay, ax + w, by,cap,parent, bool)
  633. table.insert(labels, lbl)
  634. if (r == nil) then r = 255 end
  635. if (g == nil) then g = 255 end
  636. if (b == nil) then b = 255 end
  637. guiLabelSetColor(lbl,r,g,b)
  638. ax = ax + w
  639. r,g,b = tonumber("0x"..col:sub(1, 2)), tonumber("0x"..col:sub(3, 4)), tonumber("0x"..col:sub(5, 6))
  640. end
  641. last = e + 1
  642. s, e, cap, col = str:find(pat, last)
  643. end
  644. if (last <= #str) then
  645. cap = str:sub(last)
  646. local w = dxGetTextWidth(cap)
  647. lbl2 = guiCreateLabel(ax, ay, ax + w, by,cap,parent, bool)
  648. table.insert(labels, lbl2)
  649. guiLabelSetColor(lbl2,r,g,b)
  650. end
  651. return labels
  652. end
  653. ---------------------------------------------------------------------------
  654. -- Global instance
  655. ---------------------------------------------------------------------------
  656. g_CToptimes = CToptimes:create()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement