• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

RPG Custom Attribute System

Status
Not open for further replies.
Level 5
Joined
Feb 1, 2009
Messages
107
After asking for so many things and getting so many of my doubts solved, I decided to make a small contribution to the forum myself =P

This system is nearly completed. I don't have a map attachment for it yet, this is just an explanation of what I'm doing in my RPG and how do I do it.

Also feel free to suggest optimization changes and report any leaks/bugs/things that won't work, if they exist.

So, my system has 6 attributes: Attack Power, Defense, Stamina, Spellpower, Knowledge and Resistance.
All my RPG characters are normal units (not heroes), so they don't have the classic attributes (str/agi/int).

-Attack Power:
Kinda self-explanatory... Damage done by the character's normal attacks. This is done by using a Real Variable with array = to the namber of Players the map can support (in my case, 8).
Unfortunatly, there is no way that I know of to convert a variable into the damage property of the unit, so we have to calculate the damage using triggers. We must specify an event for our trigger when a unit takes damage, but there is no such event for generic units. So we must do a small Damage Detection with another trigger. Here is how it works:

  • Set Damage Detection
  • Events
  • Time - Elapsed game time is 0.01 seconds
  • Conditions
  • Actions
  • Unit Group - Pick every unit in (Units owned by Neutral Hostile) and do (Trigger - Add to Attack Power <gen> the event (Unit - (Picked unit) Takes damage))
  • Attack Power
  • Events
  • Conditions
  • (Damage taken) Less than or equal to 5.00
  • Actions
  • Unit - Cause Playerchar[(Player number of (Owner of (Damage source)))] to damage (Triggering unit), dealing attackvalue[(Player number of (Owner of (Damage source)))] damage of attack type Normal and damage type Normal
Variables:
"Playerchar" = Unit Variable which is set when the player selects his character.
"attackvalue" = Real Variable that represents the Attack Power attribute. You can do whatever you want after you input its value, like multiplying it by 10, or dividing, or even adding one more arithmetic calculation and adding some random values to add to the base damage.
Whenever a character acquires an item or ability that increases his Attack Power, there will be a trigger to "Set attackvalue[number of player]" to add whatever the item/ability gives.
It's recommended to set all damage caused by your characters to 1 in the object editor, so that when they attack they deal only the damage calculated in this trigger.

So, when an unit from Neutral Hostile takes damage, the second trigger will deal additional damage, based on our Attack Power variable, to that unit. Then you ask: "But this way, won't the unit take damage twice?". Well, yes, but that isn't a problem because, in this system, the base damage our characters do is always small, like 1 or 2, remember? So the first damage it takes is irrelevant. It's purpose is only to make the second trigger run.

The condition on the second trigger - (Damage taken) Less than or equal to 5.00 - makes it run only when the damage done comes from our characters, avoiding the trigger to enter an infinite loop.

-Defense
Value subtracted from the damage our characters would receive... Could be a raw value or a percentage. Like the attack power, we can't make the armor property of a unit the value of a variable, so here comes another trigger:

  • Defense
    • Events
      • Unit - A unit Is attacked
    • Conditions
      • (Triggering unit) Equal to Playerchar[(Player number of (Owner of (Triggering unit)))]
    • Actions
      • Unit - Set life of (Triggering unit) to ((Life of (Triggering unit)) - ((Damage taken) - (defensevalue[(Player number of (Owner of (Triggering unit)))] / 10.00)))
Variables:
Playerchar: We already know this one :D
defensevalue: Real Variable that represents the amount of damage prevented. Like the attack power, you can do many things with it, like dividing, making it a percentage, etc.
As with the Attack Power system, it's recommended to set the armor of your characters to 0 and make it "unarmored", so that the only damage prevented is the one expected by the defense value.

-Stamina and Knowledge
Those are the coolest attributes of the system :D. That's because we can actually change the HitPointsMaximum and ManaPointsMaximum of our characters with them. This is done using blade.dk's SetUnitMaxState system. It's a JASS system that uses an Unit Variable and an Integer Variable to set the Unit's max life/mana to the Integer value. So, in this case, we need our stamina and knowledge variables to be Integer variables, not Real variables, like the other ones. We also need a unit variable, but we already have our beloved "Playerchar[nº of owning player]" :D. Then we just "call" the script, specify our unit and our stamina/knowledge variable, and there it is! :D

