1. Evolution complete! Make Darwin proud and go vote in the Techtree Contest #12 - Poll.
    Dismiss Notice
  2. Icon Contest #17 - Results are out! Step by to congratulate our winners!
    Dismiss Notice
  3. We've created the Staff Job Openings thread. We're currently in need of icon, video production, and social/multimedia positions to be filled. Thank you!
    Dismiss Notice
  4. Melee Mapping Contest #2 - Results are out! Step by to congratulate the winners!
    Dismiss Notice
  5. C'thun has spoken! Texturing Contest #29 - Results are published - check 'em out!
    Dismiss Notice

Custom XP System : From Preparations to Creation

Discussion in 'General Mapping Tutorials' started by Vladadamm, Jan 6, 2013.

  1. Vladadamm

    Vladadamm

    Joined:
    Apr 19, 2011
    Messages:
    1,258
    Resources:
    9
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    Resources:
    9
    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 :
    Code (vJASS):
    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 :

    Easy incomplete one

    • 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 :

    More complete

    • 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 :

    Even More Complete

    • 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: Jan 6, 2013
  2. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,196
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Ue hidden tags, some of the triggers are strecthing the page.

    Null the location and unit group variables after you destroy the groups and locations, to prevent leaks.
     
  3. Vladadamm

    Vladadamm

    Joined:
    Apr 19, 2011
    Messages:
    1,258
    Resources:
    9
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    Resources:
    9
    [​IMG][​IMG][​IMG] Custom script: call DestroyGroup(udg_TempGroup)
    [​IMG][​IMG][​IMG] Custom script: call RemoveLocation(udg_TempPoint)
    Leaks were cleared in triggers.

    I'm gonna add hidden tags.
     
  4. Vladadamm

    Vladadamm

    Joined:
    Apr 19, 2011
    Messages:
    1,258
    Resources:
    9
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    Resources:
    9
    What is happening in each trigger depends of the user's algorithm, so i'm providing only some examples, but it might not look as the trigger the user will made.
     
  5. Chaosy

    Chaosy

    Joined:
    Jun 9, 2011
    Messages:
    10,271
    Resources:
    17
    Maps:
    1
    Spells:
    10
    Tutorials:
    6
    Resources:
    17
    finally someone made this, it's asked too many times
     
  6. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,196
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Easy incomplete one

    • 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.
     
  7. Vladadamm

    Vladadamm

    Joined:
    Apr 19, 2011
    Messages:
    1,258
    Resources:
    9
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    Resources:
    9
    Does that even matter ? What is 4 bytes nowadays ?

    And also those are examples, nothing more.
     
  8. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,196
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    According to my calculations, the 4 bytes of today is the equivalent of 4 bytes of old.

    The leak is not that big or significant, but if you can prevent it, then why not do it?
     
  9. Vladadamm

    Vladadamm

    Joined:
    Apr 19, 2011
    Messages:
    1,258
    Resources:
    9
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    Resources:
    9
    Back in days, comp had 256 or 512 mb of ram. Today we have 4 or 8 gb. That means 8-16 times more. So it's not 4 bytes in an example that will change anything.
     
  10. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,387
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    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.
     
  11. Daffa the Mage

    Daffa the Mage

    Map Reviewer

    Joined:
    Jan 30, 2013
    Messages:
    7,051
    Resources:
    21
    Packs:
    1
    Maps:
    7
    Spells:
    12
    Tutorials:
    1
    Resources:
    21
    this is useful,may I add it to my system pack? Of Course Credits and Link to Tutorial will be given

    Please PM me Vladadamm for your answer. thanks.
     
  12. Vladadamm

    Vladadamm

    Joined:
    Apr 19, 2011
    Messages:
    1,258
    Resources:
    9
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    Resources:
    9
    No problems with it. Do whatever you want since there's no real system but only examples shown in this tutorial.
     
  13. Daffa the Mage

    Daffa the Mage

    Map Reviewer

    Joined:
    Jan 30, 2013
    Messages:
    7,051
    Resources:
    21
    Packs:
    1
    Maps:
    7
    Spells:
    12
    Tutorials:
    1
    Resources:
    21
    Okay, I'll make it then link the tutorial :)
     
  14. alucy0210

    alucy0210

    Joined:
    Apr 10, 2015
    Messages:
    5
    Resources:
    0
    Resources:
    0
  15. SAUS

    SAUS

    Joined:
    May 22, 2015
    Messages:
    1,048
    Resources:
    0
    Resources:
    0
    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.

    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.
     
  16. Rheiko

    Rheiko

    Joined:
    Aug 27, 2013
    Messages:
    2,942
    Resources:
    7
    Icons:
    2
    Spells:
    3
    Tutorials:
    2
    Resources:
    7
    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*