• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • ✅ HD Level Design Contest #1 POLL is now OPEN! Check out the stunning visuals of the final entries. 🔗Click here to cast your vote!

[vJASS] Simple Math Functions

Here's a collection of useful math functions for vJASS. I looked around a bit and couldn't find a concise collection of them, so I decided to make my own and post it in case others find these useful. A few of the functions reflect existing functions in the WorldEditor but have been slightly rewritten to avoid the use of Locations.

Most of the functions contain relatively simple math that can just be substituted in place of a function call, but many of these functions can help make code more readable and easier to digest. Feel free to adjust or modify your own versions however you see fit.

vJASS:
/*
    Collection of simple math functions involving real and integer types
  
    Functions:
        AngleXY         : Calculates the angle from (x1, y1) to (x2, y2)
        DistanceXY      : Calculates the straight-line distance from (x1, y1) to (x2, y2)
        PolarX          : Calculates a new X coordinate by moving it 'dist' units in 'angle' direction
        PolarY          : Calculates a new Y coordinate by moving it 'dist' units in 'angle' direction
        AbsR            : Calculates the absolute value for real numbers
        AbsI            : Calculates the absolute value for integer numbers numbers
        Round           : Rounds a real number to the nearest integer
        Floor           : Takes a real value and returns the closest integer less than or equal to it
        Ceiling         : Takes a real value and returns the closest integer greater than or equal to it
        Mod             : Returns the modulus of two integer values
        MinR            : Calculates the minimum of two real numbers
        MaxR            : Calculates the maximum of two real numbers
        MinI            : Calculates the minimum of two integer numbers
        MaxI            : Calculates the maximum of two integer numbers
        ClampR          : Restricts a real number between a minimum and maximum value
        ClampI          : Restricts an integer number between a minimum and maximum value
        ClampBetweenR   : Restricts a real number between two other real values.
        ClampBetweenI   : Restricts an integer number between two other integer values.
        Lerp            : Gives a linear interpolation between two real values based on a percentage input
        InvLerp         : Gives the percentage input that would produce the desired value between two real values
        Transform       : Takes a value between two numbers and returns a new value that is similarly positioned between two new numbers
*/

