limit_menu.lua 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. if UiContainer == nil then UiContainer = {} end
  2. local ROOT = "LimitMenu.Container."
  3. --- Inside width of the limit bar.
  4. local BAR_WIDTH = 54
  5. --- Number of limit levels, and of techniques of each level.
  6. local LEVELS = 4
  7. local TECHNIQUES = 2
  8. --- What the player is doing with the levels.
  9. local MODE = { SET = 1, CHECK = 2 }
  10. --- Colour of the levels with learned techniques, and of the others.
  11. local COLOUR_ACTIVE = { 1.0, 1.0, 1.0 }
  12. local COLOUR_INACTIVE = { 0.45, 0.45, 0.35 }
  13. local function widget(path)
  14. return ui_manager:get_widget(ROOT .. path)
  15. end
  16. --- Is a technique of the character learned?
  17. local function is_learned(character, level, technique)
  18. local learned = character.limit.learned[level]
  19. return learned ~= nil and learned[technique] == true
  20. end
  21. --- Gets the definition (name and description) of a technique, or nil if it isn't known.
  22. local function get_technique(char_id, level, technique)
  23. local definition = Game.Characters[char_id]
  24. if definition == nil or definition.limits == nil or definition.limits[level] == nil then
  25. return nil
  26. end
  27. local entry = definition.limits[level].techniques[technique]
  28. if entry == nil then return nil end
  29. return Game.Attacks[entry.command]
  30. end
  31. --- The limit menu.
  32. --
  33. -- On top there are two choices: Set, to choose the limit level of the character, and Check, to see
  34. -- the techniques learned at each level. Both let the player move over the four levels.
  35. -- * Set: choosing a level with learned techniques asks for confirmation. Confirming assigns it
  36. -- and empties the limit bar.
  37. -- * Check: choosing a level with learned techniques lets the player move between its techniques,
  38. -- showing their description.
  39. -- Choosing a level without learned techniques plays the error sound.
  40. UiContainer.LimitMenu = UiContainer.Menu.new{
  41. id = "limit",
  42. parent = "main",
  43. --- ID of the character being shown.
  44. char_id = -1,
  45. --- Set or check (MODE).
  46. mode = MODE.SET,
  47. --- Cursor over Set and Check.
  48. mode_cursor = UiContainer.Cursor.new{
  49. widget = ROOT .. "Character.Modes.Cursor",
  50. total = 2,
  51. },
  52. --- Cursor over the four levels, in a 2x2 grid.
  53. level_cursor = UiContainer.Cursor.new{
  54. widget = ROOT .. "Body.LevelCursor",
  55. total = 4,
  56. sound = false,
  57. },
  58. --- Cursor over the techniques of the chosen level.
  59. tech_cursor = UiContainer.Cursor.new{
  60. total = 2,
  61. on_move = function(position)
  62. UiContainer.LimitMenu:update_technique(position)
  63. end,
  64. },
  65. --- Cursor over Yes and No in the confirmation window.
  66. confirm_cursor = UiContainer.Cursor.new{
  67. widget = ROOT .. "Confirm.Cursor",
  68. total = 2,
  69. },
  70. states = {
  71. --- Choosing Set or Check.
  72. [""] = {
  73. cursor = function(self) return self.mode_cursor end,
  74. axis = "horizontal",
  75. confirm = function(self, cursor)
  76. self.mode = cursor:index()
  77. self.level_cursor:set(1)
  78. widget("Body.LevelCursor"):set_visible(true)
  79. self:set_state("level")
  80. end,
  81. cancel = function(self)
  82. script:request_end_sync(Script.UI, "LimitMenu", "hide", 0)
  83. end,
  84. },
  85. --- Choosing a level.
  86. level = {
  87. buttons = UiContainer.grid_buttons("level_cursor", 2),
  88. confirm = function(self)
  89. local level = self.level_cursor:index()
  90. if not self:has_learned(level) then return false end
  91. if self.mode == MODE.SET then
  92. self.confirm_cursor:set(2) -- No.
  93. widget("Confirm"):set_visible(true)
  94. self:set_state("confirm")
  95. else
  96. widget("Body.LevelCursor"):set_visible(false)
  97. widget("Body.TechCursor"):set_visible(true)
  98. self.tech_cursor:set(1)
  99. self:set_state("technique")
  100. end
  101. end,
  102. cancel = function(self)
  103. widget("Body.LevelCursor"):set_visible(false)
  104. self:set_state("")
  105. end,
  106. },
  107. --- Moving between the techniques of a level.
  108. technique = {
  109. cursor = function(self) return self.tech_cursor end,
  110. axis = "vertical",
  111. cancel = function(self)
  112. widget("Body.TechCursor"):set_visible(false)
  113. widget("Help.Help"):set_text("")
  114. widget("Body.LevelCursor"):set_visible(true)
  115. self:set_state("level")
  116. end,
  117. },
  118. --- Confirming the change of level.
  119. confirm = {
  120. cursor = function(self) return self.confirm_cursor end,
  121. axis = "vertical",
  122. confirm = function(self, cursor)
  123. if cursor:index() == 1 then
  124. self:set_level(self.level_cursor:index())
  125. end
  126. widget("Confirm"):set_visible(false)
  127. self:set_state("level")
  128. end,
  129. cancel = function(self)
  130. widget("Confirm"):set_visible(false)
  131. self:set_state("level")
  132. end,
  133. },
  134. },
  135. --- Does the character know any technique of a level?
  136. has_learned = function(self, level)
  137. local character = Characters[self.char_id]
  138. for technique = 1, TECHNIQUES do
  139. if is_learned(character, level, technique) then return true end
  140. end
  141. return false
  142. end,
  143. --- Assigns a limit level to the character and empties its limit bar.
  144. set_level = function(self, level)
  145. local character = Characters[self.char_id]
  146. character.limit.current = level
  147. character.limit.bar = 0
  148. self:populate_limit(character)
  149. end,
  150. --- Moves the technique cursor and shows the description of the technique.
  151. update_technique = function(self, position)
  152. local level = self.level_cursor:index()
  153. widget("Body.TechCursor"):set_default_animation("Position" .. tostring((level - 1) * 2 + position))
  154. local description = ""
  155. if is_learned(Characters[self.char_id], level, position) then
  156. local attack = get_technique(self.char_id, level, position)
  157. if attack ~= nil then description = attack.description end
  158. end
  159. widget("Help.Help"):set_text(description)
  160. end,
  161. --- Shows the limit level and bar of the character.
  162. populate_limit = function(self, character)
  163. widget("Character.LimitLevel"):set_text(tostring(character.limit.current))
  164. UiContainer.set_limit_bar(ROOT .. "Character.LimitLinePart", character, BAR_WIDTH)
  165. end,
  166. --- Shows the names of the levels and of their learned techniques.
  167. populate = function(self)
  168. local character = Characters[self.char_id]
  169. UiContainer.populate_character_data(ROOT .. "Character", character)
  170. widget("Character.Portrait"):set_image("characters/" .. tostring(self.char_id) .. ".png")
  171. self:populate_limit(character)
  172. for level = 1, LEVELS do
  173. local learned = self:has_learned(level)
  174. local colour = learned and COLOUR_ACTIVE or COLOUR_INACTIVE
  175. local label = widget("Body.Level" .. tostring(level) .. ".Lbl")
  176. label:set_colour(colour[1], colour[2], colour[3])
  177. label:set_text("LEVEL " .. tostring(level))
  178. for technique = 1, TECHNIQUES do
  179. local name = ""
  180. if is_learned(character, level, technique) then
  181. local attack = get_technique(self.char_id, level, technique)
  182. if attack ~= nil then name = attack.name end
  183. end
  184. widget("Body.Level" .. tostring(level) .. ".Tech" .. tostring(technique)):set_text(name)
  185. end
  186. end
  187. widget("Help.Help"):set_text("")
  188. end,
  189. --- Opens the limit menu for UiContainer.current_character_id.
  190. show = function(self)
  191. self.char_id = UiContainer.current_character_id
  192. self:activate()
  193. self:populate()
  194. self.mode_cursor:set(1)
  195. widget("Body.LevelCursor"):set_visible(false)
  196. widget("Body.TechCursor"):set_visible(false)
  197. widget("Confirm"):set_visible(false)
  198. ui_manager:get_widget("LimitMenu"):set_visible(true)
  199. return 0
  200. end,
  201. --- Hides the limit menu and goes back to the main menu.
  202. hide = function(self)
  203. ui_manager:get_widget("LimitMenu"):set_visible(false)
  204. self:deactivate()
  205. return 0
  206. end,
  207. }