Hello.
So, I am porting a RUBY script to lua.
This script will allow easier pause menu creation, replacing cursor position by user defined positions. Like so
local elements = {
config = {save = true},
{"rupee_bag", 68, 78, "info"},
{"bomb_bag", 68, 104, "info"},
{"quiver", 68, 130, "info"},
{"deku_nuts_bag", 68, 156, "info"},
{"bombchu_bag", 68, 182, "info"},
{"sword", 217, 84, "action"},
{"tunic", 209, 180, "action", variant = "_1"},
{"tunic", 233, 180, "action", variant = "_2"},
{"tunic", 257, 180, "action", variant = "_3"},
{"glove", 209, 132, "info"},
{"shield", 233, 132, "info"},
{"climb_ring", 257, 132, "info"},
{"sword_biggoron", 249, 84, "action"},
}
The 2nd and 3rd index is used to place an item on the X and Y axis, as well as the cursor
This is the RUBY script I'm trying to port
# Initialize variables for the weightings on the vertical and horizontal
# directions
wv, wh = 0, 0
# The weightings for the secondary and primary axis relative to input
w1, w2 = 1, 2
# Initialize a variable for the direction and get the direction
# pressed by the user
input_dir = 0
input_dir = 2 if Input.repeat?(Input::DOWN)
input_dir = 4 if Input.repeat?(Input::LEFT)
input_dir = 6 if Input.repeat?(Input::RIGHT)
input_dir = 8 if Input.repeat?(Input::UP)
# Do nothing if no button was pressed
return if input_dir == 0
#get the item
item = self.item
#if the item is left toggle and the input direction is left
if item == :left_toggle && input_dir == 4
#move to the left window
return $scene.move_window(6)
#elsif the item is right toggle and the input direction is right
elsif item == :right_toggle && input_dir == 6
#move to the right window
return $scene.move_window(4)
end
# Setup the weightings for each direction
if (input_dir == 2 or input_dir == 8)
wv, wh = w1, w2
elsif (input_dir == 4 or input_dir == 6)
wv, wh = w2, w1
end
# Get the xy position of the current item
cxy = @xy_pos[@index]
# Create default value for the closest item's distance (absurdly large)
closest_index = -1
closest_distance = 9999999
# Loop through every item
for i in 0...@xy_pos.size
# Skip if it is the old item or is in the opposite direction
if @index == i or
(input_dir == 2 and @xy_pos[i][1] < cxy[1]) or
(input_dir == 4 and @xy_pos[i][0] > cxy[0]) or
(input_dir == 6 and @xy_pos[i][0] < cxy[0]) or
(input_dir == 8 and @xy_pos[i][1] > cxy[1])
next
end
# Get the distance from the last highlighted item to this tested one
dist_h = (@xy_pos[i][0] - cxy[0]).abs
dist_v = (@xy_pos[i][1] - cxy[1]).abs
# If it is really against the primary axis
if (wh == w1 and w2 * dist_h < dist_v) or
(wv == w1 and w2 * dist_v < dist_h)
next
end
# Get the distance multiplied with their weightings
dist = dist_h * wh + dist_v * wv
# Set at closest item if appropriate
if (dist < closest_distance)
closest_distance = dist
closest_index = i
end
end
# Do nothing if nothing was selected
return if closest_index == -1
@index = closest_index
#move cursor
move_cursor
@xy_pos is already defined in the elements variable, @cxy is the current cursor position, they are already defined
The only problem, RUBY have a skip iterator whereas I can't find the closest thing for lua
This is my attempt in Lua, which still fails, the cursor will still highlight the current item forever
function submenu:set_cursor_position(command)
local width = sol.video.get_quest_size()
width = width / 2 - 160
local current_x = self.cursor_position.x
local current_y = self.cursor_position.y
-- Create default value for the closest item's distance
local closest_index = -1
local closest_distance = 320
-- Initialize variables for the weightings on the vertical and horizontal direction
local wv, wh = 0, 0
-- The weightings for the secondary and primary axis relative to input
local w1, w2 = 1, 2
-- Setup the weightings for each direction
if (command == "down" or command == "up") then
wv, wh = w1, w2
elseif (command == "left" or command == "right") then
wv, wh = w2, w1
end
for i = 1, #self.items do
local item = self.items[i]
local item_x = item.x
local item_y = item.y
local current_item_index = self:find_item(self:find_item_axis(self.cursor_position.x, self.cursor_position.y))
-- Skip if it is the old item or is in the opposite direction
if current_item_index == i or (command == "down" and item_y < current_y) or (command == "left" and item_x > current_x) or (command == "right" and item_x < current_x) or (command == "up" and item_y > current_y) then
-- tried goto
end
-- Get the distance of the current item and the new one
local dist_h = math.abs(item_x - current_x)
local dist_v = math.abs(item_y - current_y)
if (wh == w1 and w2 * dist_h < dist_v) or (wv == w1 and w2 * dist_v < dist_h) then
goto matched
end
::matched::
-- # Get the distance multiplied with their weightings
local dist = (dist_h * wh + dist_v * wv)
-- # Set at closest item if appropriate
if (dist < closest_distance) then
closest_distance = dist
closest_index = i
end
end
local item = self.items[closest_index]
local x = item.x
local y = item.y - 5
self.cursor_position = {x = x, y = y + 5}
self.cursor_sprite_x = x + width
self.cursor_sprite_y = y
self.game:set_custom_command_effect("action", item.effect)
local caption_item = item.item .. "_" .. self.game:get_item(item.item):get_variant()
if item.item == "tunic" then
caption_item = "tunic_" .. self:get_tunic_variant()
end
self:set_caption(self.caption_text_keys[caption_item])
self.game:set_value("equipment_last_index", position)
end
Is there a Lua equivalent of "next" ?
Next = https://www.tutorialspoint.com/ruby/ruby_loops.htm
Jumps to the next iteration of the most internal loop. Terminates execution of a block if called within a block (with yield or call returning nil).
I don't think that there are a Lua equivalent to the next statement of Ruby, but you can easily reproduce this with a variable.
For example :
for i in 0...@xy_pos.size
if (condition)
next
end
# rest of the code
end
becomes :
for i = 1, #items do
local to_next = false
if (condition) then
to_next = true
end
if not to_next then
-- rest of the code
end
end
There isn't an equivalent to next in lua, but you can accomplish the same thing using if statements. Take the two simplified examples (using lua syntax for illustration purposes)
for i = 1, #self.items do
if index == i then
next --not valid lua
end
print("not skipped")
end
--equivalent to the following
for i = 1, #self.items do
if index ~= i then
print("not skipped")
end
end
So in your for block you could do the following in lua (note I have not tested it so there may be errors):
for i,item in ipairs(self.items) do
local item_x = item.x
local item_y = item.y
local current_item_index = self:find_item(self:find_item_axis(self.cursor_position.x, self.cursor_position.y))
-- Skip if it is the old item or is in the opposite direction
if current_item_index ~= i and (command ~= "down" or item_y >= current_y) and (command ~= "left" or item_x <= current_x) and (command ~= "right" or item_x >= current_x) and (command ~= "up" or item_y <= current_y) then
-- Get the distance of the current item and the new one
local dist_h = math.abs(item_x - current_x)
local dist_v = math.abs(item_y - current_y)
if (wh ~= w1 or w2 * dist_h >= dist_v) and (wv ~= w1 or w2 * dist_v >= dist_h) then
-- # Get the distance multiplied with their weightings
local dist = (dist_h * wh + dist_v * wv)
-- # Set at closest item if appropriate
if (dist < closest_distance) then
closest_distance = dist
closest_index = i
end
else
--equivalent to next, do nothing this iteration
end
else
--equivalent to next, do nothing this iteration
end
end
Also note that instead of doing
for i = 1, #self.items do
local item = self.items[i]
...
end
it is better to use
for i,item in ipairs(self.items) do
...
end
This kinda work, it is better than last time because now the cursor and item change.
However, this is messy, it only loops through 2 items, the distance system works but it only loops between 2 items, light be the command stuff but it looks ok ...
function submenu:set_cursor_position(command)
local width = sol.video.get_quest_size()
width = width / 2 - 160
local current_x = self.cursor_position.x
local current_y = self.cursor_position.y
-- Create default value for the closest item's distance
local closest_index = -1
local closest_distance = 9999999
local index = self:find_item(self:find_item_axis(current_x, current_y))
-- Initialize variables for the weightings on the vertical and horizontal direction
local wv, wh = 0, 0
-- The weightings for the secondary and primary axis relative to input
local w1, w2 = 1, 2
-- Setup the weightings for each direction
if (command == "down" or command == "up") then
wv, wh = w1, w2
elseif (command == "left" or command == "right") then
wv, wh = w2, w1
end
for i, item in ipairs(self.items) do
local x = item.x
local y = item.y
-- This isn't the old item or the opposite direction
if index ~= i or (command ~= "down" and y > current_y) or (command ~= "left" and x < current_x) or (command ~= "right" and x > current_x) or (command ~= "up" and y < current_y) then
-- Get the distance of the current item and the new one
local dist_h = math.abs(x - current_x)
local dist_v = math.abs(y - current_y)
if (wh ~= w1 or w2 * dist_h > dist_v) and (wv ~= w1 or w2 * dist_v > dist_h) then
local dist = (dist_h * wh + dist_v * wv)
-- Set at closest item if appropriate
if (dist < closest_distance) then
closest_distance = dist
closest_index = i
end
end
end
end
local item = self.items[closest_index]
local x = item.x
local y = item.y - 5
self.cursor_position = {x = x, y = y + 5}
self.cursor_sprite_x = x + width
self.cursor_sprite_y = y
self.game:set_custom_command_effect("action", item.effect)
local caption_item = item.item .. "_" .. self.game:get_item(item.item):get_variant()
self:set_caption(self.caption_text_keys[caption_item])
self.game:set_value(self.menu .. "_last_index", tostring(x) .. "," .. tostring(y + 5))
end
index prints the right item index in the array so this is not the culprit there
Hmmm, that's the 1st time a ruby script port grinds my gears
Do you have a sample project available? It's a bit hard to troubleshoot from the forum.
Also double-check that I negated those if statements correctly.
Quote from: llamazing on June 25, 2017, 10:05:02 PM
Do you have a sample project available? It's a bit hard to troubleshoot from the forum.
Also double-check that I negated those if statements correctly.
I will upload a sample demo tomorrow, i'm currently very busy
Cool! ;D We will start testing it soon.
Somehow I got the thing to work properly, I don't even know how
function submenu:set_cursor_position(command)
-- Initialize variables for the weightings on the vertical and horizontal
-- directions
local wv, wh = 0, 0
-- The weightings for the secondary and primary axis relative to input
local w1, w2 = 1, 2
local input = -1
if command == "right" then
input = 0
elseif command == "up" then
input = 1
elseif command == "left" then
input = 2
elseif command == "down" then
input = 3
end
if input == -1 then return end
-- Setup the weightings for each direction
if (input == 1 or input == 3) then
wv, wh = w1, w2
elseif (input == 0 or input == 2) then
wv, wh = w2, w1
end
local width = sol.video.get_quest_size()
width = width / 2 - 160
local current_x = self.cursor_position.x
local current_y = self.cursor_position.y
-- Create default value for the closest item's distance
local closest_index = -1
local closest_distance = 9999999
local index = self:find_item(self:find_item_axis(current_x, current_y))
for i, item in ipairs(self.items) do
local item_x = item.x
local item_y = item.y
-- Skip if it is the old item or is in the opposite direction
if index ~= i and (input ~= 3 or item_y >= current_y) and (input ~= 2 or item_x <= current_x) and (input ~= 0 or item_x >= current_x) and (input ~= 1 or item_y <= current_y) then
-- Get the distance of the current item and the new one
local dist_h = math.abs(item_x - current_x)
local dist_v = math.abs(item_y - current_y)
if (wh ~= w1 or w2 * dist_h >= dist_v) and (wv ~= w1 or w2 * dist_v >= dist_h) then
-- # Get the distance multiplied with their weightings
local dist = (dist_h * wh + dist_v * wv)
-- # Set at closest item if appropriate
if (dist < closest_distance) then
closest_distance = dist
closest_index = i
end
end
end
end
if closest_index == -1 then return end
local item = self.items[closest_index]
local x = item.x
local y = item.y - 5
self.cursor_position = {x = x, y = y + 5}
self.cursor_sprite_x = x + width
self.cursor_sprite_y = y
self.game:set_custom_command_effect("action", item.effect)
self:set_caption(self.caption_text_keys[caption_item])
self.game:set_value(self.menu .. "_last_index", closest_index)
end
There is still some problem regarding some items but that's because I use some wizzard stuffs, for example, you need a separate item for each tunic variant, else it will be stuck on the tunic.
What makes this useful is, the simpliciity of menu customisation, you just have to put a x and y value for your item, the script determine the input pressed and stuffs, instead of using cursor position stuffs
This was my Quest status menu before the change
(http://i.imgur.com/WjX4S8u.png)
Notice how it is done ... Manually by stuffs
Now, it just looks like this
(http://i.imgur.com/lv4cJQH.png)
All of my menues now run this code
The pro is that it is easier to make and place objects in the menues, the cons is that every objects need to be an item