• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Custom XP System : From Preparations to Creation

Today, i'll learn you how to create your own Custom XP System and make it work properly. Note that I won't push the coding/triggering part so much as it's simple triggering.

You said Custom XP System ? What the f*** is that ?

A Custom XP System, or Custom Experience System (but, Experience is long to write...), is a system, different of Warcraft 3's basic XP system, that manages the XP gain of heroes.

Why would i need a Custom XP System if i already have Warcraft's XP System ?

Having a Custom XP System has some advantages :
  • You need to make it yourself, so it's always a good way to practice and learn new things ;)
  • It offers easier and better configuration and managing of the XP gains. You won't need to touch to the Constants and such everytime you want to change a little thing.
  • The Warcraft 3's basic XP system works kinda strange (that's only my opinion) and so you'll have a XP System that will do what you want.
Many maps are using a Custom XP System, such as DotA (sry, but don't have any other examples under my hand ^^").

But what does it do exactly ?

A XP System, as i said previously, manages the XP gains of Heroes. It generally gives XP to all Heroes, which are enemies of the dying unit/hero ofc, within a certain area.
Usually (and mostly), the XP gained by Heroes depends of how many hereoes there are near the dying unit/hero, the level of the dying unit/hero and also if it's an unit or an hero which died.
Of course, it can be a bit more elaborated, to gain less XP if the unit is "denied" as in DotA or such things.

Now, we will see how to create one and how to make it work in a map, that means "disabling" the Warcraft's basic XP System so that it doesn't interferes with the new one and also creating the system itself.

I - Preparation :

In this Part, we will touch to the constants, yes i know, you will have to lose 1 hour searching specific lines in the constant and you'll be very happy.

As we can't remove the Warcraft's basic XP System, we should find a way to "disable" or "neutralize" it. Don't worry it's kinda easy. Just open the Constants (for beginners : in the Tool Bar, Advanced and then Constants)

Search for the lines called "Exp Hero Gained". The simpliest way is that you set them all to 0.
Be sure that you don't change the lines "Exp Hero Required" too.

After that, it should be ok. If you really want it, you can set some other lines to 0 such as "Range Gain Hero Experience Maximum" (i know, my traductions are really precise), but it shouldn't be needed.

Note that disabling Experience Gain for Heroes using trigger won't work as it will also disable Experience Gain that you'll give to the Heroes with triggers (so the Custom XP System won't work).

II - Creation :

Now, let's tell you how to create the Custom XP System.

Someday, Blizzard created that action :
  • Hero - Add <Integer> experience to <Unit>, Show level-up graphics
Or in Jass :
JASS:
call AddHeroXP( integer, unit, boolean )
The boolean is to show the level-up graphics. So, in most of case you will set it to True.

And that's what we will be using to make the hero gain XP.

The System itself is really simple, as it can be that :


  • XP System
    • Events
      • Unit - A unit Dies
    • Conditions
    • Actions
      • Set TempPoint = (Position of (Triggering unit))
      • Set TempGroup = (Units within 1000.00 of TempPoint matching ((((Matching unit) is a Hero) Egal to TRUE) and (((Matching unit) belongs to an enemy of (Triggering player)) Egal to TRUE))
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • Hero - Add 50 experience to (Picked unit), Show level-up graphics
      • Custom script : call DestroyGroup(udg_TempGroup)
      • Custom script : call RemoveLocation(udg_TempPoint)


In fact, it's really a piece of cake. Really, why would we need a tutorial for that ?

Yes, kinda but that's a really simplified version. Here the heroes will gain 50 experience every time a nearby enemy unit dies, even if it's an hero or some really big unit. And so you can't use that in your map.

But before continuing, i would recommend you to use two triggers instead of only one. One for the configuration and one for the system itself. So that it will be easy to modify it later.

As i said before, a good Custom XP System should at least give XP depending of Level of dying unit/hero, if it's either an Unit or a Hero and finally of how much Hero are gaining XP from this death.

So, it should look a bit more like this :


  • XP System Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set XPS_BaseXPU = 30
      • Set XPS_BaseXPH = 200
      • Set XPS_IncrXPU = 10
      • Set XPS_IncrXPH = 50
      • For each (Integer A) from 1 to 25, do (Actions)
        • Boucle - Actions
          • Set XPS_XPH[(Integer A)] = ((XPS_IncrXPH x (Integer A)) + XPS_BaseXPH)
          • Set XPS_XPU[(Integer A)] = ((XPS_IncrXPU x (Integer A)) + XPS_BaseXPU)
      • Set XPS_XPArea = 1000.00
      • Set XPS_XPGainPH[1] = 100
      • Set XPS_XPGainPH[2] = 85
      • Set XPS_XPGainPH[3] = 72
      • Set XPS_XPGainPH[4] = 61
      • Set XPS_XPGainPH[5] = 52
  • XP System
    • Events
      • Unit - A unit Dies
    • Conditions
      • ((Triggering unit) is A Building ) Equal to FALSE
    • Actions
      • Set TempPoint = (Position of (Triggering unit))
      • Set TempGroup = (Units within XPS_XPArea of TempPoint matching (((((Matching unit) is A Hero) Equal to TRUE) and (((Matching unit) belongs to an enemy of (Triggering player)) Equal to TRUE)) and ((Owner of (Matching unit)) Different of Neutral Passive)))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Triggering unit) is A Hero) Equal to TRUE
        • Then - Actions
          • Set TempInt = (XPS_XPH[(Hero level of (Triggering unit))] x (XPS_XPGainPH[(Number of units in TempGroup)] / 100))
        • Else - Actions
          • Set TempInt = (XPS_XPU[(Level of (Triggering unit))] x (XPS_XPGainPH[(Number of units in TempGroup)] / 100))
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • Hero - Add TempInt experience to (Picked unit), Show level-up graphics
      • Custom script: call DestroyGroup(udg_TempGroup)
      • Custom script: call RemoveLocation(udg_TempPoint)


Of course, it depends of the complexity of the Custom XP System you want.

As example, here is the one i'm using in my AoS which also includes XP Reduction if the unit has been denied and gives also XP to another hero which is bound to the main hero :


  • XP System Init
    • Events
      • Map initialization
    • Conditions
    • Actions
      • Set XPS_BaseXPU = 30
      • Set XPS_BaseXPH = 200
      • Set XPS_IncrXPU = 10
      • Set XPS_IncrXPH = 50
      • For each (Integer A) from 1 to 25, do (Actions)
        • Loop - Actions
          • Set XPS_XPH[(Integer A)] = ((XPS_IncrXPH x (Integer A)) + XPS_BaseXPH)
          • Set XPS_XPU[(Integer A)] = ((XPS_IncrXPU x (Integer A)) + XPS_BaseXPU)
      • Set XPS_XPArea = 1000.00
      • Set XPS_XPGainPH[1] = 100
      • Set XPS_XPGainPH[2] = 85
      • Set XPS_XPGainPH[3] = 72
      • Set XPS_XPGainPH[4] = 61
      • Set XPS_XPGainPH[5] = 52
      • Set XPS_XPGainDenyPerc = 80
  • XP System
    • Events
      • Unit - A unit Dies
    • Conditions
      • ((Triggering unit) is A Building) Equal to FALSE
    • Actions
      • Set TempPoint = (Position of (Triggering unit))
      • Set TempGroup = (Units within XPS_XPArea of TempPoint matching (((((Matching unit) is A Hero) Equal to True) and (((Matching unit) belongs to an enemy of (Triggering player)) Equal to TRUE)) and ((Owner of (Matching unit)) Different of Neutral Passive)))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Triggering unit) is A Hero) Equal to TRUE
        • Then - Action
          • Set TempInt = (XPS_XPH[(Hero level of (Triggering unit))] x (XPS_XPGainPH[(Number of units in TempGroup)] / 100))
        • Else - Actions
          • Set TempInt = (XPS_XPU[(Level of (Triggering unit))] x (XPS_XPGainPH[(Number of units in TempGroup)] / 100))
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Killing unit) belongs to an ally of (Triggering player)) Equal to TRUE
        • Then - Actions
          • Set TempInt = ((TempInt x XPS_XPGainDenyPerc) / 100)
        • Else - Actions
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • Hero - Add TempInt experience to (Picked unit), Show level-up graphics
          • Hero - Add TempInt experience to Dummy_Hero[(Player number of (Owner of (Picked unit)))], Show level-up graphics
      • Custom script: call DestroyGroup(udg_TempGroup)
      • Custom script: call RemoveLocation(udg_TempPoint)


