Menu help

Started by wizard_wizzle (aka ZeldaHistorian), November 08, 2015, 12:47:47 AM

Previous topic - Next topic
November 10, 2015, 12:34:05 AM #15 Last Edit: November 10, 2015, 12:44:07 AM by Username
Quote from: wrightmat on November 10, 2015, 12:16:44 AM
Username - that makes sense, but I'm not sure how to fix it. I use game:on_warp_started() to call sol.menu.start() because I pass a variable - initial_point (from self:get_name() of the custom entity) to the menu and I couldn't figure how to do that from sol.menu.start() directly. Is that possible?

Diarandor - is it possible to change maps while paused? Have you seen an instance of this in my game, or another game?

As for the set_custom_command_effect lines, I didn't have them in there yet, sorry. Updated code is below!

Code (lua) Select

local game = ...
local warp_menu = {}  -- The warp menu.
local initial_point
local initial_y = 10
local initial_volume
local index

-- Warp point name, Companion point, Warp to map, Coordinate x on minimap, Coordinate y on minimap, Name of warp.
warp_points = {         -- Intentionally Global!
  b1500 = { "b1501", "133", 166, 102, "Old Kasuto" },
  b1501 = { "b1500", "46", 178, 220, "Hidden Village" },
  b1502 = { "b1503", "51", 90, 194, "Kakariko City" },
  b1503 = { "b1502", "11", 162, 372, "Ordon Village" },
  b1504 = { "b1505", "72", 2, 228, "Gerudo Camp" },
  b1505 = { "b1504", "66", 208, 178, "Goron City" },
  b1506 = { "b1507", "82", 50, 346, "Beach" },
  b1507 = { "b1506", "37", 218, 266, "Lost Woods" },
  b1508 = { "b1509", "60", 4, 180, "Snowpeak" },
  b1509 = { "b1508", "88", 15, 25, "Calatia Peaks" },
  b1510 = { "b1511", "56", 160, 150, "Septen Heights" },
  b1511 = { "b1510", "139", 178, 126, "Three Eye Rock" },
  b1512 = { "b1513", "57", 184, 150, "Zora's Domain" },
  b1513 = { "b1512", "93", 34, 40, "Rito Town" },
  b1514 = { "b1515", "34", 120, 258, "Lake Hylia" },
  b1515 = { "b1514", "13", 210, 365, "Floria Peninsula" }
}

function game:on_warp_started(point)
  initial_point = point
  if not sol.menu.is_started(warp_menu) then sol.menu.start(game, warp_menu) end
end

function warp_menu:on_started()
  self.hero_head_sprite = sol.sprite.create("menus/hero_head")
  self.hero_head_sprite:set_animation("tunic" .. game:get_item("tunic"):get_variant())
  self.background_surfaces = sol.surface.create("pause_submenus.png", true)
  self.background_surfaces:set_opacity(192)
  self.cursor_sprite = sol.sprite.create("menus/pause_cursor")
  self.caption_text_1 = sol.text_surface.create{
    horizontal_alignment = "center",
    vertical_alignment = "middle",
    font = "fixed",
    font = menu_font,
    font_size = menu_font_size,
  }
  self.caption_text_2 = sol.text_surface.create{
    horizontal_alignment = "center",
    vertical_alignment = "middle",
    font = "fixed",
    font = menu_font,
    font_size = menu_font_size,
  }

  -- Show a world map.
  self.caption_text_1:set_text(sol.language.get_string("map.caption.warp"))
  self.outside_world_minimap_size = { width = 225, height = 399 }
  self.world_minimap_img = sol.surface.create("menus/warp_map.png")
  self.world_minimap_movement = nil

  -- Initialize the cursor and scroll map to initial point.
  for k, v in pairs(warp_points) do
    if k == initial_point then
      index = k
      self:set_cursor_position(v[3], v[4])
      if v[4] >= 133 then initial_y = v[4] - 133 + 10 else initial_y = 0 end
      self.world_minimap_visible_xy = {x = 0, y = initial_y }
    end
  end

  -- Update HUD icons (not working).
  game:set_custom_command_effect("action", nil)
  game:set_custom_command_effect("attack", "validate")
  game:set_custom_command_effect("pause", "return")

  -- Ensure the hero can't move.
  game:get_map():get_hero():freeze()

  -- Lower the volume (so ocarina sound can be heard when point selected).
  initial_volume = sol.audio.get_music_volume()
  sol.audio.set_music_volume(initial_volume/3)
end

