diff --git a/engine/source/openborscript/math.c b/engine/source/openborscript/math.c index 453abb57e..bddf5fe8f 100644 --- a/engine/source/openborscript/math.c +++ b/engine/source/openborscript/math.c @@ -14,163 +14,489 @@ // written by White Dragon. #include "scriptcommon.h" +#include "ScriptVariantInteger.h" -HRESULT math_sin(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) +#include +#include + +#define MATH_PI 3.14159265358979323846264338327950288 + +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get a 0-359 table index from an integer +* angle variant without narrowing 64-bit +* carriers through legacy LONG. +*/ +static HRESULT math_angle_index(ScriptVariant *var, int *pindex) { - LONG ltemp; - if(SUCCEEDED(ScriptVariant_IntegerValue(varlist[0], <emp))) - { - ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); - (*pretvar)->dblVal = sin_table[(ltemp % 360 + 360) % 360]; + int64_t signed_value; + uint64_t unsigned_value; + int index; + + if (!var || !pindex) { + return E_FAIL; + } + + if (var->vt == VT_UINTEGER64) { + unsigned_value = var->ullVal; + *pindex = (int)(unsigned_value % 360u); return S_OK; } - *pretvar = NULL; + + if (ScriptVariant_Integer64Value(var, &signed_value) != S_OK) { + return E_FAIL; + } + + index = (int)(signed_value % 360); + + if (index < 0) { + index += 360; + } + + *pindex = index; + + return S_OK; +} + +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Set an integer script variant from a truncated +* decimal value. Preserves legacy VT_INTEGER +* results when possible and promotes to 64-bit +* integer carriers when needed. +*/ +static HRESULT math_set_truncated_integer(ScriptVariant *pretvar, DOUBLE value) +{ + DOUBLE truncated; + + if (!pretvar || !isfinite((double)value)) { + return E_FAIL; + } + + truncated = trunc(value); + + if (truncated >= (DOUBLE)LONG_MIN && + truncated <= (DOUBLE)LONG_MAX) { + + ScriptVariant_ChangeType(pretvar, VT_INTEGER); + pretvar->lVal = (LONG)truncated; + return S_OK; + } + + if (truncated >= (DOUBLE)INT64_MIN && + truncated < 9223372036854775808.0) { + + ScriptVariant_ChangeType(pretvar, VT_INTEGER64); + pretvar->llVal = (int64_t)truncated; + return S_OK; + } + + if (truncated >= 0.0 && + truncated < 18446744073709551616.0) { + + ScriptVariant_ChangeType(pretvar, VT_UINTEGER64); + pretvar->ullVal = (uint64_t)truncated; + return S_OK; + } + return E_FAIL; } -HRESULT math_cos(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get sine of a degree angle as a decimal. +* Cheaper than math_ssin() for integer angles +* that can be indexed directly into the sine +* table. +*/ +HRESULT math_sin(ScriptVariant **varlist, ScriptVariant **pretvar, int paramCount) { - LONG ltemp; - if(SUCCEEDED(ScriptVariant_IntegerValue(varlist[0], <emp))) + int index; + + if (math_angle_index(varlist[0], &index) == S_OK) { ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); - (*pretvar)->dblVal = cos_table[(ltemp % 360 + 360) % 360]; + (*pretvar)->dblVal = sin_table[index]; return S_OK; } + *pretvar = NULL; return E_FAIL; } -HRESULT math_ssin(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get cosine of a degree angle as a decimal. +* Cheaper than math_scos() for integer angles +* that can be indexed directly into the cosine +* table. +*/ +HRESULT math_cos(ScriptVariant **varlist, ScriptVariant **pretvar, int paramCount) { - DOUBLE dbltemp; + int index; - if(SUCCEEDED(ScriptVariant_DecimalValue(varlist[0], &dbltemp))) + if (math_angle_index(varlist[0], &index) == S_OK) { - double PI = 3.14159265; - ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); - (*pretvar)->dblVal = (DOUBLE)sin(dbltemp*PI/180.0); + (*pretvar)->dblVal = cos_table[index]; return S_OK; } + *pretvar = NULL; return E_FAIL; } +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get cosine of a degree angle as a decimal. +*/ HRESULT math_scos(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) { DOUBLE dbltemp; if(SUCCEEDED(ScriptVariant_DecimalValue(varlist[0], &dbltemp))) { - double PI = 3.14159265; - ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); - (*pretvar)->dblVal = (DOUBLE)cos(dbltemp*PI/180.0); + (*pretvar)->dblVal = (DOUBLE)cos(dbltemp*MATH_PI/180.0); return S_OK; } *pretvar = NULL; return E_FAIL; } -HRESULT math_sqrt(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get square root of a variant as a decimal. +*/ +HRESULT math_sqrt(ScriptVariant **varlist, ScriptVariant **pretvar, int paramCount) { DOUBLE dbltemp; - float inv; - if(SUCCEEDED(ScriptVariant_DecimalValue(varlist[0], &dbltemp))) + if (ScriptVariant_DecimalValue(varlist[0], &dbltemp) == S_OK && + dbltemp >= 0.0) { ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); - inv = invsqrt((float)dbltemp); - assert(inv != 0.0f); - (*pretvar)->dblVal = (DOUBLE)1.0 / inv; + (*pretvar)->dblVal = (DOUBLE)sqrt((double)dbltemp); return S_OK; } + *pretvar = NULL; + return E_FAIL; +} + +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Safely raise a signed 64-bit integer base to +* a non-negative integer exponent. +*/ +static int math_pow_signed64(int64_t base, uint64_t exponent, int64_t *result) +{ + int64_t current = base; + int64_t output = 1; + + if (!result) { + return 0; + } + while (exponent) { + if (exponent & 1u) { + if (!ScriptVariant_MulSigned64(output, current, &output)) { + return 0; + } + } + + exponent >>= 1u; + + if (exponent && + !ScriptVariant_MulSigned64(current, current, ¤t)) { + return 0; + } + } + + *result = output; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Safely raise an unsigned 64-bit integer base to +* a non-negative integer exponent. +*/ +static int math_pow_unsigned64(uint64_t base, uint64_t exponent, uint64_t *result) +{ + uint64_t current = base; + uint64_t output = 1; + + if (!result) { + return 0; + } + + while (exponent) { + if (exponent & 1u) { + if (!ScriptVariant_MulUnsigned64(output, current, &output)) { + return 0; + } + } + + exponent >>= 1u; + + if (exponent && + !ScriptVariant_MulUnsigned64(current, current, ¤t)) { + return 0; + } + } + + *result = output; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-08 +* +* *POW!* +* +* Get punched in the face by Batman. Also +* raise one variant to the power of another. +* +* Integer operands with non-negative integer +* exponents stay in integer space when the +* result fits an integer carrier. Decimal +* operands, negative exponents, and values +* that exceed 64-bit integer range fall back +* to decimal pow() behavior. +* +* Examples: +* pow(2, 8) -> VT_INTEGER +* pow(2, 32) -> VT_INTEGER64 or VT_UINTEGER64 depending setter policy/LONG size +* pow(2, 63) -> VT_UINTEGER64 +* pow(-2, 63) -> VT_INTEGER64 +* pow(2, -1) -> VT_DECIMAL +* pow(2.5, 2) -> VT_DECIMAL +*/ +HRESULT math_pow(ScriptVariant **varlist, ScriptVariant **pretvar, int paramCount) +{ + /* + * Decimal path preserves legacy floating-point + * behavior when either operand is decimal. + */ + if (varlist[0]->vt == VT_DECIMAL || varlist[1]->vt == VT_DECIMAL) { + DOUBLE base; + DOUBLE exponent; + + if (ScriptVariant_DecimalValue(varlist[0], &base) == S_OK && + ScriptVariant_DecimalValue(varlist[1], &exponent) == S_OK) { + + ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); + (*pretvar)->dblVal = (DOUBLE)pow((double)base, (double)exponent); + return S_OK; + } + + *pretvar = NULL; + return E_FAIL; + } + + /* + * Unsigned integer power. Use this path for + * explicit unsigned bases and non-negative + * signed bases so results above INT64_MAX + * can still stay integer as VT_UINTEGER64. + */ + { + uint64_t base; + uint64_t exponent; + uint64_t result; + + if (ScriptVariant_Unsigned64Value(varlist[0], &base) == S_OK && + ScriptVariant_Unsigned64Value(varlist[1], &exponent) == S_OK && + math_pow_unsigned64(base, exponent, &result)) { + + ScriptVariant_SetUnsignedIntegerResult(*pretvar, result, 0); + return S_OK; + } + } + + /* + * Signed integer power for negative signed + * bases and signed results. The exponent must + * be non-negative. + */ + { + int64_t base; + int64_t signed_exponent; + int64_t result; + + if (ScriptVariant_Integer64Value(varlist[0], &base) == S_OK && + ScriptVariant_Integer64Value(varlist[1], &signed_exponent) == S_OK && + signed_exponent >= 0 && + math_pow_signed64(base, (uint64_t)signed_exponent, &result)) { + + ScriptVariant_SetSignedIntegerResult(*pretvar, result, 0); + return S_OK; + } + } + + /* + * Fallback to legacy decimal pow() behavior. + */ + { + DOUBLE base; + DOUBLE exponent; + + if (ScriptVariant_DecimalValue(varlist[0], &base) == S_OK && + ScriptVariant_DecimalValue(varlist[1], &exponent) == S_OK) { + + ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); + (*pretvar)->dblVal = (DOUBLE)pow((double)base, (double)exponent); + return S_OK; + } + } + + *pretvar = NULL; return E_FAIL; } -HRESULT math_pow(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get arcsine of a variant as degrees. +* Clamps input to [-1, 1] to avoid domain errors. +*/ +HRESULT math_asin(ScriptVariant **varlist, ScriptVariant **pretvar, int paramCount) { - DOUBLE dbltempA, dbltempB; + DOUBLE dbltemp; - if( SUCCEEDED(ScriptVariant_DecimalValue(varlist[0], &dbltempA)) && SUCCEEDED(ScriptVariant_DecimalValue(varlist[1], &dbltempB)) ) + if (ScriptVariant_DecimalValue(varlist[0], &dbltemp) == S_OK) { + if (dbltemp > 1.0) { + dbltemp = 1.0; + } + + if (dbltemp < -1.0) { + dbltemp = -1.0; + } + ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); - (*pretvar)->dblVal = pow((double)dbltempA,(double)dbltempB); + (*pretvar)->dblVal = (DOUBLE)(asin((double)dbltemp) * 180.0 / MATH_PI); return S_OK; } + *pretvar = NULL; return E_FAIL; } -HRESULT math_asin(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get sine of a degree angle as a decimal. +*/ +HRESULT math_ssin(ScriptVariant **varlist, ScriptVariant **pretvar, int paramCount) { DOUBLE dbltemp; - if(SUCCEEDED(ScriptVariant_DecimalValue(varlist[0], &dbltemp))) + if (ScriptVariant_DecimalValue(varlist[0], &dbltemp) == S_OK) { - double PI = 3.14159265; - ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); - (*pretvar)->dblVal = (DOUBLE)(asin((double)dbltemp) * 180.0 / PI); + (*pretvar)->dblVal = (DOUBLE)sin(dbltemp * MATH_PI / 180.0); return S_OK; } + *pretvar = NULL; return E_FAIL; } +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get arccosine of a variant as a decimal degree. +* Clamps input to [-1, 1] to avoid domain errors. +*/ HRESULT math_acos(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) { DOUBLE dbltemp; - if(SUCCEEDED(ScriptVariant_DecimalValue(varlist[0], &dbltemp))) - { - double PI = 3.14159265; + if(SUCCEEDED(ScriptVariant_DecimalValue(varlist[0], &dbltemp))) { // Clamp for safety: acos domain is [-1, 1] if (dbltemp > 1.0) { dbltemp = 1.0; } if (dbltemp < -1.0) { dbltemp = -1.0; } ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); - (*pretvar)->dblVal = (DOUBLE)(acos((double)dbltemp) * 180.0 / PI); + (*pretvar)->dblVal = (DOUBLE)(acos((double)dbltemp) * 180.0 / MATH_PI); return S_OK; } *pretvar = NULL; return E_FAIL; } +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get arctangent of a variant as a decimal degree. +*/ HRESULT math_atan(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) { DOUBLE dbltemp; if(SUCCEEDED(ScriptVariant_DecimalValue(varlist[0], &dbltemp))) { - double PI = 3.14159265; - ScriptVariant_ChangeType(*pretvar, VT_DECIMAL); - (*pretvar)->dblVal = (DOUBLE)(atan((double)dbltemp) * 180.0 / PI); + (*pretvar)->dblVal = (DOUBLE)(atan((double)dbltemp) * 180.0 / MATH_PI); return S_OK; } *pretvar = NULL; return E_FAIL; } -HRESULT math_trunc(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get truncated value of a variant as an integer. +* Preserves legacy VT_INTEGER results when possible +* and promotes to 64-bit integer carriers when needed. +*/ +HRESULT math_trunc(ScriptVariant **varlist, ScriptVariant **pretvar, int paramCount) { DOUBLE dbltemp; - if(SUCCEEDED(ScriptVariant_DecimalValue(varlist[0], &dbltemp))) - { - ScriptVariant_ChangeType(*pretvar, VT_INTEGER); - (*pretvar)->lVal = (LONG)(trunc(dbltemp)); + if (ScriptVariant_DecimalValue(varlist[0], &dbltemp) == S_OK && + math_set_truncated_integer(*pretvar, dbltemp) == S_OK) { return S_OK; } + *pretvar = NULL; return E_FAIL; } +/* +* Caskey, Damon V. +* 2026-06-08 +* +* Get rounded value of a variant as a decimal. +*/ HRESULT math_round(ScriptVariant **varlist , ScriptVariant **pretvar, int paramCount) { DOUBLE dbltemp; diff --git a/engine/source/scriptlib/Instruction.c b/engine/source/scriptlib/Instruction.c index 939bdd6f0..c3a649601 100644 --- a/engine/source/scriptlib/Instruction.c +++ b/engine/source/scriptlib/Instruction.c @@ -288,18 +288,16 @@ static HRESULT Instruction_ParseIntegerConstant(ScriptVariant *pvar, const char } /* - * Unsuffixed huge hex constants are commonly - * bitmasks. Let them land in unsigned 64. For - * decimal, require U/UL/ULL to avoid accidental - * unsigned. + * Positive literals above INT64_MAX still fit + * the unsigned 64-bit carrier. Let them land + * in VT_UINTEGER64 so script literals behave + * like values produced by integer math, such + * as pow(2, 63). */ - if (hex_constant) { - ScriptVariant_ChangeType(pvar, VT_UINTEGER64); - pvar->ullVal = magnitude; - return S_OK; - } - return E_FAIL; + ScriptVariant_ChangeType(pvar, VT_UINTEGER64); + pvar->ullVal = magnitude; + return S_OK; } /* @@ -472,10 +470,9 @@ void Instruction_ConvertConstant(Instruction *pins) { pvar, sc, pins->theToken->theType == TOKEN_HEXCONSTANT) != S_OK) { - /* - * Keep old behavior non-fatal unless the compiler - * has a better error reporting path available here. - */ + + printf("Invalid integer constant '%s'.\n", sc); + ScriptVariant_ChangeType(pvar, VT_INTEGER); pvar->lVal = 0; } diff --git a/engine/source/scriptlib/ScriptVariant.c b/engine/source/scriptlib/ScriptVariant.c index 49734b6d5..423fdce85 100644 --- a/engine/source/scriptlib/ScriptVariant.c +++ b/engine/source/scriptlib/ScriptVariant.c @@ -14,6 +14,7 @@ #include #include "globals.h" #include "ScriptVariant.h" +#include "ScriptVariantInteger.h" #define STRCACHE_INC 64 @@ -617,49 +618,6 @@ static int ScriptVariant_Is64BitMath(ScriptVariant *left, ScriptVariant *right) right->vt == VT_UINTEGER64; } -/* -* Caskey, Damon V. -* 2026-06-04 -* -* Set the result of a SIGNED integer math -* operation. Handles overflow and type -* promotion to 64-bit integers when necessary. -*/ -static void ScriptVariant_SetSignedIntegerResult(ScriptVariant *retvar, int64_t value, int force64) { - - if (!force64 && value >= (int64_t)LONG_MIN && value <= (int64_t)LONG_MAX) { - ScriptVariant_ChangeType(retvar, VT_INTEGER); - retvar->lVal = (LONG)value; - - } else { - - ScriptVariant_ChangeType(retvar, VT_INTEGER64); - retvar->llVal = value; - } -} - -/* -* Caskey, Damon V. -* 2026-06-04 -* -* Set the result of an UNSIGNED integer math -* operation. Handles overflow and type -* promotion to 64-bit integers when necessary. -*/ -static void ScriptVariant_SetUnsignedIntegerResult(ScriptVariant *retvar, uint64_t value, int force64) { - - if (!force64 && value <= (uint64_t)LONG_MAX) { - - ScriptVariant_ChangeType(retvar, VT_INTEGER); - retvar->lVal = (LONG)value; - - } else { - - ScriptVariant_ChangeType(retvar, VT_UINTEGER64); - retvar->ullVal = value; - } -} - // light version, for compiled call, faster than above, but not safe in some situations ScriptVariant *ScriptVariant_Assign(ScriptVariant *svar, ScriptVariant *rightChild ) { @@ -1774,46 +1732,6 @@ ScriptVariant *ScriptVariant_Shr(ScriptVariant *svar, ScriptVariant *rightChild) return &retvar; } -/* -* Caskey, Damon V. -* 2026-06-02 -* -* Safely add two signed 64-bit integers, -* checking for overflow. -* -* Returns 1 on success, 0 on overflow. -*/ -static int ScriptVariant_AddSigned64(int64_t left, int64_t right, int64_t *result) { - - if ((right > 0 && left > INT64_MAX - right) || - (right < 0 && left < INT64_MIN - right)) { - return 0; - } - - *result = left + right; - return 1; -} - -/* -* Caskey, Damon V. -* 2026-06-04 -* -* Safely add two unsigned 64-bit integers, -* checking for overflow. -* -* Returns 1 on success, 0 on overflow. -*/ -static int ScriptVariant_AddUnsigned64(uint64_t left, uint64_t right, uint64_t *result) { - - if (left > UINT64_MAX - right) { - return 0; - } - - *result = left + right; - - return 1; -} - /* * Caskey, Damon V. * 2026-06-04 @@ -1940,47 +1858,6 @@ ScriptVariant *ScriptVariant_Add(ScriptVariant *svar, ScriptVariant *rightChild) return &retvar; } -/* -* Caskey, Damon V. -* 2026-06-04 -* -* Safely subtract two signed 64-bit integers, -* checking for overflow. -* -* Returns 1 on success, 0 on overflow. -*/ -static int ScriptVariant_SubSigned64(int64_t left, int64_t right, int64_t *result) { - - if ((right < 0 && left > INT64_MAX + right) || - (right > 0 && left < INT64_MIN + right)) { - return 0; - } - - *result = left - right; - - return 1; -} - -/* -* Caskey, Damon V. -* 2026-06-04 -* -* Safely subtract two unsigned 64-bit integers, -* checking for underflow. -* -* Returns 1 on success, 0 on underflow. -*/ -static int ScriptVariant_SubUnsigned64(uint64_t left, uint64_t right, uint64_t *result) { - - if (left < right) { - return 0; - } - - *result = left - right; - - return 1; -} - /* * Caskey, Damon V. * 2026-06-05 @@ -2066,56 +1943,6 @@ ScriptVariant *ScriptVariant_Sub(ScriptVariant *svar, ScriptVariant *rightChild) return &retvar; } -/* -* Caskey, Damon V. -* 2026-06-05 -* -* Safely multiply two signed 64-bit integers, -* checking for overflow. -* -* Returns 1 on success, 0 on overflow. -*/ -static int ScriptVariant_MulSigned64(int64_t left, int64_t right, int64_t *result) { - - if (left > 0) { - - if ((right > 0 && left > INT64_MAX / right) || - (right < 0 && right < INT64_MIN / left)) { - return 0; - } - - } else if (left < 0) { - - if ((right > 0 && left < INT64_MIN / right) || - (right < 0 && left < INT64_MAX / right)) { - return 0; - } - } - - *result = left * right; - return 1; -} - -/* -* Caskey, Damon V. -* 2026-06-05 -* -* Safely multiply two unsigned 64-bit integers, -* checking for overflow. -* -* Returns 1 on success, 0 on overflow. -*/ -static int ScriptVariant_MulUnsigned64(uint64_t left, uint64_t right, uint64_t *result) { - - if (right && left > UINT64_MAX / right) { - return 0; - } - - *result = left * right; - - return 1; -} - /* * Caskey, Damon V. * 2026-06-05 @@ -2199,61 +2026,6 @@ ScriptVariant *ScriptVariant_Mul(ScriptVariant *svar, ScriptVariant *rightChild) return &retvar; } -/* -* Caskey, Damon V. -* 2026-06-05 -* -* Safely divide two signed 64-bit integers. -* Fail on divide by zero and the one signed -* division overflow case. -* -* Returns 1 on success, 0 on failure. -*/ -static int ScriptVariant_DivSigned64(int64_t left, int64_t right, int64_t *result) { - - /* - * Divide by 0 attempt. - */ - - if (right == 0) { - return 0; - } - - /* - * Overflow case: INT64_MIN / -1. This - * would produce a result of 2^63, which - * cannot be represented in an int64_t. - */ - - if (left == INT64_MIN && right == -1) { - return 0; - } - - *result = left / right; - - return 1; -} - -/* -* Caskey, Damon V. -* 2026-06-05 -* -* Safely divide two unsigned 64-bit integers. -* Checks for divide by zero. -* -* Returns 1 on success, 0 on failure. -*/ -static int ScriptVariant_DivUnsigned64(uint64_t left, uint64_t right, uint64_t *result) { - - if (right == 0) { - return 0; - } - - *result = left / right; - - return 1; -} - /* * Caskey, Damon V. * 2026-06-05 @@ -2340,61 +2112,6 @@ ScriptVariant *ScriptVariant_Div(ScriptVariant *svar, ScriptVariant *rightChild) return &retvar; } -/* -* Caskey, Damon V. -* 2026-06-05 -* -* Safely perform signed 64-bit modulo. -* Fails on modulo by zero and the one signed -* division overflow case. -* -* Returns 1 on success, 0 on failure. -*/ -static int ScriptVariant_ModSigned64(int64_t left, int64_t right, int64_t *result) { - - /* - * Modulo by 0 attempt. - */ - - if (right == 0) { - return 0; - } - - /* - * Overflow case: INT64_MIN % -1. Even though - * the mathematical remainder is 0, C evaluates - * this through signed division rules. - */ - - if (left == INT64_MIN && right == -1) { - return 0; - } - - *result = left % right; - - return 1; -} - -/* -* Caskey, Damon V. -* 2026-06-05 -* -* Safely perform unsigned 64-bit modulo. -* Fails on modulo by zero. -* -* Returns 1 on success, 0 on failure. -*/ -static int ScriptVariant_ModUnsigned64(uint64_t left, uint64_t right, uint64_t *result) { - - if (right == 0) { - return 0; - } - - *result = left % right; - - return 1; -} - /* * Caskey, Damon V. * 2026-06-05 diff --git a/engine/source/scriptlib/ScriptVariantInteger.c b/engine/source/scriptlib/ScriptVariantInteger.c new file mode 100644 index 000000000..2de3f5e6a --- /dev/null +++ b/engine/source/scriptlib/ScriptVariantInteger.c @@ -0,0 +1,337 @@ +#include "ScriptVariantInteger.h" +#include + +/* +* Caskey, Damon V. +* 2026-06-04 +* +* Set the result of a SIGNED integer math +* operation. Handles overflow and type +* promotion to 64-bit integers when necessary. +*/ +HRESULT ScriptVariant_SetSignedIntegerResult(ScriptVariant *retvar, int64_t value, int force64) +{ + if (!retvar) { + return E_FAIL; + } + + if (!force64 && value >= (int64_t)LONG_MIN && value <= (int64_t)LONG_MAX) { + ScriptVariant_ChangeType(retvar, VT_INTEGER); + retvar->lVal = (LONG)value; + + } else { + ScriptVariant_ChangeType(retvar, VT_INTEGER64); + retvar->llVal = value; + } + + return S_OK; +} + +/* +* Caskey, Damon V. +* 2026-06-04 +* +* Set the result of an UNSIGNED integer math +* operation. Handles overflow and type +* promotion to 64-bit integers when necessary. +*/ +HRESULT ScriptVariant_SetUnsignedIntegerResult(ScriptVariant *retvar, uint64_t value, int force64) +{ + if (!retvar) { + return E_FAIL; + } + + if (!force64 && value <= (uint64_t)LONG_MAX) { + ScriptVariant_ChangeType(retvar, VT_INTEGER); + retvar->lVal = (LONG)value; + + } else { + ScriptVariant_ChangeType(retvar, VT_UINTEGER64); + retvar->ullVal = value; + } + + return S_OK; +} + +/* +* Caskey, Damon V. +* 2026-06-02 +* +* Safely add two signed 64-bit integers, +* checking for overflow. +* +* Returns 1 on success, 0 on overflow. +*/ +int ScriptVariant_AddSigned64(int64_t left, int64_t right, int64_t *result) { + + if (!result) { + return 0; + } + + if ((right > 0 && left > INT64_MAX - right) || + (right < 0 && left < INT64_MIN - right)) { + return 0; + } + + *result = left + right; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-04 +* +* Safely add two unsigned 64-bit integers, +* checking for overflow. +* +* Returns 1 on success, 0 on overflow. +*/ +int ScriptVariant_AddUnsigned64(uint64_t left, uint64_t right, uint64_t *result) { + + if(!result) { + return 0; + } + + if (left > UINT64_MAX - right) { + return 0; + } + + *result = left + right; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-04 +* +* Safely subtract two signed 64-bit integers, +* checking for overflow. +* +* Returns 1 on success, 0 on overflow. +*/ +int ScriptVariant_SubSigned64(int64_t left, int64_t right, int64_t *result) { + + if (!result) { + return 0; + } + + if ((right < 0 && left > INT64_MAX + right) || + (right > 0 && left < INT64_MIN + right)) { + return 0; + } + + *result = left - right; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-04 +* +* Safely subtract two unsigned 64-bit integers, +* checking for underflow. +* +* Returns 1 on success, 0 on underflow. +*/ +int ScriptVariant_SubUnsigned64(uint64_t left, uint64_t right, uint64_t *result) { + + if (!result) { + return 0; + } + + if (left < right) { + return 0; + } + + *result = left - right; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-05 +* +* Safely multiply two signed 64-bit integers, +* checking for overflow. +* +* Returns 1 on success, 0 on overflow. +*/ +int ScriptVariant_MulSigned64(int64_t left, int64_t right, int64_t *result) { + + if (!result) { + return 0; + } + + if (left > 0) { + + if ((right > 0 && left > INT64_MAX / right) || + (right < 0 && right < INT64_MIN / left)) { + return 0; + } + + } else if (left < 0) { + + if ((right > 0 && left < INT64_MIN / right) || + (right < 0 && left < INT64_MAX / right)) { + return 0; + } + } + + *result = left * right; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-05 +* +* Safely multiply two unsigned 64-bit integers, +* checking for overflow. +* +* Returns 1 on success, 0 on overflow. +*/ +int ScriptVariant_MulUnsigned64(uint64_t left, uint64_t right, uint64_t *result) { + + if (!result) { + return 0; + } + + if (right && left > UINT64_MAX / right) { + return 0; + } + + *result = left * right; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-05 +* +* Safely divide two signed 64-bit integers. +* Fail on divide by zero and the one signed +* division overflow case. +* +* Returns 1 on success, 0 on failure. +*/ +int ScriptVariant_DivSigned64(int64_t left, int64_t right, int64_t *result) { + + if (!result) { + return 0; + } + + /* + * Divide by 0 attempt. + */ + + if (right == 0) { + return 0; + } + + /* + * Overflow case: INT64_MIN / -1. This + * would produce a result of 2^63, which + * cannot be represented in an int64_t. + */ + + if (left == INT64_MIN && right == -1) { + return 0; + } + + *result = left / right; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-05 +* +* Safely divide two unsigned 64-bit integers. +* Checks for divide by zero. +* +* Returns 1 on success, 0 on failure. +*/ +int ScriptVariant_DivUnsigned64(uint64_t left, uint64_t right, uint64_t *result) { + + if (!result) { + return 0; + } + + if (right == 0) { + return 0; + } + + *result = left / right; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-05 +* +* Safely perform signed 64-bit modulo. +* Fails on modulo by zero and the one signed +* division overflow case. +* +* Returns 1 on success, 0 on failure. +*/ +int ScriptVariant_ModSigned64(int64_t left, int64_t right, int64_t *result) { + + if (!result) { + return 0; + } + + /* + * Modulo by 0 attempt. + */ + + if (right == 0) { + return 0; + } + + /* + * Overflow case: INT64_MIN % -1. Even though + * the mathematical remainder is 0, C evaluates + * this through signed division rules. + */ + + if (left == INT64_MIN && right == -1) { + return 0; + } + + *result = left % right; + + return 1; +} + +/* +* Caskey, Damon V. +* 2026-06-05 +* +* Safely perform unsigned 64-bit modulo. +* Fails on modulo by zero. +* +* Returns 1 on success, 0 on failure. +*/ +int ScriptVariant_ModUnsigned64(uint64_t left, uint64_t right, uint64_t *result) { + + if (!result) { + return 0; + } + + if (right == 0) { + return 0; + } + + *result = left % right; + + return 1; +} \ No newline at end of file diff --git a/engine/source/scriptlib/ScriptVariantInteger.h b/engine/source/scriptlib/ScriptVariantInteger.h new file mode 100644 index 000000000..efdaef66d --- /dev/null +++ b/engine/source/scriptlib/ScriptVariantInteger.h @@ -0,0 +1,21 @@ +#ifndef SCRIPTVARIANT_INTEGER_H +#define SCRIPTVARIANT_INTEGER_H + +#include "ScriptVariant.h" +#include + +HRESULT ScriptVariant_SetSignedIntegerResult(ScriptVariant *retvar, int64_t value, int force64); +HRESULT ScriptVariant_SetUnsignedIntegerResult(ScriptVariant *retvar, uint64_t value, int force64); + +int ScriptVariant_AddSigned64(int64_t left, int64_t right, int64_t *result); +int ScriptVariant_AddUnsigned64(uint64_t left, uint64_t right, uint64_t *result); +int ScriptVariant_SubSigned64(int64_t left, int64_t right, int64_t *result); +int ScriptVariant_SubUnsigned64(uint64_t left, uint64_t right, uint64_t *result); +int ScriptVariant_MulSigned64(int64_t left, int64_t right, int64_t *result); +int ScriptVariant_MulUnsigned64(uint64_t left, uint64_t right, uint64_t *result); +int ScriptVariant_DivSigned64(int64_t left, int64_t right, int64_t *result); +int ScriptVariant_DivUnsigned64(uint64_t left, uint64_t right, uint64_t *result); +int ScriptVariant_ModSigned64(int64_t left, int64_t right, int64_t *result); +int ScriptVariant_ModUnsigned64(uint64_t left, uint64_t right, uint64_t *result); + +#endif \ No newline at end of file diff --git a/engine/version.tmp b/engine/version.tmp deleted file mode 100644 index da3e59338..000000000 --- a/engine/version.tmp +++ /dev/null @@ -1,20 +0,0 @@ -/* - * OpenBOR - http://www.ChronoCrash.com - * ----------------------------------------------------------------------- - * All rights reserved, see LICENSE in OpenBOR root for details. - * - * Copyright (c) OpenBOR Team - */ - -#ifndef VERSION_H -#define VERSION_H - -#define VERSION_NAME "OpenBOR" -#define VERSION_MAJOR "4" -#define VERSION_MINOR "0" -#define VERSION_BUILD "7779" -#define VERSION_BUILD_INT 7779 -#define VERSION_COMMIT "fa1c220" -#define VERSION "v"VERSION_MAJOR"."VERSION_MINOR" Build "VERSION_BUILD" (commit hash: "VERSION_COMMIT")" - -#endif