[XP] Calling specific item IDs and targets in Scene_Item

Discussion in 'RGSSx Script Support' started by Tehprince, Nov 14, 2017.

  1. Tehprince

    Tehprince Someone

    Messages:
    56
    Likes Received:
    5
    Location:
    Somewhere
    First Language:
    English
    Primarily Uses:
    RMXP
    I've been working for a while on making an item that modifies a character's number of skill points, realized it can't be done with events, and moved on to looking at the base script library.

    From what I can tell, Scene_Item is where the scope and target(s) of an item are defined. I am unsure as to how exactly,

    Code:
    target = $game_party.actors[@target_window.index]
    works. (This particular line is under #If single target) I think that line is defining the actor that will be the target of an item by checking which actor is being highlighted in the target window.

    Is there a way that I can first specify the ID of one particular item, (The item that will increase skill points, which happens to be 32 in my case) and then use,

    Code:
    target = $game_party.actors[@target_window.index]
    to return the ID of the target actor, so that I can make something like this?

    Code:
    if target = 1
    # Actor 1 receives a skill point
    if target = 2
    # Actor 2 receives a skill point
     
    #1
  2. BoisterousHero

    BoisterousHero RMXP Fiend

    Messages:
    29
    Likes Received:
    18
    First Language:
    English
    Primarily Uses:
    RMXP
    Hey, I am happy to hear you made it this far! Sorry I never got back to you--I've been incredibly busy.

    http://www.creationasylum.net/index.php?showforum=82 This might help a bit, it explains a lot of stuff that I talk about. You'll definitely need to understand how ruby methods (they're called functions in other programming languages) work.

    This is exactly where I was going to suggest having a look. So for that section,
    "target = $game_party.actors[@target_window.index]" determines which actor is the "target" based on the the Target Window's (the window that pops up and displays all the characters in the item menu) index.
    The "index" is more simply the list number. It starts at 1. So the first item in the list has an index of 1. The second item, an index of 2...etc.

    Here's the thing. "target" does not equal 1, 2, 3. It is equal to the actor, which is an array of values. For instance, if we look at:
    $game_party.actors[1]. This is going to be our first actor in the game, Aluxes and all of his associated variables. It actually looks something like this:
    Code:
    $game_party.actors[1] = [1, "Aluxus", 1, 200, 300, ...] 
    Where each value would be [ID, name, level, hp, sp...]

    So you need to use the built in "id" method. I discussed this in the previous post, and it's described in detail in the link I gave above. $game_party.actors[1].id would give us the value "1". Just like $game_party.actors[1].name would give us "Aluxus", $game_party.actors[1].hp would give us "200", etc.

    Now on to what you want to do. You can use "target" to return the ID of the actor, by using if "target == target.id", but this isn't very good logic. Using a "case" to check each ID number is much better.

    Looking at this snippet here:
    Code:
    # If single target
          if @target_window.index >= 0
            # Apply item use effects to target actor
            target = $game_party.actors[@target_window.index]
            used = target.item_effect(@item)
          end
    You could put in a method that checks each time you use an item whether or not the item used was a special skill point item. Maybe something like this?:
    EDIT: Might be better (or necessary) to define the actor ID and item ID variables, before passing it to your method.

    Code:
    # If single target
          if @target_window.index >= 0
            # Apply item use effects to target actor
            target = $game_party.actors[@target_window.index]
           # Check if item being used is a skill points item
           # Define local variables
           item_id = @item.id
           actor_id = target.id
           if @item.id == #you would put the ID of the item that gives your actor skill points here
                 #Call the skill points method, providing it with the actor ID and the item ID, then do something with those values
                  give_skill_points(actor_id, item_id)
           end #end if
            used = target.item_effect(@item)
          end
    Then, somewhere else in your new Scene_Item script, you would put a method definition that takes the actor ID and the item ID you gave it, and does something special. I assume you want the flexibility of different skill point items giving different amounts of skill points, and maybe different actors get different amounts from those items? I'm not sure, but you could do something like this:
    Code:
    def get_skill_points(actor_id, item_id)
        #Check the item ID
        case item_ID
             #When the item ID is 1...
        when 1
             SP_Given = 10
        when 2
             SP_Given = 20
        else
             #exception handling
        end
    
        #Then do something with the actor
        case actor_id
        when 1
             #give actor 1 skill points, maybe based on the item ID?
        when 2
             #give actor 2 skill points
        else
             #exception handling
        end
    end
    Hopefully this gets you going in the right direction. It's not expert work, there may be a better way to do it, but hopefully this helps. Someone more experienced can correct me!
     
    Last edited: Nov 14, 2017
    #2
  3. Tehprince

    Tehprince Someone

    Messages:
    56
    Likes Received:
    5
    Location:
    Somewhere
    First Language:
    English
    Primarily Uses:
    RMXP
    Thanks for the continued support. With this, I finally got the item to work correctly!

    I have absolutely no idea why it works, but it works.

    Code:
    # If single target
          if @target_window.index >= 0
            # Apply item use effects to target actor
            target = $game_party.actors[@target_window.index]
           # Check if item being used is a skill points item
           # Define local variables
           item_id = @item.id
           actor_id = target.id
          def get_skill_points(actor_id, item_id)
        #Check the item ID
        case item_id
             #When the item ID is 1...
        when 1
             $game_actors[actor_id].skill_points += 1
        when 2
             $game_actors[actor_id].skill_points += 1
        when 3
          $game_actors[actor_id].skill_points += 1
        when 4
          $game_actors[actor_id].skill_points += 1
          else
             #exception handling
        end
    
        #Then do something with the actor
        case actor_id
        when 1
             $game_actors[1].skill_points += 1
        when 2
             $game_actors[2].skill_points += 1
        when 3
             $game_actors[3].skill_points += 1
       when 4
             $game_actors[4].skill_points += 1
             else
             #exception handling
        end
    end
          
           if @item.id == 32#you would put the ID of the item that gives your actor skill points here
                 #Call the skill points method, providing it with the actor ID and the item ID, then do something with those values
                  get_skill_points(actor_id, item_id)
           end #end if
            used = target.item_effect(@item)
          end
          
    It took a bit of trial and error, but this is what I ended up with. I kind of thought that the item_id case was supposed to be related to the database value of the item, but when I tried messing with it, it stopped working. In any case, it works now, and it works as intended. Thanks again for the help.
     
    #3
  4. BoisterousHero

    BoisterousHero RMXP Fiend

    Messages:
    29
    Likes Received:
    18
    First Language:
    English
    Primarily Uses:
    RMXP
    You're welcome! Here are some comments to help you sort out why it works. I reorganized it a bit for you.

    I think you would want to put the "get_skill_points" method at the bottom of your script, for organizational purposes. "def" means "definition" and it is what the script looks for and runs when we type "get_skill_points". It will still be called by the script happily even if it isn't right next to it. I assume you edited the Scene_Item class directly, but it is much better practice to have it at the bottom instead. Try adding this in as a separate script at the bottom; it re-writes the Scene_Item class and makes sure the original stays in-tact.

    I added the item_id so you can have more than 1 item that gives a different amount of base SP. So for instance, item ID 32 might give 1 SP, but item ID 55 might give 2 SP!

    You could then further edit each actor to respond differently in the definition below. If you wanted Aluxus to be special, and get 5x the amount of SP from the item, you could make that line "$game_actors[1].skill_points += SP_Amount * 5"

    There is a lot of flexibility when you figure out RGSS!

    Here you go:
    Code:
    #==============================================================================
    # ** Scene_Item
    #------------------------------------------------------------------------------
    #  This includes a modified "update_target" method that handles
    #  special skill point items.
    #==============================================================================
    
      #--------------------------------------------------------------------------
      # * Frame Update (when target window is active)
      #--------------------------------------------------------------------------
      def update_target
        # If B button was pressed
        if Input.trigger?(Input::B)
          # Play cancel SE
          $game_system.se_play($data_system.cancel_se)
          # If unable to use because items ran out
          unless $game_party.item_can_use?(@item.id)
            # Remake item window contents
            @item_window.refresh
          end
          # Erase target window
          @item_window.active = true
          @target_window.visible = false
          @target_window.active = false
          return
        end
        # If C button was pressed
        if Input.trigger?(Input::C)
          # If items are used up
          if $game_party.item_number(@item.id) == 0
            # Play buzzer SE
            $game_system.se_play($data_system.buzzer_se)
            return
          end
          # If target is all
          if @target_window.index == -1
            # Apply item effects to entire party
            used = false
            for i in $game_party.actors
              used |= i.item_effect(@item)
            end
          end
          # If single target
          if @target_window.index >= 0
            # Apply item use effects to target actor
            target = $game_party.actors[@target_window.index]
            # Define local variables
            item_id = @item.id
            actor_id = target.id
            # Check if item being used is a skill points item
            if @item.id == 32 #you would put the ID of the item that gives your actor skill points here.
                 #You could add more with "or", like this: if @item.id == 32 or 22 or 53
                 #Call the skill points method, providing it with the actor ID and the item ID, then do something with those values
                 get_skill_points(actor_id, item_id)
            end #end if
            used = target.item_effect(@item) #Use up the item and remove it from inventory
          end
         
          end
          # If an item was used
          if used
            # Play item use SE
            $game_system.se_play(@item.menu_se)
            # If consumable
            if @item.consumable
              # Decrease used items by 1
              $game_party.lose_item(@item.id, 1)
              # Redraw item window item
              @item_window.draw_item(@item_window.index)
            end
            # Remake target window contents
            @target_window.refresh
            # If all party members are dead
            if $game_party.all_dead?
              # Switch to game over screen
              $scene = Scene_Gameover.new
              return
            end
            # If common event ID is valid
            if @item.common_event_id > 0
              # Common event call reservation
              $game_temp.common_event_id = @item.common_event_id
              # Switch to map screen
              $scene = Scene_Map.new
              return
            end
          end
          # If item wasn't used
          unless used
            # Play buzzer SE
            $game_system.se_play($data_system.buzzer_se)
          end
          return
        end
    
      #--------------------------------------------------------------------------
      # * Frame Update (when target window is active)
      #--------------------------------------------------------------------------
      def get_skill_points(actor_id, item_id)
          #Check the item ID
        case item_id
             #When the item ID is 32...
        when 32
             #Set the variable "SP_Amount" to 1
             SP_Amount = 1
        when 55
             SP_Amount = 2
        else
             #If it is another item ID not specified
             SP_Amount = 1
        end
    
        #Check the actor ID
        case actor_id
        #When it is the first actor
        when 1
            #Give the first actor the amount of skill points based on the item ID above
             $game_actors[1].skill_points += SP_Amount
        #When it is the second actor...
        when 2
             $game_actors[2].skill_points += SP_Amount
        when 3
             $game_actors[3].skill_points += SP_Amount
        when 4
             $game_actors[4].skill_points += SP_Amount
        #If it is an actor not specified
        else
            #Do nothing
        end
      end #get_skill_points
     
     end #Scene_Item
    Note that if you have another script that modifies "Scene_Item", like a menu script or something, you may want to put this below it.
     
    Last edited: Nov 15, 2017
    #4
  5. Tehprince

    Tehprince Someone

    Messages:
    56
    Likes Received:
    5
    Location:
    Somewhere
    First Language:
    English
    Primarily Uses:
    RMXP
    That's much more organized than what I have, and would probably work better.

    I modified a small portion of the script, just to have the item ID define a game variable, because apparently it didn't like the "SP_Amount" variable.

    Code:
     def get_skill_points(actor_id, item_id)
          #Check the item ID
        case item_id
             #When the item ID is 32...
        when 31
             #Set the variable "SP_Amount" to 1
             $game_variables[8] = 1
        when 32
             $game_variables[8] = 2
        else
             #If it is another item ID not specified
             $game_variables[8] = 0
        end
    
        #Check the actor ID
        case actor_id
        #When it is the first actor
        when 1
            #Give the first actor the amount of skill points based on the item ID above
             $game_actors[1].skill_points += $game_variables[8]
        #When it is the second actor...
        when 2
             $game_actors[2].skill_points += $game_variables[8]
        when 3
             $game_actors[3].skill_points += $game_variables[8]
        when 4
             $game_actors[4].skill_points += $game_variables[8]
        #If it is an actor not specified
        else
            #Do nothing
        end
      end #get_skill_points
    
      end #Scene_Item
    That's the only section I touched, but for some reason, the script crashes on startup saying, "line 434: SyntaxError occurred."
    That particular line is the final, "end" which is supposed to be ending, "Scene_Item." I tried removing it, and the game started fine, but then the skill point item didn't do anything.

    I tried using a new game, starting in a test area, I tried moving the script to main, or scene_debug, but neither did anything. The script looks solid, so my guess is that there might just be a typo somewhere.
     
    #5
  6. BoisterousHero

    BoisterousHero RMXP Fiend

    Messages:
    29
    Likes Received:
    18
    First Language:
    English
    Primarily Uses:
    RMXP
    Wew. Forgot to define the scene_item class. I thought I did but I didn't.
    "class Scene_Item" needs to be added to the top, that's all.

    Here is how it should be:
    Code:
    #==============================================================================
    # ** Scene_Item
    #------------------------------------------------------------------------------
    #  This includes a modified "update_target" method that handles
    #  special skill point items.
    #==============================================================================
    class Scene_Item
      #--------------------------------------------------------------------------
      # * Frame Update (when target window is active)
      #--------------------------------------------------------------------------
      def update_target
        # If B button was pressed
        if Input.trigger?(Input::B)
          # Play cancel SE
          $game_system.se_play($data_system.cancel_se)
          # If unable to use because items ran out
          unless $game_party.item_can_use?(@item.id)
            # Remake item window contents
            @item_window.refresh
          end
          # Erase target window
          @item_window.active = true
          @target_window.visible = false
          @target_window.active = false
          return
        end
        # If C button was pressed
        if Input.trigger?(Input::C)
          # If items are used up
          if $game_party.item_number(@item.id) == 0
            # Play buzzer SE
            $game_system.se_play($data_system.buzzer_se)
            return
          end
          # If target is all
          if @target_window.index == -1
            # Apply item effects to entire party
            used = false
            for i in $game_party.actors
              used |= i.item_effect(@item)
            end
          end
          # If single target
          if @target_window.index >= 0
            # Apply item use effects to target actor
            target = $game_party.actors[@target_window.index]
            # Define local variables
            item_id = @item.id
            actor_id = target.id
            # Check if item being used is a skill points item
            if @item.id == 32 #you would put the ID of the item that gives your actor skill points here.
                 #You could add more with "or", like this: if @item.id == 32 or 22 or 53
                 #Call the skill points method, providing it with the actor ID and the item ID, then do something with those values
                 get_skill_points(actor_id, item_id)
            end #end if
            used = target.item_effect(@item) #Use up the item and remove it from inventory
          end
        
          end
          # If an item was used
          if used
            # Play item use SE
            $game_system.se_play(@item.menu_se)
            # If consumable
            if @item.consumable
              # Decrease used items by 1
              $game_party.lose_item(@item.id, 1)
              # Redraw item window item
              @item_window.draw_item(@item_window.index)
            end
            # Remake target window contents
            @target_window.refresh
            # If all party members are dead
            if $game_party.all_dead?
              # Switch to game over screen
              $scene = Scene_Gameover.new
              return
            end
            # If common event ID is valid
            if @item.common_event_id > 0
              # Common event call reservation
              $game_temp.common_event_id = @item.common_event_id
              # Switch to map screen
              $scene = Scene_Map.new
              return
            end
          end
          # If item wasn't used
          unless used
            # Play buzzer SE
            $game_system.se_play($data_system.buzzer_se)
          end
          return
        end
    
      #--------------------------------------------------------------------------
      # * Frame Update (when target window is active)
      #--------------------------------------------------------------------------
     def get_skill_points(actor_id, item_id)
          #Check the item ID
        case item_id
             #When the item ID is 32...
        when 31
             #Set the variable "SP_Amount" to 1
             $game_variables[8] = 1
        when 32
             $game_variables[8] = 2
        else
             #If it is another item ID not specified
             $game_variables[8] = 0
        end
    
        #Check the actor ID
        case actor_id
        #When it is the first actor
        when 1
            #Give the first actor the amount of skill points based on the item ID above
             $game_actors[1].skill_points += $game_variables[8]
        #When it is the second actor...
        when 2
             $game_actors[2].skill_points += $game_variables[8]
        when 3
             $game_actors[3].skill_points += $game_variables[8]
        when 4
             $game_actors[4].skill_points += $game_variables[8]
        #If it is an actor not specified
        else
            #Do nothing
        end
      end #get_skill_points
    
      end #Scene_Item
    
     
    #6
  7. Tehprince

    Tehprince Someone

    Messages:
    56
    Likes Received:
    5
    Location:
    Somewhere
    First Language:
    English
    Primarily Uses:
    RMXP
    That fixed it. Thank you for all of your help.
     
    #7
  8. Sixth

    Sixth Veteran

    Messages:
    1,799
    Likes Received:
    627
    First Language:
    Hungarian
    Primarily Uses:
    RMVXA
    Using the item_effect(item) method on the battler object is a much more elegant solution, and it will make this work even in battles or in custom scripts (if there are some which forcibly uses a skill/item, for example).
    It is called on the target itself, so we have access to the target and item there too.

    Code:
    class Game_Battler
    
      alias add_new_eff5524 item_effect
      def item_effect(item)
        custom_sp_gain(item)
        add_new_eff5524(item)
      end
    
      def custom_sp_gain(item)
        case item
        when RPG::Item # For items
          case item.id # Item ID check here
          when 1; sp_val = 2
          when 2; sp_val = 4
          # And so on...
          else; sp_val = 0
          end
        when RPG::Skill # For skills
          case item.id # Skill ID check here
          when 1; sp_val = 3
          when 2; sp_val = 5
          # And so on...
          else; sp_val = 0
          end
        end
        case self
        when Game_Actor # For actors only
          case self.id # Actor ID check here
          when 1; self.skill_points += sp_val
          when 2; self.skill_points += sp_val * 2
          # And so on...
          end
        when Game_Enemy # For enemies only
          case self.id # Enemy ID check here
          when 1; self.skill_points += sp_val
          when 2; self.skill_points += sp_val * 2
          # And so on...
          end
        end
      end
    
    end

    Note that what I wrote is a pseudo-code only, I don't have XP, so I don't know if the classes are called the way I wrote them or not, I only guessed their name based on the class names from Ace.

    The code above also differentiates items and skills (since that method can get an item or skill for it's argument - again, if it works the same way as Ace), and actors and enemies as well.

    It is not necessary to strictly use local variables as arguments, btw.
    Here is how you should decide if it's worth to set an otherwise accessible non-local variable to a local one before doing something else with it:
    If you will use that variable multiple times in the same method, it might be worth to set it to a local variable.
    But if you only use it once, it is better to just use it as it is, unless it got a very long name, and you want to keep the maximum character width in your syntax layout/format constant.
     
    Last edited: Nov 15, 2017
    #8
  9. Tehprince

    Tehprince Someone

    Messages:
    56
    Likes Received:
    5
    Location:
    Somewhere
    First Language:
    English
    Primarily Uses:
    RMXP
    The only things that I think would need to be changed for XP are the, "RPG : : Skill" lines and maybe the "effect" pieces. I've never seen anything like it in XP before, (Bear in mind I'm not very experienced in coding) but the, "effect" portion might work.

    Thanks for the input.
     
    #9
  10. BoisterousHero

    BoisterousHero RMXP Fiend

    Messages:
    29
    Likes Received:
    18
    First Language:
    English
    Primarily Uses:
    RMXP
    Thank you for jumping in, I was worried my solution wasn't a very good one, I forgot all about item_effect.

    Ah-ha! I wasn't sure on this, either. Thanks for the clarification.


    @Tehprince I agree that what Sixth presented is a much better solution. "RPG::Skill" exists, it is a special class that is sort of built into the system, you would call it just like that. You can actually find more details by opening "Help" within RPG Maker XP.

    "item_effect(item)" is located in the "Game_Battler 3" script.
     
    #10
  11. Tehprince

    Tehprince Someone

    Messages:
    56
    Likes Received:
    5
    Location:
    Somewhere
    First Language:
    English
    Primarily Uses:
    RMXP
    I looked through the manual, and did find "RPG::Skill" there, in the Data Structure section.

    The script works, but I'm curious as to how you can use, "sp_val" without strictly defining it first. Does the, "val" part of it define a value, which is then named, "sp_val"? Also, I understand the regular, "effect" now, but what is the, "add_new_eff5524(item)" and what does it do?
     
    #11
  12. Sixth

    Sixth Veteran

    Messages:
    1,799
    Likes Received:
    627
    First Language:
    Hungarian
    Primarily Uses:
    RMVXA
    sp_val is just a local variable name. You can name your variables however you want. The value of that variable is set after the equal sign, and it's value can be anything as long as it is a correct syntax.
    Local variables don't need to be defined before you can use them. I know some other code languages require that you define their data type before actually setting their value, but in Ruby, that is not necessary.
    The confusion about this may be from thinking that sp_val is a method name. Well, it is not. Ruby will first check for any method defined with that name. If there isn't one, it will be treated as a local variable instead.
    If you have a method with the same name, and still use that name for a local variable which will store a new value, the local variable's value will be used over the method's value in the scope of that method definition. Kinda confusing, but if you never use the same name for a method and a local variable (and you really shouldn't), this can't even happen, so don't let this bother you much.

    The add_new_eff5524 is an alias method name. It saves the original method by defining a new method called add_new_eff5524 with the contents of the original method before the method modification, so you can modify the original method without overwriting it. You can than call this method with the alias method name you used. You can name your alias methods however you want, but you must never use the same name for more than one alias method in the same class, or else your game will crash (it will end up in an endless loop and break). This is why I always put 4 random numbers at the end, to prevent that from happening. It still has a chance of ending up with a used alias name, but that chance is so low, it can be ignored, especially because I rarely see anyone doing the same.
    In short, it's just a name I choose for the alias method. It could have been named any other way too. Point is, you have to use the same method name when you want to call the saved original method (like I did in the item_effect method).
    Ohh, and the alias method will have the same arguments like the original method.
    Another good thing to know is that you CAN call alias methods even in other methods, not just in the original method you aliased.

    I understand the confusion about these, I was there too when I started coding. :D
     
    #12

Share This Page