Author Topic: [SOLVED] Trouble porting a script  (Read 2121 times)

MetalZelda

  • Hero Member
  • *****
  • Posts: 551
    • View Profile
[SOLVED] Trouble porting a script
« on: June 25, 2017, 04:40:28 pm »
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).
« Last Edit: July 03, 2017, 01:25:32 pm by MetalZelda »

Maxs

  • Newbie
  • *
  • Posts: 19
    • View Profile
Re: Trouble porting a script
« Reply #1 on: June 25, 2017, 06:35:43 pm »
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

llamazing

  • Full Member
  • ***
  • Posts: 212
    • View Profile
Re: Trouble porting a script
« Reply #2 on: June 25, 2017, 06:41:04 pm »
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

MetalZelda

  • Hero Member
  • *****
  • Posts: 551
    • View Profile
Re: Trouble porting a script
« Reply #3 on: June 25, 2017, 09:44:27 pm »
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
« Last Edit: June 25, 2017, 09:47:59 pm by MetalZelda »

llamazing

  • Full Member
  • ***
  • Posts: 212
    • View Profile
Re: Trouble porting a script
« Reply #4 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.

MetalZelda

  • Hero Member
  • *****
  • Posts: 551
    • View Profile
Re: Trouble porting a script
« Reply #5 on: June 29, 2017, 05:54:36 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

Diarandor

  • Hero Member
  • *****
  • Posts: 1061
  • Cats are cool! (ΦωΦ)
    • View Profile
Re: Trouble porting a script
« Reply #6 on: June 29, 2017, 06:22:56 pm »
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.”

MetalZelda

  • Hero Member
  • *****
  • Posts: 551
    • View Profile
Re: Trouble porting a script
« Reply #7 on: July 02, 2017, 03:47:13 pm »
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
« Last Edit: July 03, 2017, 01:12:56 pm by MetalZelda »