chat.lua 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. local love = require("compat")
  2. local chat = {
  3. lines = {},
  4. active = false,
  5. enterText = "",
  6. time = 0,
  7. }
  8. local CHAT_WIDTH = 300
  9. local chatSide = "left"
  10. local CHAT_INPUT_CHARACTERS = 100
  11. -- Used for line breaking:
  12. local letter = "[%z\1-\127\194-\244][\128-\191]*"
  13. local word = "[%S]* " -- not space followed by space
  14. local colNormal = {255,255,255,255}
  15. local colServer = {255,200,64,255}
  16. local panel = require( "panel" )
  17. function chat:init()
  18. CHAT_WIDTH = math.min(love.graphics.getWidth()/2 - 40, 500)
  19. end
  20. function chat:reset()
  21. self.lines = {} -- "", "", "", "", "", "", "", "Press enter to chat.", "Welcome!" }
  22. for k = 1, 11 do
  23. table.insert( self.lines, {txt = "", col=colNormal} )
  24. end
  25. table.insert( self.lines, {txt = "Press enter to chat.", col=colServer} )
  26. self.panel = panel:new( 0, 0, CHAT_WIDTH, 20*(#self.lines) + 10 )
  27. end
  28. function chat:show()
  29. end
  30. function chat:draw()
  31. local fontHeight = love.graphics.getFont():getHeight()
  32. local x
  33. local y = love.graphics.getHeight() - 20*(#self.lines+1) - 40
  34. if map.loaded and client and client:getID() then
  35. if map:hasCar( client:getID() ) then
  36. local c = map:getCar( client:getID() )
  37. if c.vY > 0 then
  38. if chatSide == "left" then
  39. if c.vX < 0 then
  40. chatSide = "right"
  41. end
  42. else
  43. if c.vX > 0 then
  44. chatSide = "left"
  45. end
  46. end
  47. end
  48. end
  49. end
  50. if chatSide == "left" then
  51. x = 20
  52. else
  53. x = love.graphics.getWidth() - 20 - CHAT_WIDTH
  54. end
  55. --love.graphics.rectangle( "fill", x, y,
  56. --CHAT_WIDTH, 20*(#self.lines) + 10 )
  57. self.panel:draw( x, y )
  58. x = x + 5
  59. y = y + 10
  60. for k = 1, #self.lines do
  61. love.graphics.setColor( self.lines[k].col )
  62. love.graphics.print( self.lines[k].txt, x, y )
  63. y = y + 20
  64. end
  65. local x, y = 20, love.graphics.getHeight() - 40
  66. if self.active then
  67. local str = self.enterText
  68. local inputLen = love.graphics.getFont():getWidth( "Say: " .. str )
  69. inputLen = math.max(inputLen, 50 )
  70. love.graphics.setColor( 0, 0, 0, 200 )
  71. love.graphics.rectangle( "fill",
  72. x, y, inputLen + 13, fontHeight + 10 )
  73. love.graphics.setColor( 255, 255, 255, 255 )
  74. if math.sin(self.time*3) > 0 then
  75. love.graphics.print( "Say: " .. str .. "|", x + 5, y + 5 )
  76. else
  77. love.graphics.print( "Say: " .. str, x + 5, y + 5 )
  78. end
  79. end
  80. end
  81. function chat:update( dt )
  82. if STATE == "Lobby" or STATE == "Game" then
  83. if self.active then
  84. self.time = self.time + dt
  85. end
  86. end
  87. end
  88. function chat:newLine( text, col )
  89. -- remove leading whitespace:
  90. text = text:match( "%s*(.*)" )
  91. local font = love.graphics.getFont()
  92. local restStr
  93. -- Wrap text if necessary:
  94. local wLines = {} -- lines that have been wrapped
  95. if font:getWidth( text ) <= CHAT_WIDTH - 10 then
  96. table.insert( wLines, text )
  97. else
  98. local restLine = text .. " "
  99. local tmpLine, shortLine
  100. while #restLine > 0 do
  101. local i = 1
  102. local breakingCondition = false
  103. tmpLine = nil
  104. shortLine = nil
  105. repeat -- look for spaces!
  106. tmpLine = restLine:match( word:rep(i) )
  107. if tmpLine then
  108. if font:getWidth(tmpLine) > CHAT_WIDTH - 10 then
  109. breakingCondition = true
  110. else
  111. shortLine = tmpLine
  112. end
  113. else
  114. breakingCondition = true
  115. end
  116. i = i + 1
  117. until breakingCondition
  118. if not shortLine then -- if there weren't enough spaces then:
  119. breakingCondition = false
  120. i = 1
  121. repeat -- ... look for letters:
  122. tmpLine = restLine:match( letter:rep(i) )
  123. if tmpLine then
  124. if font:getWidth(tmpLine) > self.width then
  125. breakingCondition = true
  126. else
  127. shortLine = tmpLine
  128. end
  129. else
  130. breakingCondition = true
  131. end
  132. i = i + 1
  133. until breakingCondition
  134. end
  135. table.insert( wLines, shortLine )
  136. restLine = restLine:sub( #shortLine+1 )
  137. end
  138. end
  139. for k, l in ipairs(wLines) do
  140. -- Add the text to the table of text lines:
  141. for k = 1, #self.lines-1 do
  142. self.lines[k] = self.lines[k+1]
  143. end
  144. self.lines[#self.lines] = {txt = l, col = col}
  145. end
  146. end
  147. function chat:newLineSpeech( text )
  148. self:newLine( text, colNormal )
  149. end
  150. function chat:newLineServer( text )
  151. self:newLine( text, colServer )
  152. end
  153. function chat:keypressed( key )
  154. if STATE == "Game" or STATE == "Lobby" then
  155. if key == "return" then
  156. if self.active then
  157. if client then
  158. if #self.enterText > 0 then
  159. client:send( CMD.CHAT, self.enterText )
  160. end
  161. end
  162. self.enterText = ""
  163. self.active = false
  164. else
  165. if client then
  166. self.active = true
  167. end
  168. end
  169. elseif key == "backspace" then
  170. if #self.enterText > 0 then
  171. self.enterText = self.enterText:sub( 1, #self.enterText - 1 )
  172. -- Check if the last char is part of an umlaut or similar. If so, remove it:
  173. local last = self.enterText:sub(-1)
  174. local byte = string.byte(last)
  175. if byte and byte >= 194 then
  176. self.enterText = self.enterText:sub( 1, #self.enterText - 1 )
  177. end
  178. end
  179. elseif key == "escape" then
  180. self.enterText = ""
  181. self.active = false
  182. end
  183. end
  184. end
  185. function chat:textinput( letter )
  186. if STATE == "Game" or STATE == "Lobby" then
  187. if self.active then
  188. if letter ~= "|" then
  189. if love.graphics.getFont():getWidth( "Say: " .. self.enterText )
  190. < love.graphics.getWidth() - 60 then
  191. self.enterText = self.enterText .. letter
  192. end
  193. end
  194. end
  195. end
  196. end
  197. return chat