function warp_menu:on_command_pressed(command)
  if command == "left" or command == "up" then
    self:previous_warp_point()
    handled = true
  elseif command == "right" or command == "down" then
    self:next_warp_point()
    handled = true
  elseif command == "action" or command == "attack" then
    for k, v in pairs(warp_points) do
      if k == index and game:get_value(v[1]) then
        game:start_dialog("warp.to_"..v[2], function(answer)
          if answer == 1 then
            sol.menu.stop(warp_menu)
            game:get_map():get_hero():set_animation("ocarina")
            sol.audio.play_sound("ocarina_wind")
            game:get_map():get_entity("hero"):teleport(v[2], "ocarina_warp", "fade")
          end
        end)
      end
    end
  elseif command == "pause" then
    sol.menu.stop(warp_menu)
  end

  return true
end

function warp_menu:next_warp_point()
  if index == "b1500" then index = "b1501"
  elseif index == "b1501" then index = "b1502"
  elseif index == "b1502" then index = "b1503"
  elseif index == "b1503" then index = "b1504"
  elseif index == "b1504" then index = "b1505"
  elseif index == "b1505" then index = "b1506"
  elseif index == "b1506" then index = "b1507"
  elseif index == "b1507" then index = "b1508"
  elseif index == "b1508" then index = "b1509"
  elseif index == "b1509" then index = "b1510"
  elseif index == "b1510" then index = "b1511"
  elseif index == "b1511" then index = "b1512"
  elseif index == "b1512" then index = "b1513"
  elseif index == "b1513" then index = "b1514"
  elseif index == "b1514" then index = "b1515"
  elseif index == "b1515" then index = "b1500" end

  -- Move cursor and scroll map to new warp point.
  for k, v in pairs(warp_points) do
    if k == index and game:get_value(v[1]) then
      self:set_cursor_position(v[3], v[4])
      if v[4] >= 133 then initial_y = v[4] - 133 + 10 else initial_y = 0 end
      self.world_minimap_visible_xy = {x = 0, y = initial_y }
    end
  end
end

function warp_menu:previous_warp_point()
  if index == "b1500" then index = "b1515"
  elseif index == "b1501" then index = "b1500"
  elseif index == "b1502" then index = "b1501"
  elseif index == "b1503" then index = "b1502"
  elseif index == "b1504" then index = "b1503"
  elseif index == "b1505" then index = "b1504"
  elseif index == "b1506" then index = "b1505"
  elseif index == "b1507" then index = "b1506"
  elseif index == "b1508" then index = "b1507"
  elseif index == "b1509" then index = "b1508"
  elseif index == "b1510" then index = "b1509"
  elseif index == "b1511" then index = "b1510"
  elseif index == "b1512" then index = "b1511"
  elseif index == "b1513" then index = "b1512"
  elseif index == "b1514" then index = "b1513"
  elseif index == "b1515" then index = "b1514" end

  -- Move cursor and scroll map to new warp point.
  for k, v in pairs(warp_points) do
    if k == index and game:get_value(v[1]) then
      self:set_cursor_position(v[3], v[4])
      if v[4] >= 133 then initial_y = v[4] - 133 + 10 else initial_y = 0 end
      self.world_minimap_visible_xy = {x = 0, y = initial_y }
    end
  end
end

function warp_menu:set_cursor_position(x, y)
  self.cursor_x = x
  self.cursor_y = y
  if y > 133 then
    if y <399 then self.world_minimap_visible_xy.y = y - 51 else self.world_minimap_visible_xy.y = 399 end
  end

  -- Update the caption text.
  for k, v in pairs(warp_points) do
    if k == initial_point then self.caption_text_2:set_text(sol.language.get_string(v[5])) end
  end
end

function warp_menu:on_draw(dst_surface)
  -- Draw background.
  local width, height = dst_surface:get_size()
  self.background_surfaces:draw_region(320, 0, 320, 240, dst_surface, (width - 320) / 2, (height - 240) / 2)

  -- Draw caption (Not working currently for some reason).
  local width, height = dst_surface:get_size()
  self.caption_text_1:draw(dst_surface, width / 2, height / 2 + 83)
  self.caption_text_2:draw(dst_surface, width / 2, height / 2 + 95)

  -- Draw the minimap.
  self.world_minimap_img:draw_region(self.world_minimap_visible_xy.x, self.world_minimap_visible_xy.y, 255, 133, dst_surface, 48, 59)

  -- Draw the warp points.
  for k, v in pairs(warp_points) do
    if game:get_value(v[1]) then -- Only those that have been discovered are shown.
      local point_visible_y = v[4] - self.world_minimap_visible_xy.y
      if point_visible_y >= 10 and point_visible_y <= 133 then self.hero_head_sprite:draw(dst_surface, v[3] + 40, point_visible_y + 51) end
    end
  end

  -- Draw the cursor.
  if self.cursor_y >= (10 + self.world_minimap_visible_xy.y) and self.cursor_y <= (133 + self.world_minimap_visible_xy.y) then
    self.cursor_sprite:draw(dst_surface, self.cursor_x + 48, self.cursor_y + 55 - self.world_minimap_visible_xy.y)
  end
