Jump to content
siChainlinks

Calling different databases in a loop (VX Ace)

Recommended Posts

Hi there! Hope someone out there has an answer for this, otherwise my code is going to explode in length, which makes me sad. So what I'm trying to do is scan all the note sections in $data_items for my notetags, then proceed with the same scan in weapons and armours. Instead of copying the same code three times, I thought I could simply pass in a variable that will change depending on the database, something like this:

def notetag_search search_array = [$data_items, $data_weapons, $data_armors] for element in search_array range = element.size - 1 for i in 0..range element[i].note(my regexp) my_code_goes_here end end# OR, I have also tried: size = search_array.size - 1 for i in 0..size range = search_array[i].size - 1 for j in 0..range search_array[i][j].note(my regexp) my_code_goes_here end endend

Now the rest of the code works like a charm when I hard-set 'element' to $data_items, but fails when I try to generalize (using either method). Why is this? Is there a work-around I can use, or am I stuck copying this same code three times, one for each database?

I would usually just struggle on in the dark until I find something that works, but for this one, I suspect the issue is that RPG Maker or ruby syntax deals with references to its databases slightly differently than I thought (or hoped?) it did.

Thanks for reading!

 

EDIT: I thought it would be easier to ask this question with a more general format, but I don't seem to be able to communicate my issue very well (I apologize, I am very new at coding, and most definitely still learning). Here is the working code that I've been using to scan a single database:

 

 

    def self.find_recipes()
      item_size = $data_items.size
        for i in 1..item_size
          next if $data_items[i].nil?
          @recipe = Array.new()
          ingredients = Array.new()
          items = Array.new()
          weapons = Array.new()
          armours = Array.new()
          $data_items[i].note[/<(\w*) Recipe[ ]*(\d*):[ ]*([i,w,a])(\d+),*[ ]*([i,w,a])(\d+),*[ ]*([i,w,a])*(\d*),*[ ]*([i,w,a])*(\d*),*[ ]*([i,w,a])*(\d*)>/i]   
          if $1 && $1 != "" && $3 && $3 != ""
            p($data_items[i].note)
            range = 4
            $4  ? ingredients[0] = [$3.to_s,  $4.to_i]    : next
            $6  ? ingredients[1] = [$5.to_s,  $6.to_i]    : next
            $8  ? ingredients[2] = [$7.to_s,  $8.to_i]    : range = 1
            $10 ? ingredients[3] = [$9.to_s,  $10.to_i]   : range = 2
            $12 ? ingredients[4] = [$11.to_s, $12.to_i]   : range = 3
            for j in 0..range
              type = ingredients[j][0]
              p(type)
              if type == "i" or type == "I"
                items.push(ingredients[j][1])
              elsif type == "w" or type == "W"
                weapons.push(ingredients[j][1])
              elsif type == "a" or type == "A"
                armours.push(ingredients[j][1])
              else
                next
              end
            end
            @recipe[0] = $2.to_i
            @recipe[1] = items
            @recipe[2] = weapons
            @recipe[3] = armours
              # cook_recipes_known is an array of recipe arrays, up to five ingredients ea.
              # cook_recipe_index is an array of result, known? (ie t/f) and text to display
              if $1.to_s == "Cook" || $1.to_s == "cook"
                p("cook recipe")
                p(@recipe)
                $game_system.cook_recipes_known.push(@recipe)
                $game_system.cook_recipe_index.push([i, false, ""])
              elsif $1.to_s == "Smith" || $1.to_s == "smith"
                p("smith recipe")
                $game_system.smith_recipes_known.push(@recipe) 
                $game_system.smith_recipe_index.push([i, false, ""])
              else
              end
            p(@recipe)
            p($game_system.cook_recipes_known)
            p($game_system.cook_recipe_index)
          else
            p("No Recipe")
          end # if statement close
        end # for loop close
      p($game_system.cook_recipes_known)
    end

 

 

 

 

What I'd like to be able to do, ideally, is make this piece of code scan item, weapon and armor databases, and not only the item database. It's long, and it's messy, but since I seem to have a very limited understanding of the problem, it's all I can offer.

