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
613
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.
  • Monovertex Monovertex:
    How are you all? :D
    +1
  • Ghan Ghan:
    Howdy
  • Ghan Ghan:
    Still lurking
    +3
  • The Helper The Helper:
    I am great and it is fantastic to see you my friend!
    +1
  • The Helper The Helper:
    If you are new to the site please check out the Recipe and Food Forum https://www.thehelper.net/forums/recipes-and-food.220/
  • Monovertex Monovertex:
    How come you're so into recipes lately? Never saw this much interest in this topic in the old days of TH.net
  • Monovertex Monovertex:
    Hmm, how do I change my signature?
  • tom_mai78101 tom_mai78101:
    Signatures can be edit in your account profile. As for the old stuffs, I'm thinking it's because Blizzard is now under Microsoft, and because of Microsoft Xbox going the way it is, it's dreadful.
  • The Helper The Helper:
    I am not big on the recipes I am just promoting them - I use the site as a practice place promoting stuff
    +2
  • Monovertex Monovertex:
    @tom_mai78101 I must be blind. If I go on my profile I don't see any area to edit the signature; If I go to account details (settings) I don't see any signature area either.
  • The Helper The Helper:
    You can get there if you click the bell icon (alerts) and choose preferences from the bottom, signature will be in the menu on the left there https://www.thehelper.net/account/preferences
  • The Helper The Helper:
    I think I need to split the Sci/Tech news forum into 2 one for Science and one for Tech but I am hating all the moving of posts I would have to do
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top