• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[GUI-friendly] Movement Speed System 2.0.1

[GUI-Friendly] Movement Speed System v2.0.1

This system facilitates the modifcation of unit movement speed using the SetUnitMoveSpeed JASS native. The system itself keeps track of modifications to unit movement speed and allows for two types of modifications: bonus (additive) or multiplier (multiplicative). The system does not provide a way to clear bonuses. Instead, the user should keep track of bonuses that have been added and reduce the same amount when it is required.

Additionally, the system offers the possibility to set values for the minimum and maximum movement speed set by the system. These values, however, are still subject to the limits set by the movement Gameplay Constants, which you can edit in the Advanced menu of the World Editor.

There exists a vJASS system with similar functionality to GMSS: Movement Modifier. If you would like to freely alter unit stats, other than move speed, using triggers, check out the Custom Stat System.

Movement Speed:

The formula for unit movement speed is:
speed = (default speed * multiplier + bonus + other1)*other2

The "other" variables are movement speed bonuses offered by the object editor from abilities such as Unholy Aura and Item Movement Speed Bonus. Additive abilities such as the Boots of Speed contribute to "other1" while multiplicative abilities such as Endurance Aura contribute to "other2".

Hashtable addresses:
Positive Unit Handle ID -> Move Bonus
Negative Unit Handle ID -> Move Multiplier

How to Import:

1. Open World Editor. File -> Preferences -> Tick box for "Automatically create unknown variables (...)"
2. Copy the trigger category "GUI Move Speed System" into your map
3.
a. If you don't want to use the Table optional requirement, delete the Table trigger
b. If you do want to use Table, you can delete the GMSS_Init trigger.
c. If you don't want to use GUI at all, you can then delete GMSS_Main and GMSS_Init.
d. If you don't want to use GUI or Table, follow step 3c and change INIT_HASHTABLE to 'true' in the advanced configurations of the MoveSpeedBonus library​
4.
a. If you are using GUI, and want to use a custom hashtable instead of creating a new one, follow the instructions in the GMSS_Init trigger.
b. If you are using not using GUI or Table, and want to use a custom hashtable, change INIT_HASHTABLE to 'false' in the advanced configurations of the MoveSpeedBonus library and follow instructions.​
5. Done!​

Using the System:

Change Bonus/Multiplier

Limit Speed

Get Bonus/Multiplier

Configure Limits

Configure Hashtable

JASS API


With this system, each unit has it's own movement speed bonus (additive) and multiplier (multiplicative). This function allows you to either add a value to the bonus of a given unit and/or multiply its multiplier by another value. After you make a change, if you want to restore the unit's movement speed, simply reduce the bonus by the opposite amount and/or multiply the multiplier by the inverse amount.

This function will also set the unit's speed to a value between the default limits of the system, which you can configure with the Configure Limits function.

  • Actions
    • Set GMSS_MoveBonus = YourBonus
    • Set GMSS_MoveMultiplier = YourMultiplier
    • Set GMSS_Target = YourUnit
    • Trigger - Run GMSS Main <gen> (checking conditions)
After your run the "GMSS Main" trigger, the GMSS_MoveBonus variable will be set to the current total bonus of the unit and the GMSS_MoveMultiplier will be set to its current total multiplier.

This function is similar to Change Bonus/Multiplier, however, you can also specify the minimum and maximum value that the unit's movement speed can take after applying the change. You can also limit the unit's speed without changing the bonus or multiplier. To do so, simply set GMSS_Bonus to 0 and GMSS_Multiplier to 1 before running the trigger, while setting the limit variables to the values you wish.

  • Actions
    • Set GMSS_MoveBonus = YourBonus
    • Set GMSS_MoveMultiplier = YourMultiplier
    • Set GMSS_MinimumSpeed = YourMinSpeed
    • Set GMSS_MaximumSpeed = YourMaxSpeed
    • Set GMSS_Target = YourUnit
    • Trigger - Run GMSS Main <gen> (ignoring conditions)
