1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still haven't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. Lead your forces to battle in the 15th Techtree Contest. The call is yours, commander!
    Dismiss Notice
  4. The reforging of the races is complete. Come see the 14th Techtree Contest Results.
    Dismiss Notice
  5. It's time to choose your horse in the race - the 32nd Modeling Contest Poll is up!
    Dismiss Notice
  6. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

[Trigger] Custom Increment in Stats

Discussion in 'Triggers & Scripts' started by moomoocow1314, Jun 11, 2009.

  1. moomoocow1314

    moomoocow1314

    Joined:
    Dec 10, 2008
    Messages:
    59
    Resources:
    0
    Resources:
    0
    Hello Hive.

    Once more, a dota-referenced question.

    For those of you who play dota, the question is simple: How do I produce Ursa Warrior's Ulti? Or Barathrum's Empowering Haste's atk increment effect?

    For those of you who don't, it means: How do I, via triggers, increase a unit's Attack stat? As of current, I do not see some kind of trigger that increases a unit's attack and displays it on the status bar.

    Thanks for the help.
     
  2. Cokemonkey11

    Cokemonkey11

    Wurst Reviewer

    Joined:
    May 9, 2006
    Messages:
    3,234
    Resources:
    18
    Tools:
    1
    Maps:
    5
    Spells:
    3
    Tutorials:
    2
    JASS:
    7
    Resources:
    18
    Create a dummy attack bonus ability (from item), give it to the unit, and then set the ability's level.
     
  3. Feroc1ty

    Feroc1ty

    Joined:
    Aug 9, 2008
    Messages:
    60
    Resources:
    0
    Resources:
    0
    REQUIREMENTS: JASS NEW GEN

    You will need to create a few abilities. Firstly, copy the attack damage bonus ability from items section, make its object ID = 'DM+a', and set the damage bonus to +1. Now copy this item, set the object ID to 'DM+b', and set the damage bonus to +2. For the third time, you will copy the ability again, set the object ID to 'DM+c', and set the damage bonus to +4. I'm hoping that by now you've started to notice a patern, basically keep creating those abilities, progressing in the alphabet, and doubling the damage bonus. So the next few abilities ID's would be DM+d, DM+e, and damages +8, +16. Keep creating those abilities up to damage bonus of 256. This will let you set your units damage to anything from 0 up to 511.

    This was the easy object editor part, time for some code.

    Firstly, you will need to make a new trigger, after that convert it into text, and remove anything that's in there.

    Now we'll type in "library DamageBonus", press enter, and type in "endlibrary."

    We're finished with the library! Well not quite, it still needs a couple of things inside of it.

    What your trigger should look like right now is:
    Code (vJASS):
    library DamageBonus
    endlibrary


    Next part to do is create a struct, which is simple. Firstly create the struct, the struct declaration is "struct" followed by a name (ex. struct DamageBonus), and ended with "endstruct"

    Now declare a unit with a name of "obj", and an integer with a name of "dmg" inside of the struct.

    Your code should look like this:
    Code (vJASS):
    library DamageBonus

    struct DamageBonus
        integer dmg
        unit obj
    endstruct

    endlibrary


    Basically, now we have something to hold the units damage information in. You'll need to declare two new variables inside of your struct. Both of them are integer, name one pow, and the other cdmg. Make both of those last created variables into static variables. You do this by declaring the word "static" in front of them. Make the cdmg values equal to 'DM+a', and make pow equal to 8.

    Right now your code should look like this:
    Code (vJASS):
    library DamageBonus

    struct DamageBonus
        integer         dmg = 0
        unit            obj = 0  
        static integer  pow = 8
        static integer cdmg = 'DM+a'
    endstruct

    endlibrary


    What you want to do right now is make all of those variables private, you do so by placing the keyword "private" in front of them.

    After you have made it private, create a static method called create, make it take a unit, and return DamageBonus.

    Create a local DamageBonus, create it using allocate method, and let obj variable equal to the unit given, after you have done that, return the DamageBonus struct.

    Right now your code should look like this:
    Code (vJASS):
    library DamageBonus

    struct DamageBonus
        private integer         dmg = 0
        private unit            obj = null
        private static integer  pow = 8
        private static integer cdmg = 'DM+a'
       
        static method create takes unit u returns DamageBonus
            local DamageBonus this = DamageBonus.allocate()
            set this.obj = u
            return this
        endmethod
       
    endstruct

    endlibrary


    What you are going to do now, is creating a few method operators. You create them just like a regular method, but after the method keyword you place the word operator (ex. method operator damage takes nothing returns integer). You place the symbol "=" after the method name if you are adjusting a value, not receiving it (ex. method operator damage= takes integer s returns nothing).

    Create a get method operator, call it object, and make it return the obj value. Create a duplicate set method, and instead of return the obj value, set obj value to the receiving value. Create two similar methods for dmg variable aswell.

    Right now your code should look like this:
    Code (vJASS):
    library DamageBonus

    struct DamageBonus
        private integer         dmg = 0
        private unit            obj = null
        private static integer  pow = 8
        private static integer cdmg = 'DM+a'
       
        static method create takes unit u returns DamageBonus
            local DamageBonus this = DamageBonus.allocate()
            set this.obj = u
            return this
        endmethod
       
        method operator object takes nothing returns unit
            return .obj
        endmethod
       
        method operator object= takes unit s returns nothing
            set .obj = s
        endmethod
       
        method operator damage takes nothing returns integer
            return .dmg
        endmethod
       
        method operator damage= takes integer s returns nothing
            set .dmg = s
        endmethod
       
    endstruct

    endlibrary


    We're almost done! All we need now is a method that will actually give the abilities to the units.

    Create a method called update_dmg above all the method operator, but below the create method.

    Make the last created method have 2 local integers, call one i, and the other num. Set i = .pow, and num = .dmg.

    Now create an if statement, make sure that the num value is less than 512. If that's true, than return, and no else statement.

    Create a loop, and for the exit statement place i < 0. Inside of the loop check if Pow( 2, i) is less then or equal to num. If so, add an ability to the .obj, for the ability ID use .cdmg + i. After the add function call, set num = num - R2I(Pow(2,i)). Now for the else statement, remove an ability from the object, for the ability id use .cdmg + i. After the if statement, set i to itself minus one. End the loop.

    Right now your code should look like this:
    Code (vJASS):
    library DamageBonus

    struct DamageBonus
        private integer         dmg = 0
        private unit            obj = null
        private static integer  pow = 8
        private static integer cdmg = 'DM+a'
       
        static method create takes unit u returns DamageBonus
            local DamageBonus this = DamageBonus.allocate()
            set this.obj = u
            return this
        endmethod
       
        private method update_dmg takes nothing returns nothing
            local integer i = .pow
            local integer num = .dmg
            if num > 511 then
                return
            endif
            loop
                exitwhen i < 0
                if Pow(2,i) <= num then
                    call UnitAddAbility( .obj, .cdmg + i )
                    set num = num - R2I(Pow(2,i))
                else
                    call UnitRemoveAbility( .obj, .cdmg + i )
                endif
                set i = i - 1
            endloop
        endmethod
       
        method operator object takes nothing returns unit
            return .obj
        endmethod
       
        method operator object= takes unit s returns nothing
            set .obj = s
        endmethod
       
        method operator damage takes nothing returns integer
            return .dmg
        endmethod
       
        method operator damage= takes integer s returns nothing
            set .dmg = s
        endmethod
       
    endstruct

    endlibrary


    Now what you're gonna have to do, is go back to the method operator where you adjusted the damage value, and after the value is adjusted, call .update_dmg().

    Only thing left to do, is create an onDestroy method. Inside the method, create a local integer, with the name of i, and set it's value to .pow.
    Than create a loop, exitwhen i is less than 0. Inside of the loop remove each of the abilities on the unit. Set i to equal itself minus one. After the loop, set .obj to null.

    Now our code should look like this:
    Code (vJASS):
    library DamageBonus

    struct DamageBonus
        private integer         dmg = 0
        private unit            obj = null
        private static integer  pow = 8
        private static integer cdmg = 'DM+a'
       
        static method create takes unit u returns DamageBonus
            local DamageBonus this = DamageBonus.allocate()
            set this.obj = u
            return this
        endmethod
       
        private method update_dmg takes nothing returns nothing
            local integer i = .pow
            local integer num = .dmg
            if num > 511 then
                return
            endif
            loop
                exitwhen i < 0
                if Pow(2,i) <= num then
                    call UnitAddAbility( .obj, .cdmg + i )
                    set num = num - R2I(Pow(2,i))
                else
                    call UnitRemoveAbility( .obj, .cdmg + i )
                endif
                set i = i - 1
            endloop
        endmethod
       
        method operator object takes nothing returns unit
            return .obj
        endmethod
       
        method operator object= takes unit s returns nothing
            set .obj = s
        endmethod
       
        method operator damage takes nothing returns integer
            return .dmg
        endmethod
       
        method operator damage= takes integer s returns nothing
            set .dmg = s
            call .update_dmg()
        endmethod

        private method onDestroy takes nothing returns nothing
            local integer i = .pow
            loop
                exitwhen i < 0
                call UnitRemoveAbility(.obj, .cdmg + i)
                set i = i - 1
            endloop
            set .obj = null
        endmethod
       
    endstruct

    endlibrary


    The system is finished!

    Now what we have to do to use it, is create a DamageBonus struct, and set the struct damage to whatever you want. You can even do so in a GUI trigger.

    • Untitled Trigger 001
      • Events
        • Map initialization
      • Conditions
      • Actions
        • Custom script: local DamageBonus this = DamageBonus.create(some_unit)
        • Custom script: set this.damage=200


    Now, there is one issue with this code, it will leak when the units die, so what we will have to do, is attach the structs to the units user data, create a group, and when a unit with the struct attached dies his struct will be destroyed.

    Here is the final code with self clean-up type of thing enabled:
    Code (vJASS):
    library DamageBonus initializer init

    globals
        unit some_unit
    endglobals

    struct DamageBonus
        private integer         dmg = 0
        private unit            obj = null
        private static integer  pow = 8
        private static integer cdmg = 'DM+a'
        static group            grp = null
       
        static method create takes unit u returns DamageBonus
            local DamageBonus this = DamageBonus.allocate()
            if IsUnitInGroup(u, .grp) then
                debug call BJDebugMsg("Trying to create multiple damage bonuses for unit " + GetUnitName(.obj))
                return null
            endif
            call GroupAddUnit( .grp, u)
            set this.obj = u
            return this
        endmethod
       
        private method update_dmg takes nothing returns nothing
            local integer i = .pow
            local integer num = .dmg
            if num > 511 then
                return
            endif
            loop
                exitwhen i < 0
                if Pow(2,i) <= num then
                    call UnitAddAbility( .obj, .cdmg + i )
                    set num = num - R2I(Pow(2,i))
                else
                    call UnitRemoveAbility( .obj, .cdmg + i )
                endif
                set i = i - 1
            endloop
        endmethod
       
        method operator object takes nothing returns unit
            return .obj
        endmethod
       
        method operator object= takes unit s returns nothing
            set .obj = s
        endmethod
       
        method operator damage takes nothing returns integer
            return .dmg
        endmethod
       
        method operator damage= takes integer s returns nothing
            set .dmg = s
            call .update_dmg()
        endmethod
       
        private method onDestroy takes nothing returns nothing
            local integer i = .pow
            if .obj == null then
                debug call BJDebugMsg("Trying to double release a struct attached to unit " + GetUnitName(.obj))
                return
            endif
            loop
                exitwhen i < 0
                call UnitRemoveAbility(.obj, .cdmg + i)
                set i = i - 1
            endloop
            call GroupRemoveUnit(.grp, .obj)
            set .obj = null
        endmethod
       
        static method onInit takes nothing returns nothing
            set .grp = CreateGroup()
        endmethod
       
    endstruct

    private function condition takes nothing returns boolean
        local DamageBonus d = GetUnitUserData(GetTriggerUnit())
        if IsUnitInGroup(d.object, d.grp) then
            return true
        endif
        return false
    endfunction

    private function action takes nothing returns nothing
        local DamageBonus d = GetUnitUserData(GetTriggerUnit())
        call d.destroy()
    endfunction

    private function init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(t,Condition(function condition))
        call TriggerAddAction(t, function action)
    endfunction

    endlibrary


    To use the system above you would have to add one more line to your GUI trigger, here is how it would look.

    • Untitled Trigger 001
      • Events
        • Map initialization
      • Conditions
      • Actions
        • Custom script: local DamageBonus this = DamageBonus.create(some_unit)
        • Custom script: set this.damage=200
        • Custom script: call SetUnitUserData(some_unit, this)
     
  4. moomoocow1314

    moomoocow1314

    Joined:
    Dec 10, 2008
    Messages:
    59
    Resources:
    0
    Resources:
    0
    @Feroc1ty

    thanks for the long post and help. I'll take some time off to explore it. i really appreciate your help =D
     
  5. Feroc1ty

    Feroc1ty

    Joined:
    Aug 9, 2008
    Messages:
    60
    Resources:
    0
    Resources:
    0
    Tried to make it a tutorial, so you learn as you make it, but if you're just a person who just wants to use the code, I guess you can just copy+paste the last example code given. What you WILL have to do is create those abilities tho.

    EDIT: If anyone wants me to explain any part of the code, you can post and ask.
     
  6. moomoocow1314

    moomoocow1314

    Joined:
    Dec 10, 2008
    Messages:
    59
    Resources:
    0
    Resources:
    0
    to be honest, I pretty much don't understand the overall method of handling Jass/vJASS.

    But with this, I guess I'll use it as a benchmark if I were to finally take that leap into JASS (but I haven't even mastered GUI to a degree...oh well)
     
  7. Cokemonkey11

    Cokemonkey11

    Wurst Reviewer

    Joined:
    May 9, 2006
    Messages:
    3,234
    Resources:
    18
    Tools:
    1
    Maps:
    5
    Spells:
    3
    Tutorials:
    2
    JASS:
    7
    Resources:
    18
    Read the last function first, which is almost always an initializer. If you want to know how to do something in jass, convert a gui function and then look at the BJ's used for info on how the natives work.

    I'd recommend looking at some proper tutorials for beginners though, as we could spend weeks explaining stuff to you if you learn in an improper order.
     
  8. moomoocow1314

    moomoocow1314

    Joined:
    Dec 10, 2008
    Messages:
    59
    Resources:
    0
    Resources:
    0
    hmm, wokay.

    on a totally different note, what does BJ stand for and what does it do?

    Also, those object = null and some_unit things, i should replace it with my own Object ID?

    oh yeah, that initializer init, i'm guessing the init means the trigger name to initialize the system?
     
    Last edited: Jun 13, 2009
  9. Cokemonkey11

    Cokemonkey11

    Wurst Reviewer

    Joined:
    May 9, 2006
    Messages:
    3,234
    Resources:
    18
    Tools:
    1
    Maps:
    5
    Spells:
    3
    Tutorials:
    2
    JASS:
    7
    Resources:
    18
    BJ stands for blizzard.j function, which are all the functions blizzard made to make programming "easier," they simply perform actions using the natives. It's generally considered to avoid them, but some have a use at certain times over straight natives.

    init refers to the function, trigger is usually created in the initializer function.
     
  10. Feroc1ty

    Feroc1ty

    Joined:
    Aug 9, 2008
    Messages:
    60
    Resources:
    0
    Resources:
    0
    You will remove the global block, the some_unit variable was there to make sure code compiled, and you will have to create 8 or 9 abilities (i forgot) with the pattern that i showed you in the very start of the mini tutorial, you will start with ability id o DM+a, than go down into DM+b, DM+c etc... Base the ability off the weapon damage bonus ability from items.

    EDIT: Toward "Cokemonkey11," I tend to place initialization functions at end of code for personal reasons :).
     
  11. moomoocow1314

    moomoocow1314

    Joined:
    Dec 10, 2008
    Messages:
    59
    Resources:
    0
    Resources:
    0
    i see...

    another question: the event trigger for the system u posted is Map initialization, can i change it to "unit begins the effect of an ability" so it happens when I use a skill? (provided I can find the part where I can modify it to % of my hp/mp etc....)

    and I just have to say this out: my first time ever typing a JASS code (thx to Feroc1ty), and it feels...awesome. Lol

    EDIT: oh wait, the part where I can modify it to % of my hp/mp is the damage struct in the GUI trigger right?
     
  12. Feroc1ty

    Feroc1ty

    Joined:
    Aug 9, 2008
    Messages:
    60
    Resources:
    0
    Resources:
    0
    I don't think you comprehend how this system works... Look at the trigger example, you type in 3 custom lines of code per unit you want to have custom damage. Any unit can have it.
     
  13. Lord_BoNes

    Lord_BoNes

    Joined:
    Sep 5, 2007
    Messages:
    264
    Resources:
    0
    Resources:
    0
    I honestly don't see why people use a system of "damage +2, +4, +8, etc."
    I created my own little "damage bonus" system, using +1, +10, +100, +1000, +10000. Each with 9 lvls. So, With 5 abilities, I can have any number between 1-99,999. With another ability, I'd have 999,999.

    Can anyone tell me why people use the binary way instead of the decimal way? :confused:
     
  14. moomoocow1314

    moomoocow1314

    Joined:
    Dec 10, 2008
    Messages:
    59
    Resources:
    0
    Resources:
    0
    The part I don't get is, which line should I edit in order to make a (or any) unit have it?

    EDIT: You said something about removing the global block, why should i do that?
     
  15. Feroc1ty

    Feroc1ty

    Joined:
    Aug 9, 2008
    Messages:
    60
    Resources:
    0
    Resources:
    0
    Because it was for the test trigger, you set the system up by doing "Custom script: local DamageBonus this = DamageBonus.create(some_unit)", and replacing some_unit with the unit which you want it to be.

    Each one of those abilities will add around +1 second of loading time, and you have five of them, so you're looking at at least 5 extra seconds of loading time for a simple damage system (whilst level one abilities will get widgetized into an slk and turn the loading time into around 0.05 seconds). Another reason this system is better, is because I have one macro that does the binary, so in one line of code (and a few object editor abilities) I can add a completely new stat, such as strength, agility, intelligence, etc...
     
  16. moomoocow1314

    moomoocow1314

    Joined:
    Dec 10, 2008
    Messages:
    59
    Resources:
    0
    Resources:
    0
    i replaced it with (in my case) a unit with a rawcode ID of h000, i was wondering if I should replaced the null in obj with the same rawcode ID?
     
  17. Feroc1ty

    Feroc1ty

    Joined:
    Aug 9, 2008
    Messages:
    60
    Resources:
    0
    Resources:
    0
    ?

    Why are you placing an ID of the unit into the section... It has to be an actual unit...
     
  18. Lord_BoNes

    Lord_BoNes

    Joined:
    Sep 5, 2007
    Messages:
    264
    Resources:
    0
    Resources:
    0
    I see. I've used optimisers before, but I don't know how they work. What is the deal with SLKs? I understand that optimising the SLK reduces the loading time, but how? And, why won't it work on abilities with more than 1 level?
     
  19. Feroc1ty

    Feroc1ty

    Joined:
    Aug 9, 2008
    Messages:
    60
    Resources:
    0
    Resources:
    0
    Object editor crap is placed in a shitty way, what slk does is display the information better, so warcraft gets all of the information quicker. It works on abilities that are level 3 at most.
     
  20. Lord_BoNes

    Lord_BoNes

    Joined:
    Sep 5, 2007
    Messages:
    264
    Resources:
    0
    Resources:
    0
    Well, you could still cut the number of abilities down then, right? You use single level abilities, you could be using triple level, and have 1/3 the number of required abilities.
    Tell me if I'm wrong here.