Example:
  • Stamina
    • Events
      • Unit - A unit Acquires an item
    • Conditions
      • (Item being manipulated) Equal to some_item_that_adds_stamina
    • Actions
      • Set stamina[(Player number of (Owner of (Triggering unit)))] = (stamina[(Player number of (Owner of (Triggering unit)))] + amount_of_stamina_added)
      • Custom script: call SetUnitMaxState(udg_Playerchar[GetPlayerId ( GetTriggerUnit ( GetOwningPlayer() )) + 1], UNIT_STATE_MAX_LIFE, udg_stamina[GetPlayerId ( GetTriggerUnit ( GetOwningPlayer() )) + 1])
I may have misswritten some parts of the Custom script, I'm kinda new to JASS, but you get the general idea. The same is done for the knowledge variable. I'll not show another Trigger just for that, because it's pretty simple... Just change the variable from stamina to knowledge, manipulate an item that adds knowledge, and change the "UNIT_STATE_MAX_LIFE" to "UNIT_STATE_MAX_MANA" in the Custom script.

Also, we can make health and mana regeneration based on our stamina/knowledge:

  • Health and Mana Regen
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
    • Actions
      • Player Group - Pick every player in (All players matching (((Matching player) slot status) Equal to Is playing)) and do (Actions)
        • Loop - Actions
          • Unit - Set life of Playerchar[(Player number of (Picked player))] to ((Life of Playerchar[(Player number of (Picked player))]) + ((Real(stamina[(Player number of (Picked player))])) / 100.00))
          • Unit - Set mana of Playerchar[(Player number of (Picked player))] to ((Life of Playerchar[(Player number of (Picked player))]) + ((Real(knowledge[(Player number of (Picked player))])) / 100.00))
That will "regenerate" our characters life/mana every second, based on their stamina and knowledge divided by, say, 100. Of course, you can divide by whatever value you want. It's up to you to decide how will each Attribute affect the regen.
The "((Real(knowledge[(Player number of (Picked player))])) / 100.00))" part is done by converting an Integer to Real, because, as we know, our stamina and knowledge variables are Integer variables, but for this trigger we need them to be Real variables.

-Spellpower
Spellpower works similarly to the Attack Power... Except we won't calculate the damage when our unit attacks, but when it casts its spells.

Example:
  • Spell Damage
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to some_custom_ability
      • (Triggering unit) Equal to Playerchar[(Player number of (Owner of (Triggering unit)))]
    • Actions
      • Unit - Cause (Triggering unit) to damage circular area after 0.00 seconds of radius 500.00 at (Position of (Triggering unit)), dealing (spellpower[(Player number of (Owner of (Triggering unit)))] x 10.00) damage of attack type Normal and damage type Normal
      • Special Effect - Create a special effect at (Target point of ability being cast) using some_special_effect
So, basically we use Spellpower in each trigger we do for our custom abilities. Of course, it can be added to the damage of other abilities that are made in the Object Editor in the same way. I don't know if I need to mention: the variable used is "spellpower[nº of player], which is a Real.

-Resistance
It's similar to defense, but used to subtract damage from spells.

Example:
  • Resistance
    • Events
      • Unit - A unit owned by Neutral Hostile Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to some_ability_we_gave_to_our_NPC
    • Actions
      • Unit - Set life of (Target unit of ability being cast) to ((Life of (Target unit of ability being cast)) - (((Damage taken) - resistancevalue[(Player number of (Owner of (Target unit of ability being cast)))]) + 1.00))
Variable used is "resistancevalue", which is a Real :)

I just realized there is a small leak in the defense and resistance triggers. I think that by using "Damage taken - defense/resistance", I'm assuming the unit has already taken the damage, so the trigger would only make the unit take that damage again, but now with the reduced value calculated. This can be fixed by adding "Life of unit + Damage taken" and then the rest "- Damage taken". Sounds silly, but would make our unit regain the life it lost and then take the damage we want it to take. There may be a easier method, I'll work on it and keep editing this post.

So, that's it for my Custom Attribute System. Needs a improvement here and there, I think, but may help some people who want to do their own RPGs. Hope you guys like it :D.
 
