[SOLVED] Trouble porting a script

Started by MetalZelda, June 25, 2017, 04:40:28 PM

Previous topic - Next topic
June 25, 2017, 04:40:28 PM Last Edit: July 03, 2017, 01:25:32 PM by MetalZelda
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

Code (lua) Select

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

Code (ruby) Select
# 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

Code (lua) Select

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 :

Code (ruby) Select

for i in 0...@xy_pos.size
  if (condition)
     next
  end
  # rest of the code
end


becomes :

Code (lua) Select

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
SQE developer

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)

Code ( lua) Select

for i = 1, #self.items do
    if index == i then
        next --not valid lua
    end
   
    print("not skipped")
end


Code ( lua) Select
--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):
Code ( lua) Select
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
Code ( lua) Select
for i = 1, #self.items do
    local item = self.items[i]
    ...
end


it is better to use
Code ( lua) Select
for i,item in ipairs(self.items) do
    ...
end

June 25, 2017, 09:44:27 PM #3 Last Edit: June 25, 2017, 09:47:59 PM by MetalZelda
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 ...

Code (lua) Select
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.
"If you make people think they're thinking, they'll love you. But if you really make them think, they'll hate you."

July 02, 2017, 03:47:13 PM #7 Last Edit: July 03, 2017, 01:12:56 PM by MetalZelda
Somehow I got the thing to work properly, I don't even know how

Code (lua) Select
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


Notice how it is done ... Manually by stuffs

Now, it just looks like this


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