Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

[Resolved] Adding RPG::Weapon attributes

Status
Not open for further replies.

khmp

Sponsor

I'm having trouble adding an attribute to 'class RPG::Weapon'. I'm not using any other scripts but I can't seem to add a class variable to the class previously mentioned. So I guess its time to see the code:

Code:
class RPG::Weapon
  RARITY_LEVELS = [1,2,3]
  DEFAULT_RARITY = 0
  
  attr_accessor :n_rarity
  
  alias old_initialize initialize
  def initialize
    # Extra stuff added to the Weapon class.
    @n_rarity = RARITY_LEVELS[DEFAULT_RARITY] # The rarity level of the weapon.
    print("I acknowledge weapon has an initialize")
    old_initialize
  end
end

class Database_Init
  def alter_attr_weapons
    for i in $data_weapons
      i.n_rarity = rand(3) + 1
    end
  end
end

This script is located above main and below everything else. In Scene_Title right after all the database entries are loaded or I assume are loaded I create a Database_Init class and call alter_attr_weapons. Immediately it crashes the first time it encounters 'i.n_rarity = rand(3) + 1' claiming n_rarity is nil. Well I guess so since the 'RPG::Weapon's initialize was never encountered.

1.) So right off the bat does $data_weapons represent an array of 'RPG::Weapon's?
2.) Does the variable the accessor represents require declaration within the class? You just can't have the accessor you need the @variable somewhere in the functionality of the class?':|

I hope someone can help with this because I'm straining my tiny head for answers. And no misspellings this time I think.;)
 
Your problem is that initialize is never actually called. Whenever you press save, it checks the data in the database and writes everything before the script editor is even opened.

Try something like this:

Code:
class RPG::Weapon
  RARITY_LEVELS = {}
  RARITY_LEVELS.default = 0
  def n_rarity
    return RARITY_LEVELS[@id]
  end
end

Now, you can't actually modify instances of specific weapons (everything dealing with weapons is just referencing to a single data object and there aren't objects ever contained anywhere).

However, if you are wanting to modify all weapon 3's rarity, it would not save from 1 savefile to the next. So you would need something to save this. You can use this, as it does this for you. Let me know if you need any help with that.

If you use that, you can have this:
Code:
class RPG::Weapon
  RARITY_LEVELS = {}
  RARITY_LEVELS.default = 0
  attr_accessor :n_rarity
  def n_rarity
    return @n_rarity.nil ? RARITY_LEVELS[@id] : @n_rarity
  end
end

Now, you can use
Code:
$data_weapons[weapon_id].n_rarity = blah

Of course, it will need to be slightly different using the Virtual Database system.



@exclude: If you don't know, don't ask. This is the second time I have seen you giving out false information. Please, only give out information if you know the actual answer.

class RPG::Weapon is the same as what you put. It's all how you prefer.
 

khmp

Sponsor

@germen: Thanks I gave the script the once over and it doesn't look like what I needed. Thanks though I appreciate you trying to help ^_^

@exclude: Using the scope resolution operator '::' eliminates the need to separate module from the class. Although I will admit that I did try that after my way failed to work thinking RGSS had another quark about syntax. :)