It's me or things are suddenly a bit more complicated ?

I would say just a bit.

There are no real limits of a Custom XP System as you might add any parameters you want to configure the system. But of course, it should give something understandable at end so that players understand how they gain xp and how much they gain in each case.
If you want you can add parameters such as distance, for example if you're next to the killed unit you gain many experience and if you're far of it, you gain less, but it's up to you.

At end, the XP Gain will always be an Algorithm depending of variables. And your Algorithm should be thinked in function of the map, it's general gameplay and such. Same goes for the Variables used in this Algorithm.



So, i think that's all. And i'm too lazy to give a Test Map, so, for other lazy guys, you have to follow this tutorial in order to have a Custom XP System ;)
 
Last edited:
empty.gif
join.gif
page.gif
Custom script: call DestroyGroup(udg_TempGroup)
empty.gif
joinbottom.gif
page.gif
Custom script: call RemoveLocation(udg_TempPoint)
Leaks were cleared in triggers.

I'm gonna add hidden tags.
 
Level 37
Joined
Mar 6, 2006
Messages
9,240

  • XP System
    • Events
      • Unit - A unit Dies
    • Conditions
    • Actions
      • Set TempPoint = (Position of (Triggering unit))
      • Set TempGroup = (Units within 1000.00 of TempPoint matching ((((Matching unit) is a Hero) Egal to TRUE) and (((Matching unit) belongs to an enemy of (Triggering player)) Egal to TRUE))
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • Hero - Add 50 experience to (Picked unit), Show level-up graphics
      • Custom script : call DestroyGroup(udg_TempGroup)
      • Custom script : call RemoveLocation(udg_TempPoint)
      • Custom script : set udg_TempGroup = null
      • Custom script : set udg_TempPoint = null


This is how not to leak. Not nulling them will leak about 4 bytes I believe.
 
This seems like it could be useful for newer users. A bit basic, but it should be fine.

As for the null leak, unless I'm mistaken it should be fine considering the globals are reassigned every time a unit dies (which usually happens quite often), thus clearing the previous references to the old handles. Of course, there is still some memory used to point to them on the very last occurrence of the event, but it is minor compared to what a local would do if it were left referencing an object.

Of course, it is still better to clear the leak, but since it is comparing apples to apples, I'll leave it.

Approved.
 
Level 12
Joined
May 22, 2015
Messages
1,051
It's nice as a starting point for me. Thanks.

One thing I noticed is that this gives the heroes XP if the are dead (if I am reading it correctly). This could be unwanted. However, it's not hard to check if the hero is dead or not.

Another thing, though. It might not work for everyone, but looping over all of the units in range seems excessive. In my map, each player can only have 1 hero, and they are already in a group (wouldn't be hard to put all heroes into a group, though). I will just have mine loop over the heroes and check if they are in range. The group is static, so I don't need to build it each time and I don't need to delete it each time. It's also probably going to be smaller most of the time, but that could just be my map - there tends to be quite a few clumped units. That is more of an optimisation thing, so it probably doesn't matter for the tutorial.


  • XP System
    • Events
      • Unit - A unit Dies
    • Conditions
    • Actions
      • Set TempPoint = (Position of (Triggering unit))
      • Set TempGroup = (Units within 1000.00 of TempPoint matching ((((Matching unit) is a Hero) Egal to TRUE) and (((Matching unit) belongs to an enemy of (Triggering player)) Egal to TRUE))
      • Unit Group - Pick every unit in TempGroup and do (Actions)
        • Loop - Actions
          • Hero - Add 50 experience to (Picked unit), Show level-up graphics
      • Custom script : call DestroyGroup(udg_TempGroup)
      • Custom script : call RemoveLocation(udg_TempPoint)
      • Custom script : set udg_TempGroup = null
      • Custom script : set udg_TempPoint = null


This is how not to leak. Not nulling them will leak about 4 bytes I believe.

I was unaware that global variables could leak. Is this accurate information, am I missing something, or have I been epically leaking 4 bytes all over the place? I know this definitely has to be done with local variables, though.
 
Level 22
Joined
Aug 27, 2013
Messages
3,973
I know the thread is 5 years old but I feel like I have to say it. Integer Variable doesn't work in division with higher number, It returns 0.
so this variable will give you 0 exp at the end.
  • Set TempInt = (XPS_XPU[(Level of (Triggering unit))] x (XPS_XPGainPH[(Number of units in TempGroup)] / 100))
It works well if you're the only hero around but when there's more than one, it gives you 0 exp.
Maybe this is also the reason why test map is important *coughs*
 
Top