library Math
    /*
        AngleXY
            Calculates the angle from (x1, y1) to (x2, y2)
      
        An equivalent to AngleBetweenPoints that doesn't use location types
        Coordinate order matters, so switching the order inverts the direction of the angle
    */
    public function AngleXY takes real x1, real y1, real x2, real y2 returns real
        return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
    endfunction
  
    /*
        DistanceXY
            Calculates the straight-line distance from (x1, y1) to (x2, y2)
          
        An equivalent to DistanceBetweenPoints that doesn't use location types
    */
    public function DistanceXY takes real x1, real y1, real x2, real y2 returns real
        local real dx = x2 - x1
        local real dy = y2 - y1
        return SquareRoot(dx * dx + dy * dy)
    endfunction
  
    /*
        PolarX
            Calculates a new X coordinate by moving it 'dist' units in 'angle' direction
          
        A partial equivalent to PolarProjectionBJ that doesn't use location types
    */
    public function PolarX takes real x, real dist, real angle returns real
        return x + dist * Cos(angle * bj_DEGTORAD)
    endfunction

    /*
        PolarY
            Calculates a new Y coordinate by moving it 'dist' units in 'angle' direction
          
        A partial equivalent to PolarProjectionBJ that doesn't use location types
    */
    public function PolarY takes real y, real dist, real angle returns real
        return y + dist * Sin(angle * bj_DEGTORAD)
    endfunction
  
    /*
        AbsR
            Calculates the absolute value for real numbers
          
        Examples:
            AbsR(1.5) gives a value of 1.5
            AbsR(-1.5) gives a value of 1.5
    */
    public function AbsR takes real value returns real
        if (value < 0) then
            return value * -1.0
        endif
        return value
    endfunction

    /*
        AbsI
            Calculates the absolute value for integer numbers numbers
          
        Examples:
            AbsI(2) gives a value of 2
            AbsI(-2) gives a value of 2
    */
    public function AbsI takes integer value returns integer
        if (value < 0) then
            return value * -1
        endif
        return value
    endfunction
  
    /*
        Round
            Rounds a real number to the nearest integer
    */
    public function Round takes real value returns integer
        return R2I(value + 0.5)
    endfunction
  
    /*
        Floor
            Takes a real value and returns the closest integer less than or equal to it
    */
    public function Floor takes real value returns integer
        return R2I(value)
    endfunction
  
    /*
        Ceiling
            Takes a real value and returns the closest integer greater than or equal to it
    */
    public function Ceiling takes real value returns integer
        local integer result = R2I(value)
        if (I2R(result) == value) then
            return result
        endif
        return result + 1
    endfunction
  
    /*
        Mod
            Returns the modulus of two integer values
          
        The modulus is the remainder after division takes place
      
        Examples:
            Mod(3, 3) gives a value of 0
            Mod(4, 3) gives a value of 1
            Mod(5, 3) gives a value of 2
            Mod(6, 3) gives a value of 0
            Mod(7, 3) gives a value of 1
            Mod(8, 3) gives a value of 2
    */
    public function Mod takes integer value, integer divisor returns integer
        return value - (value / divisor) * divisor
    endfunction

    /*
        MinR
            Calculates the minimum of two real numbers
      
        Examples:
            MinR(1.5, 2.5) gives a value of 1.5
            MinR(-3.0, 1.0) gives a value of -3.0
    */
    public function MinR takes real a, real b returns real
        if (a < b) then
            return a
        else
            return b
        endif
    endfunction
  
    /*
        MaxR
            Calculates the maximum of two real numbers
      
        Examples:
            MaxR(1.5, 2.5) gives a value of 2.5
            MaxR(-3.0, 1.0) gives a value of 1.0
    */
    public function MaxR takes real a, real b returns real
        if (a < b) then
            return b
        else
            return a
        endif
    endfunction

    /*
        MinI
            Calculates the minimum of two integer numbers
      
        Examples:
            MinI(1, 2) gives a value of 1
            MinI(-3, 1) gives a value of -3
    */
    public function MinI takes integer a, integer b returns integer
        if (a < b) then
            return a
        else
            return b
        endif
    endfunction
  
    /*
        MaxI
            Calculates the maximum of two integer numbers
      
        Examples:
            MaxI(1, 2) gives a value of 2
            MaxI(-3, 1) gives a value of 1
    */
    public function MaxI takes integer a, integer b returns integer
        if (a < b) then
            return b
        else
            return a
        endif
    endfunction
  
    /*
        ClampR
            Restricts a real number between a minimum and maximum value
      
        Examples:
            ClampR(1.0, 2.0, 4.0) gives a value of 2.0
            ClampR(2.0, 2.0, 4.0) gives a value of 2.0
            ClampR(3.0, 2.0, 4.0) gives a value of 3.0
            ClampR(4.0, 2.0, 4.0) gives a value of 4.0
            ClampR(5.0, 2.0, 4.0) gives a value of 4.0
    */
    public function ClampR takes real value, real min, real max returns real
        return MaxR(MinR(value, max), min)
    endfunction

    /*
        ClampI
            Restricts an integer number between a minimum and maximum value
      
        Examples:
            ClampI(1, 2, 4) gives a value of 2
            ClampI(2, 2, 4) gives a value of 2
            ClampI(3, 2, 4) gives a value of 3
            ClampI(4, 2, 4) gives a value of 4
            ClampI(5, 2, 4) gives a value of 4
    */
    public function ClampI takes integer value, integer min, integer max returns integer
        return MaxI(MinI(value, max), min)
    endfunction
  
    /*
        ClampBetweenR
            Restricts a real number between two other real values.
      
        This version doesn't require you to sort your min and max values

        Examples:
            ClampBetweenR(1.0, 4.0, 2.0) gives a value of 2.0
            ClampBetweenR(2.0, 4.0, 2.0) gives a value of 2.0
            ClampBetweenR(3.0, 4.0, 2.0) gives a value of 3.0
            ClampBetweenR(4.0, 4.0, 2.0) gives a value of 4.0
            ClampBetweenR(5.0, 4.0, 2.0) gives a value of 4.0
    */
    public function ClampBetweenR takes real value, real first, real second returns real
        local real min = MinR(first, second)
        local real max = MaxR(first, second)
        return ClampR(value, min, max)
    endfunction

    /*
        ClampBetweenI
            Restricts an integer number between two other integer values.
      
        This version doesn't require you to sort your min and max values

        Examples:
            ClampBetweenI(1, 4, 2) gives a value of 2
            ClampBetweenI(2, 4, 2) gives a value of 2
            ClampBetweenI(3, 4, 2) gives a value of 3
            ClampBetweenI(4, 4, 2) gives a value of 4
            ClampBetweenI(5, 4, 2) gives a value of 4
    */
    public function ClampBetweenI takes integer value, integer first, integer second returns integer
        local integer min = MinI(first, second)
        local integer max = MaxI(first, second)
        return ClampI(value, min, max)
    endfunction

    /*
        Lerp
            Gives a linear interpolation between two real values based on a percentage input
      
        A percentage value of 0.0 gives the first number.
        A percentage value of 1.0 gives the second number.
        A percentage value of 0.5 gives a value halfway between first and second
      
        The percentage can be outside 0.0-1.0 if desired
      
        Examples:
            Lerp(4.0, 8.0, 0.00) gives a value of 4.0
            Lerp(4.0, 8.0, 0.25) gives a value of 5.0
            Lerp(4.0, 8.0, 0.50) gives a value of 6.0
            Lerp(4.0, 8.0, 0.75) gives a value of 7.0
            Lerp(4.0, 8.0, 1.00) gives a value of 8.0
    */
    public function Lerp takes real first, real second, real percent returns real
        return first + (second - first) * percent
    endfunction

    /*
        InvLerp (Inverse Lerp)
            Gives the percentage input that would produce the desired value between two real values
      
        Examples:
            InvLerp(4.0, 8.0, 4.0) gives a value of 0.00 (0%)
            InvLerp(4.0, 8.0, 5.0) gives a value of 0.25 (25%)
            InvLerp(4.0, 8.0, 6.0) gives a value of 0.50 (50%)
            InvLerp(4.0, 8.0, 7.0) gives a value of 0.75 (75%)
            InvLerp(4.0, 8.0, 8.0) gives a value of 1.00 (100%)
    */
    public function InvLerp takes real first, real second, real value returns real
        return (value - first) / (second - first)
    endfunction
  
    /*
        Transform
            Takes a value between two numbers and returns a new value that is similarly positioned between two new numbers
      
        Input value does not strictly need to be between the first and second numbers
      
        Examples:
            Take a number between 2.0 and 4.0 and transform it to a number between 100.0 and 150.0
                Transform(2.0, 2.0, 4.0, 100.0, 150.0)   gives a value of 100.0
                Transform(2.5, 2.0, 4.0, 100.0, 150.0)   gives a value of 112.5
                Transform(3.0, 2.0, 4.0, 100.0, 150.0)   gives a value of 125.0
                Transform(3.5, 2.0, 4.0, 100.0, 150.0)   gives a value of 137.5
                Transform(4.0, 2.0, 4.0, 100.0, 150.0)   gives a value of 150.0
          
            An AOE spell of range 500 that deals more damage the closer you are to the center.
            Let's say the damage at the center is 150 and the damage at the edge is 50
            The distance from the center would be the input
                damage = Transform(distance, maxAOE, minAOE, minDamage, maxDamage)
                
                Transform(  0.0, 500.0, 0.0, 50.0, 150.0)   gives a value of 150.0 damage
                Transform(100.0, 500.0, 0.0, 50.0, 150.0)   gives a value of 130.0 damage
                Transform(200.0, 500.0, 0.0, 50.0, 150.0)   gives a value of 110.0 damage
                Transform(300.0, 500.0, 0.0, 50.0, 150.0)   gives a value of  90.0 damage
                Transform(400.0, 500.0, 0.0, 50.0, 150.0)   gives a value of  70.0 damage
                Transform(500.0, 500.0, 0.0, 50.0, 150.0)   gives a value of  50.0 damage
    */
    public function Transform takes real value, real first, real second, real newFirst, real newSecond returns real
        return Lerp(newFirst, newSecond, InvLerp(first, second, value))
    endfunction
