Polraudio 122 Report post Posted April 13, 2011 This is sort of a script request at the same time a tutorial request. Can someone make a tutorial/script that will allow me to add more attributes to an actor? I want to add an attribute called "Pts" to every actor and have it show on the status menu. I also need a way to manually add points to other actors. If its not to much trouble i would like to know how to add points to the actors after battle. Thanks in advance. :biggrin_002: Share this post Link to post Share on other sites
kellessdee 48 Report post Posted April 13, 2011 (edited) Sure man :) it will be a mini-tutorial but it isn't too difficult! And there is a couple of ways to do this. If you open up the script editor, and go to the script "Game_Actor." Game_Actor is the basic class for all actors, if you look through it you will find all the info (name, hp, sp, skills, etc) that an actor has. If you want to add an attribute, go to the "setup" method. This method is called when an actor is created. I am not sure why enterbrain didn't just put all this in the initialize method (as if you look in the initialize method it simply takes the actor_id, then passes it to setup. Kinda inefficient to just use a method to call another method when the original method doesn't really do anything :/) Anyways, you simply have to add a variable points or whatever you want to call it to this section and initialize it to whatever you want it to start off at. But you must make sure this is an instance variable, so it can be used anywhere within the actor class. ex. @points = 0 now whenever an actor is created, it will have a variable that is called points. The next step is to make it accessible by other scripts, to do this you must declare it as an attribute. If you look at the area before initialize, commented as Public instance Variables (which is just a fancier term for attributes) you will see how to do this. If you look there, you see attr_reader :variable_name for every attribute that can be called outside the script. In case you were wondering, there are three different types of attr (or attribute) declaractions: attr_reader - this sets the attribute as read only attr_writer - this sets the attribute as write only attr_accessor - this sets the attribute a read and write. then you need to simply put the name of the variable beside it but instead of an @ symbol, you need a colon ':'. ex. attr_reader :points now points can be called by "$game_party.actors[x].points" (if you noticed, game_party holds the game_actors class which is an array of game_actor classes. game_party is initialized in the $game_party variable, so it can be called anywhere in your game) Right now points is only read only. So at this point there are 2 things you can do, either change that to attr_accessor or define a method that will change the number of points (attr_reader is equal to saying def points return @points end) (attr_writer is like saying def points=(points) @points = points end) (attr_accessor is like defining both those methods) So whether or not you wish to declare it as accessor or write a method would depend strictly on whether you wish to associate any other code with gaining points...for example, if you look at the exp=(exp) method, you will see instead of just adding exp, it makes sure you can't go over the max, and checks if you level up as well (yes, you can mess around with max values here, just be aware you won't be able to change the max within the database however) NOTE: You do not have to name the method as points, it can be called whatever you want. If you want, you can call it gain_points or change_points. And the '=' in variable=(var) is only needed if you want to be able to call the method as $game_party.actors[x].points = number without declaring it as an accessor... you could say def gain_points(points) @points += points end then call it as $game_party.actors[x].gain_points(number) and then it will simply add the number to points...it all depends how you prefer to do this, as it all can achieve the same effect :) So, if points has either a max value or something you may want to define a method that doesn't allow points to go over that max amount or if there is any other kind of checks (like if you don't want it to ever dip below 0) it would be better to define a method, and leave it as "attr_reader" (it will need to be able to be read, in order to display it in the status menu) Next, to display it in the status menu, you will first need to (well, you don't NEED to do this step, however it will make drawing it in the menu much easier and as well as allow you to draw it in any other window, just in case) switch to the Window_Base class. If you look near the bottom, you will already see a lot of methods that draw actor attributes. You will need to make something like this, so essentially define a method that takes an x, y and actor as parameters, and get it to draw the points. to draw the points, you probably will want to draw the word "Points" then the actual value, that way the player knows what that number means. ex def draw_actor_points(x, y, actor) self.contents.draw_text(x, y, width, 32, 'Points: ') self.contents.draw_text(x + width, y, width, 32, actor.points.to_s, 2) end # Set width to however wide of a space you need to draw the points. if you can't decide on a good width, # either experiment or for a sure fire way you can use self.contents.text_size('Points: ').width # it is a method that bitmap classes have, where you can get the size of any string..you can also call height # the height of the space for the text is usually 32, because rmxp always uses this number for line row height # so just to keep it consistent. i had to call actor.points.to_s to convert it into a string, as trying to draw # a number will give you an error. I also right justified it (2) so it looks lined up, however this is not necessary # its just personal preference. once you have created a method that draws the amount of points in a window, simply head over to your Window_Status script. Within that script there are a bunch of calls for drawing different character attributes, so simply put in "draw_actor_points(x, y, actor)" x being whatever x coordinate you want and y being whatever you want. (Note: if you are using the menu I made for you, my script uses several Window_Status_... scripts, so find whichever window you wish to draw this on, and call that method. You can simply pass actor as the actor parameter since the status window takes the actor as a parameter, so just pass it on to the draw_actor_points method.) And presto! You have now added points attribute to the actors, and the status menu will display them! Hope this helps! Also, I can still explain how to add points after battle, but it may be different depending on: whether it is a fixed number, or if it depends on the enemies...and depending if you made the points as "attr_accessor" or if you defined a method to change points. Let me know and I will add the steps to adding points after battle :) Edited April 13, 2011 by kellessdee Share this post Link to post Share on other sites
joman195 9 Report post Posted April 13, 2011 I am using this to make a new attribute and I was wondering how I make them gain that attribute after they level up. Share this post Link to post Share on other sites
Polraudio 122 Report post Posted April 13, 2011 Works perfectly. I now learned how to add my own attributes. Thank you very much :biggrin_002: . As for battle i would like it to depend on how much HP you have left. EX: Actor 1 has 1%-25% Hp left so he gets 1 point. Actor 2 has 26%-50% Hp left so he gets 2 points 0 points = KO 1 points = 1%-25% 2 points = 26%-50% 3 points = 51%-75% 4 points = 76%-100% At then end of assigning points it will add all the points up that the actors gained and add it to a variable. Im using the attr_accessor method. Share this post Link to post Share on other sites
kellessdee 48 Report post Posted April 13, 2011 There's a few way to do that as well. If I understand correctly you want the attribute to increase after each level? like strength would? Well, you could either A) Make a module (which is basically an object in ruby that doesn't need to be initialized or created and works great for storing constants) And in the constant create an array, that has 100 elements, and each element would correspond to a level (1 - 99) module Stats_List ATTRIBUTE = [0, 10, 25, 35, ...] # the first element is 0 because level 0 does not exist end To use this, in the class Game_Actor, find the def level=(level) method, this handles leveling up, and just before end, put @attribute = Stats_List::ATTRIBUTE[level] Stats_List::ATTRIBUTE[level] tells ruby to look for a module called stats_list, find the constant ATTRIBUTE and take value at element "level" (which is the actor's new level). This is essentially how rmxp works for strength and other stats, there is a list of values for each corresponding level. Now however, that could be tedious. B) if the amount gained each level is constant, the same amount each time, then you can simply go into the level method and put @attribute += amount amount being however much it is increased each time, so when the character levels up, they gain the same amount. C) Very similar to B) except instead of adding the same value you could write some sort of algorithm that creates some kind of increase.. @attribute += amount * level + (@attribute - 10) not necessarily a very good algorithm to use (it may be, i haven't tested it..) but something a long the lines...its good to use level as an independant variable, to insure it increases at rate specific to level (you could also just do @attribute = amount * level, or something) or just make a formula that increases at a rate that works for you :) Hope this is what you were asking for :) Share this post Link to post Share on other sites
Polraudio 122 Report post Posted April 13, 2011 Actually i would like it after every battle. Share this post Link to post Share on other sites
kellessdee 48 Report post Posted April 13, 2011 SORRY POL, i didn't see your post after jomans! I think you posted as I was writing it up! I will post how to do what you want in a few minutes!! Share this post Link to post Share on other sites
Broken Messiah 20 Report post Posted April 13, 2011 Can I take it that this will also work in rmvx? :sweatdrop: Share this post Link to post Share on other sites
Polraudio 122 Report post Posted April 13, 2011 Can I take it that this will also work in rmvx? :sweatdrop: Yea. VX has the same classes and most of the same methods so you can. Share this post Link to post Share on other sites
kellessdee 48 Report post Posted April 13, 2011 Okay, so if I understand correctly, each player gains separate points, then the total amount of points are added to some sort of pool? And I am not sure if you wish to add it to a in-game variable or not, but I think thats what you mean if not you will probably want to create a new attribute for the Game_Party class. Any who, what you will need to do is make a loop that loops through each actor, figures out the points then adds them to a variable as well as the actors points attribute. The best kind of loop for this would be a for loop or an each loop. I will explain both (I prefer each loops, but essentially they are the exact same thing) Within the loop, you will need to calculate the current actors hp percentage, which is found by (current hp / max hp) * 100. However, if you have had experience with other programming languages (or maybe you know already because of ruby) when you divide 2 integers (or fixnum is what they are called in ruby) the end result is always an integer. Now this is bad because, if we do the math, 25 / 100 = 0.25 so multiply that by 100 and you get 25%. Good right? Well if you were to divide 25 / 100 (as integers) in ruby (well actually any programming language) you get 0. so 0 times 100 is? 0. Thats right. You will never get the percentage you want that way. so, what we can do is (since everything is an object, including integers in ruby) simply convert it into a float or floating point value ex (actor.hp / actor.maxhp.to_f) * 100 integer.to_f will convert any integer into a decimal value, or float then the next step is to decide which amount of points to assign. Most people would automatically jump to a bunch of if statements..which although would be correct and accomplish the same, I would like to show you an easier way (and one of the many reasons I LOVE ruby) you could easily use a case (or aka switch) statement! Now in most languages, for this to work, you would have to create a possibility for each value (1, 2, 3, 4, 5, etc) however with ruby's case statements, you can actually specify ranges! so, think of a for loop in ruby, for i in 0..3 that will loop from 0 to 3 inclusive (0, 1, 2, 3) and 0...3 would be (0, 1, 2) same rules apply so case percent when 1..25 actor.points+= 1 when 26..50 actor.points+= 2 when 51..75 actor.points+= 3 when 76..100 actor.points+= 4 end now, you will also have to add the total points gained by each actor. The easiest way would be to add the points within the case statement to the variable as well as to the actor's points. To call in-game variables (as you might know) you simply write $game_variables[x] = amount (all operators work with this too, such as +=, -= *=, etc) x being the variable number. so right after actor.points += amount, simply add $game_variables[x] += same_amount. so you just gotta take all that and put it in a for or each loop. The loop itself will need to go through each actor in the party, so for actor in $game_party.actors percent = (actor.hp / actor.maxhp.to_f) * 100 case percent when 1..25 actor.points+= 1 $game_variables[x]+= 1 when 26..50 actor.points+= 2 $game_variables[x]+= 2 when 51..75 actor.points+= 3 $game_variables[x]+= 3 when 76..100 actor.points+= 4 $game_variables[x]+= 4 end end just replace [x] with whichever variable you choose to put the number in. this just loops through every element of $game_party.actors, and stores the data in the temporary variable "actor" then we can directly manipulate that specific actor by adding the amounts NOTE: technically the way ruby works, is if make a variable = an instance of an object, such as an actor, that variable will actually temporarily POINT to that instance of the object, so any manipulations will directly affect the original object. If you simply want copy and object, you can use the dup method, ex. variable = object.dup here's an each loop if you were curious $game_party.actors.each {|actor| percent = (actor.hp / actor.maxhp.to_f) * 100 case percent when 1..25 actor.points+= 1 $game_variables[x]+= 1 when 26..50 actor.points+= 2 $game_variables[x]+= 2 when 51..75 actor.points+= 3 $game_variables[x]+= 3 when 76..100 actor.points+= 4 $game_variables[x]+= 4 end } it does the exact same thing, so in the end it is simply personal preference. Now, the most important step will be where to place this code. Where I would place it, is somewhere in a method at the end of the battle, probably where exp and gold is awarded to the player (so we know they have won the battle) I don't know if you are using the default battle system or not, but if you are just add it to the Start_Phase5 in Scene_Battle 2. If you are using a custom battle system, just look for where the exp is gained (well hopefully it is well documented so it's easy to find :D) Hope this helps! Share this post Link to post Share on other sites
Polraudio 122 Report post Posted April 13, 2011 Very nice. It works perfectly. Your good at teaching RGSS. Thank you for taking the time to teach me :lol: Share this post Link to post Share on other sites
kellessdee 48 Report post Posted April 13, 2011 Thank you! I appreciate your words :) I may have said it before but I really support anyone who wants to learn programming (well anything new for that matter) but I can actually help with this one! Plus I find if I take the time to explain something to someone, it helps reinforce the knowledge. so it's win-win really :) And I like to help where I can so I am glad it helped Share this post Link to post Share on other sites
joman195 9 Report post Posted April 14, 2011 I tried what you said but the luck value doesn't show up in the status menu.Here is what I did. Share this post Link to post Share on other sites
Polraudio 122 Report post Posted April 14, 2011 Odd. Here you can look at mine and compare. I marked changed scripts with a * before the name and listed what lines i added in the beginning of each script i edited. http://www.mediafire.com/?ffmh6w52ym2ry54 Share this post Link to post Share on other sites
joman195 9 Report post Posted April 14, 2011 Thanks I see what i did wrong. Share this post Link to post Share on other sites
kellessdee 48 Report post Posted April 15, 2011 Haha sorry joman I never saw that you had posted here but it sounds like you got it all straightened which is good :) thanks pol! Share this post Link to post Share on other sites