Edited by siChainlinks

Share this post


Link to post
Share on other sites

Ok maybe I misunderstood the problem.

What is the error? You need to account for nil elements as well.

Edited by Tsukihime

Share this post


Link to post
Share on other sites

The error that gets thrown is a NoMethodError, it says: "undefined method 'note' for <#Array:0x1d37150>". It's undefined because it's not interfacing properly with the database. The same error gets thrown if I try to simply set database = $data_items and then try to run database.note[regexp]. I have had it working fine without the loop (the size has a - 1 in there to make sure I don't have any nils), so I don't think that's the problem.

Edited by siChainlinks

Share this post


Link to post
Share on other sites

It's undefined because you are getting an array instead of an element in the array.

Which was why I initially asked you to check what you're actually trying to access.

Share this post


Link to post
Share on other sites

In the first case, there are instances, especially the first element, where the object doesn't exist, as in, it's set to nil. You'll always have to check if it's a valid object. You don't get the NoMethodError because it's an array, you get it because it's nil.

 

In the last case, you're calling note on the array, not the elements of the array. This is where you get the array error. Any global $data_ variable in the vanilla code is an array.

 

And yes, I did do a test case.

Share this post


Link to post
Share on other sites

@GaryCXJk: Ok, I think I understand what's going wrong. And in my code I use a range of 1..size (which avoids calling the 0th element, which would be nil), I just poorly translated. Sorry about that. Any ideas on how I can work around trying to call note on the array in order to call note on the elements, while still assigning it to a variable?

 

I know that neither of my solutions are going to work, but I'm wondering how (if at all) other coders would try to get past this problem: wanting to run the same code on $data_items, $data_weapons and $data_armors (that involves the .note method) without writing it out three times.

Share this post


Link to post
Share on other sites

def notetag_search

search_array = [$data_items, $data_weapons, $data_armors]

search_array.each do |table|

table.each do |obj|

next if obj.nil?

p obj.note

end

end

end

Edited by Tsukihime

Share this post


Link to post
Share on other sites

Thank you, Tsukihime, for your responses, and your continued help, but I don't think I fully understand what you are suggesting with the piece of code you are offering. Is obj the method I want to run? Is this a loop I would potentially run before my other loop to generate arrays of the regular expression groups that I need to use?

 

Alas, perhaps I am not literate enough with ruby code to be able to understand what you are saying. I have extended the original post with the code, line-for-line, that I am trying to modify. Most of it will be irrelevant, I think, but I hope not too distracting. Again, thank you for your patience so far. I wish I were more a more capable coder.

Share this post


Link to post
Share on other sites

To avoid having to deal with arrays inside arrays, this is probably easiest:

items_to_check = $data_items + $data_weapons + $data_armors
# loop through this instead
This is a single array with all of the objects that you want to check.

You should be able to add this to your code and it should work.

Edited by Tsukihime
  • Like 1

Share this post


Link to post
Share on other sites

I could also help with explaining Tsukihime's code.

 

Basically, you can easily iterate through an array by using this:

array.each do |element|
  <element operations>
end
What it does is it goes through all elements of an array, and performs an action for each element. For example:
primes = [2, 3, 5, 7, 11, 13]
val = 1
primes.each do |p_num|
  val*= p_num
end
p val

# Result: 30030
What happens in Tsukihime's code is, it iterates through the list of arrays ($data_items, $data_weapons and $data_armors), and then it iterates over each of these arrays. The obj variable is the object for each of these arrays.
  • Like 1

Share this post


Link to post
Share on other sites

I never thought of simply massing the three databases together, that certainly works. Thank you Tsukihime! And thank you, too, GaryCXJk, for your explaining Tsukihime's code: I'm not entirely sure that I understand what the difference is between using the for loops I was using, and using the do loops in Tsukihime's example, but it does actually work differently (and also solves the issue). For now I'll just have to accept that they deal with arrays differently, and learn more from experience about how that's different.

 

Problem solved, thanks to both of you!

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.

  • Recently Browsing   0 members

    No registered users viewing this page.

×
Top ArrowTop Arrow Highlighted