diff --git a/CHANGELOG.md b/CHANGELOG.md
index 57a994be..9d6fdf0a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -36,13 +36,20 @@
- new opcode **2302 ([write_block_to_file](https://library.sannybuilder.com/#/sa/file/2302))**
- new opcode **2303 ([resolve_filepath](https://library.sannybuilder.com/#/sa/file/2303))**
- new opcode **2304 ([get_script_filename](https://library.sannybuilder.com/#/sa/file/2304))**
+- new [Math](https://github.com/cleolibrary/CLEO5/tree/master/cleo_plugins/Math) plugin
+ - math related opcodes moved from CLEO core into separated plugin
+ - new opcode **2700 ([is_bit_set](https://library.sannybuilder.com/#/sa/math/2700))**
+ - new opcode **2701 ([set_bit](https://library.sannybuilder.com/#/sa/math/2701))**
+ - new opcode **2702 ([clear_bit](https://library.sannybuilder.com/#/sa/math/2702))**
+ - new opcode **2703 ([toggle_bit](https://library.sannybuilder.com/#/sa/math/2703))**
+ - new opcode **2704 ([is_truthy](https://library.sannybuilder.com/#/sa/math/2704))**
- new [MemoryOperations](https://github.com/cleolibrary/CLEO5/tree/master/cleo_plugins/MemoryOperations) plugin
- memory related opcodes moved from CLEO core into separated plugin
- validation of input and output parameters for all opcodes
- opcode **0A8C ([write_memory](https://library.sannybuilder.com/#/sa/memory/0A8C))** now supports strings
- new opcode **2400 ([copy_memory](https://library.sannybuilder.com/#/sa/memory/2400))**
- new opcode **2401 ([read_memory_with_offset](https://library.sannybuilder.com/#/sa/memory/2401))**
- - new opcode **2402 ([writememory_with_offset](https://library.sannybuilder.com/#/sa/memory/2402))**
+ - new opcode **2402 ([write_memory_with_offset](https://library.sannybuilder.com/#/sa/memory/2402))**
- new opcode **2403 ([forget_memory](https://library.sannybuilder.com/#/sa/memory/2403))**
- new opcode **2404 ([get_script_struct_just_created](https://library.sannybuilder.com/#/sa/memory/2404))**
- new opcode **2405 ([is_script_running](https://library.sannybuilder.com/#/sa/memory/2405))**
diff --git a/cleo_plugins/CLEO_Plugins.sln b/cleo_plugins/CLEO_Plugins.sln
index ed6aac0f..ee05f7ed 100644
--- a/cleo_plugins/CLEO_Plugins.sln
+++ b/cleo_plugins/CLEO_Plugins.sln
@@ -7,8 +7,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileSystemOperations", "Fil
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IniFiles", "IniFiles\IniFiles.vcxproj", "{6831362D-5226-4634-9DB4-266A1B6C3E6C}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IntOperations", "IntOperations\IntOperations.vcxproj", "{68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DebugUtils", "DebugUtils\DebugUtils.vcxproj", "{481896C4-0C19-4992-9602-729537774B32}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MemoryOperations", "MemoryOperations\MemoryOperations.vcxproj", "{35C80F79-8B18-4925-8C32-94B320DBE76F}"
@@ -17,6 +15,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Audio", "Audio\Audio.vcxpro
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Text", "Text\Text.vcxproj", "{BD19AEFD-626B-40AE-8D83-6D444D2EFBF8}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Math", "Math\Math.vcxproj", "{68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@@ -31,10 +31,6 @@ Global
{6831362D-5226-4634-9DB4-266A1B6C3E6C}.Debug|x86.Build.0 = Debug|Win32
{6831362D-5226-4634-9DB4-266A1B6C3E6C}.Release|x86.ActiveCfg = Release|Win32
{6831362D-5226-4634-9DB4-266A1B6C3E6C}.Release|x86.Build.0 = Release|Win32
- {68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}.Debug|x86.ActiveCfg = Debug|Win32
- {68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}.Debug|x86.Build.0 = Debug|Win32
- {68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}.Release|x86.ActiveCfg = Release|Win32
- {68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}.Release|x86.Build.0 = Release|Win32
{481896C4-0C19-4992-9602-729537774B32}.Debug|x86.ActiveCfg = Debug|Win32
{481896C4-0C19-4992-9602-729537774B32}.Debug|x86.Build.0 = Debug|Win32
{481896C4-0C19-4992-9602-729537774B32}.Release|x86.ActiveCfg = Release|Win32
@@ -51,6 +47,10 @@ Global
{BD19AEFD-626B-40AE-8D83-6D444D2EFBF8}.Debug|x86.Build.0 = Debug|Win32
{BD19AEFD-626B-40AE-8D83-6D444D2EFBF8}.Release|x86.ActiveCfg = Release|Win32
{BD19AEFD-626B-40AE-8D83-6D444D2EFBF8}.Release|x86.Build.0 = Release|Win32
+ {68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}.Debug|x86.ActiveCfg = Debug|Win32
+ {68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}.Debug|x86.Build.0 = Debug|Win32
+ {68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}.Release|x86.ActiveCfg = Release|Win32
+ {68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/cleo_plugins/IntOperations/IntOperations.vcxproj.filters b/cleo_plugins/IntOperations/IntOperations.vcxproj.filters
deleted file mode 100644
index 2d75d234..00000000
--- a/cleo_plugins/IntOperations/IntOperations.vcxproj.filters
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/cleo_plugins/IntOperations/IntOperations.cpp b/cleo_plugins/Math/Math.cpp
similarity index 71%
rename from cleo_plugins/IntOperations/IntOperations.cpp
rename to cleo_plugins/Math/Math.cpp
index de0ce001..084a807d 100644
--- a/cleo_plugins/IntOperations/IntOperations.cpp
+++ b/cleo_plugins/Math/Math.cpp
@@ -5,10 +5,10 @@
using namespace CLEO;
using namespace plugin;
-class IntOperations
+class Math
{
public:
- IntOperations()
+ Math()
{
auto cleoVer = CLEO_GetVersion();
if (cleoVer < CLEO_VERSION)
@@ -18,12 +18,15 @@ class IntOperations
return;
}
- //register opcodes
+ // register opcodes
CLEO_RegisterOpcode(0x0A8E, opcode_0A8E); // x = a + b (int)
CLEO_RegisterOpcode(0x0A8F, opcode_0A8F); // x = a - b (int)
CLEO_RegisterOpcode(0x0A90, opcode_0A90); // x = a * b (int)
CLEO_RegisterOpcode(0x0A91, opcode_0A91); // x = a / b (int)
+ CLEO_RegisterOpcode(0x0AEE, opcode_0AEE); // pow
+ CLEO_RegisterOpcode(0x0AEF, opcode_0AEF); // log
+
CLEO_RegisterOpcode(0x0B10, Script_IntOp_AND);
CLEO_RegisterOpcode(0x0B11, Script_IntOp_OR);
CLEO_RegisterOpcode(0x0B12, Script_IntOp_XOR);
@@ -39,6 +42,12 @@ class IntOperations
CLEO_RegisterOpcode(0x0B1C, Scr_IntOp_SHR);
CLEO_RegisterOpcode(0x0B1D, Scr_IntOp_SHL);
CLEO_RegisterOpcode(0x0B1E, Sign_Extend);
+
+ CLEO_RegisterOpcode(0x2700, opcode_2700); // is_bit_set
+ CLEO_RegisterOpcode(0x2701, opcode_2701); // set_bit
+ CLEO_RegisterOpcode(0x2702, opcode_2702); // clear_bit
+ CLEO_RegisterOpcode(0x2703, opcode_2703); // toggle_bit
+ CLEO_RegisterOpcode(0x2704, opcode_2704); // is_truthy
}
//0A8E=3,%3d% = %1d% + %2d% ; int
@@ -89,6 +98,30 @@ class IntOperations
return OR_CONTINUE;
}
+ //0AEE=3,%3d% = %1d% exp %2d% // all floats
+ static OpcodeResult __stdcall opcode_0AEE(CRunningScript* thread)
+ {
+ auto base = OPCODE_READ_PARAM_FLOAT();
+ auto exponent = OPCODE_READ_PARAM_FLOAT();
+
+ auto result = (float)pow(base, exponent);
+
+ OPCODE_WRITE_PARAM_FLOAT(result);
+ return OR_CONTINUE;
+ }
+
+ //0AEF=3,%3d% = log %1d% base %2d% // all floats
+ static OpcodeResult __stdcall opcode_0AEF(CRunningScript* thread)
+ {
+ auto argument = OPCODE_READ_PARAM_FLOAT();
+ auto base = OPCODE_READ_PARAM_FLOAT();
+
+ auto exponent = log(argument) / log(base);
+
+ OPCODE_WRITE_PARAM_FLOAT(exponent);
+ return OR_CONTINUE;
+ }
+
static OpcodeResult WINAPI Script_IntOp_AND(CScriptThread* thread)
/****************************************************************
Opcode Format
@@ -310,4 +343,95 @@ class IntOperations
return OR_CONTINUE;
}
-} intOperations;
+
+ //2700=2, is_bit_set value %1d% bit_index %2d%
+ static OpcodeResult WINAPI opcode_2700(CScriptThread* thread)
+ {
+ auto value = OPCODE_READ_PARAM_UINT();
+ auto bitIndex = OPCODE_READ_PARAM_INT();
+
+ if (bitIndex < 0 || bitIndex > 31)
+ {
+ SHOW_ERROR("Invalid '%d' bit index argument in script %s\nScript suspended.", bitIndex, ScriptInfoStr(thread).c_str());
+ return thread->Suspend();
+ }
+
+ bool result = (value >> bitIndex) & 1;
+
+ OPCODE_CONDITION_RESULT(result);
+ return OR_CONTINUE;
+ }
+
+ //2701=2,set_bit value %1d% bit_index %2d%
+ static OpcodeResult WINAPI opcode_2701(CScriptThread* thread)
+ {
+ auto value = OPCODE_READ_PARAM_OUTPUT_VAR_INT();
+ auto bitIndex = OPCODE_READ_PARAM_INT();
+
+ if (bitIndex < 0 || bitIndex > 31)
+ {
+ SHOW_ERROR("Invalid '%d' bit index argument in script %s\nScript suspended.", bitIndex, ScriptInfoStr(thread).c_str());
+ return thread->Suspend();
+ }
+
+ *value |= 1 << bitIndex;
+
+ return OR_CONTINUE;
+ }
+
+ //2702=2,clear_bit value %1d% bit_index %2d%
+ static OpcodeResult WINAPI opcode_2702(CScriptThread* thread)
+ {
+ auto value = OPCODE_READ_PARAM_OUTPUT_VAR_INT();
+ auto bitIndex = OPCODE_READ_PARAM_INT();
+
+ if (bitIndex < 0 || bitIndex > 31)
+ {
+ SHOW_ERROR("Invalid '%d' bit index argument in script %s\nScript suspended.", bitIndex, ScriptInfoStr(thread).c_str());
+ return thread->Suspend();
+ }
+
+ *value &= ~(1 << bitIndex);
+
+ return OR_CONTINUE;
+ }
+
+ //2703=3,toggle_bit value %1d% bit_index %2d% state %3d%
+ static OpcodeResult WINAPI opcode_2703(CScriptThread* thread)
+ {
+ auto value = OPCODE_READ_PARAM_OUTPUT_VAR_INT();
+ auto bitIndex = OPCODE_READ_PARAM_INT();
+ auto state = OPCODE_READ_PARAM_BOOL();
+
+ if (bitIndex < 0 || bitIndex > 31)
+ {
+ SHOW_ERROR("Invalid '%d' bit index argument in script %s\nScript suspended.", bitIndex, ScriptInfoStr(thread).c_str());
+ return thread->Suspend();
+ }
+
+ DWORD flag = 1 << bitIndex;
+ if (state)
+ *value |= flag;
+ else
+ *value &= ~flag;
+
+ return OR_CONTINUE;
+ }
+
+ //2704=1, is_truthy value %1d%
+ static OpcodeResult WINAPI opcode_2704(CScriptThread* thread)
+ {
+ auto paramType = OPCODE_PEEK_PARAM_TYPE();
+
+ if(IsImmString(paramType) || IsVarString(paramType))
+ {
+ OPCODE_READ_PARAM_STRING_LEN(text, 1); // one character is all we need
+ OPCODE_CONDITION_RESULT(text[0] != '\0');
+ return OR_CONTINUE;
+ }
+
+ auto value = OPCODE_READ_PARAM_ANY32();
+ OPCODE_CONDITION_RESULT(value != 0);
+ return OR_CONTINUE;
+ }
+} Math;
diff --git a/cleo_plugins/IntOperations/IntOperations.vcxproj b/cleo_plugins/Math/Math.vcxproj
similarity index 95%
rename from cleo_plugins/IntOperations/IntOperations.vcxproj
rename to cleo_plugins/Math/Math.vcxproj
index 83dd2abd..98dc5acf 100644
--- a/cleo_plugins/IntOperations/IntOperations.vcxproj
+++ b/cleo_plugins/Math/Math.vcxproj
@@ -14,7 +14,7 @@
{68A434CF-6390-4FDF-9A15-36A8A9ECEAA9}
true
Win32Proj
- IntOperations
+ Math
10.0
@@ -44,13 +44,13 @@
$(SolutionDir).output\
$(ProjectDir).obj\$(Configuration)\
- SA.IntOperations
+ SA.Math
.cleo
$(SolutionDir).output\
$(ProjectDir).obj\$(Configuration)\
- SA.IntOperations
+ SA.Math
.cleo
@@ -114,7 +114,11 @@ xcopy /Y "$(OutDir)$(TargetName).*" "$(GTA_SA_DIR)\cleo\cleo_plugins\"
-
+
+
+
+
+
diff --git a/cleo_plugins/Math/Math.vcxproj.filters b/cleo_plugins/Math/Math.vcxproj.filters
new file mode 100644
index 00000000..7b248992
--- /dev/null
+++ b/cleo_plugins/Math/Math.vcxproj.filters
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+ {20ddb375-f549-46bb-814d-53e534880d23}
+
+
+
+
+ cleo_sdk
+
+
+ cleo_sdk
+
+
+
\ No newline at end of file
diff --git a/cleo_sdk/CLEO_Utils.h b/cleo_sdk/CLEO_Utils.h
index e69e066e..239b6f0f 100644
--- a/cleo_sdk/CLEO_Utils.h
+++ b/cleo_sdk/CLEO_Utils.h
@@ -21,6 +21,8 @@ namespace CLEO
OPCODE_CONDITION_RESULT(value) // set result
OPCODE_SKIP_PARAMS(count) // ignore X params
+
+ OPCODE_PEEK_PARAM_TYPE() // get param type without advancing the script
// reading opcode input arguments
OPCODE_READ_PARAM_BOOL()
@@ -458,11 +460,12 @@ namespace CLEO
}
#define OPCODE_SKIP_PARAMS(_count) CLEO_SkipOpcodeParams(thread, _count)
+ #define OPCODE_PEEK_PARAM_TYPE() thread->PeekDataType()
// macros for reading opcode input params. Performs type validation, throws error and suspends script if user provided invalid argument type
// TOD: add range checks for limited size types?
- #define OPCODE_READ_PARAM_BOOL() _readParam(thread).bParam; \
+ #define OPCODE_READ_PARAM_BOOL() _readParam(thread).dwParam != false; \
if (!_paramWasInt()) { SHOW_ERROR("Input argument %s expected to be integer, got %s in script %s\nScript suspended.", GetParamInfo().c_str(), CLEO::ToKindStr(_lastParamType, _lastParamArrayType), CLEO::ScriptInfoStr(thread).c_str()); return thread->Suspend(); }
#define OPCODE_READ_PARAM_INT8() _readParam(thread).cParam; \
diff --git a/source/CCustomOpcodeSystem.cpp b/source/CCustomOpcodeSystem.cpp
index c05fd2c8..63e1463c 100644
--- a/source/CCustomOpcodeSystem.cpp
+++ b/source/CCustomOpcodeSystem.cpp
@@ -55,8 +55,6 @@ namespace CLEO
OpcodeResult __stdcall opcode_0AE2(CRunningScript* thread); // get_random_car_in_sphere_no_save_recursive
OpcodeResult __stdcall opcode_0AE3(CRunningScript* thread); // get_random_object_in_sphere_no_save_recursive
- OpcodeResult __stdcall opcode_0AEE(CRunningScript* thread); // pow
- OpcodeResult __stdcall opcode_0AEF(CRunningScript* thread); // log
OpcodeResult __stdcall opcode_0DD5(CRunningScript* thread); // get_platform
// 2000 free slot
// 2001 free slot
@@ -246,8 +244,6 @@ namespace CLEO
CLEO_RegisterOpcode(0x0AE1, opcode_0AE1);
CLEO_RegisterOpcode(0x0AE2, opcode_0AE2);
CLEO_RegisterOpcode(0x0AE3, opcode_0AE3);
- CLEO_RegisterOpcode(0x0AEE, opcode_0AEE);
- CLEO_RegisterOpcode(0x0AEF, opcode_0AEF);
CLEO_RegisterOpcode(0x0DD5, opcode_0DD5); // get_platform
@@ -1516,24 +1512,6 @@ namespace CLEO
return OR_CONTINUE;
}
- //0AEE=3,%3d% = %1d% exp %2d% //all floats
- OpcodeResult __stdcall opcode_0AEE(CRunningScript *thread)
- {
- float base, arg;
- *thread >> base >> arg;
- *thread << (float)pow(base, arg);
- return OR_CONTINUE;
- }
-
- //0AEF=3,%3d% = log %1d% base %2d% //all floats
- OpcodeResult __stdcall opcode_0AEF(CRunningScript *thread)
- {
- float base, arg;
- *thread >> arg >> base;
- *thread << (float)(log(arg) / log(base));
- return OR_CONTINUE;
- }
-
//0DD5=1,%1d% = get_platform
OpcodeResult __stdcall opcode_0DD5(CRunningScript* thread)
{
diff --git a/tests/cleo_tests/0AEE.txt b/tests/cleo_tests/0AEE.txt
deleted file mode 100644
index f1f10999..00000000
--- a/tests/cleo_tests/0AEE.txt
+++ /dev/null
@@ -1,60 +0,0 @@
-{$CLEO .s}
-{$USE debug}
-{$USE file}
-{$USE bitwise}
-var 0@ : Integer
-var 1@ : Integer
-var 2@ : Integer
-var 3@ : Integer
-var 4@ : Integer
-var 5@ : Integer
-var 6@ : Integer
-var 7@ : Integer
-var 8@ : Integer
-var 9@ : Integer
-var 10@ : Integer
-
-script_name "0AEE" // pow
-debug_on
-
-trace "0A9A (pow)"
-
-
-// perform 3^4
-wait 0
-0AEE: pow number 3.0 power 4.0 result 0@ // tested opcode
-if
- 0@ == 81.0
-then
- trace "~g~~h~~h~0AEE (pow), #0 PASSED"
-else
- breakpoint "~r~~h~~h~~h~0AEE (pow), #0 FAILED!~n~%f Expected~n~%f Occured" 81.0 0@
-end
-
-
-// perform 1.2^3.4
-wait 0
-0AEE: pow number 1.2 power 3.4 result 0@ // tested opcode
-if and
- 0@ > 1.8
- 0@ < 1.9
-then
- trace "~g~~h~~h~0AEE (pow), #1 PASSED"
-else
- breakpoint "~r~~h~~h~~h~0AEE (pow), #1 FAILED!~n~%f Expected~n~%f Occured" 1.858 0@
-end
-
-
-// perform 3.1415^0.0
-wait 0
-0AEE: pow number 3.1415 power 0.0 result 0@ // tested opcode
-if
- 0@ == 1.0
-then
- trace "~g~~h~~h~0AEE (pow), #2 PASSED"
-else
- breakpoint "~r~~h~~h~~h~0AEE (pow), #2 FAILED!~n~%f Expected~n~%f Occured" 1.0 0@
-end
-
-
-terminate_this_custom_script
diff --git a/tests/cleo_tests/Math/0AEE.txt b/tests/cleo_tests/Math/0AEE.txt
new file mode 100644
index 00000000..5ff58e58
--- /dev/null
+++ b/tests/cleo_tests/Math/0AEE.txt
@@ -0,0 +1,25 @@
+{$CLEO .s}
+{$INCLUDE_ONCE ../cleo_tester.inc}
+
+script_name '0AEE'
+test("0AEE (pow)", tests)
+terminate_this_custom_script
+
+function tests
+ it("should power numbers", test1)
+ return
+
+ function test1
+ 0AEE: pow {number} 3.0 {power} 4.0 {var_result} 0@
+ assert_eqf(0@, 81.0)
+
+ 0AEE: pow {number} 16.0 {power} 0.25 {var_result} 0@
+ assert_eqf(0@, 2.0)
+
+ 0AEE: pow {number} 3.1415 {power} 0.0 {var_result} 0@
+ assert_eqf(0@, 1.0)
+
+ 0AEE: pow {number} 3.0 {power} 1.0 {var_result} 0@
+ assert_eqf(0@, 3.0)
+ end
+end
diff --git a/tests/cleo_tests/Math/2700.txt b/tests/cleo_tests/Math/2700.txt
new file mode 100644
index 00000000..b9ef22ad
--- /dev/null
+++ b/tests/cleo_tests/Math/2700.txt
@@ -0,0 +1,227 @@
+{$CLEO .s}
+{$INCLUDE_ONCE ../cleo_tester.inc}
+
+script_name '2700'
+test("2700 (is_bit_set)", tests)
+terminate_this_custom_script
+
+function tests
+ it("should has no bit set", test1)
+ it("should has all bits set", test2)
+ it("should test some bits", test3)
+ return
+
+ function test1
+ 0@ = 0x00000000
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 0
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 1
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 2
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 3
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 4
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 5
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 6
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 7
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 8
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 9
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 10
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 11
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 12
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 13
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 14
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 15
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 16
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 17
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 18
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 19
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 20
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 21
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 22
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 23
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 24
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 25
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 26
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 27
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 28
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 29
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 30
+ assert_result_false()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 31
+ assert_result_false()
+ end
+
+ function test2
+ 0@ = 0xFFFFFFFF
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 0
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 1
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 2
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 3
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 4
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 5
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 6
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 7
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 8
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 9
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 10
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 11
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 12
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 13
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 14
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 15
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 16
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 17
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 18
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 19
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 20
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 21
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 22
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 23
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 24
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 25
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 26
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 27
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 28
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 29
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 30
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0@ {bitIndex} 31
+ assert_result_true()
+ end
+
+ function test3
+ 2700: is_bit_set {number} 0x00000001 {bitIndex} 0
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0x00000004 {bitIndex} 2
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0x00004000 {bitIndex} 14
+ assert_result_true()
+
+ 2700: is_bit_set {number} 0x80000000 {bitIndex} 31
+ assert_result_true()
+ end
+end
diff --git a/tests/cleo_tests/Math/2701.txt b/tests/cleo_tests/Math/2701.txt
new file mode 100644
index 00000000..492f2814
--- /dev/null
+++ b/tests/cleo_tests/Math/2701.txt
@@ -0,0 +1,37 @@
+{$CLEO .s}
+{$INCLUDE_ONCE ../cleo_tester.inc}
+
+script_name '2701'
+test("2701 (set_bit)", tests)
+terminate_this_custom_script
+
+function tests
+ it("should set bits", test1)
+ return
+
+ function test1
+ 0@ = 0x12345678
+ 2701: set_bit {var_number} 0@ {bitIndex} 0
+ assert_eq(0@, 0x12345679)
+
+ 0@ = 0x12345678
+ 2701: set_bit {var_number} 0@ {bitIndex} 3 // already set
+ assert_eq(0@, 0x12345678)
+
+ 0@ = 0x12345678
+ 2701: set_bit {var_number} 0@ {bitIndex} 13
+ assert_eq(0@, 0x12347678)
+
+ 0@ = 0x12345678
+ 2701: set_bit {var_number} 0@ {bitIndex} 14 // already set
+ assert_eq(0@, 0x12345678)
+
+ 0@ = 0x12345678
+ 2701: set_bit {var_number} 0@ {bitIndex} 28 // already set
+ assert_eq(0@, 0x12345678)
+
+ 0@ = 0x12345678
+ 2701: set_bit {var_number} 0@ {bitIndex} 31
+ assert_eq(0@, 0x92345678)
+ end
+end
diff --git a/tests/cleo_tests/Math/2702.txt b/tests/cleo_tests/Math/2702.txt
new file mode 100644
index 00000000..5986d426
--- /dev/null
+++ b/tests/cleo_tests/Math/2702.txt
@@ -0,0 +1,37 @@
+{$CLEO .s}
+{$INCLUDE_ONCE ../cleo_tester.inc}
+
+script_name '2702'
+test("2702 (clear_bit)", tests)
+terminate_this_custom_script
+
+function tests
+ it("should clear bits", test1)
+ return
+
+ function test1
+ 0@ = 0x12345678
+ 2702: clear_bit {var_number} 0@ {bitIndex} 0 // was not set
+ assert_eq(0@, 0x12345678)
+
+ 0@ = 0x12345678
+ 2702: clear_bit {var_number} 0@ {bitIndex} 3
+ assert_eq(0@, 0x12345670)
+
+ 0@ = 0x12345678
+ 2702: clear_bit {var_number} 0@ {bitIndex} 13 // was not set
+ assert_eq(0@, 0x12345678)
+
+ 0@ = 0x12345678
+ 2702: clear_bit {var_number} 0@ {bitIndex} 14
+ assert_eq(0@, 0x12341678)
+
+ 0@ = 0x12345678
+ 2702: clear_bit {var_number} 0@ {bitIndex} 28
+ assert_eq(0@, 0x02345678)
+
+ 0@ = 0x12345678
+ 2702: clear_bit {var_number} 0@ {bitIndex} 31 // was not set
+ assert_eq(0@, 0x12345678)
+ end
+end
diff --git a/tests/cleo_tests/Math/2703.txt b/tests/cleo_tests/Math/2703.txt
new file mode 100644
index 00000000..7d19d440
--- /dev/null
+++ b/tests/cleo_tests/Math/2703.txt
@@ -0,0 +1,87 @@
+{$CLEO .s}
+{$INCLUDE_ONCE ../cleo_tester.inc}
+
+script_name '2703'
+test("2703 (toggle_bit)", tests)
+terminate_this_custom_script
+
+function tests
+ it("should toggle bits", test1)
+ it("should handle numbers as bool", test2)
+ return
+
+ function test1
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} true
+ assert_eq(0@, 0x12345679)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} false // was not set
+ assert_eq(0@, 0x12345678)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 3 {state} true // already set
+ assert_eq(0@, 0x12345678)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 3 {state} false
+ assert_eq(0@, 0x12345670)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 13 {state} true
+ assert_eq(0@, 0x12347678)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 13 {state} false // was not set
+ assert_eq(0@, 0x12345678)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 14 {state} true // already set
+ assert_eq(0@, 0x12345678)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 14 {state} false
+ assert_eq(0@, 0x12341678)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 28 {state} true // already set
+ assert_eq(0@, 0x12345678)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 28 {state} false
+ assert_eq(0@, 0x02345678)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 31 {state} true
+ assert_eq(0@, 0x92345678)
+
+ 0@ = 0x12345678
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 31 {state} false // was not set
+ assert_eq(0@, 0x12345678)
+ end
+
+ function test2
+ 0@ = 0xF
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} 0
+ assert_eq(0@, 0xE)
+
+ 0@ = 0x0
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} 1
+ assert_eq(0@, 0x1)
+
+ 0@ = 0x0
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} 2
+ assert_eq(0@, 0x1)
+
+ 0@ = 0x0
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} -1
+ assert_eq(0@, 0x1)
+
+ 0@ = 0x0
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} 0x00010000
+ assert_eq(0@, 0x1)
+
+ 0@ = 0x0
+ 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} 0x10000000
+ assert_eq(0@, 0x1)
+end
diff --git a/tests/cleo_tests/Math/2704.txt b/tests/cleo_tests/Math/2704.txt
new file mode 100644
index 00000000..0c1fcfdb
--- /dev/null
+++ b/tests/cleo_tests/Math/2704.txt
@@ -0,0 +1,111 @@
+{$CLEO .s}
+{$INCLUDE_ONCE ../cleo_tester.inc}
+
+script_name '2704'
+test("2704 (is_truthy)", tests)
+terminate_this_custom_script
+
+function tests
+ it("should be false", test1)
+ it("should be true", test2)
+ return
+
+ function test1
+ // int
+ 2704: is_truthy {value} 0
+ assert_result_false()
+
+ 0@ = 0
+ 2704: is_truthy {value} 0@
+ assert_result_false()
+
+ // float
+ 2704: is_truthy {value} 0.0
+ assert_result_false()
+
+ 0@ = 0.0
+ 2704: is_truthy {value} 0@
+ assert_result_false()
+
+ // short string
+ 2704: is_truthy {value} ''
+ assert_result_false()
+
+ 0@s = ''
+ 2704: is_truthy {value} 0@s
+ assert_result_false()
+
+ // long string
+ 2704: is_truthy {value} ""
+ assert_result_false()
+
+ 0@v = ""
+ 2704: is_truthy {value} 0@v
+ assert_result_false()
+ end
+
+ function test2
+ // int
+ 2704: is_truthy {value} 1
+ assert_result_true()
+
+ 0@ = 1
+ 2704: is_truthy {value} 0@
+ assert_result_true()
+
+ 2704: is_truthy {value} 0x00001000
+ assert_result_true()
+
+ 2704: is_truthy {value} -1
+ assert_result_true()
+
+ // float
+ 0@ = 0.000001
+ 2704: is_truthy {value} 0@
+ assert_result_true()
+
+ 2704: is_truthy {value} 1.0
+ assert_result_true()
+
+ 0@ = 0.000001
+ 2704: is_truthy {value} 0@
+ assert_result_true()
+
+ 2704: is_truthy {value} 0.000001
+ assert_result_true()
+
+ 2704: is_truthy {value} -0.0 // it is 0x80000000
+ assert_result_true()
+
+ // short string
+ 2704: is_truthy {value} 'a'
+ assert_result_true()
+
+ 0@s = 'a'
+ 2704: is_truthy {value} 0@s
+ assert_result_true()
+
+ 2704: is_truthy {value} ' '
+ assert_result_true()
+
+ 2704: is_truthy {value} 'null'
+ assert_result_true()
+
+ // long string
+ 2704: is_truthy {value} "a"
+ assert_result_true()
+
+ 0@v = "a"
+ 2704: is_truthy {value} 0@v
+ assert_result_true()
+
+ 2704: is_truthy {value} " "
+ assert_result_true()
+
+ 2704: is_truthy {value} "null"
+ assert_result_true()
+
+ 2704: is_truthy {value} "some very long testing string"
+ assert_result_true()
+ end
+end