name_menu.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. if UiContainer == nil then UiContainer = {} end
  2. --- The name menu.
  3. UiContainer.NameMenu = {
  4. --- Indicates if a chocobo is being renamed instead of a character.
  5. chocobo = false,
  6. --- ID of the character or chocobo being renamed.
  7. id = -1,
  8. --- Default name.
  9. default_name = "",
  10. --- Currently input-ed name.
  11. name = "",
  12. --- Max number of characters allowed in a name.
  13. max_characters = 12,
  14. --- Current text cursor
  15. text_cursor = 1,
  16. --- Accepted characters in a name.
  17. letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ",
  18. --- Current options cursor position.
  19. options_position = 1,
  20. --- Total options cursor position.
  21. options_position_total = 3,
  22. --- Current confirm dialog cursor position.
  23. confirm_position = 1,
  24. --- Total confirm dialog cursor position.
  25. confirm_position_total = 2,
  26. --- Run when the menu is creaded.
  27. --
  28. -- It does nothing.
  29. on_start = function(self)
  30. return 0
  31. end,
  32. --- Handles button events.
  33. --
  34. -- For the current submenu, handles directional keys, enter and escape events.
  35. -- @param button Pressed button string key. "Up", "Left", "Enter" and "Escape" are handled.
  36. -- @param event Trigger event. Normally, "Press".
  37. on_button = function(self, button, event)
  38. if UiContainer.current_menu == "name" then
  39. if UiContainer.current_submenu == "confirm" then
  40. if button == "Right" then
  41. audio_manager:play_sound("Cursor")
  42. self.confirm_position = self.confirm_position + 1
  43. if self.confirm_position > self.confirm_position_total then
  44. self.confirm_position = 1
  45. end
  46. ui_manager:get_widget("NameMenu.Container.Confirm.Cursor"):set_default_animation("Position" .. self.confirm_position)
  47. elseif button == "Left" then
  48. audio_manager:play_sound("Cursor")
  49. self.confirm_position = self.confirm_position - 1
  50. if self.confirm_position < 1 then
  51. self.confirm_position = self.confirm_position_total
  52. end
  53. ui_manager:get_widget("NameMenu.Container.Confirm.Cursor"):set_default_animation("Position" .. self.confirm_position)
  54. elseif button == "Enter" then
  55. audio_manager:play_sound("Cursor")
  56. if self.confirm_position == 2 then -- Back
  57. UiContainer.current_submenu = ""
  58. ui_manager:get_widget("NameMenu.Container.Confirm"):set_visible(false)
  59. elseif self.confirm_position == 1 then
  60. ui_manager:get_widget("NameMenu.Container.Confirm"):set_visible(false)
  61. self.apply_name(self);
  62. end
  63. end
  64. elseif UiContainer.current_submenu == "" then
  65. -- Before handling buttons, get keycode, for letters and space.
  66. local character_index
  67. if button == "Space" then
  68. character_index = string.find(self.letters, " ")
  69. else
  70. character_index = string.find(self.letters, button)
  71. end
  72. -- Handle buttons.
  73. if button == "Down" then
  74. audio_manager:play_sound("Cursor")
  75. self.options_position = self.options_position + 1
  76. if self.options_position > self.options_position_total then
  77. self.options_position = 1
  78. end
  79. ui_manager:get_widget("NameMenu.Container.Options.Cursor"):set_default_animation("Position" .. self.options_position)
  80. elseif button == "Up" then
  81. audio_manager:play_sound("Cursor")
  82. self.options_position = self.options_position - 1
  83. if self.options_position < 1 then
  84. self.options_position = self.options_position_total
  85. end
  86. ui_manager:get_widget("NameMenu.Container.Options.Cursor"):set_default_animation("Position" .. self.options_position)
  87. elseif button == "Left" then
  88. if self.text_cursor > 1 then
  89. self.text_cursor = self.text_cursor - 1
  90. self.draw_cursor(self)
  91. audio_manager:play_sound("Cursor")
  92. else
  93. audio_manager:play_sound("Error")
  94. end
  95. elseif button == "Right" then
  96. if self.text_cursor < self.max_characters then
  97. audio_manager:play_sound("Cursor")
  98. self.text_cursor = self.text_cursor + 1
  99. self.draw_cursor(self)
  100. else
  101. audio_manager:play_sound("Error")
  102. end
  103. elseif button == "Enter" then
  104. if self.options_position == 1 then -- Clear name.
  105. audio_manager:play_sound("Cursor")
  106. self.name = ""
  107. self.text_cursor = 1
  108. self.populate_name(self)
  109. self.draw_cursor(self)
  110. elseif self.options_position == 2 then -- Default name.
  111. audio_manager:play_sound("Cursor")
  112. self.name = self.default_name
  113. self.text_cursor = math.min(#(self.name) + 1, self.max_characters)
  114. self.populate_name(self)
  115. self.draw_cursor(self)
  116. elseif self.options_position == 3 then -- Show confirm dialog.
  117. self.format_name(self)
  118. self.populate_name(self)
  119. self.draw_cursor(self)
  120. if #(self.name) > 0 then
  121. audio_manager:play_sound("Cursor")
  122. UiContainer.current_submenu = "confirm"
  123. local name_display = self.name -- Pad with spaces, to display only.
  124. while #(name_display) < self.max_characters do
  125. name_display = " " .. name_display
  126. end
  127. ui_manager:get_widget("NameMenu.Container.Confirm.Name"):set_text(name_display)
  128. ui_manager:get_widget("NameMenu.Container.Confirm"):set_visible(true)
  129. self.confirm_position = 1
  130. ui_manager:get_widget("NameMenu.Container.Options.Cursor"):set_default_animation("Position" .. self.options_position)
  131. else
  132. audio_manager:play_sound("Error")
  133. end
  134. end
  135. -- TODO: Implement backspace, but how?
  136. -- Letters and spaces
  137. elseif character_index ~= nil then
  138. audio_manager:play_sound("Cursor")
  139. self.set_char(self, character_index)
  140. self.text_cursor = math.min(self.text_cursor + 1, self.max_characters)
  141. self.populate_name(self)
  142. self.draw_cursor(self)
  143. end
  144. end
  145. end
  146. return 0
  147. end,
  148. --- Opens the name menu.
  149. --
  150. -- Populates and updates displayed data before opening. It also pauses the game. Shows a fade
  151. -- effect.
  152. show = function(self)
  153. entity_manager:set_paused(true)
  154. MenuSettings.pause_available = false
  155. script:request_end_sync(Script.UI, "Fade", "fade_out", 0)
  156. ui_manager:get_widget("NameMenu"):set_visible(true)
  157. UiContainer.current_menu = "name"
  158. UiContainer.current_submenu = ""
  159. self.options_position = 1
  160. self.confirm_position = 1
  161. ui_manager:get_widget("NameMenu.Container.Confirm.Cursor"):set_default_animation("Position" .. self.confirm_position)
  162. ui_manager:get_widget("NameMenu.Container.Options.Cursor"):set_default_animation("Position" .. self.options_position)
  163. ui_manager:get_widget("NameMenu.Container.Character.Portrait"):set_image("images/characters/" .. tostring(self.id) .. ".png")
  164. if (string.lower(Characters[self.id].name) == "ex-soldier") then
  165. -- HACK: Hack for Ex-Soldier default. Can this be extracted from menu.lgp?
  166. self.default_name = "Cloud"
  167. self.name = "Cloud"
  168. else
  169. self.default_name = Characters[self.id].name
  170. self.name = Characters[self.id].name
  171. end
  172. self.text_cursor = math.min(#(self.name) + 1, self.max_characters)
  173. self.populate_name(self)
  174. self.draw_cursor(self)
  175. script:request_end_sync(Script.UI, "Fade", "fade_in", 0)
  176. return 0;
  177. end,
  178. --- Redraws the text cursor, indicating the current character.
  179. draw_cursor = function(self)
  180. for i = 1, self.max_characters do
  181. if self.text_cursor == i then
  182. ui_manager:get_widget("NameMenu.Container.Character.Name.Score" .. tostring(i)):set_height(1.8)
  183. else
  184. ui_manager:get_widget("NameMenu.Container.Character.Name.Score" .. tostring(i)):set_height(0.3)
  185. end
  186. end
  187. end,
  188. --- Writes the name characters in the name input line.
  189. populate_name = function(self)
  190. for i = 1, self.max_characters do
  191. if #(self.name) < i then
  192. ui_manager:get_widget("NameMenu.Container.Character.Name.Char" .. tostring(i)):set_text("")
  193. else
  194. ui_manager:get_widget("NameMenu.Container.Character.Name.Char" .. tostring(i)):set_text(self.name:sub(i, i))
  195. end
  196. end
  197. end,
  198. --- Sets a character in the current cursor position.
  199. set_char = function(self, character_index)
  200. local temp_name = ""
  201. for i = 1, self.max_characters do
  202. if i == self.text_cursor then
  203. -- First position or after space: Use upper case.
  204. if i == 1 or temp_name:sub(i - 1, i - 1) == " " then
  205. temp_name = temp_name .. self.letters:sub(character_index, character_index)
  206. else
  207. temp_name = temp_name .. string.lower(self.letters:sub(character_index, character_index))
  208. end
  209. elseif #(self.name) >= i then
  210. if i == 1 or temp_name:sub(i - 1, i - 1) == " " then
  211. temp_name = temp_name .. string.upper(self.name:sub(i, i))
  212. else
  213. temp_name = temp_name .. string.lower(self.name:sub(i, i))
  214. end
  215. else
  216. temp_name = temp_name .. " "
  217. end
  218. end
  219. self.name = temp_name
  220. end,
  221. --- Formats the current name.
  222. --
  223. -- Removes leading, trailing and double spaces, trims the length, and ensures capitalization.
  224. format_name = function(self)
  225. local temp_name = self.name
  226. -- Trailing and leading spaces: Remove.
  227. temp_name = string.gsub(temp_name, '^%s*(.-)%s*$', '%1')
  228. -- Double (or more) spaces: One space.
  229. temp_name = temp_name:gsub("%s+", " ")
  230. -- Length. Trim to self.max_characters
  231. if #(temp_name) > self.max_characters then
  232. temp_name = temp_name:sub(1, self.max_characters)
  233. end
  234. -- Capitalization
  235. self.name = ""
  236. for i = 1, #(temp_name) do
  237. if i == 1 or temp_name:sub(i - 1, i - 1) == " " then
  238. self.name = self.name .. string.upper(temp_name:sub(i, i))
  239. else
  240. self.name = self.name .. string.lower(temp_name:sub(i, i))
  241. end
  242. end
  243. end,
  244. apply_name = function(self)
  245. if self.chocobo == false then
  246. Characters[self.id].name = self.name
  247. export_character_names()
  248. else
  249. -- TODO: Do chocobo.
  250. end
  251. self.hide(self)
  252. end,
  253. --- Hides the item menu and goes back to the main menu.
  254. --
  255. -- It also unpauses the game. Shows a fade effect.
  256. hide = function(self)
  257. script:request_end_sync(Script.UI, "Fade", "fade_out", 0)
  258. ui_manager:get_widget("NameMenu"):set_visible(false)
  259. UiContainer.current_menu = ""
  260. UiContainer.current_submenu = ""
  261. MenuSettings.pause_available = true
  262. entity_manager:set_paused(false)
  263. script:request_end_sync(Script.UI, "Fade", "fade_in", 0)
  264. return 0;
  265. end,
  266. }