endlibrary
 
Last edited:
Level 12
Joined
Jan 10, 2023
Messages
191
These are two I added to my math library, I'm definitely going to start using some of these.

I'm also curious if these two I'm throwing out there seem viable to others (or if there are similar functions I am unaware of)

They aren't really math, but I consider them math-y enough...
JASS:
public function I2B takes integer i returns boolean
    if i == 0 then
        return false
    endif
    return true
endfunction

public function B2I takes boolean b returns integer
    if b == true then
        return 1
    endif
    return 0
endfunction

Revised after @Bribe made some good comments on the suggested functions:

JASS:
// after hearing Bribe's response I realize how unnecessary this function is
public function I2B takes integer i returns boolean
    return i != 0
endfunction

public function B2I takes boolean b returns integer
    if b then
        return 1
    endif
    return 0
endfunction
 
Last edited:
Level 12
Joined
Jan 10, 2023
Messages
191
Right, thank you!
I'll keep that in mind for better/ more concise code.

It is rare, but I've found some cases where I would like to use a boolean in my math to apply a shift, a recent example was using collision sizes and accounting for the offset of some sizes (units of size 16.00-31.99, and 48.00-1024.00 are not centered on their 'collision map')
There are several ways I could have done it, (in hindsight I could just divide by 16 and come up with something like:
Code:
e=R2I((size)/16)
X + (1+(-1)^e)/2
But then for numbers between 48.00-1024.00 (or whatever the max may be) the pattern doesn't follow and units don't actually get any 'bigger', so the equation fails, so in the past I opted for a boolean-like integer, setting an integer to either 0 or 1 to circumvent this.

The I2B function seems a little useless now, since any time I might need a boolean I might as well just check.

I'm still learning many tricks of the trade though, so I'm all ears if I'm missing something that would save me trouble/ be better than what I'm doing.
 
Level 23
Joined
Jan 1, 2011
Messages
1,488
JASS:
public function Round takes real value returns integer
        return R2I(value + 0.5)
    endfunction
There are rounding issues using your prescribed function. There is a thread that gets into it here.
Jass has a function named MathRound, that rounds numbers. Not many people know about it, so I recommend replacing your function with it, or at least make it a wrapper.
 
Top