Snippet SpeedMod

Discussion in 'Systems and Snippets' started by Dirac, Nov 12, 2011.

  1. Dirac

    Dirac 22710180

    Ratings:
    +147 / 0 / -0
    JASS:
    library SpeedMod /* v2.1.0
    
    */uses/*
    */  LinkedListModule        /*  thehelper.net/forums/showthread.php/168775-LinkedListModule
    */  optional UnitIndexer    /*
    */  optional AIDS           /*
    
    **********************************************************************
    *
    *   struct SpeedMod
    *       -   Handles unit's movement speed modifications.
    *
    *       static method create takes unit whichUnit, real percent returns SpeedMod
    *           -   Modifies the unit's speed in the given percent.
    *           -   1.0 means 100% increase.
    *       static method base takes unit whichUnit, real amount returns nothing
    *           -   Modifies the unit's base speed by the given amount.
    *           -   Giving it 20 adds 20 movement speed.
    *       method destroy takes nothing returns nothing
    *           -   Destroys the mod.
    *       real amount
    *           -   Is the percentage of speed this SpeedMod awards, if
    *           -   set to another value it applies the effect.
    *
    *********************************************************************/
        
        private struct UnitBaseSpeed extends array
            implement LinkedList
            
            real add
            real total
            
            thistype node
            
            static if LIBRARY_UnitIndexer then
                method index takes nothing returns nothing
                    set this.node = createNode()
                endmethod
                method deindex takes nothing returns nothing
                    call this.node.flushNode()
                endmethod
            else
                method AIDS_onCreate takes nothing returns nothing
                    set this.node = createNode()
                endmethod
                method AIDS_onDestroy takes nothing returns nothing
                    call this.node.flushNode()
                endmethod
            endif
            
            implement optional UnitIndexStruct
            //! runtextmacro optional AIDS()
        endstruct
        
        struct SpeedMod extends array
            
            readonly unit target
            private real value
            private real input
            
            method operator amount= takes real v returns nothing
                local UnitBaseSpeed index=GetUnitUserData(target)
                local real speed=index.add+GetUnitDefaultMoveSpeed(target)
                set index.total=index.total-value
                set value=v*speed
                set input=v
                set index.total=index.total+value
                call SetUnitMoveSpeed(target,speed+index.total)
            endmethod
            
            static method base takes unit whichUnit, real value returns nothing
                local UnitBaseSpeed index=GetUnitUserData(whichUnit)
                local UnitBaseSpeed this = index.node.next
                set index.add=index.add+value
                call SetUnitMoveSpeed(whichUnit,GetUnitDefaultMoveSpeed(whichUnit)+index.add+index.total)
                loop
                    exitwhen this.head
                    set thistype(this).amount=thistype(this).input
                    set this=this.next
                endloop
            endmethod
            
            method operator amount takes nothing returns real
                return input
            endmethod
            
            static method create takes unit whichUnit, real v returns thistype
                local thistype this=UnitBaseSpeed.allocate()
                local UnitBaseSpeed index=GetUnitUserData(whichUnit)
                local real speed=index.add+GetUnitDefaultMoveSpeed(whichUnit)
                set value=v*speed
                set input=v
                set target=whichUnit
                set index.total=index.total+value
                call SetUnitMoveSpeed(whichUnit,speed+index.total)
                call index.node.insertNode(this)
                return this
            endmethod
            
            method destroy takes nothing returns nothing
                local UnitBaseSpeed index=GetUnitUserData(target)
                set index.total=index.total-value
                call UnitBaseSpeed(this).removeNode()
                call UnitBaseSpeed(this).deallocate()
                call SetUnitMoveSpeed(target,GetUnitDefaultMoveSpeed(target)+index.add+index.total)
            endmethod
            
        endstruct
        
    endlibrary
     
  2. PurgeandFire

    PurgeandFire zxcvmkgdfg

    Ratings:
    +513 / 0 / -0
    Nice job, very useful. :)
     
  3. Dirac

    Dirac 22710180

    Ratings:
    +147 / 0 / -0
    Thanks purge

    Updated
    -Multiple bugs occurred when dealing with MS above 522 or below 1, this is now fixed
    -No longer requires a unit indexing system

    Thoughts on v2.0.0
    Percentage speed modificiation is a tricky thing to deal with, there are 2 ways to look at it:

    (The way this snippet does)
    if the unit has 400 movement speed and receives 50% slow, it would have it's movement speed reduced down to 200, but if it's reduced by 50% again it would reduce it's speed down to 100, when the first effect wears out the unit would have 300 speed. But hey, shouldn't it be 200? The unit has a 50% ms reduction effect applied and it had originally 400 movement speed!
    Yes, turns out that this would be quite hard to do
    In order to properly apply movement speed to units a priority queue must be created (using linked lists and such).

    (The proper way)
    X unit receives a 20% ms reduction, after that a 35% reduction and then a 60% increase.
    If the unit's X movement speed was 400 when it first received the first reduction it's new speed would be

    400-20%=320
    320-35%=208
    208+60%=332.8

    Ok now imagine that the second effect (35%) wears off, because this effect reduced a total of 112 movement speed (from 320 down to 208) the unit would gain the speed lost, ending up with 332.8+112 = 444.8
    Lets redo the math to see what happened

    400-20%=320
    320+60%=512

    Well that's not right, why does it have 444.8 and not 512?
    The system needs this fix, but it's going to be heavy, i'll add it in the next update
     
  4. Dirac

    Dirac 22710180

    Ratings:
    +147 / 0 / -0
    Google chrome is making me double post sometimes
     
  5. Sgqvur

    Sgqvur FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi

    Ratings:
    +62 / 0 / -0
    Dirac:
    1. (The proper way)
    X unit receives a 20% ms reduction, after that a 35% reduction and then a 60% increase.
    If the X'x movement speed was 400 when it first received the reduction it's new speed would be

    400-20%=320
    320-35%=208
    208+60%=332.8

    1. That's not the way the warcraft 3 game does it.
    The percentage is always based on the default movement speed, so your example becomes:

    400 - 20% = 400 - 80 // current mv speed 400 - 80 = 320
    400 - 35% = 400 - 140 // current mv speed 320 - 140 = 180
    400 + 60% = 400 + 240 // current mv speed 180 + 240 = 420 = 400 + 5%

    You don't need "priority queue", just basic arithmetic.
     
  6. Dirac

    Dirac 22710180

    Ratings:
    +147 / 0 / -0
    Well too bad because i don't agree with w3's way of doing things.
    If your unit has boots that increase movement speed by 100 that would mean that the "base" movement speed should include the boot's bonus, this is why the system takes into account the current movement speed rather than the default one
     
  7. Sgqvur

    Sgqvur FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi

    Ratings:
    +62 / 0 / -0
    Well the 100 movement speed would just be added to the base/default of the unit, i.e not the current movement speed. So that new percentage bonuses will be calculated from the new default/base?
     
  8. Jesus4Lyf

    Jesus4Lyf Good Idea™

    Ratings:
    +394 / 0 / -0
    Don't we... have this?
    JASS:
    //              - MoveSpeed (modMoveSpeedBonus, getMoveSpeedBonus)
    //              - MoveSpeedPercent (modMoveSpeedPercentBonus, getMoveSpeedPercentBonus) // percent of current move speed (after normal bonuses).

    Except your one still obeys the 522 cap and breaks if anything slows units by normal means, I think?

    Kind of funny, Status applies % bonus last, your system applies % bonus first. Wonder which is more correct? lol, not so relevant.. :p
     
  9. Dirac

    Dirac 22710180

    Ratings:
    +147 / 0 / -0
    v2.0
    -Changed everything
     
  10. Sgqvur

    Sgqvur FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi

    Ratings:
    +62 / 0 / -0
    Works but not quite.

    Ex:

    A hero with 200 default movement speed set in the OE/Units tab

    Dirac.SpeedMod:

    SpeedMod.create(<hero>, 0.1 /* +10% */) // now the hero has 220 movement speed.
    SpeedMod.base(<hero>, +50) // now the hero has 250 movement speed?! =)

    wc3:

    the hero becomes under the effect of endurance aura +10% level 1 Tauren Chieftain // now the hero has 220 movement speed
    the hero gets a boots of speed +50 // now the hero has 275 movement speed

    Why 275 and not 270 or even 250? What happened in the wc3's case is that when the base movement speed changed (when the hero equipped the boots of speed)
    all the speed percent bonuses attached to the unit got recalculated. In this case only the endurance aura effect was recalculated. (200 + 50 = 250 + 10% = 275)

    So if you do intend to replicate the wc3's "style/way" I think you'll need a list of SpeedMods attached to the unit and which have to be recalculated each time the base movement speed changes with the SpeedMod.base(...)



    *default movement speed = Movement Speed Base in OE/Units
    *base movement speed = default movement speed + boots of speed like bonus (not a percent bonus but a flat bonus)
     
  11. KaerfNomekop

    KaerfNomekop Swim, fishies. Swim through the veil of steel.

    Ratings:
    +609 / 0 / -0
    Do percentages always get a lower priority than specific increases? Or is it just Boots that add to a unit's base MS?
     
  12. Dirac

    Dirac 22710180

    Ratings:
    +147 / 0 / -0
    @Sgqvur
    Make up your mind, you can't change the unit's default movement speed inside the game, you just can't.
    Therefore your example won't be 275 but 270

    Also, v2.0.1
    -Fixed a bug that caused unit's with active speed mods to be deleted when the unit had it's base speed changed
     
  13. Sgqvur

    Sgqvur FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi

    Ratings:
    +62 / 0 / -0
    >Therefore your example won't be 275 but 270

    JASS:
    struct test
    
        static method it takes nothing returns nothing
            local unit paly = CreateUnit(Player(0), 'Hpal', 0, 0, 0) // Movement - Speed Base = 200 in OE/Units/Human/Melee/Heroes/Paladin don't forget to set it
            local unit tc
            
            call BJDebugMsg("paly.move_speed = " + R2S(GetUnitMoveSpeed(paly)))
            set tc = CreateUnit(Player(0), 'Otch', 0, 0, 0)
            call IssueImmediateOrderById(tc, 'AOae') // learn endurance aura
            call TriggerSleepAction(4) // wait for the aura to kick in
            call BJDebugMsg("paly.move_speed = " + R2S(GetUnitMoveSpeed(paly)))
            call UnitAddItemById(paly, 'bspd') // boots of speed +50 (default is +60 so change this as well) Units/Abilities/Special/Items/Item Move Speed Bonus
            call BJDebugMsg("paly.move_speed = " + R2S(GetUnitMoveSpeed(paly)))
        endmethod
        
        static method onInit takes nothing returns nothing
            call it.execute()
        endmethod
        
    endstruct
     
  14. Ayanami

    Ayanami 칼리

    Ratings:
    +287 / 0 / -0
    It actually does become 275. The MS percentage factor is applied to any permanent MS bonus as well.
     
  15. Dirac

    Dirac 22710180

    Ratings:
    +147 / 0 / -0
    Like i quoted Sgqvur in the post before, he said otherwise in a previous post.
    Glad to see you tested it out, do realize that you said
    "The percentage is always based on the default movement speed"
    and that's not true.
    For justice i'll update this system (soon) using linked lists to loop through speed mods and update their values when units get a base movement speed gain.
     
  16. Dirac

    Dirac 22710180

    Ratings:
    +147 / 0 / -0
    v2.1.0
    -Added AIDS or UnitIndexer as a requirement
    -Removed Alloc as a requirement, the system now uses LinkedList for smart allocation.
    -Changing the unit's "base" speed now affects all speed mods on the unit.
     
  17. Juggernaut

    Juggernaut I don't know what to change it to

    Ratings:
    +32 / 0 / -0
    Sorry for necro but for a jass newbie how can I use this ?
    Can you post a sample trigger where the units' speed is modified using this tool?
    ----
    no one ?
     

Share This Page