Snippet SpeedMod

Dirac

22710180
Reaction score
147
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
 

Dirac

22710180
Reaction score
147
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
 

Sgqvur

FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi
Reaction score
62
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.
 

Dirac

22710180
Reaction score
147
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
 

Sgqvur

FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi
Reaction score
62
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?
 

Jesus4Lyf

Good Idea™
Reaction score
397
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
 

Sgqvur

FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi
Reaction score
62
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)
 

KaerfNomekop

Swim, fishies. Swim through the veil of steel.
Reaction score
612
Do percentages always get a lower priority than specific increases? Or is it just Boots that add to a unit's base MS?
 

Dirac

22710180
Reaction score
147
@Sgqvur
That's not the way the warcraft 3 game does it.
The percentage is always based on the default movement speed
What happened in the wc3's case is that when the base movement speed changed (when the hero equipped the boots of speed)
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
 

Sgqvur

FullOfUltimateTruthsAndEt ernalPrinciples, i.e shi
Reaction score
62
>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), &#039;Hpal&#039;, 0, 0, 0) // Movement - Speed Base = 200 in OE/Units/Human/Melee/Heroes/Paladin don&#039;t forget to set it
        local unit tc
        
        call BJDebugMsg(&quot;paly.move_speed = &quot; + R2S(GetUnitMoveSpeed(paly)))
        set tc = CreateUnit(Player(0), &#039;Otch&#039;, 0, 0, 0)
        call IssueImmediateOrderById(tc, &#039;AOae&#039;) // learn endurance aura
        call TriggerSleepAction(4) // wait for the aura to kick in
        call BJDebugMsg(&quot;paly.move_speed = &quot; + R2S(GetUnitMoveSpeed(paly)))
        call UnitAddItemById(paly, &#039;bspd&#039;) // boots of speed +50 (default is +60 so change this as well) Units/Abilities/Special/Items/Item Move Speed Bonus
        call BJDebugMsg(&quot;paly.move_speed = &quot; + R2S(GetUnitMoveSpeed(paly)))
    endmethod
    
    static method onInit takes nothing returns nothing
        call it.execute()
    endmethod
    
endstruct
 

Ayanami

칼리
Reaction score
288
@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

It actually does become 275. The MS percentage factor is applied to any permanent MS bonus as well.
 

Dirac

22710180
Reaction score
147
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.
 

Dirac

22710180
Reaction score
147
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.
 

Juggernaut

I don't know what to change it to
Reaction score
33
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 ?
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top