@SephirothSpawn:
...(everything dealing with weapons is just referencing to a single data object and there aren't objects ever contained anywhere).
Does this mean the global $data_weapons does not point to an array of database entries in the weapon section, sword1 at index 0 and sword2 at index 1 after $data_weapons = load_data("Data/Weapons.rxdata")? Just as an example.

I'll take your word for it. I'm just having trouble accepting the database can't be edited on the fly without an intermediary. I guess it'll take time and I'll understand eventually. I will use your awesome the virtual database script since that looked like it allowed such modification.:D

Not be a bother but adding an attribute or functionality to any or all weapons how is that done using the virtual database. I see it has the ability to edit pre-existing attributes but no instructions to add. Like if I wanted the ability for an weapon be alchemized with another item so I make a 'def alchemize' function, how would it be added. Does the code I have posted in the very first spot become active or what? Sorry for asking so many questions.
 
Does this mean the global $data_weapons does not point to an array of database entries in the weapon section, sword1 at index 0 and sword2 at index 1 after $data_weapons = load_data("Data/Weapons.rxdata")? Just as an example.

What I mean in like Game_Actor, it contains @weapon_id, not weapon. The same is found true in armors, skills, common events, etc. What I was saying is that the database saves everything you create to your .rxdata files before you open the game (when you press Save in the game editor). You can auto-set your instance variables with something like this:

Code:
class RPG::Weapon
  N_Rarity = {}
  N_Rarity.default = 0
  attr_accessor :n_rarity
  def n_rarity_setup
    @n_rarity = N_Rarity[@id]
  end
end

class Scene_Title
  alias_method :sephkhmp_weaponnrares_scnttl_cng, :command_new_game
  def command_new_game
    for weapon in $data_weapons
      next if weapon.nil?
      weapon.n_rarity_setup
    end
    sephkhmp_weaponnrares_scnttl_cng
  end
end

Now, once your game is started, it auto-sets your instance variables. I personally don't like this, as it takes time to run those methods, but also creates an instance in those objects, which takes memory (both don't really matter. Ruby was made for power not speed).

Anyways, if you want to do something like the above method, using the virtual database, if you wanted to change the weapons n_rarity and have it save, you can use:

Code:
object = $game_virtualdb.data_weapon(weapon_id)
object.n_rarity = n
objects = $game_virtualdb.data_weapons
objects[weapon_id] = object
$game_virtualdb.data_weapons = objects

Something like that does the trick with the above code.




So, here's your two options:

A)
Code:
class RPG::Weapon
  RARITY_LEVELS = {}
  RARITY_LEVELS.default = 0
  attr_accessor :n_rarity
  def n_rarity
    return @n_rarity.nil ? RARITY_LEVELS[@id] : @n_rarity
  end
end

B)
Code:
class RPG::Weapon
  N_Rarity = {}
  N_Rarity.default = 0
  attr_accessor :n_rarity
  def n_rarity_setup
    @n_rarity = N_Rarity[@id]
  end
end

class Scene_Title
  alias_method :sephkhmp_weaponnrares_scnttl_cng, :command_new_game
  def command_new_game
    for weapon in $data_weapons
      next if weapon.nil?
      weapon.n_rarity_setup
    end
    sephkhmp_weaponnrares_scnttl_cng
  end
end

Both work essentially the same, but A doesn't create the instances unless it has to and instead relies directly on the constant setup (which I didn't explain. Let me know if I need to).



Either way you choose, using the virtual database script, using the call script I should you will allow to change the rarities from one save to another.


Let me know if anything is unclear.
 

khmp

Sponsor

Thanks for taking the time to clear up the database thing. One last thing and then I think that should be it... should. Anyway just tell me if the following will work.

Code:
class Scene_Title
  RARITY_WEAPONS = 1..30

  alias_method old_cmd command_new_game

  def command_new_game
    weapons = []
    n_index = 0
    loop do
      weapon = $game_virtualdb.data_weapon(n_index)
      weapon.n_rarity = RARITY_WEAPONS[n_index]
      weapons.push(weapon)
      n_index += 1
      break if n_index == $game_virtualdb.data_weapon.size || n_index == RARITY_WEAPONS.size
    end
    $game_virtualdb.data_weapons = weapons
    old_cmd
  end
end

Just figure I'd ask before I put in the SDK and your script in and learn the harsh reality of why I should have used alias'ing early on.
 
Without coding, just explain to me exactly what you are trying to do. Then we can go from there. I think you are trying to do something things you don't need to do. If you are wanting to give weapons new attributes, you are going about it the hard way.

Just tell me exactly what we are trying to accomplish here.
 

khmp

Sponsor

S'alright sorry about that. What I am trying to do is add a rarity factor to a weapon. And possibly other attributes but I figured once one was done the rest would be "ctrl-c ctrl-v". So to sum up what is the easiest way about adding a rarity attribute to a weapon, and I want the ability to change this rarity variable if necessary after its initial initialization.

$RARITY_LEVELS = [1,2,3,4,5]
End result. In code or call script be able to do this:

