Menu help

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

Previous topic - Next topic
At the request of my brother, I've created a new warp menu for my game. Everything basically works, but I have a couple things that aren't working as well as they could, and I was hoping I could get some help.

1) The caption (the last part of on_draw) is not displaying, and I don't know why. This is based off of christopho's map submenu. I've checked that there is text in the variables (and there is) and I've tried to change the draw coordinates to no avail.

2) I can't figure out how to change the HUD icons. I've frozen the hero when the menu starts so you don't move around when trying to interact with the menu, but that's also frozen the HUD. I would like the attack icon to be "Confirm" (validate) and the pause icon to be "Back".

Code (lua) Select

local game = ...
local warp_menu = {}  -- The warp menu.
local initial_point
local initial_y = 10
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:get_map(), warp_menu) end
end

function warp_menu:on_started()
  game:get_map():get_hero():freeze()
  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
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 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

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

function warp_menu:on_finished()
  game:get_map():get_hero():unfreeze()
end

Hi. This seems hard...

For (1), I would first try to set some explicit text with
Code (Lua) Select

self.caption_text_1:set_text("TESTING TEXT")
self.caption_text_2:set_text("TESTING AGAIN")

just to be sure that there is some text different from the empty string ("") or something like that. If the string is not the problem, then I have no idea, it is very strange.

For (2) it should not be too hard, but maybe long. If I am not wrong, in "Zelda: Mystery of Solarus", when you open the weapon menu, the behaviour and text of the HUD changes. So I would study Christopho's scripts and try to adapt them to your menu. You will probably need to add some casewise functions to the scripts of the attack and action icons, I mean, you will need to check if the warp menu is open or not, to display the correct icons.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

November 08, 2015, 02:12:58 PM #2 Last Edit: November 08, 2015, 02:51:12 PM by Username
Quote2) I can't figure out how to change the HUD icons. I've frozen the hero when the menu starts so you don't move around when trying to interact with the menu, but that's also frozen the HUD. I would like the attack icon to be "Confirm" (validate) and the pause icon to be "Back".

Have you tried game:set_custom_command_effect("pause", "back") game:set_custom_command_effect("attack", "confirm")  in warp_menu:on_started()

For the 1 : Is there any errors ?

Diarandor, setting explicit text didn't work. I had already run a check to see that the correct string was in the caption, and I've tried moving it around the screen. Nothing has worked. I even tried moving where the code is in the drawing function, and it doesn't seem to matter.

I did base this off of the map and inventory pause submenus from ZSDX, where Christopho uses set_custom_command_effect (as Username mentions) to change the HUD icons. I have tried to include these commands, both in the on_started and in a cursor update function like Christopho does, and neither appears to have any effect on the HUD.

There are no errors. I've basically finished the menu and eliminated all errors, and these are the odd things that are left to iron out. I'm stumped.

get/set_custom_command_effect are not in the Solarus API, there are added in pure in Lua in game_manager.lua in ZSDX. If I remember correctly, the HUD silently does nothing if get_custom_command_effect does not exist. Maybe this is why there is no result and no error?

November 08, 2015, 08:35:23 PM #5 Last Edit: November 08, 2015, 08:47:01 PM by Username
Quote from: Christopho on November 08, 2015, 07:41:50 PM
get/set_custom_command_effect are not in the Solarus API, there are added in pure in Lua in game_manager.lua in ZSDX. If I remember correctly, the HUD silently does nothing if get_custom_command_effect does not exist. Maybe this is why there is no result and no error?


I do used BoM source when I started my project, set_custom_command works properly (I use it for some custom entity interraction), maybe the culprit is the hud script itself since he now use another hud script (Mercuris Chest)

He does have set/get_custom_command_effect and his hud script seems to have no problem, I don't know why it don't work actually
https://github.com/wrightmat/zbom/blob/master/data/scripts/game_manager.lua#L102

November 08, 2015, 10:19:44 PM #6 Last Edit: November 08, 2015, 10:24:54 PM by Diarandor
I think there are no custom commands called "confirm" or "back" in the list effects_indexes of your attack icon script, here:
https://github.com/wrightmat/zbom/blob/master/data/scripts/hud/attack_icon.lua

