Set Variables equal to amount of Items

Discussion in 'Learning Ruby and RGSSx' started by Tw0Face, Jul 12, 2019 at 12:48 AM.

  1. Tw0Face

    Tw0Face Chief Executive Officer Veteran

    Messages:
    172
    Likes Received:
    253
    First Language:
    German
    Primarily Uses:
    RMVXA
    Hi, folks.

    I want to set a Variable equal to an Item's value in the Inventory. This can be easily done by using the Event Editor. Like this:
    Code:
    @>Control Variables:[0001:Variable for Item1] = [Item 1] in Inventory
    But I don't want to do it that way. I want to understand some basic scripting. So I tried it and wrote this:
    Code:
    module Whatever
      def Set_Variable_equal_to_Item
    $game_variables[1] = $game_party.item_number($data_items[1]).group
    $game_variables[2] = $game_party.item_number($data_items[2]).group
    $game_variables[3] = $game_party.item_number($data_items[4]).group
    $game_variables[4] = $game_party.item_number($data_items[5]).group
    $game_variables[5] = $game_party.item_number($data_items[5]).group
    $game_variables[6] = $game_party.item_number($data_items[6]).group
    $game_variables[7] = $game_party.item_number($data_items[7]).group
    $game_variables[8] = $game_party.item_number($data_items[8]).group
    $game_variables[9] = $game_party.item_number($data_items[9]).group
    $game_variables[10] = $game_party.item_number($data_items[10]).group
    $game_variables[11] = $game_party.item_number($data_items[11]).group
    $game_variables[12] = $game_party.item_number($data_items[12]).group
    $game_variables[13] = $game_party.item_number($data_items[13]).group
    $game_variables[14] = $game_party.item_number($data_items[14]).group
    $game_variables[15] = $game_party.item_number($data_items[15]).group
    $game_variables[16] = $game_party.item_number($data_items[16]).group
    $game_variables[17] = $game_party.item_number($data_items[17]).group
    $game_variables[18] = $game_party.item_number($data_items[18]).group
    $game_variables[19] = $game_party.item_number($data_items[19]).group
    $game_variables[20] = $game_party.item_number($data_items[20]).group
    $game_variables[21] = $game_party.item_number($data_items[21]).group
    $game_variables[22] = $game_party.item_number($data_items[22]).group
    $game_variables[23] = $game_party.item_number($data_items[23]).group
    $game_variables[24] = $game_party.item_number($data_items[24]).group
     end
    end
    
    At least I thought it would work, but it doesn't. Is someone willing to explain me what I did wrong?

    EDIT: RGSS3, Vx Ace.

    Greetings,
    Tw0Face
     
    Last edited: Jul 12, 2019 at 1:00 AM
    #1
  2. Another Fen

    Another Fen Veteran Veteran

    Messages:
    508
    Likes Received:
    232
    First Language:
    German
    Hey there,

    In general, if you want to replicate an event command in Ruby it's often a helpful first step to look it up in the Game_Interpreter script. You may have already done that here though. I'm not sure if you need the .group calls here. I don't think there is such a method for numbers by default, and ending with item_number(...) should already return you the number of items carried.

    Anyways, you haven't specified what exactly you did with that code, so some general info about it:
    Writing
    Code:
    def name
      ...
    end

    means you are doing a method definition. Doing this will not execute the code you put in the method, but allows you to call the method later on (similar to a common event call in eventing), so if all you did was putting that code into a new script and run it, you now know what piece was missing.
    There is also a distinction between instance methods and static methods:

    Static methods are bound to a single object. In the default scripts you can find them primarily in the XXXManager modules. You can define a static method by putting the objects reference (like self or the name of your module) before the method name:
    Code:
    module Whatever
      def self.set_variable_to_item
        ...
      end
    end

    Once defined you can then call that method from whereever you have access to your Whatever module:
    Whatever.set_variable_to_item
    I'd guess this is what you were looking for here.

    Instance methods are defined without such a reference before the method name. You cannot call an instance method directly through the class/module you defined it in, but only though the objects you created from that class/module.
    As an example, take the "exp" method in the Game_Actor class:
    Code:
    class Game_Actor
      ...
      def exp
        @exp[@class_id]
      end
      ...
    end

    Since this is an instance method you cannot use it through Game_Actor.exp in your scripts. This would not make much sense either, since there is no universal experience value. However, the method is available for every actor you create from that class, so
    $game_actors[1].exp
    $game_actors[2].exp
    $game_actors[3].exp
    ...

    will give you that actors personal exp value.

    Not that good at explaining I fear, but I hope it helps a bit. :)
     
    Last edited: Jul 12, 2019 at 2:29 AM
    #2
    Tw0Face and Bex like this.
  3. Bex

    Bex Veteran Veteran

    Messages:
    1,149
    Likes Received:
    247
    First Language:
    German
    Primarily Uses:
    RMMV
    Iam not a Scripter but thanks to the Script Call List and the help of awesome community Scripters that helped alot, i picked up the concept of the "For Loop".
    With Arrays i have no clue, have to learn them myself, but the "For Loop" is awesome.

    The following code puts the amount owned Item, Ids 1 to 999 into the Variables 1 to 999.
    Code:
    for a in (1..999)
    if  $game_party.item_number($data_items[a]) != nil
    $game_variables[a] = $game_party.item_number($data_items[a])
    end ; end
    Edit: I executed the code in the Eventcommand Script on the 3rd Page of Eventcommands.
    You are safing yourself the work of doing 999 lines of conditional branch code.
    Iam not sure if the Weapons and Armor is also counted, but i hope so.

    Here the VX-Ace Script Call List:
    https://forums.rpgmakerweb.com/index.php?threads/script-call-collection-for-vxace.25759/

    Edit: LOL i believe i got this Loop Code by Another Fen, Irrlicht or Playm a few Years ago.
    I totaly loved Another Fens Self Variables Script for Events and the addon for Actors.
    Could you please reupload those, those rpgmaker websites went down over the years.
     
    Last edited: Jul 12, 2019 at 2:46 AM
    #3
    Another Fen and Tw0Face like this.
  4. Tw0Face

    Tw0Face Chief Executive Officer Veteran

    Messages:
    172
    Likes Received:
    253
    First Language:
    German
    Primarily Uses:
    RMVXA
    Hey, guys. Thanks to both of you for your help.

    I don't want to execute the code using Events because I don't want to have another constantly running parallel process. If I wanted to do that, I could as well use the Event Command shown in the OP. Instead, I want to run it as a script, so it works like a parallel process, but less harmful to the performance. :)

    Greetings,
    Tw0Face
     
    #4
  5. Bex

    Bex Veteran Veteran

    Messages:
    1,149
    Likes Received:
    247
    First Language:
    German
    Primarily Uses:
    RMMV
    Ah understand, but does it need to run parallel?
    Maybe its enough to call it only one time when needed?
    Does it need to work in shop Screens? Which shop Scripts do you use?

    And much more important, why would you safe the amnount of an Item into a Variable.
    The Item itself is like a Variable which allready contains the amount of that Item.
    You are doing it twice, or you got a good reason for it? Would you mind sharing some of the Information about this?
     
    #5
    Another Fen likes this.
  6. Another Fen

    Another Fen Veteran Veteran

    Messages:
    508
    Likes Received:
    232
    First Language:
    German
    The way scripts achieve these effects is usually by tapping into existing methods. The game is processed through a network of method calls, which is set up by your scripts and then kicked off with SceneManager.run in the "main" script.
    So in order to execute Whatever.set_variable_to_item whenever something happens (or in regular intervals), you'd usually look for the right place(s) in the system and modify the related existing method(s) to add your own stuff to them.

    That being said, I strongly agree with Bex here.
    If performance is the issue here, chances are you could reduce the load quite a bit by reducing the number of updates by either updating the variables after the party changed items, or right before the variables are actually used.

    When eventing, this would probably come with the downside that you'd need additional update calls throughout all your events. If you wanted to update your variables whenever your parties inventory may have changed for example, you'd have to perform a manual update after every battle, "Shop Processing" and "Gain Item", assuming the items cannot also be used from the menu.
    When scripting, one main advantage is that you can modify such processes to do that stuff automatically, without you having to look through all your events and expand them.

    So you could add your new method for example to "update" from Scene_Map in order to update your variables with every frame while you are on the map screen. You also could add it to Game_Party#gain_item in order to update every time the party gains (or loses) an item.



    You can replace an existing method by defining it again in your script. The latest definition of a method takes precedence. If possible, those replacements should be done using alias:
    Code:
    class Game_Party
     
      # This creates a copy of the current version of this method under the
      # new name. This way, other changes to the method are not lost
      alias_method(:new_unique_name_for_gain_item, :gain_item)
    
      # Replace the previous definition of this method to add custom stuff to it
      def gain_item(item, amount, include_equip = false)
        # Execute the previous content of gain_item
        new_unique_name_for_gain_item(item, amount, include_equip)
        # ... and add custom stuff to it
        Whatever.set_variable_to_item
      end
    
    end
    This can be further optimized by only updating the item in question of course, but I hope it brings the idea across somehow. :)


    @Bex: Yeah, that was a pity. Can see if I find the script again tomorrow (edit: well, tomorrow tomorrow), although PK8 has also made a way more extensive Self Data script you might be interested in:
    https://forums.rpgmakerweb.com/inde...-data-suite-support-thread.42500/#post-895425

    Edit: Fixed a paragraph
     
    Last edited: Jul 15, 2019 at 5:20 AM
    #6
  7. TheoAllen

    TheoAllen Self-proclaimed jack of all trades Veteran

    Messages:
    4,145
    Likes Received:
    4,578
    Location:
    Riftverse
    First Language:
    Indonesian
    Primarily Uses:
    RMVXA
    Just a heads up: changing the value of Game_Variables with turn refresh flag to ON, so even if you're making "parallel process" out of the script, it will still lag because the game will constantly check the game event. Another Fen's suggestion to add your own method in Game_Party#gain_item may do the trick, but personally, if you just want to make a certain variable to always return a number of item, you could just force it

    For example, I'd do this instead
    Code:
    class Game_Variables
      alias :force_return :[]
      def [](id)
        case id
        when 1,2,3,4,5,6
          return $game_party.item_number($data_items[id])
        else
          return force_return(id)
        end
      end
    end
     
    #7
    A-Moonless-Night likes this.

Share This Page