diff --git a/.gitignore b/.gitignore index dadad45..db77b9e 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ scripts/Libraries/* !scripts/Libraries/ExampleLibrary.lua !scripts/Libraries/ExampleDependency.lua !scripts/Libraries/ExampleDependencyError.lua +!scripts/Libraries/Math.lua ## ignore vscode settings .vscode/* diff --git a/scripts/Libraries/Math.lua b/scripts/Libraries/Math.lua new file mode 100644 index 0000000..01e4ef1 --- /dev/null +++ b/scripts/Libraries/Math.lua @@ -0,0 +1,123 @@ +local Tinkr, Bastion = ... + +local NAN = math.huge * 0 +local IS_NAN_GT_INF = (NAN or 0 ) > math.huge +local NAN_STR = tostring(NAN) + +Bastion:RegisterLibrary(Bastion.Library:New({ + name = 'Math', + exports = { + default = function(self) -- Function exports are called when the library is loaded + -- Return default first, and then the remaining exports + local Math = {} + + Math.__index = Math + + ---Returns NAN + ---@return number + function Math.GetNan() + assert(NAN) + return NAN + end + ---checks if a value is NAN + ---@param value number + ---@return boolean @whether or not the value is NAN + function Math.IsNan(value) + if not NAN then error("NAN not set") end + if IS_NAN_GT_INF then + -- if NAN > math.huge (which it is in Wow's version of lua) + return value > math.huge and tostring(value) == NAN_STR + else + return tostring(value) == NAN_STR + end + end + + ---Rounds a number to the nearest significant value + ---@param value number The number to be rounded + ---@param sig number The value to round to the nearest multiple of (defaults to 1) + ---@return number + function Math.Round(value, sig) + sig = sig or 1 + return math.floor((value / sig) + 0.5) * sig + end + + + ---Rounds a value down to a specified significant value. + ---@param value number The number to be rounded + ---@param sig? number The value to round down to the nearest multiple of (defaults to 1) + ---@return number + function Math.Floor(value, sig) + sig = sig or 1 + return math.floor(value / sig) * sig + end + + ---Rounds a value up to a specified significant value. + ---@param value number The number to be rounded + ---@param sig? number The value to round up to the nearest multiple of (defaults to 1) + ---@return number + function Math.Ceil(value, sig) + sig = sig or 1 + return math.ceil(value / sig) * sig + end + + ---Scales a value from one range to another. + ---@param value number The number to be scaled + ---@param fromStart number The start value of the range to scale from + ---@param fromEnd number The end value of the range to scale from (can be less than fromStart) + ---@param toStart number The start value of the range to scale to + ---@param toEnd number The end value of the range to scale to (can be less than toStart) + ---@return number + function Math.Scale(value, fromStart, fromEnd, toStart, toEnd) + assert(value >= math.min(fromStart, fromEnd) and value <= math.max(fromStart, fromEnd)) + return toStart + ((value - fromStart) / (fromEnd - fromStart)) * (toEnd - toStart) + end + + ---Bounds a number between a min and max value. + ---@param value number The number to be bounded + ---@param minValue number The min value + ---@param maxValue number The max value + ---@return number + function Math.Bound(value, minValue, maxValue) + return math.min(math.max(value, minValue), maxValue) + end + + ---This code is a method that generates a random number within a given range. + ---It ensures that there are at least 50 possible choices by making multiple copies of the range if necessary. + --- It also allows for the number to be divided by a specified divisor for decimals + ---@param lowRange number The low end of the range + ---@param highRange number The high end of the range + ---@param divisor? number The divisor to divide the number by + ---@return number + function Math.RandomNumberGenerator(lowRange, highRange, divisor) + local lowNum, highNum + if not highRange then + highNum = lowRange + lowNum = 1 + else + lowNum = lowRange + highNum = highRange + end + local total = 1 + if math.abs(highNum - lowNum + 1) < 50 then -- if total values is less than 50 + total = math.modf(50/math.abs(highNum - lowNum + 1)) -- make x copies required to be above 50 + end + local choices = {} + for i = 1, total do -- iterate required number of times + for x = lowNum, highNum do -- iterate between the range + choices[#choices +1] = x -- add each entry to a table + end + end + local rtnVal = math.random(#choices) -- will now do a math.random of at least 50 choices + for i = 1, 10 do + rtnVal = math.random(#choices) -- iterate a few times for random randomness + end + if divisor then + return choices[rtnVal] / divisor + end + return choices[rtnVal] + end + + return Math + end + } +}))