Hi all,
I have been working on creating a new pause inventory screen dealing with allies.
I have gotten the pause screen working but I haven't figured out how to create a colored surface
for the icons to rest on.
I was also wondering about adding a new Ally Icon system with a custom key binding.
Any help and comments to help get this working.
Thanks.
The Allies Pause Inventory.
local submenu = require("menus/pause_submenu")
local allies_status_submenu = submenu:new()
--
local item_names = {
"ally_butterfly",
}
function allies_status_submenu:on_started()
submenu.on_started(self)
self.cursor_sprite = sol.sprite.create("menus/pause_cursor")
self.sprites = {}
self.counters = {}
self.captions = {}
for k = 1, #item_names do
-- Get the item, its possession state and amount.
local item = self.game:get_item(item_names[k])
local variant = item:get_variant()
if variant > 0 then
if item:has_amount() then
-- Show a counter in this case.
local amount = item:get_amount()
local maximum = item:get_max_amount()
self.counters[k] = sol.text_surface.create{
horizontal_alignment = "center",
vertical_alignment = "top",
text = item:get_amount(),
font = (amount == maximum) and "green_digits" or "white_digits",
}
end
-- Initialize the sprite and the caption string.
self.sprites[k] = sol.sprite.create("entities/items")
self.sprites[k]:set_animation(item_names[k])
self.sprites[k]:set_direction(variant - 1)
end
end
-- Initialize the cursor
local index = self.game:get_value("pause_inventory_last_item_index") or 0
local row = math.floor(index / 8)
local column = index % 8
self:set_cursor_position(row, column)
end
function allies_status_submenu:on_finished()
if submenu.on_finished then
submenu.on_finished(self)
end
if self:is_assigning_item() then
self:finish_assigning_item()
end
if self.game.hud ~= nil then
self.game.hud.allies_icon_1.surface:set_opacity(255)
end
end
function allies_status_submenu:set_cursor_position(row, column)
self.cursor_row = row
self.cursor_column = column
local index = row * 8 + column
self.game:set_value("pause_inventory_last_item_index", index)
-- Update the caption text and the action icon.
local item_name = item_names[index + 1]
local item = item_name and self.game:get_item(item_name) or nil
local variant = item and item:get_variant() or 0
local item_icon_opacity = 128
if variant > 0 then
self:set_caption("inventory.caption.item." .. item_name .. "." .. variant)
self.game:set_custom_command_effect("action", "info")
if item:is_assignable() then
item_icon_opacity = 255
end
else
self:set_caption(nil)
self.game:set_custom_command_effect("action", nil)
end
self.game.hud.allies_icon_1.surface:set_opacity(item_icon_opacity)
end
function allies_status_submenu:get_selected_index()
return self.cursor_row * 7 + self.cursor_column
end
function allies_status_submenu:is_item_selected()
local item_name = item_names[self:get_selected_index() + 1]
return self.game:get_item(item_name):get_variant() > 0
end
function allies_status_submenu:on_command_pressed(command)
local handled = submenu.on_command_pressed(self, command)
if not handled then
if command == "action" then
if self.game:get_command_effect("action") == nil
and self.game:get_custom_command_effect("action") == "info" then
self:show_info_message()
handled = true
end
elseif command == "ally_1" then
if self:is_item_selected() then
self:assign_item(1)
handled = true
end
elseif command == "left" then
if self.cursor_column == 0 then
self:previous_submenu()
else
sol.audio.play_sound("cursor")
self:set_cursor_position(self.cursor_row, self.cursor_column - 1)
end
handled = true
elseif command == "right" then
if self.cursor_column == 6 then
self:next_submenu()
else
sol.audio.play_sound("cursor")
self:set_cursor_position(self.cursor_row, self.cursor_column + 1)
end
handled = true
elseif command == "up" then
sol.audio.play_sound("cursor")
self:set_cursor_position((self.cursor_row + 3) % 4, self.cursor_column)
handled = true
elseif command == "down" then
sol.audio.play_sound("cursor")
self:set_cursor_position((self.cursor_row + 1) % 4, self.cursor_column)
handled = true
end
end
return handled
end
function allies_status_submenu:on_draw(dst_surface)
self:draw_background(dst_surface)
self:draw_caption(dst_surface)
-- Draw each inventory item.
local quest_width, quest_height = dst_surface:get_size()
local initial_x = quest_width / 2 - 96
local initial_y = quest_height / 2 - 38
local y = initial_y
local k = 0
for i = 0, 3 do
local x = initial_x
for j = 0, 6 do
k = k + 1
if item_names[k] ~= nil then
local item = self.game:get_item(item_names[k])
if item:get_variant() > 0 then
-- The player has this item: draw it.
self.sprites[k]:draw(dst_surface, x, y)
if self.counters[k] ~= nil then
self.counters[k]:draw(dst_surface, x + 8, y)
end
end
end
x = x + 32
end
y = y + 32
end
-- Draw the cursor.
self.cursor_sprite:draw(dst_surface, initial_x + 32 * self.cursor_column, initial_y - 5 + 32 * self.cursor_row)
-- Draw the item being assigned if any.
if self:is_assigning_item() then
self.item_assigned_sprite:draw(dst_surface)
end
self:draw_save_dialog_if_any(dst_surface)
end
-- Shows a message describing the item currently selected.
-- The player is supposed to have this item.
function allies_status_submenu:show_info_message()
local item_name = item_names[self:get_selected_index() + 1]
local variant = self.game:get_item(item_name):get_variant()
local map = self.game:get_map()
-- Position of the dialog (top or bottom).
if self.cursor_row >= 2 then
self.game:set_dialog_position("top") -- Top of the screen.
else
self.game:set_dialog_position("bottom") -- Bottom of the screen.
end
self.game:set_custom_command_effect("action", nil)
self.game:set_custom_command_effect("attack", nil)
self.game:start_dialog("_item_description." .. item_name .. "." .. variant, function()
self.game:set_custom_command_effect("action", "info")
self.game:set_custom_command_effect("attack", "save")
self.game:set_dialog_position("auto") -- Back to automatic position.
end)
end
-- Assigns the selected item to a slot (1 or 2).
-- The operation does not take effect immediately: the item picture is thrown to
-- its destination icon, then the assignment is done.
-- Nothing is done if the item is not assignable.
function allies_status_submenu:assign_item(slot)
local index = self:get_selected_index() + 1
local item_name = item_names[index]
local item = self.game:get_item(item_name)
-- If this item is not assignable, do nothing.
if not item:is_assignable() then
return
end
-- If another item is being assigned, finish it immediately.
if self:is_assigning_item() then
self:finish_assigning_item()
end
-- Memorize this item.
self.item_assigned = item
self.item_assigned_sprite = sol.sprite.create("entities/items")
self.item_assigned_sprite:set_animation(item_name)
self.item_assigned_sprite:set_direction(item:get_variant() - 1)
self.item_assigned_destination = slot
-- Play the sound.
sol.audio.play_sound("throw")
-- Compute the movement.
local x1 = 60 + 32 * self.cursor_column
local y1 = 75 + 32 * self.cursor_row
local x2 = (slot == 1) and 20 or 72
local y2 = 46
self.item_assigned_sprite:set_xy(x1, y1)
local movement = sol.movement.create("target")
movement:set_target(x2, y2)
movement:set_speed(500)
movement:start(self.item_assigned_sprite, function()
self:finish_assigning_item()
end)
end
-- Returns whether an item is currently being thrown to an icon.
function allies_status_submenu:is_assigning_item()
return self.item_assigned_sprite ~= nil
end
-- Stops assigning the item right now.
-- This function is called when we want to assign the item without
-- waiting for its throwing movement to end, for example when the inventory submenu
-- is being closed.
function allies_status_submenu:finish_assigning_item()
-- If the item to assign is already assigned to the other icon, switch both items.
local slot = self.item_assigned_destination
local current_item = self.game:get_item_assigned(slot)
local other_item = self.game:get_item_assigned(3 - slot)
if other_item == self.item_assigned then
self.game:set_item_assigned(3 - slot, current_item)
end
self.game:set_item_assigned(slot, self.item_assigned)
self.item_assigned_sprite:stop_movement()
self.item_assigned_sprite = nil
self.item_assigned = nil
end
return allies_status_submenu
Allies Hud Icon
-- An icon that shows the inventory item assigned to a slot.
local allies_icon = {}
function allies_icon:new(game, slot)
local object = {}
setmetatable(object, self)
self.__index = self
object:initialize(game, slot)
return object
end
function allies_icon:initialize(game, slot)
self.game = game
self.slot = slot
self.surface = sol.surface.create(32, 28)
self.background_img = sol.surface.create("hud/item_icon_" .. slot .. ".png")
self.item_sprite = sol.sprite.create("entities/items")
self.item_displayed = nil
self.item_variant_displayed = 0
self.amount_text = sol.text_surface.create{
horizontal_alignment = "center",
vertical_alignment = "top"
}
self.amount_displayed = nil
self.max_amount_displayed = nil
self:check()
self:rebuild_surface()
end
function allies_icon:check()
local need_rebuild = false
-- Item assigned.
local item = self.game:get_item_assigned(self.slot)
if self.item_displayed ~= item then
need_rebuild = true
self.item_displayed = item
self.item_variant_displayed = nil
if item ~= nil then
self.item_sprite:set_animation(item:get_name())
end
end
if item ~= nil then
-- Variant of the item.
local item_variant = item:get_variant()
if self.item_variant_displayed ~= item_variant then
need_rebuild = true
self.item_variant_displayed = item_variant
self.item_sprite:set_direction(item_variant - 1)
end
-- Amount.
if item:has_amount() then
local amount = item:get_amount()
local max_amount = item:get_max_amount()
if self.amount_displayed ~= amount
or self.max_amount_displayed ~= max_amount then
need_rebuild = true
self.amount_displayed = amount
self.max_amount_displayed = max_amount
end
elseif self.amount_displayed ~= nil then
need_rebuild = true
self.amount_displayed = nil
self.max_amount_displayed = nil
end
elseif self.amount_displayed ~= nil then
need_rebuild = true
self.amount_displayed = nil
self.max_amount_displayed = nil
end
-- Redraw the surface only if something has changed.
if need_rebuild then
self:rebuild_surface()
end
-- Schedule the next check.
sol.timer.start(self.game, 50, function()
self:check()
end)
end
function allies_icon:rebuild_surface()
self.surface:clear()
-- Background image.
self.background_img:draw(self.surface)
if self.item_displayed ~= nil then
-- Item.
self.item_sprite:draw(self.surface, 12, 17)
if self.amount_displayed ~= nil then
-- Amount.
self.amount_text:set_text(tostring(self.amount_displayed))
if self.amount_displayed == self.max_amount_displayed then
self.amount_text:set_font("green_digits")
else
self.amount_text:set_font("white_digits")
end
self.amount_text:draw(self.surface, 18, 16)
end
end
end
function allies_icon:set_dst_position(x, y)
self.dst_x = x
self.dst_y = y
end
function allies_icon:on_draw(dst_surface)
if not self.game:is_dialog_enabled() then
local x, y = self.dst_x, self.dst_y
local width, height = dst_surface:get_size()
if x < 0 then
x = width + x
end
if y < 0 then
y = height + y
end
self.surface:draw(dst_surface, x, y)
end
end
return allies_icon
Found the solution in the Surface API at least for the color...
http://www.solarus-games.org/doc/latest/lua_api_surface.html
About the functionality though...
While creating the new pause menu panel...
I found that the new menu panel doesn't move in sequence from inventory to quest to allies etc...
I checked my code but haven't found a solution or explanation as to why the menus are displaying out of order, erratically.
Only the new allies menu though.
Any suggestions?
Hi,
I you use the same pause system as Zelda Mystery of Solarus DX, the order of pause submenus in pause.lua, in game:start_pause_menu().
If this is correct, maybe there is something wrong in your allies menu that make it stop too soon?
I am not sure, but this could be the problem:
In the pause_submenu.lua file of Zelda Mystery of Solarus DX, in submenu:previous_submenu(), in line 125 you have
submenu_index = (submenu_index + 2) % #submenus + 1
which works fine only for 4 menus I think, but not in other cases. Try to change that line by:
submenu_index = (submenu_index + #submenus - 2) % #submenus + 1
But I am not sure at all if that will fix your problem.
EDIT: I suggest changing that line in the repository of Zelda Mystery of Solarus DX, to avoid more people having the same problem with the menus in case they copy the script. (But before we need confirmation that it works fine.)
Hi Christopho and Diarandor!
Diarandor, The fix worked great.
I now have a working allies menu with selectable allies that doesn't appear irratically.
I had looked all through the pause.lua and other files in the menu folder I just don't yet have enough experience with lua to know what everything means yet.
Thank you so much for your help.
PG
POST TEXT: I needed to create a new menu via the pausesubmenu.png I just put it in the right most position to have the new menu surface display. With out it... it allows for a nice unlabled screen with icons hanging across the screen. Still selectable also.
Cheers.
There was indeed an error in the code. I think this also works, and is shorter:
submenu_index = (submenu_index - 2) % #submenus + 1
Yes, I think you are right. (I wasn't sure how the mod (%) operator works with a negative numerator, so I added that #submenus term. I think your code works fine too.)