Last edited:
Level 12
Joined
Mar 16, 2006
Messages
992
You should be using a damage detection system for this.

As it is now, I could just right click spam a unit and press stop to overwhelm it with buggy unreal damage. You could also factor in the armor/reduction into the attack itself using attacked unit(defense). I've done it in my map and it works better than having two separate triggers.
 
Level 5
Joined
Feb 1, 2009
Messages
107
You should be using a damage detection system for this.

As it is now, I could just right click spam a unit and press stop to overwhelm it with buggy unreal damage. You could also factor in the armor/reduction into the attack itself using attacked unit(defense). I've done it in my map and it works better than having two separate triggers.

Thanks for the advice, I tested it and ordering unit / stopping unit really makes the order happen like a spam. How do I use a damage detection system to fix that?

About making 1 trigger for both attack power and defence, I don't think you get my idea. This attributes are not for the entire map. Creeps won't have custom attack powers and defences. So I need a trigger for the damage my character will cause and another trigger for the damage he will receive... Can't have a trigger for both causing and receiving damage.
 
Level 5
Joined
Feb 1, 2009
Messages
107
Ok I created the Damage Detection system ^^
Really simple one, done using GUI. It's perfect for my map because it requires units to do only small ammounts of damage by themselves (like 2 damage), which is my case. Damage in my map is all trigger-based, even from normal attacks, so all my units have damage = 1, as I have already explained in the first post. So it's possible to do this:

  • Set Damage Detection
    • Events
      • Time - Elapsed game time is 0.01 seconds
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units owned by Player 9 (Gray)) and do (Trigger - Add to Attack Power <gen> the event (Unit - (Picked unit) Takes damage))
  • Attack Power
    • Events
    • Conditions
      • (Damage taken) Less than or equal to 5.00
    • Actions
      • Unit - Cause Playerchar[(Player number of (Owner of (Damage source)))] to damage (Triggering unit), dealing attackvalue[(Player number of (Owner of (Damage source)))] damage of attack type Normal and damage type Normal
Comments:
Player 9 (Gray) is the one I use for the hostile forces in my map.
The condition in the second trigger - (Damage taken) Less than or equal to 5.00 - makes the system work. If it wasn't like this, when the unit took the initial damage (1, from the basic attack of my character), that would run the second trigger. As the second trigger also makes the unit take damage, it would re-run it, and it would enter an infinite loop, crashing the game. Putting that condition allows the trigger to only run when my units attack, because I know that any damage smaller then 5 would only be dealt by the basic attack of my units.

I'll update this triggers on the main post now :). That's 1 less leak for my system XD
 
Level 7
Joined
Jul 20, 2008
Messages
377
  • Set Damage Detection
  • Events
  • Time - Elapsed game time is 0.01 seconds
  • Conditions
  • Actions
  • Unit Group - Pick every unit in (Units owned by Player 9 (Gray)) and do (Trigger - Add to Attack Power <gen> the event (Unit - (Picked unit) Takes damage))
Heh, that's going to get nasty with a lot of units on the map.
 
Level 36
Joined
Feb 5, 2009
Messages
4,630
to fix that, you might want to have an area of effect... like

"distance between Unit and attacked unit 2 is 60 " ..

lol it will probably bug it even more but lol im a noob at Jass...so i only know shiity GUI

I will tell you now that GUI is in no stretch of the imagination shitty. Some people swear by Jass, but I'm here to tell them that there's nothing you can do in Jass that can't be done in GUI.

Ask the great Paladon himself, he has made MANY awesome spells using nothing but GUI (Take his jump-spell for instance. Pure perfection and all done with GUI).

If you need help with using GUI, just ask Paladon via chat or PM. He's the sort of bloke who's always happy to help. Helped me out. I'm the reason he posted his Jump Spell in the first place :p
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
I will tell you now that GUI is in no stretch of the imagination shitty. Some people swear by Jass, but I'm here to tell them that there's nothing you can do in Jass that can't be done in GUI.

Right...

- Functions, with parameters and return value
- Structs ...
- "Local" code (only execute code for 1 player)
- Leakless code
- Trackables
- Attachment systems

And the stuff gui does, can never be done as clean and efficient as in jass. Not to mention the fact jesp-standard spells are probably the most user-friendly spells made even for gui users.
 
Status
Not open for further replies.
Top