end

function warp_menu:on_finished()
  sol.audio.set_music_volume(initial_volume)
  game:get_map():get_hero():unfreeze()
end


Yeah that's the one I tested, I didn't see that there were sol.menu.start, which make the thing a lot weirder  :o
That's a tough issue

November 10, 2015, 12:53:03 AM #16 Last Edit: November 10, 2015, 01:25:01 AM by Username
For the text I found the culprit

  self.caption_text_(1 and 2) = sol.text_surface.create{
    horizontal_alignment = "center",
    vertical_alignment = "middle",
    font = "fixed",
    font = menu_font,
    font_size = menu_font_size,


There is no menu_font, menu_font_size declared so the game cannot render the text with nothing, plus, there is 2 fonts section

You should replaced "fixed" (nil) by an existing fonts in /font folder and font_size is up to you

(I do tested with font = "lttp" and font_size = 12, here's the result, text caption 2 display nothing for some reasons, maybe the variable isn't correct ?)

Edit  : for caption_text 2, there is no value for them in strings.dat.
Please test caption 2



Now let's see about custom action

You're a genius, great find! Thanks!

That fix definitely worked. The weird thing is that I copied that code from another of my menus, and it didn't cause a problem (that I noticed) in that one. *shrugs* I fixed it in the other menu too, just in case.

November 10, 2015, 08:02:29 AM #18 Last Edit: November 10, 2015, 08:04:43 AM by Diarandor
For the attack_icon issue, I think what could be causing the problem, in this file
https://github.com/wrightmat/zbom/blob/master/data/scripts/hud/attack_icon.lua
I was using a modified version of Christopho's script where I changed two parts that had this code
game:get_custom_command_effect("attack") or game:get_command_effect("attack")
for this new one
game:get_command_effect("attack") or game:get_custom_command_effect("attack")
(see the "attack_icon:initialize(game)" and "attack_icon:check()" functions) and since you used some of my scripts (for carrying custom entities), you have this part different too. So if you have some command_effect for the attack icon (value different from nil), then the script will not change the hud (this was the behaviour I wanted to make my own interactions compatible with the hud, because I wanted to give priority to built-in command effects). If that was the problem, then it was my fault (sorry for the inconvenience!). I also modified the action_icon script in the same way.

If that solves the problem, that could create a new one since my script custom_interactions.lua might not work correctly, but I am not sure at all. (The custom_command_effect attack is not used there, but the custom_command_effect action is used, so if you change back the modified script of the action_icon, then the "lift" caption might not be shown fof portable entities. On the other hand, I was using the attack icon to show the "throw" label of "portable_entities", which might not work correctly if you change back the atack_icon script.)

Quote from: wrightmat on November 10, 2015, 12:16:44 AM
Diarandor - is it possible to change maps while paused? Have you seen an instance of this in my game, or another game?

Yes, I made a menu to switch heroes from one map to a different map, which uses a teleport function, and it worked. The map changed with the usual transition, with the menu open and game paused all the time (even after teleporting). As I said, there seems to be a bug, so if there are custom entities in the new map, they won't be suspended (they can move and their animations are not stopped) although the game is paused (this only seems to affect custom entities). As a workaround for the bug, I closed the menu and unpaused the game after switching hero (after teleporting).
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

November 10, 2015, 08:54:39 AM #19 Last Edit: November 10, 2015, 08:56:28 AM by Diarandor
The reason why I changed those lines of code was to allow talking with npcs while carrying custom entities (to allow giving them objects of type "portable_entity"), so I needed to give priority to the built-in action effect. (In an older version of my script I used the action button to throw the entity, which is also used to talk with normal npcs, so I changed the priority for the built-in talking effect.) But probably you are not using that feature. Anyway, it should be possible to modify the scripts to make everything work correctly with the original code (but that would mean to remove this feature, although that may be fine for your purposes if you don't plan to use it).

In case you change back that code, there might happen that you open the pause menu while carrying a portable_entity, so the custom_command_effects change during the menu, and hence after closing the menu you cannot throw the entity because the custom_command_effects have been changed. The solution should be easy: just store the value of the custom_command_effects in some variables when you open some menu and restore those values after closing the menu.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

Quote from: Diarandor on November 10, 2015, 08:54:39 AM
The reason why I changed those lines of code was to allow talking with npcs while carrying custom entities (to allow giving them objects of type "portable_entity"), so I needed to give priority to the built-in action effect. (In an older version of my script I used the action button to throw the entity, which is also used to talk with normal npcs, so I changed the priority for the built-in talking effect.) But probably you are not using that feature. Anyway, it should be possible to modify the scripts to make everything work correctly with the original code (but that would mean to remove this feature, although that may be fine for your purposes if you don't plan to use it).

In case you change back that code, there might happen that you open the pause menu while carrying a portable_entity, so the custom_command_effects change during the menu, and hence after closing the menu you cannot throw the entity because the custom_command_effects have been changed. The solution should be easy: just store the value of the custom_command_effects in some variables when you open some menu and restore those values after closing the menu.

Hmmm, strange thing is that you can't set the custom effect from the debug console in-game, it always return that set_custom_command_effect doesn't exist

Quote from: Username on November 10, 2015, 10:22:54 AM
Hmmm, strange thing is that you can't set the custom effect from the debug console in-game, it always return that set_custom_command_effect doesn't exist

I don't understand what exactly you mean. The function set_custom_command_effect is not a built-in function as Christopho said, it is fully scripted in Lua (in this case it is in the game_manager script); if you get an error is because you have not written it in your scripts. The command_effect is the built-in one, which cannot be changed directly.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

November 10, 2015, 11:04:54 AM #22 Last Edit: November 10, 2015, 11:08:04 AM by Username
Quote from: Diarandor on November 10, 2015, 10:30:08 AM
Quote from: Username on November 10, 2015, 10:22:54 AM
Hmmm, strange thing is that you can't set the custom effect from the debug console in-game, it always return that set_custom_command_effect doesn't exist

I don't understand what exactly you mean. The function set_custom_command_effect is not a built-in function as Christopho said, it is fully scripted in Lua (in this case it is in the game_manager script); if you get an error is because you have not written it in your scripts. The command_effect is the built-in one, which cannot be changed directly.

Right !
For this issue, There must be in newer releases of Solarus a game:freeze_all(bool), just like when you press "d", because, interestingly , you can move while you're in the menu and trigger an error, the menu would still work.
My guess is, at the moment, that the menu isn't halting/freezing stuffs (only the hero is freez'd), so the engine might still consider that it need to update some values (and, it still update the ocarina patch's custom interraction while you're in the warp menu), other than that, I don't know what is causing this issue, that's quite strange honestly



Username- If you want to suspend all entities, you can use game:set_paused(true) when you open the menu, and game:set_paused(false) to unpause the game. A menu can be used during the pause.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

Username, I tried moving the hero away from the ocarina patch before freezing, and the "Check" action does go away (as your previous comments would suggest), but any new action is not represented. I'm sure Diarandor's fix would work, but I don't think I want to break something else at this time. For now I think I'll just keep the hero moved, which dims the HUD, and everything else works great!

Thanks all for the help!

November 10, 2015, 11:51:44 PM #25 Last Edit: November 10, 2015, 11:55:19 PM by Diarandor
wrightmat- I found a better and easy solution. First define two new methods
"game:get_menu_command_effect(command)" and "game:set_menu_command_effect(command, effect)"
and we will use them only for effects during menus. Then, we give more priority to these menu command effects. To do this, just write
game:get_menu_command_effect("attack") or  game:get_command_effect("attack") or game:get_custom_command_effect("attack")
instead of
game:get_command_effect("attack") or game:get_custom_command_effect("attack")
in the attack_icon script (and similarly for the action effect in the action_icon script). Also, don't forget to set the menu_command_effects to nil when you close the menu. With this you will not need to move the hero before teleporting, and everything will work as before.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

Diarandor - I did a quick test, and I think that your solution would work with enough tweaking, but I don't think I want to make the requisite changes at this time. For now I'll stick with greying out the HUD, and will refer to this topic later if I decide to do something differently.

You guys have been an amazing help and I greatly appreciate it!!!