name_menu.lua 13 KB

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