name_menu.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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. FFVII.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. ui_manager:get_widget("NameMenu.Container.Character.Portrait"):set_image("images/characters/" .. tostring(self.id) .. ".png")
  160. if (string.lower(Characters[self.id].name) == "ex-soldier") then
  161. -- HACK: Hack for Ex-Soldier default. Can this be extracted from menu.lgp?
  162. self.default_name = "Cloud"
  163. self.name = "Cloud"
  164. else
  165. self.default_name = Characters[self.id].name
  166. self.name = Characters[self.id].name
  167. end
  168. self.text_cursor = math.min(#(self.name) + 1, self.max_characters)
  169. self.populate_name(self)
  170. self.draw_cursor(self)
  171. script:request_end_sync(Script.UI, "Fade", "fade_in", 0)
  172. return 0;
  173. end,
  174. --- Redraws the text cursor, indicating the current character.
  175. draw_cursor = function(self)
  176. for i = 1, self.max_characters do
  177. if self.text_cursor == i then
  178. ui_manager:get_widget("NameMenu.Container.Character.Name.Score" .. tostring(i)):set_height(1.8)
  179. else
  180. ui_manager:get_widget("NameMenu.Container.Character.Name.Score" .. tostring(i)):set_height(0.3)
  181. end
  182. end
  183. end,
  184. --- Writes the name characters in the name input line.
  185. populate_name = function(self)
  186. for i = 1, self.max_characters do
  187. if #(self.name) < i then
  188. ui_manager:get_widget("NameMenu.Container.Character.Name.Char" .. tostring(i)):set_text("")
  189. else
  190. ui_manager:get_widget("NameMenu.Container.Character.Name.Char" .. tostring(i)):set_text(self.name:sub(i, i))
  191. end
  192. end
  193. end,
  194. --- Sets a character in the current cursor position.
  195. set_char = function(self, character_index)
  196. local temp_name = ""
  197. for i = 1, self.max_characters do
  198. if i == self.text_cursor then
  199. -- First position or after space: Use upper case.
  200. if i == 1 or temp_name:sub(i - 1, i - 1) == " " then
  201. temp_name = temp_name .. self.letters:sub(character_index, character_index)
  202. else
  203. temp_name = temp_name .. string.lower(self.letters:sub(character_index, character_index))
  204. end
  205. elseif #(self.name) >= i then
  206. if i == 1 or temp_name:sub(i - 1, i - 1) == " " then
  207. temp_name = temp_name .. string.upper(self.name:sub(i, i))
  208. else
  209. temp_name = temp_name .. string.lower(self.name:sub(i, i))
  210. end
  211. else
  212. temp_name = temp_name .. " "
  213. end
  214. end
  215. self.name = temp_name
  216. end,
  217. --- Formats the current name.
  218. --
  219. -- Removes leading, trailing and double spaces, trims the length, and ensures capitalization.
  220. format_name = function(self)
  221. local temp_name = self.name
  222. -- Trailing and leading spaces: Remove.
  223. temp_name = string.gsub(temp_name, '^%s*(.-)%s*$', '%1')
  224. -- Double (or more) spaces: One space.
  225. temp_name = temp_name:gsub("%s+", " ")
  226. -- Length. Trim to self.max_characters
  227. if #(temp_name) > self.max_characters then
  228. temp_name = temp_name:sub(1, self.max_characters)
  229. end
  230. -- Capitalization
  231. self.name = ""
  232. for i = 1, #(temp_name) do
  233. if i == 1 or temp_name:sub(i - 1, i - 1) == " " then
  234. self.name = self.name .. string.upper(temp_name:sub(i, i))
  235. else
  236. self.name = self.name .. string.lower(temp_name:sub(i, i))
  237. end
  238. end
  239. end,
  240. apply_name = function(self)
  241. if self.chocobo == false then
  242. Characters[self.id].name = self.name
  243. export_character_names()
  244. else
  245. -- TODO: Do chocobo.
  246. end
  247. self.hide(self)
  248. end,
  249. --- Hides the item menu and goes back to the main menu.
  250. --
  251. -- It also unpauses the game. Shows a fade effect.
  252. hide = function(self)
  253. script:request_end_sync(Script.UI, "Fade", "fade_out", 0)
  254. ui_manager:get_widget("NameMenu"):set_visible(false)
  255. UiContainer.current_menu = ""
  256. UiContainer.current_submenu = ""
  257. FFVII.MenuSettings.pause_available = true
  258. entity_manager:set_paused(false)
  259. script:request_end_sync(Script.UI, "Fade", "fade_in", 0)
  260. return 0;
  261. end,
  262. }