However, there are already custom commands called "validate" and "return", so you can use them instead (or define new ones in the list, which is probably unnecessary and you would also need to add them to the png image).

Edit: he has the functions "get/set_custom_command_effect" defined in his game manager, here:
https://github.com/wrightmat/zbom/blob/master/data/scripts/game_manager.lua
so it is strange that the hud shows nothing.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

Great research everyone, thanks!

Diarandor, I've tried "validate" and "return" as well, but still no luck. The HUD continues to display what was there before the menu appears.

Anyone who has more experience with menus - does the structure of my menu script look okay? Maybe it's something unrelated to get/set_custom_command_effect and something wrong with the menu itself?

November 08, 2015, 11:51:15 PM #8 Last Edit: November 08, 2015, 11:56:40 PM by Username
Quote from: wrightmat on November 08, 2015, 11:13:42 PM
Great research everyone, thanks!

Diarandor, I've tried "validate" and "return" as well, but still no luck. The HUD continues to display what was there before the menu appears.

Anyone who has more experience with menus - does the structure of my menu script look okay? Maybe it's something unrelated to get/set_custom_command_effect and something wrong with the menu itself?

If you have a early version of you game, you might try if this work, if yesn then that should be :
- the hud script or your script
- https://github.com/christopho/zelda_mercuris_chest/blob/master/data/scripts/hud/hud.lua#L21
https://github.com/wrightmat/zbom/blob/master/data/scripts/hud/hud.lua#L15
Mercuri's Chest Hud.lua have get/set_custom_command declared on it and use the hud_manager.game: , while your game manager use game:, and since you changed the hud script, the game:get/set_blabla in game_manager might be obsolete

This is confusing  :o

Every other script that I have (such as the pause submenus) which changes the HUD icons works though, so I'm reticent to go changes a bunch of stuff for one menu.

Quote from: wrightmat on November 09, 2015, 12:13:52 AM
Every other script that I have (such as the pause submenus) which changes the HUD icons works though, so I'm reticent to go changes a bunch of stuff for one menu.


If that work for others then this is not the thing I described above, hmmmm, that's a strange issue.

November 09, 2015, 02:32:55 AM #11 Last Edit: November 10, 2015, 06:57:03 AM by Diarandor
In the code of your warp menu, above, I don't see any call to the set_custom_command_effect function. You shoould have something like
Code (Lua) Select
game:set_custom_command_effect("attack","validate")
Where have you written it?
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

November 09, 2015, 02:40:23 AM #12 Last Edit: November 09, 2015, 03:07:18 AM by Diarandor
By the way, I found a possible bug which happens when changing map while the game is paused. When you do so, custom entities of the new map seem not to be paused (they move and their animations are not stopped). Could you check if you have this problem too? Just to confirm it. Just use your teleport menu (set it semitransparent to see the entities of the map), and check if the custom entities of the new map are moving (after teleporting without closing the menu, so the game is still paused).

EDIT: to confirm the bug, you need not closing the menu (to keep the pause of the game) after teleporting.

I have opened an issue on github for this:
https://github.com/christopho/solarus/issues/789
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

November 09, 2015, 09:24:23 AM #13 Last Edit: November 09, 2015, 07:02:19 PM by Username
Oh, yeah, that might be this, "confirm" doesn't exist as a action, so validate might be right thing

https://github.com/wrightmat/zbom/blob/master/data/scripts/hud/action_icon.lua#L41
Edit : Oh he does already have these.

Edit 2 : The custom_interraction script is called each frame when the hero step on the ocarina patch or any custom entity, so it can't call "validate" from the menu since it is immediately replaced by the custom entity's interraction one(check).

The problem is : Your warp script isn't a real menu, judging by how it is called in ocarina_patch, you should consider using http://www.solarus-games.org/doc/latest/lua_api_menu.html#lua_api_menu_start, game:on_warp_started() doesn't halt upcoming map update and thus entities are still updating since it runs at the same time, unlike a menu.

If you put a print("blabla") after game:add_collision_test in custom_interraction and another print in your on_called menu, you will see what i'm talking about, if you "regular pause", the interaction is halted because sol.menu take the advantage. (Am I right ?)


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