After your run the "GMSS Main" trigger, the GMSS_MoveBonus variable will be set to the current total bonus of the unit and the GMSS_MoveMultiplier will be set to its current total multiplier.


This function allows you to get the current bonus and multiplier of a unit. After you run the "GMSS Main" trigger, the values will be stored in GMSS_MoveBonus and GMSS_MoveMultiplier. The default bonus is 0 and the default multiplier is 1.

  • Actions
    • Set GMSS_MoveMultiplier = NegativeNumber
    • Set GMSS_Target = YourUnit
    • Trigger - Run GMSS Main <gen> (ignoring conditions)

When you select the "GMSS Main" trigger, you will find the following code at the top:

JASS:
//===================================================
// Simple configuration
//===================================================
/*
Just change these numbers to whatever you want, you can also set them to a variable (remember to
put "udg_" in front of the variable)
*/
function GMSS_GetDefaultMaxSpeed takes nothing returns real

    return 522.0  // Value for Default Maximum Speed

endfunction

function GMSS_GetDefaultMinSpeed takes nothing returns real

    return 0.000  // Value for Default Minimum Speed

endfunction
//===================================================

To configure the system's default limits, simply change the numbers 0.0 and 522.0 to whatever you need. You can also use a GUI real variable instead, and the system's default limits will be the values of the variables you set. Please note that, if you do this, the limit's will not be constant, since you can change the values of the variables.


If you use the Table optional requirement (included in the Test Map), then you do not need to worry about this section.

You can use this system without changing the hashtable. If you have little experience with hashtables, you can ignore this method if you are unsure.

Since this system only requires the usage of 1 Child Hashtable, it is not necessary to create a whole need Parent Hashtable for the system. Therefore, you can configure the system to use another hashtable instead of creating a new one, by changing the value of the GMSS_Hashtable variable. Please note that you need to make sure that the Child Hashtable of number equal to GMSS_HASHTABLE_ADDRESS is free and will not be written to except by the system.

This is how the configurable part of the initialization trigger looks like:
  • Actions
    • -------- YOU DON'T NEED TO CREATE A HASHTABLE, YOU CAN USE ONE YOU ALREADY HAVE --------
    • Hashtable - Create a hashtable
    • -------- ------------------------------------- --------
    • -------- If you don't want to create a hashtable, delete the line above and set the value of the GMSS_Hashtable to that of another hashtable --------
    • Set GMSS_Hashtable = (Last created hashtable)
    • -------- ------------------------------------- --------
    • -------- This is the child hashtable used by the system. Make sure it has free addresses in the range of Unit Handle IDs --------
    • Set GMSS_HASHTABLE_ADDRESS = 0
To use another hashtable, you would change it to this:
  • Actions
    • Set GMSS_Hashtable = YOUR_HASHTABLE
    • -------- ------------------------------------- --------
    • -------- This is the child hashtable used by the system. Make sure it has free addresses in the range of Unit Handle IDs --------
    • Set GMSS_HASHTABLE_ADDRESS = YOUR_FREE_CHILD_HASHTABLE_NUMBER
Please note that YOUR_HASHTABLE must have been created before GMSS_Hashtable is set to it. If GMSS_Hashtable is not properly initialized, the system will throw an error when the "GMSS Init" trigger is run. If this happens, you may need to put the line below in another trigger (the one where YOUR_HASHTABLE is created), or change the Event of the "GMSS Init" trigger so that it fires after the hashtable is created.

  • Set GMSS_Hashtable = YOUR_HASHTABLE

The system is built so it can also be used by calling JASS functions. If you do not intend to use the GUI addon, then you can simple remove the GMSS_Init and GMSS_Main triggers (see import instructions for more details.)

JASS:
'                                            API                                                   '