weapon.rarity = $RARITY_LEVELS[0]
or
weapon.rarity = $RARITY_LEVELS[3]
etc.
 
Ok. Instead of going through all that mumbo jumbo, let me show you something.

This is the number A method I showed you from above (I changed attr_accessor to writer, as that's all you need for this part).

Code:
class RPG::Weapon
  RARITY_LEVELS = {}
  RARITY_LEVELS.default = 0
  attr_writer :n_rarity
  def n_rarity
    return @n_rarity.nil ? RARITY_LEVELS[@id] : @n_rarity
  end
end

Now, there's a few important things to see here.

Code:
  RARITY_LEVELS = {}
  RARITY_LEVELS.default = 0

Ok. This constant right here is going to hold your initial weapon rarity levels. Think of this as an expansion of your database, just all script.

Instead of an array, where you have to define a giant list of numbers, here, you have the option of settings defaults, so you only have to define x weapons, instead of them all. It's just easier to manage in my opinion on adding attributes (trust me. 2 years exp doing this now lol).

So, "RARITY_LEVELS.default = 0" is the line that defines the default for all weapon rarities not defined in the line above it. The line above it, you have RARITY_LEVELS = { weapon_id => rarity, weapon_id => rarity, ... } for all your weapons you want. To make things a little easier, we can use functions to set these for us.

Code:
RARITY_LEVELS = {}
  # weapons 2, 6, 10 & 15 have rarity of 1
  for n in [2, 6, 10, 14]
    RARITY_LEVELS[n] = 1
  end
  # weapons 3, 7, 11 & 16 have rarity of 2
  for n in [3, 7, 11, 15]
    RARITY_LEVELS[n] = 2
  end
  for n in [4, 8, 12, 16]
    RARITY_LEVELS[n] = 3
  end
  for n in [5, 9, 13, 17]
    RARITY_LEVELS[n] = 4
  end

Ok. Now the next line:
Code:
  attr_writer :n_rarity

This will allow us to to alter our @n_rarity instance to our object. By default, this is nil, and we don't need to define it at all. We are only using attr_writer, because instead of the basic return the exact instance, we are making something a little trickier.

Code:
  # Instead of
  def n_rarity
    return @n_rarity
  end
  # we have
  def n_rarity
    return @n_rarity.nil ? RARITY_LEVELS[@id] : @n_rarity
  end

As I said, with this method, we don't have to set our @n_rarity instance if we don't want to. If we don't set it, it uses our constant setting. If we do set it, it then returns our instance.

As I said above, this prevents us from having to have a method run to set the method, and defining the instance, saving memory (again, not major, but a good coding practice).


So in all honesty, if you wanted to add a rarity value to your weapons, you need only to add that code at the top. Then, with use of the Virtual Database, you can change a weapons rarity and have it carryover from one savefile to the next. No need to ever alias the command new game method, no need for that complex loop function or any of that. Just 1 method to return the rarity value, specified or running off a constant setup. Simple right?

Just let me know if anything is unclear.
 

khmp

Sponsor

Only one question and I think I'm done. Where would you go about placing that initializing code for the RARITY_LEVELS hash? You know those for loops setting the indexes.

Code:
for n in [2, 6, 10, 14]
  RARITY_LEVELS[n] = 1
end
# weapons 3, 7, 11 & 16 have rarity of 2
for n in [3, 7, 11, 15]
  RARITY_LEVELS[n] = 2
end
for n in [4, 8, 12, 16]
  RARITY_LEVELS[n] = 3
end
for n in [5, 9, 13, 17]
  RARITY_LEVELS[n] = 4
end

Must it go inside class RPG::Weapon initialize?
 
Nope. It's a constant. Above when I said that you cannot add to the initialize method. That is true, however, any other methods can be modified as you wish. Constants are initialized when the game is opened. What I gave you is all you need. Just have all those weapon rarities set directly below the Constant creation.
 
You are welcome. If you need anything else, don't hesitate to ask. :D


This topic has been resolved. If khmp or any other users have any questions or further problems regarding this topic, please create a new thread about them.

Thank you!
 
Status
Not open for further replies.

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top