// Adds "amount" to unit speed bonus and sets move speed between "minSpeed" and "maxSpeed".
function GMSS_UnitAddMoveSpeedEx
    takes
        unit whichUnit
        real amount   => //!The amount to add to the unit's move speed.
        real minSpeed => //!The unit's new speed will not be lower than this value.
        real maxSpeed => //!The unit's new speed will not be higher than this value.
    returns
        real => //!The unit's flat move speed bonus after changes are applied.
endfunction

// Multiplies unit speed multiplier by "amount" and sets move speed between "minSpeed" and "maxSpeed".
function GMSS_UnitMultiplyMoveSpeedEx
    takes
        unit whichUnit
        real amount   => //!The amount to add to the unit's move speed.
        real minSpeed => //!The unit's new speed will not be lower than this value.
        real maxSpeed => //!The unit's new speed will not be higher than this value.
    returns
        real => //!The unit's move speed multiplier after changes are applied.
endfunction

// Like GMSS_UnitAddMoveSpeedEx, but min and max values are drawn from GMSS_GetDefaultMax(Min)Speed.
function GMSS_UnitAddMoveSpeed takes unit whichUnit, real amount returns real
    takes
        unit whichUnit
        real amount   => //!The amount to add to the unit's move speed.
    returns
        real => //!The unit's flat move speed bonus after changes are applied.
endfunction

// Like GMSS_UnitMultiplyMoveSpeedEx, but min and max values are drawn from GMSS_GetDefaultMax(Min)Speed.
function GMSS_UnitMultiplyMoveSpeed takes unit whichUnit, real amount returns real
    takes
        unit whichUnit
        real amount   => //!The amount to add to the unit's move speed.
    returns
        real => //!The unit's move speed multiplier after changes are applied.
endfunction


function GMSS_UnitGetMoveBonus takes unit whichUnit returns real
    takes
        unit whichUnit
    returns
        real => //!The unit's movement speed flat bonus.
endfunction

function GMSS_UnitGetMoveMultiplier takes unit whichUnit returns real
    takes
        unit whichUnit
    returns
        real => //!The unit's movement speed multiplier.
endfunction

// Clears all Hashtable or Table data stored for 'whichUnit' in the system.
// You won't need to call this yourself unless AUTO_CLEANUP is set to false.
function GMSS_ClearData takes unit whichUnit returns nothing
    takes
        unit whichUnit
    returns
        nothing
endfunction



Test Map:


Command

Action

add x

add x stacking bonus to unit movement (can be negative)

mul x

multiply unit movement by x stacking

get

show unit move speed

mod

show unit move bonus and multiplier

The Test Map is currently very simple, featuring only a few hero units (including DK for Unholy Aura and TC for Endurance Aura) and two boots of speed. To test the system, use the above commands.


Updates and Version History:
v1:
1.0.0 > Initial Release​
v2:
2.0.0 > System changed to vJass
2.0.1 > Changed the way the system initializes. Optimizing the map is no longer required to not generate an empty hashtable regardless of INIT_HASHTABLE value. Documentation errors fixed.​
Upcoming:
Better testmap with more examples and use cases.​
Contents

Guhun's Movement Speed System (Map)

Can this be used along with UnitMovementSpeedX?
I believe they should work together, as UnitMovementSpeedX uses hooks. However, you will have to set GMSS_MaximumSpeed to higher than 522, or change the default maximum speed.

The -get command in the testmap would not work, however, you would have to change it to use UnitMovementSpeedX's custom function.

The modifiers themselves are stored completely separtely from the unit's speed, so there is no reason for the systems to not be compatible.

However, items that give movement speed with Object Editor data should not work. But I believe they also do not work with UnitMovementSpeedX. You will have to trigger your items to use UnitMovementSpeedX alongside this system.
 
Last edited:
This looks good to me. My only hesitation is that I'm not certain about threading guarantees when setting and reading globals between a trigger condition and action.

I would prefer if they're done in the same place -- either all in the condition or all in the action.

Approving.

Looks good
 

Attachments

  • 1713955934939.png
    1713955934939.png
    28.2 KB · Views: 17
Top