├── .github ├── dependabot.yml └── workflows │ ├── add-job-output.js │ ├── main.yml │ ├── markdown.js │ ├── nightly.yml │ ├── tag-custom-build.js │ ├── test.yml │ └── version.js ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CLEO5.sln ├── CLEO5.vcxproj ├── CLEO5.vcxproj.filters ├── LICENSE.md ├── README.md ├── SETUP.md ├── cleo_plugins ├── Audio │ ├── Audio.cpp │ ├── Audio.vcxproj │ ├── Audio.vcxproj.filters │ ├── C3DAudioStream.cpp │ ├── C3DAudioStream.h │ ├── CAudioStream.cpp │ ├── CAudioStream.h │ ├── CInterpolatedValue.h │ ├── CSoundSystem.cpp │ ├── CSoundSystem.h │ ├── SA.Audio.ini │ └── bass │ │ ├── bass.dll │ │ ├── bass.h │ │ └── bass.lib ├── CLEO_Plugins.sln ├── DebugUtils │ ├── DebugUtils.cpp │ ├── DebugUtils.vcxproj │ ├── DebugUtils.vcxproj.filters │ ├── SA.DebugUtils.ini │ ├── ScreenLog.cpp │ ├── ScreenLog.h │ └── ScriptLog.h ├── FileSystemOperations │ ├── FileSystemOperations.cpp │ ├── FileSystemOperations.vcxproj │ ├── FileSystemOperations.vcxproj.filters │ ├── FileUtils.cpp │ ├── FileUtils.h │ └── Utils.h ├── GameEntities │ ├── GameEntities.cpp │ ├── GameEntities.vcxproj │ └── GameEntities.vcxproj.filters ├── IniFiles │ ├── IniFiles.cpp │ ├── IniFiles.vcxproj │ └── IniFiles.vcxproj.filters ├── Math │ ├── Math.cpp │ ├── Math.vcxproj │ └── Math.vcxproj.filters ├── MemoryOperations │ ├── MemoryOperations.cpp │ ├── MemoryOperations.vcxproj │ └── MemoryOperations.vcxproj.filters ├── Resource.rc └── Text │ ├── CTextManager.cpp │ ├── CTextManager.h │ ├── ScriptDrawing.cpp │ ├── ScriptDrawing.h │ ├── ScriptDrawsState.h │ ├── Text.cpp │ ├── Text.vcxproj │ ├── Text.vcxproj.filters │ ├── crc32.cpp │ └── crc32.h ├── cleo_sdk ├── CLEO.h ├── CLEO_SDK_RU.chm └── CLEO_Utils.h ├── examples ├── Audio_Demo.txt ├── CLEO_Sound_Button.txt ├── Check_CLEO_Version.txt ├── Color_Blend.txt ├── Free_ID_Lister.txt ├── Homie_Help.txt ├── Limits_Info.txt ├── Mission_Trigger.txt ├── Pickup_Shirt.txt ├── Screen_Drawing.txt ├── Skin_Selector.txt ├── Sounds_Browser.txt ├── Train_Spawner.txt └── Vehicle_Flags.txt ├── setup_env.bat ├── source ├── CCodeInjector.cpp ├── CCodeInjector.h ├── CCustomOpcodeSystem.cpp ├── CCustomOpcodeSystem.h ├── CDebug.cpp ├── CDebug.h ├── CDmaFix.cpp ├── CDmaFix.h ├── CGameMenu.cpp ├── CGameMenu.h ├── CGameVersionManager.cpp ├── CGameVersionManager.h ├── CLEO.ico ├── CLEO5.rc ├── CModuleSystem.cpp ├── CModuleSystem.h ├── CPluginSystem.cpp ├── CPluginSystem.h ├── CScriptEngine.cpp ├── CScriptEngine.h ├── CleoBase.cpp ├── CleoBase.h ├── FileEnumerator.h ├── Mem.h ├── OpcodeInfoDatabase.cpp ├── OpcodeInfoDatabase.h ├── ScmFunction.cpp ├── ScmFunction.h ├── ScriptDelegate.h ├── Singleton.h ├── cleo.def ├── cleo_config.ini ├── crc32.cpp ├── crc32.h ├── dllmain.cpp ├── exports.cpp ├── resource.h ├── stdafx.cpp └── stdafx.h ├── tests ├── .cleo_tests_runner.txt └── cleo_tests │ ├── .Compile_All.bat │ ├── Audio │ ├── 0AAC.txt │ ├── 0AAD.txt │ ├── 0AAE.txt │ ├── 0AAF.txt │ ├── 0AB9.txt │ ├── 0ABB.txt │ ├── 0ABC.txt │ ├── 0AC0.txt │ ├── 0AC1.txt │ ├── 0AC2.txt │ ├── 0AC4.txt │ ├── 2507.txt │ ├── 2508.txt │ ├── 250B.txt │ ├── 250C.txt │ ├── Ding.mp3 │ └── Speech.mp3 │ ├── Cleo │ ├── 0AB2.txt │ └── 2000.txt │ ├── FilesystemOperations │ ├── 0A99.txt │ ├── 0A9A.txt │ ├── 0A9B.txt │ ├── 0A9C.txt │ ├── 0A9D.txt │ ├── 0A9E.txt │ ├── 0AAB.txt │ ├── 0AD6.txt │ ├── 0AD7.txt │ ├── 0AE4.txt │ ├── 0AE5.txt │ ├── 0B00.txt │ ├── 0B01.txt │ ├── 0B02.txt │ ├── 0B03.txt │ ├── 0B04.txt │ ├── 0B05.txt │ ├── 2301.txt │ ├── 2302.txt │ └── 2305.txt │ ├── GameEntities │ ├── 0AB5.txt │ ├── 0AB6.txt │ ├── 0AB7.txt │ ├── 0AB8.txt │ ├── 0ABD.txt │ ├── 0ABE.txt │ ├── 0ABF.txt │ ├── 0AD2.txt │ ├── 0ADD.txt │ ├── 0AE1.txt │ ├── 0AE2.txt │ └── 0AE3.txt │ ├── IniFiles │ ├── 0AF0.txt │ ├── 0AF1.txt │ ├── 0AF2.txt │ ├── 0AF3.txt │ ├── 0AF4.txt │ ├── 0AF5.txt │ ├── 2800.txt │ └── 2801.txt │ ├── Math │ ├── 0AEE.txt │ ├── 2700.txt │ ├── 2701.txt │ ├── 2702.txt │ ├── 2703.txt │ ├── 2704.txt │ ├── 2705.txt │ ├── 2706.txt │ ├── 2707.txt │ └── 2708.txt │ ├── MemoryOperations │ ├── 0A8C.txt │ ├── 0A8D.txt │ ├── 0A96.txt │ ├── 0A97.txt │ ├── 0A98.txt │ ├── 0AA3.txt │ ├── 0AA4.txt │ ├── 0AA8.txt │ ├── 0AC6.txt │ ├── 0AC7.txt │ ├── 0AC8.txt │ ├── 0AC9.txt │ ├── 0AE9.txt │ ├── 0AEA.txt │ ├── 0AEB.txt │ ├── 0AEC.txt │ ├── 2400.txt │ ├── 2401.txt │ ├── 2402.txt │ ├── 2403.txt │ ├── 2404.txt │ └── 2407.txt │ ├── Text │ ├── 0AD3.txt │ ├── 0AD4.txt │ ├── 0ADB.txt │ ├── 0ADE.txt │ ├── 0ADF.txt │ ├── 0AE0.txt │ ├── 0AED.txt │ ├── 2600.txt │ ├── 2601.txt │ ├── 2602.txt │ ├── 2603.txt │ ├── 2604.txt │ ├── 2606.txt │ ├── 2607.txt │ ├── 2608.txt │ ├── 2609.txt │ └── Test.fxt │ └── cleo_tester.inc └── third-party └── simdjson ├── README.md ├── simdjson.cpp └── simdjson.h /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | 8 | - package-ecosystem: "gitsubmodule" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" -------------------------------------------------------------------------------- /.github/workflows/add-job-output.js: -------------------------------------------------------------------------------- 1 | const { appendFileSync } = require("fs"); 2 | 3 | const { GITHUB_OUTPUT } = process.env; 4 | const { EOL } = require("os"); 5 | 6 | function addOutput(key, value) { 7 | appendFileSync(GITHUB_OUTPUT, `${key}=${value}${EOL}`, { encoding: "utf-8" }); 8 | } 9 | 10 | module.exports = addOutput -------------------------------------------------------------------------------- /.github/workflows/markdown.js: -------------------------------------------------------------------------------- 1 | const showdown = require('showdown'); 2 | const {readFileSync, writeFileSync} = require('fs'); 3 | 4 | const md = new showdown.Converter({ 5 | literalMidWordUnderscores: true, 6 | disableForced4SpacesIndentedSublists: true, 7 | noHeaderId: true, 8 | completeHTMLDocument: true, 9 | simplifiedAutoLink: true, 10 | }); 11 | 12 | const readme = md.makeHtml(readFileSync('README.md', 'utf8')); 13 | const changelog = md.makeHtml(readFileSync('CHANGELOG.md', 'utf8')); 14 | 15 | writeFileSync('README.html', readme, 'utf8'); 16 | writeFileSync('CHANGELOG.html', changelog, 'utf8'); 17 | -------------------------------------------------------------------------------- /.github/workflows/tag-custom-build.js: -------------------------------------------------------------------------------- 1 | const { readFileSync, writeFileSync } = require("fs"); 2 | const addJobOutput = require('./add-job-output'); 3 | const { GITHUB_SHA } = process.env; 4 | 5 | if (GITHUB_SHA) { 6 | const sha = GITHUB_SHA.slice(0, 7); 7 | 8 | // update cleo.h to replace version string 9 | const cleoH = readFileSync("cleo_sdk/cleo.h", { encoding: "utf-8" }); 10 | 11 | // read build version from the cleo.h header 12 | const [, CLEO_VERSION_MAIN] = cleoH.match('#define\\s+CLEO_VERSION_MAIN\\s+(\\d+)'); 13 | const [, CLEO_VERSION_MAJOR] = cleoH.match('#define\\s+CLEO_VERSION_MAJOR\\s+(\\d+)'); 14 | const [, CLEO_VERSION_MINOR] = cleoH.match('#define\\s+CLEO_VERSION_MINOR\\s+(\\d+)'); 15 | const buildVersion = [CLEO_VERSION_MAIN, CLEO_VERSION_MAJOR, CLEO_VERSION_MINOR].join('.'); 16 | console.log(`Build version ${buildVersion}`); 17 | 18 | const newCleoH = cleoH 19 | .replace('(CLEO_VERSION_MAIN.CLEO_VERSION_MAJOR.CLEO_VERSION_MINOR)', `(CLEO_VERSION_MAIN.CLEO_VERSION_MAJOR.CLEO_VERSION_MINOR-${sha})`); 20 | console.log(`Tagging current build with sha ${sha}`); 21 | writeFileSync("cleo_sdk/cleo.h", newCleoH, { encoding: "utf-8" }); 22 | 23 | addJobOutput("sha", sha); 24 | addJobOutput("version", buildVersion); 25 | } -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CLEO 5 Test Build 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - ".github/*" 7 | - "*.md" 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: windows-2022 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | submodules: "recursive" 18 | 19 | - name: Add msbuild to PATH 20 | uses: microsoft/setup-msbuild@v2 21 | 22 | - name: Tag Custom build with current commit SHA 23 | id: custom_build 24 | run: node.exe .github/workflows/tag-custom-build.js 25 | 26 | - name: Core - Build 27 | shell: cmd 28 | run: | 29 | set PLUGIN_SDK_DIR=%GITHUB_WORKSPACE%\third-party\plugin-sdk 30 | msbuild -m CLEO5.sln /property:Configuration=Release /property:Platform=GTASA 31 | 32 | - name: Core - VirusTotal Scan 33 | uses: crazy-max/ghaction-virustotal@v4 34 | with: 35 | vt_api_key: ${{ secrets.VT_KEY }} 36 | files: './.output/Release/CLEO.asi' 37 | 38 | - name: Plugins - Build 39 | shell: cmd 40 | run: | 41 | set PLUGIN_SDK_DIR=%GITHUB_WORKSPACE%\third-party\plugin-sdk 42 | msbuild -m cleo_plugins/CLEO_Plugins.sln /property:Configuration=Release /property:Platform=x86 43 | 44 | - name: Plugins - VirusTotal Scan 45 | uses: crazy-max/ghaction-virustotal@v4 46 | with: 47 | vt_api_key: ${{ secrets.VT_KEY }} 48 | files: './cleo_plugins/.output/*.cleo' 49 | 50 | - name: Gather Output Files 51 | id: prepare_archive 52 | shell: cmd 53 | run: | 54 | @REM create output directory 55 | mkdir .output\Release\cleo 56 | mkdir .output\Release\cleo\cleo_plugins 57 | 58 | @REM copy files 59 | copy third-party\bass\bass.dll .output\Release\bass.dll 60 | copy source\cleo_config.ini .output\Release\cleo\.cleo_config.ini 61 | copy cleo_plugins\.output\*.cleo .output\Release\cleo\cleo_plugins 62 | copy cleo_plugins\.output\*.ini .output\Release\cleo\cleo_plugins 63 | 64 | - name: Upload Result 65 | uses: actions/upload-artifact@v4 66 | with: 67 | compression-level: 6 68 | name: SA.CLEO-v${{steps.custom_build.outputs.version}}-${{ steps.custom_build.outputs.sha }} 69 | path: | 70 | .output\Release\* 71 | !.output\Release\*.pdb 72 | !.output\Release\*.lib 73 | !.output\Release\*.exp 74 | -------------------------------------------------------------------------------- /.github/workflows/version.js: -------------------------------------------------------------------------------- 1 | const { readFileSync, writeFileSync } = require("fs"); 2 | const { EOL } = require("os"); 3 | const { GITHUB_REF_NAME } = process.env; 4 | const addJobOutput = require('./add-job-output'); 5 | 6 | if (GITHUB_REF_NAME) { 7 | const version = GITHUB_REF_NAME.startsWith("v") ? GITHUB_REF_NAME.slice(1) : GITHUB_REF_NAME; 8 | addJobOutput("version", version); 9 | 10 | // update cleo.h to replace version 11 | const cleoH = readFileSync("cleo_sdk/cleo.h", { encoding: "utf-8" }); 12 | 13 | const [, main, major, minor] = version.match(/(\d+)\.(\d+)\.(\d+).*/); 14 | 15 | const newCleoH = cleoH 16 | .replace(/#define\s+CLEO_VERSION_MAIN\s+.*/, `#define CLEO_VERSION_MAIN ${main}`) 17 | .replace(/#define\s+CLEO_VERSION_MAJOR\s+.*/, `#define CLEO_VERSION_MAJOR ${major}`) 18 | .replace(/#define\s+CLEO_VERSION_MINOR\s+.*/, `#define CLEO_VERSION_MINOR ${minor}`) 19 | .replace(/#define\s+CLEO_VERSION_STR\s+.*/, `#define CLEO_VERSION_STR "${version}"`); 20 | writeFileSync("cleo_sdk/cleo.h", newCleoH, { encoding: "utf-8" }); 21 | } 22 | 23 | const changelog = readFileSync("CHANGELOG.md", { encoding: "utf-8" }); 24 | writeFileSync("changes.txt", getChanges().join(EOL), { encoding: "utf-8" }); 25 | 26 | 27 | function getChanges() { 28 | const lines = changelog.split(EOL); 29 | const result = [ 30 | `## Download Instructions`, 31 | `An ASI loader is required for CLEO 5 to work. CLEO 5 comes pre-packaged with several popular ASI Loaders ([Silent's ASI Loader](https://cookieplmonster.github.io/mods/gta-sa/#asiloader) and [Ultimate ASI Loader](https://github.com/ThirteenAG/Ultimate-ASI-Loader)).`, 32 | `#### If you don't have an ASI loader installed already or unsure which one to download:`, 33 | `- Download [CLEO ${GITHUB_REF_NAME} with Silent's ASI Loader](https://github.com/cleolibrary/CLEO5/releases/download/${GITHUB_REF_NAME}/SA.CLEO-${GITHUB_REF_NAME}+Silent_ASI_Loader.zip)`, 34 | `#### If you prefer Ultimate ASI Loader:`, 35 | `- Download [CLEO ${GITHUB_REF_NAME} with Ultimate ASI Loader](https://github.com/cleolibrary/CLEO5/releases/download/${GITHUB_REF_NAME}/SA.CLEO-${GITHUB_REF_NAME}+Ultimate_ASI_Loader.zip)`, 36 | `#### If you have an ASI loader installed already:`, 37 | `- Download [this archive](https://github.com/cleolibrary/CLEO5/releases/download/${GITHUB_REF_NAME}/SA.CLEO-${GITHUB_REF_NAME}.zip) which contains ONLY CLEO 5 library and plugins.`, 38 | `## Installation`, 39 | `- Unzip the archive to GTA San Andreas game directory.`, 40 | `## Changelog`, 41 | ]; 42 | 43 | for (let i = 0; i < lines.length; i++) { 44 | const line = lines[i]; 45 | if (line.trimStart().startsWith("## ")) { 46 | for (let j = i + 1; j < lines.length; j++) { 47 | const line = lines[j]; 48 | if (line.trimStart().startsWith("## ")) { 49 | return result; 50 | } 51 | result.push(line); 52 | } 53 | } 54 | } 55 | 56 | return result; 57 | } 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .output/ 3 | *.APS 4 | *.VC.db 5 | *.VC.opendb 6 | *.asi 7 | *.cleo 8 | *.pdb 9 | *.opensdf 10 | *.suo 11 | *.sdf 12 | *.user 13 | *.cdf 14 | *.cache 15 | *.obj 16 | *.ilk 17 | *.resources 18 | *.tlb 19 | *.tli 20 | *.tlh 21 | *.tmp 22 | *.rsp 23 | *.pgc 24 | *.pgd 25 | *.meta 26 | *.tlog 27 | *.manifest 28 | *.res 29 | *.pch 30 | *.exp 31 | *.idb 32 | *.rep 33 | *.xdc 34 | *.pdb 35 | *_manifest.rc 36 | *.bsc 37 | *.sbr 38 | Debug/* 39 | Release/* 40 | ipch/ 41 | .vs/ 42 | *.zip 43 | *.lib 44 | node_modules/ 45 | tests/**/*.s -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "plugin-sdk"] 2 | path = third-party/plugin-sdk 3 | url = https://github.com/cleolibrary/plugin-sdk 4 | branch = CLEO_5 5 | -------------------------------------------------------------------------------- /CLEO5.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33213.308 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CLEO5", "CLEO5.vcxproj", "{B212DDA4-2A8E-45B2-914D-7BEEB31D06B1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|GTASA = Debug|GTASA 11 | Release|GTASA = Release|GTASA 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {B212DDA4-2A8E-45B2-914D-7BEEB31D06B1}.Debug|GTASA.ActiveCfg = Debug|Win32 15 | {B212DDA4-2A8E-45B2-914D-7BEEB31D06B1}.Debug|GTASA.Build.0 = Debug|Win32 16 | {B212DDA4-2A8E-45B2-914D-7BEEB31D06B1}.Release|GTASA.ActiveCfg = Release|Win32 17 | {B212DDA4-2A8E-45B2-914D-7BEEB31D06B1}.Release|GTASA.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {A5B531E5-EEEB-487A-8E07-75A94EE159D3} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2007-2023, CLEO Library by Seemann, Alien, Deji and Miran 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SETUP.md: -------------------------------------------------------------------------------- 1 | # CLEO project configuration 2 | 3 | This project depends on Plugin SDK (https://github.com/DK22Pac/plugin-sdk). Using SDK's installer results in creation of PLUGIN_SDK_DIR envinroment variable in operating system. If installer is not used then please manually enter path to the sdk directory in setup_env.bat. 4 | If GTA SA is installed in different than default location please open setup_env.bat file and configure correct path. 5 | Run setup_env.bat to setup required envinroment variables. 6 | 7 | After opening project solution in Visual Studio it should be possible to build as well as debug CLEO in game. 8 | -------------------------------------------------------------------------------- /cleo_plugins/Audio/C3DAudioStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CAudioStream.h" 3 | 4 | namespace CLEO 5 | { 6 | class C3DAudioStream : public CAudioStream 7 | { 8 | public: 9 | C3DAudioStream(const char* filepath); 10 | 11 | // overloaded actions 12 | virtual void Set3dPosition(const CVector& pos); 13 | virtual void Set3dSourceSize(float radius); 14 | virtual void SetHost(CEntity* host, const CVector& offset); 15 | virtual void Process(); 16 | virtual float CalculateVolume(); 17 | virtual float CalculateSpeed(); 18 | 19 | protected: 20 | const float Volume_3D_Adjust = 0.5f; // match other ingame sound sources 21 | static double CalculateDistanceDecay(float radius, float distance); 22 | static float CalculateDirectionDecay(const CVector& listenerDir, const CVector& relativePos); 23 | 24 | CEntity* host = nullptr; 25 | eEntityType hostType = ENTITY_TYPE_NOTHING; 26 | CVector offset = { 0.0f, 0.0f, 0.0f }; // offset in relation to host 27 | float radius = 0.5f; // size of sound source 28 | 29 | bool placed = false; 30 | CVector position = { 0.0f, 0.0f, 0.0f }; // last world position 31 | CVector velocity = { 0.0f, 0.0f, 0.0f }; 32 | 33 | C3DAudioStream(const C3DAudioStream&) = delete; // no copying! 34 | void UpdatePosition(); 35 | }; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /cleo_plugins/Audio/CAudioStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CSoundSystem.h" 3 | #include "CInterpolatedValue.h" 4 | #include "plugin.h" 5 | #include "bass.h" 6 | 7 | namespace CLEO 8 | { 9 | #pragma pack(push,4) 10 | class CAudioStream 11 | { 12 | public: 13 | enum StreamState 14 | { 15 | Stopped = -1, 16 | PlayingInactive, // internal: playing, but not processed yet or the sound system is silenced right now 17 | Playing, 18 | Paused, 19 | }; 20 | 21 | CAudioStream(const char* filepath); // filesystem or URL 22 | virtual ~CAudioStream(); 23 | 24 | bool IsOk() const; 25 | HSTREAM GetInternal(); // get BASS stream 26 | 27 | StreamState GetState() const; 28 | void Play(); 29 | void Pause(bool changeState = true); 30 | void Stop(); 31 | void Resume(); 32 | 33 | void SetLooping(bool enable); 34 | bool GetLooping() const; 35 | 36 | float GetLength() const; 37 | 38 | void SetProgress(float value); 39 | float GetProgress() const; 40 | 41 | void SetSpeed(float value, float transitionTime = 0.0f); 42 | float GetSpeed() const; 43 | 44 | void SetType(eStreamType value); 45 | eStreamType GetType() const; 46 | 47 | void SetVolume(float value, float transitionTime = 0.0f); 48 | float GetVolume() const; 49 | 50 | // 3d 51 | virtual void Set3dPosition(const CVector& pos); 52 | virtual void Set3dSourceSize(float radius); 53 | virtual void SetHost(CEntity* placable, const CVector& offset); 54 | 55 | virtual void Process(); 56 | virtual float CalculateVolume(); 57 | virtual float CalculateSpeed(); 58 | 59 | protected: 60 | HSTREAM streamInternal = 0; 61 | StreamState state = Paused; 62 | eStreamType type = eStreamType::SoundEffect; 63 | bool ok = false; 64 | float rate = 44100.0f; // file's sampling rate 65 | CInterpolatedValue speed = { 1.0f }; 66 | CInterpolatedValue volume = { 1.0f }; 67 | 68 | CAudioStream() = default; 69 | CAudioStream(const CAudioStream&) = delete; // no copying! 70 | }; 71 | #pragma pack(pop) 72 | } 73 | -------------------------------------------------------------------------------- /cleo_plugins/Audio/CInterpolatedValue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CInterpolatedValue 4 | { 5 | public: 6 | CInterpolatedValue(float value) 7 | { 8 | currValue = value; 9 | targetValue = value; 10 | step = 0.0f; 11 | } 12 | 13 | float value() const { return currValue; } 14 | 15 | void setValue(float target, float transitionTime) 16 | { 17 | targetValue = target; 18 | 19 | if (transitionTime <= 0.0f) 20 | { 21 | currValue = target; 22 | return; 23 | } 24 | 25 | step = (targetValue - currValue) / transitionTime; 26 | } 27 | 28 | void update(float elapsedTime) 29 | { 30 | if (currValue == targetValue) 31 | { 32 | return; // done 33 | } 34 | 35 | currValue += step * elapsedTime; 36 | 37 | // check progress 38 | auto remaining = targetValue - currValue; 39 | remaining *= (step > 0.0f) ? 1.0f : -1.0f; 40 | if (remaining <= 0.0f) // overshoot 41 | { 42 | currValue = targetValue; 43 | } 44 | } 45 | 46 | void finish() 47 | { 48 | currValue = targetValue; 49 | } 50 | 51 | private: 52 | float currValue = 0.0f; 53 | float targetValue = 0.0f; 54 | float step = 0.0f; 55 | }; 56 | -------------------------------------------------------------------------------- /cleo_plugins/Audio/CSoundSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "bass.h" 3 | #include "CVector.h" 4 | #include 5 | 6 | namespace CLEO 7 | { 8 | class CAudioStream; 9 | class C3DAudioStream; 10 | 11 | enum eStreamType 12 | { 13 | None = 0, // user controlled 14 | SoundEffect, // conforms to global SFX volume and in-game speed 15 | Music, // conforms to global music volume, muted if game speed is not 1.0 16 | UserInterface // conforms to global SFX volume 17 | }; 18 | 19 | class CSoundSystem 20 | { 21 | friend class CAudioStream; 22 | friend class C3DAudioStream; 23 | 24 | std::set streams; 25 | BASS_INFO SoundDevice = { 0 }; 26 | bool initialized = false; 27 | bool paused = false; 28 | 29 | static bool useFloatAudio; 30 | static bool CSoundSystem::allowNetworkSources; 31 | 32 | static CVector position; 33 | static CVector direction; 34 | static CVector velocity; 35 | static bool skipFrame; // do not apply changes during this frame 36 | static float timeStep; // delta time for current frame 37 | static float masterSpeed; // game simulation speed 38 | static float masterVolumeSfx; 39 | static float masterVolumeMusic; 40 | 41 | public: 42 | static eStreamType LegacyModeDefaultStreamType; 43 | 44 | CSoundSystem() = default; // TODO: give to user an ability to force a sound device to use (ini-file or cmd-line?) 45 | ~CSoundSystem(); 46 | 47 | bool Init(); 48 | bool Initialized(); 49 | 50 | CAudioStream* CreateStream(const char *filename, bool in3d = false); 51 | void DestroyStream(CAudioStream *stream); 52 | 53 | bool HasStream(CAudioStream* stream); 54 | void Clear(); // destroy all created streams 55 | 56 | void Pause(); 57 | void Resume(); 58 | void Process(); 59 | }; 60 | 61 | static bool isNetworkSource(const char* path) { return _strnicmp("http:", path, 5) == 0 || _strnicmp("https:", path, 6) == 0; } 62 | static float dot(CVector a, CVector b) { return a.x * b.x + a.y * b.y + a.z * b.z; } 63 | static float lerp(float a, float b, float progress) { return a * (1.0f - progress) + b * progress; } 64 | static CVector lerp(CVector a, CVector b, float progress) { return a * (1.0f - progress) + b * progress; } 65 | static BASS_3DVECTOR toBass(const CVector& v) { return BASS_3DVECTOR(v.x, v.z, v.y); } // convert GTA to BASS coordinate system 66 | } 67 | -------------------------------------------------------------------------------- /cleo_plugins/Audio/SA.Audio.ini: -------------------------------------------------------------------------------- 1 | [General] 2 | ; Manually select audio device. See `cleo.log` file to check list of available options. -1 for automatic 3 | AudioDevice=-1 4 | 5 | ; Allow playing streams from http(s) locations 6 | AllowNetworkSources=1 7 | 8 | ; Sounds created from scripts in legacy mode (*.cs3 or *.cs4) should use by default game's volume settings: 0 - None, 1 - SFX, 2 - Music, 3 - UI 9 | ; Select 1 if you have older mods that play sounds too loud 10 | LegacyModeDefaultStreamType=0 11 | -------------------------------------------------------------------------------- /cleo_plugins/Audio/bass/bass.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cleolibrary/CLEO5/c1c74036121f4d782d42467f693eb00a61ad81b3/cleo_plugins/Audio/bass/bass.dll -------------------------------------------------------------------------------- /cleo_plugins/Audio/bass/bass.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cleolibrary/CLEO5/c1c74036121f4d782d42467f693eb00a61ad81b3/cleo_plugins/Audio/bass/bass.lib -------------------------------------------------------------------------------- /cleo_plugins/DebugUtils/DebugUtils.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | plugin_sdk 8 | 9 | 10 | plugin_sdk 11 | 12 | 13 | plugin_sdk 14 | 15 | 16 | plugin_sdk 17 | 18 | 19 | plugin_sdk 20 | 21 | 22 | plugin_sdk 23 | 24 | 25 | plugin_sdk 26 | 27 | 28 | plugin_sdk 29 | 30 | 31 | 32 | 33 | 34 | cleo_sdk 35 | 36 | 37 | cleo_sdk 38 | 39 | 40 | 41 | 42 | 43 | {296646eb-cf0f-4ce8-81bc-b9de4fa37b9f} 44 | 45 | 46 | {7293454f-2941-4f6c-b0d3-b52d27a88286} 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /cleo_plugins/DebugUtils/SA.DebugUtils.ini: -------------------------------------------------------------------------------- 1 | [General] 2 | LegacyDebugOpcodes = 0 ; Opcodes 0662, 0663, 0664: 0 - off, 1 - enabled 3 | 4 | 5 | [ScreenLog] 6 | Level = 2 ; Level: 0 - off, 1 - errors and warnings, 2 - debug messages, 3 - all 7 | MessageTime = 3000 ; Minimum display time of single message 8 | MessagesMax = 32 ; Maximum count of messages visible at the same time (~row count) 9 | FontSize = 56 ; Font size 10 | FontStyle = 1 ; Font style: 0 - gothic, 1 - subtitles, 2 - menu, 3 - pricedown 11 | ; Messages colors: hexadecimal RGBA 12 | ColorError = "FF30EEFF" 13 | ColorDebug = "FFEE30FF" 14 | ColorSystem = "DDDDDDFF" 15 | 16 | 17 | ; game freeze prevention. Any script exceeding the limits will be suspended 18 | [Limits] 19 | Command = 2000000 ; maximum instructions of script per render frame. Set to 0 to disable the limit 20 | Time = 5 ; maximum lag time in seconds of script per render frame. Set to 0 to disable the limit 21 | -------------------------------------------------------------------------------- /cleo_plugins/DebugUtils/ScriptLog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CLEO.h" 3 | #include 4 | 5 | struct ScriptLog 6 | { 7 | CRunningScript* thread = nullptr; 8 | clock_t startTime = 0; 9 | size_t commandCounter = 0; 10 | 11 | void Begin(CRunningScript* thread) 12 | { 13 | this->thread = thread; 14 | startTime = clock(); 15 | commandCounter = 0; 16 | } 17 | 18 | void Clear() 19 | { 20 | thread = nullptr; 21 | startTime = 0; 22 | commandCounter = 0; 23 | } 24 | 25 | void ProcessCommand(CRunningScript* thread) 26 | { 27 | if (this->thread != thread) Begin(thread); 28 | 29 | commandCounter++; 30 | } 31 | 32 | inline size_t GetElapsedSeconds() const 33 | { 34 | return (clock() - startTime) / CLOCKS_PER_SEC; 35 | } 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /cleo_plugins/FileSystemOperations/FileSystemOperations.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | cleo_sdk 12 | 13 | 14 | cleo_sdk 15 | 16 | 17 | 18 | 19 | {a2c39c52-f49e-4ffe-bb0a-661ab07131b9} 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /cleo_plugins/FileSystemOperations/FileUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CLEO.h" 3 | #include 4 | #include 5 | 6 | class File 7 | { 8 | public: 9 | static void initialize(CLEO::eGameVersion version); 10 | 11 | static DWORD open(const char* filename, const char* mode, bool legacy); 12 | static void close(DWORD handle); 13 | 14 | static bool isOk(DWORD handle); 15 | 16 | static DWORD getSize(DWORD handle); 17 | static bool seek(DWORD handle, int offset, DWORD orign); 18 | static DWORD getPos(DWORD handle); 19 | static bool isEndOfFile(DWORD handle); 20 | 21 | static DWORD read(DWORD handle, void* buffer, DWORD size); 22 | static char readChar(DWORD handle); 23 | static char* readString(DWORD handle, char* buffer, DWORD bufferSize); 24 | 25 | static DWORD write(DWORD handle, const void* buffer, DWORD size); 26 | static bool writeString(DWORD handle, const char* text); 27 | static DWORD scan(DWORD handle, const char* format, void** outputParams); 28 | static bool flush(DWORD handle); 29 | 30 | static bool isLegacy(DWORD handle); // Legacy modes for CLEO 3 31 | static FILE* handleToFile(DWORD handle); 32 | 33 | private: 34 | static DWORD FUNC_fopen; 35 | static DWORD FUNC_fclose; 36 | static DWORD FUNC_fread; 37 | static DWORD FUNC_fwrite; 38 | static DWORD FUNC_fgetc; 39 | static DWORD FUNC_fgets; 40 | static DWORD FUNC_fputs; 41 | static DWORD FUNC_fseek; 42 | static DWORD FUNC_fprintf; 43 | static DWORD FUNC_ftell; 44 | static DWORD FUNC_fflush; 45 | static DWORD FUNC_feof; 46 | static DWORD FUNC_ferror; 47 | 48 | static DWORD fileToHandle(FILE* file, bool legacy); 49 | static void updateState(DWORD handle); 50 | }; 51 | -------------------------------------------------------------------------------- /cleo_plugins/FileSystemOperations/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CLEO.h" 3 | #include 4 | #include 5 | 6 | std::string stringPrintf(const char* format, ...) 7 | { 8 | va_list args; 9 | 10 | va_start(args, format); 11 | auto len = std::vsnprintf(nullptr, 0, format, args) + 1; 12 | va_end(args); 13 | 14 | std::string result(len, '\0'); 15 | 16 | va_start(args, format); 17 | std::vsnprintf(result.data(), result.length(), format, args); 18 | va_end(args); 19 | 20 | return result; 21 | } 22 | 23 | std::string scriptInfoStr(CLEO::CRunningScript* thread) 24 | { 25 | std::string info(1024, '\0'); 26 | CLEO_GetScriptInfoStr(thread, true, info.data(), info.length()); 27 | return std::move(info); 28 | } 29 | 30 | const char* TraceVArg(CLEO::eLogLevel level, const char* format, va_list args) 31 | { 32 | static char szBuf[1024]; 33 | vsprintf(szBuf, format, args); // put params into format 34 | CLEO_Log(level, szBuf); 35 | return szBuf; 36 | } 37 | 38 | void Trace(CLEO::eLogLevel level, const char* format, ...) 39 | { 40 | va_list args; 41 | va_start(args, format); 42 | TraceVArg(level, format, args); 43 | va_end(args); 44 | } 45 | 46 | void Trace(const CLEO::CRunningScript* thread, CLEO::eLogLevel level, const char* format, ...) 47 | { 48 | if (CLEO_GetScriptVersion(thread) < CLEO::eCLEO_Version::CLEO_VER_5) 49 | { 50 | return; // do not log this in older versions 51 | } 52 | 53 | va_list args; 54 | va_start(args, format); 55 | TraceVArg(level, format, args); 56 | va_end(args); 57 | } 58 | 59 | void ShowError(const char* format, ...) 60 | { 61 | va_list args; 62 | va_start(args, format); 63 | auto msg = TraceVArg(CLEO::eLogLevel::Error, format, args); 64 | va_end(args); 65 | 66 | QUERY_USER_NOTIFICATION_STATE pquns; 67 | SHQueryUserNotificationState(&pquns); 68 | bool fullscreen = (pquns == QUNS_BUSY) || (pquns == QUNS_RUNNING_D3D_FULL_SCREEN) || (pquns == QUNS_PRESENTATION_MODE); 69 | 70 | if (fullscreen) 71 | { 72 | PostMessage(NULL, WM_SYSCOMMAND, SC_MINIMIZE, 0); 73 | ShowWindow(NULL, SW_MINIMIZE); 74 | } 75 | 76 | MessageBox(NULL, msg, "CLEO error", MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONERROR | MB_OK); 77 | 78 | if (fullscreen) 79 | { 80 | PostMessage(NULL, WM_SYSCOMMAND, SC_RESTORE, 0); 81 | ShowWindow(NULL, SW_RESTORE); 82 | } 83 | } 84 | 85 | #define TRACE(format,...) {Trace(CLEO::eLogLevel::Default, format, __VA_ARGS__);} 86 | #define LOG_WARNING(script, format, ...) {Trace(script, CLEO::eLogLevel::Error, format, __VA_ARGS__);} 87 | #define SHOW_ERROR(a,...) {ShowError(a, __VA_ARGS__);} 88 | 89 | static const size_t MinValidAddress = 0x10000; // used for validation of pointers received from scripts. First 64kb are for sure reserved by Windows. 90 | #define OPCODE_VALIDATE_POINTER(x) if((size_t)x <= MinValidAddress) { auto info = scriptInfoStr(thread); SHOW_ERROR("Invalid '0x%X' pointer param in script %s \nScript suspended.", x, info.c_str()); return thread->Suspend(); } 91 | -------------------------------------------------------------------------------- /cleo_plugins/IniFiles/IniFiles.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /cleo_plugins/Math/Math.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | {20ddb375-f549-46bb-814d-53e534880d23} 9 | 10 | 11 | 12 | 13 | cleo_sdk 14 | 15 | 16 | cleo_sdk 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /cleo_plugins/MemoryOperations/MemoryOperations.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | plugin_sdk 7 | 8 | 9 | plugin_sdk 10 | 11 | 12 | plugin_sdk 13 | 14 | 15 | plugin_sdk 16 | 17 | 18 | plugin_sdk 19 | 20 | 21 | plugin_sdk 22 | 23 | 24 | plugin_sdk 25 | 26 | 27 | 28 | 29 | {1903661c-d3a7-4f51-8910-54b32282a46d} 30 | 31 | 32 | {0c8900ae-85e5-4dc1-9d7b-173b6f8cd435} 33 | 34 | 35 | 36 | 37 | cleo_sdk 38 | 39 | 40 | cleo_sdk 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /cleo_plugins/Resource.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cleolibrary/CLEO5/c1c74036121f4d782d42467f693eb00a61ad81b3/cleo_plugins/Resource.rc -------------------------------------------------------------------------------- /cleo_plugins/Text/CTextManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CText.h" 3 | #include "crc32.h" 4 | #include 5 | #include 6 | 7 | namespace CLEO 8 | { 9 | class CTextManager 10 | { 11 | class FxtEntry 12 | { 13 | friend class CTextManager; 14 | std::string text; 15 | bool is_static; 16 | FxtEntry(const char *_text, bool _static = false); 17 | }; 18 | 19 | typedef std::unordered_map fxt_map_type; 20 | typedef fxt_map_type::iterator fxt_iterator; 21 | typedef fxt_map_type::const_iterator const_fxt_iterator; 22 | fxt_map_type fxts; 23 | 24 | public: 25 | CTextManager(); 26 | ~CTextManager(); 27 | 28 | void LoadFxts(); 29 | void Clear(); 30 | 31 | const char* Get(const char* key); 32 | bool AddFxt(const char *key, const char *value, bool dynamic = true); 33 | bool RemoveFxt(const char *key); 34 | // find fxt text by its key 35 | const char *LocateFxt(const char *key); 36 | // erase all fxts, added by scripts 37 | void ClearDynamicFxts(); 38 | size_t ParseFxtFile(std::istream& stream, bool dynamic = false, bool remove = false); 39 | }; 40 | } 41 | -------------------------------------------------------------------------------- /cleo_plugins/Text/ScriptDrawing.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ScriptDrawing.h" 3 | #include "CLEO_Utils.h" 4 | #include 5 | #include 6 | 7 | using namespace CLEO; 8 | 9 | 10 | void ScriptDrawing::ScriptProcessingBegin(CLEO::CRunningScript* script) 11 | { 12 | if (!script->IsCustom()) return; 13 | 14 | m_globalDrawingState.Store(); 15 | m_scriptDrawingStates[script].Apply(true); // initialize for new frame 16 | 17 | m_currCustomScript = script; 18 | } 19 | 20 | void ScriptDrawing::ScriptProcessingEnd(CLEO::CRunningScript* script) 21 | { 22 | if (!script->IsCustom()) return; 23 | 24 | if (script->IsActive()) m_scriptDrawingStates[script].Store(); 25 | m_globalDrawingState.Apply(); 26 | 27 | m_currCustomScript = nullptr; 28 | } 29 | 30 | void ScriptDrawing::ScriptUnregister(CLEO::CRunningScript* script) 31 | { 32 | if (!script->IsCustom()) return; 33 | 34 | m_scriptDrawingStates.erase(script); 35 | } 36 | 37 | void ScriptDrawing::Draw(bool beforeFade) 38 | { 39 | if (std::all_of(m_scriptDrawingStates.cbegin(), m_scriptDrawingStates.cend(), [](auto& p) { return p.second.IsEmpty(); })) 40 | { 41 | return; // no custom scripts with draws 42 | } 43 | 44 | m_globalDrawingState.Store(); 45 | 46 | for(auto& [script, state] : m_scriptDrawingStates) 47 | { 48 | if (state.IsEmpty()) continue; 49 | 50 | state.Apply(); 51 | CHud::DrawScriptText(beforeFade); 52 | } 53 | 54 | m_globalDrawingState.Apply(); 55 | } 56 | 57 | RwTexture* ScriptDrawing::GetScriptTexture(CLEO::CRunningScript* script, DWORD slot) 58 | { 59 | if (script == nullptr || slot == 0 || slot > _countof(CTheScripts::ScriptSprites)) 60 | { 61 | return nullptr; // invalid param 62 | } 63 | slot -= 1; // to 0-based index 64 | 65 | if (script->IsCustom()) 66 | { 67 | if (script == m_currCustomScript) 68 | { 69 | return CTheScripts::ScriptSprites[slot].m_pTexture; 70 | } 71 | else 72 | { 73 | return (m_scriptDrawingStates.find(script) != m_scriptDrawingStates.end()) ? CTheScripts::ScriptSprites[slot].m_pTexture : nullptr; 74 | } 75 | } 76 | else 77 | { 78 | return (m_currCustomScript == nullptr) ? CTheScripts::ScriptSprites[slot].m_pTexture : m_globalDrawingState.sprites[slot].m_pTexture; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /cleo_plugins/Text/ScriptDrawing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CLEO.h" 3 | #include "ScriptDrawsState.h" 4 | #include 5 | 6 | 7 | class ScriptDrawing 8 | { 9 | public: 10 | void ScriptProcessingBegin(CLEO::CRunningScript* script); 11 | void ScriptProcessingEnd(CLEO::CRunningScript* script); 12 | void ScriptUnregister(CLEO::CRunningScript* script); 13 | 14 | void Draw(bool beforeFade); // draw buffered script draws to screen 15 | 16 | RwTexture* GetScriptTexture(CLEO::CRunningScript* script, DWORD slot); 17 | 18 | private: 19 | ScriptDrawsState m_globalDrawingState; 20 | CLEO::CRunningScript* m_currCustomScript = nullptr; // currently processed script 21 | std::map m_scriptDrawingStates; // buffered script draws 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /cleo_plugins/Text/ScriptDrawsState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | 6 | struct ScriptDrawsState 7 | { 8 | eUseTextCommandState useTextCommands = eUseTextCommandState::DISABLED; 9 | 10 | WORD textsCount = 0; 11 | std::array texts; 12 | 13 | WORD rectanglesCount = 0; 14 | std::array rectangles; 15 | 16 | std::array sprites; 17 | 18 | ScriptDrawsState() = default; 19 | ScriptDrawsState(const ScriptDrawsState&) = delete; // no copying! 20 | ~ScriptDrawsState() = default; 21 | 22 | void Store() 23 | { 24 | useTextCommands = CTheScripts::UseTextCommands; 25 | 26 | textsCount = CTheScripts::NumberOfIntroTextLinesThisFrame; 27 | std::memcpy(texts.data(), CTheScripts::IntroTextLines, texts.size() * sizeof(tScriptText)); 28 | 29 | rectanglesCount = CTheScripts::NumberOfIntroRectanglesThisFrame; 30 | std::memcpy(rectangles.data(), CTheScripts::IntroRectangles, rectangles.size() * sizeof(tScriptRectangle)); 31 | 32 | std::memcpy(sprites.data(), CTheScripts::ScriptSprites, sprites.size() * sizeof(CSprite2d)); 33 | } 34 | 35 | void Apply(bool newFrame = false) 36 | { 37 | if (!newFrame) 38 | { 39 | CTheScripts::UseTextCommands = useTextCommands; 40 | 41 | // texts 42 | CTheScripts::NumberOfIntroTextLinesThisFrame = textsCount; 43 | std::memcpy(CTheScripts::IntroTextLines, texts.data(), texts.size() * sizeof(tScriptText)); 44 | 45 | // rectangles 46 | CTheScripts::NumberOfIntroRectanglesThisFrame = rectanglesCount; 47 | std::memcpy(CTheScripts::IntroRectangles, rectangles.data(), rectangles.size() * sizeof(tScriptRectangle)); 48 | } 49 | else 50 | { 51 | CTheScripts::UseTextCommands = (useTextCommands == eUseTextCommandState::DISABLE_NEXT_FRAME) ? eUseTextCommandState::DISABLED : useTextCommands; 52 | 53 | // texts 54 | CTheScripts::NumberOfIntroTextLinesThisFrame = 0; 55 | std::fill( 56 | CTheScripts::IntroTextLines, 57 | CTheScripts::IntroTextLines + _countof(CTheScripts::IntroTextLines), 58 | tScriptText()); 59 | 60 | // rectangles 61 | CTheScripts::NumberOfIntroRectanglesThisFrame = 0; 62 | std::fill( 63 | CTheScripts::IntroRectangles, 64 | CTheScripts::IntroRectangles + _countof(CTheScripts::IntroRectangles), 65 | tScriptRectangle()); 66 | } 67 | 68 | // loaded textures 69 | std::memcpy(CTheScripts::ScriptSprites, sprites.data(), sprites.size() * sizeof(CSprite2d)); 70 | } 71 | 72 | bool IsEmpty() const 73 | { 74 | return !rectanglesCount && !textsCount; 75 | } 76 | }; 77 | -------------------------------------------------------------------------------- /cleo_plugins/Text/crc32.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | unsigned long crc32(const unsigned char *buf, unsigned long len); 5 | unsigned long crc32FromUpcaseString(const char *str); 6 | unsigned long crc32FromUpcaseStdString(const std::string& str); 7 | unsigned long crc32FromString(const char *str); 8 | unsigned long crc32FromStdString(const std::string& str); 9 | -------------------------------------------------------------------------------- /cleo_sdk/CLEO_SDK_RU.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cleolibrary/CLEO5/c1c74036121f4d782d42467f693eb00a61ad81b3/cleo_sdk/CLEO_SDK_RU.chm -------------------------------------------------------------------------------- /examples/CLEO_Sound_Button.txt: -------------------------------------------------------------------------------- 1 | // CLEO5 example script 2 | // Sanny Builder 4 3 | // mode: GTA SA (v1.0 - SBL) 4 | 5 | {$CLEO .cs} 6 | 7 | const Path_Sound_Button = ".\cleo_tests\Audio\Ding.mp3" 8 | 9 | 10 | // init sounds 11 | int asButton 12 | if 13 | not asButton = load_audio_stream {audioFileName} Path_Sound_Button 14 | then 15 | // failed to load the file. Print error and exit 16 | debug_on 17 | trace "CLEO Sound Button: ~r~~h~~h~Failed to load sound file '%s'" Path_Sound_Button 18 | terminate_this_script 19 | end 20 | set_audio_stream_type asButton {type} AudioStreamType.UserInterface 21 | 22 | 23 | // main loop 24 | int counter = 0 25 | while true 26 | //wait {time} 16 // cap this script loop at 60 FPS 27 | wait {time} 0 // as fast as game renders 28 | 29 | // slow increment button 30 | if 31 | is_key_pressed {keyCode} KeyCode.Space 32 | then 33 | set_audio_stream_state asButton {action} AudioStreamAction.Stop 34 | set_audio_stream_state asButton {action} AudioStreamAction.Play 35 | counter += 1 36 | 37 | // wait for key release or timeout 38 | TimerA = 0 39 | while true 40 | if or 41 | not is_key_pressed {keyCode} KeyCode.Space 42 | TimerA > 100 43 | then 44 | break // exit the loop 45 | end 46 | 47 | wait {time} 0 48 | end 49 | end 50 | 51 | // rapid increment button 52 | if 53 | is_key_pressed {keyCode} KeyCode.Shift 54 | then 55 | set_audio_stream_state asButton {action} AudioStreamAction.Stop 56 | set_audio_stream_state asButton {action} AudioStreamAction.Play 57 | counter += 1 58 | end 59 | 60 | // display message 61 | print_formatted_now {format} "Count: %d~n~Press ~h~SPACE~s~ or ~h~SHIFT~s~ to increment." {time} 150 {args} counter // display longer than button timeout delay, so no text flashing occur 62 | end 63 | 64 | 65 | terminate_this_script // never executed, but good to have 66 | -------------------------------------------------------------------------------- /examples/Check_CLEO_Version.txt: -------------------------------------------------------------------------------- 1 | // CLEO5 example script 2 | // Sanny Builder 4 3 | // mode: GTA SA (v1.0 - SBL) 4 | {$CLEO .cs} 5 | 6 | script_name {name} 'mymod' 7 | 8 | // wait for game to fade in from black screen 9 | wait {time} 4000 10 | 11 | CHECK_CLEO_VERSION() 12 | 13 | // your script code here 14 | debug_on 15 | trace "~g~~h~~h~My Mod is working fine!" // CLEO5 opcode, would crash older versions 16 | 17 | terminate_this_custom_script 18 | 19 | 20 | function CHECK_CLEO_VERSION() 21 | int lib, proc, ver 22 | if 23 | lib = load_dynamic_library "CLEO.asi" 24 | then 25 | if 26 | proc = get_dynamic_library_procedure "_CLEO_GetVersion@0" {library} lib 27 | then 28 | ver = call_function_return proc {params} 0 {pop} 0 29 | end 30 | free_dynamic_library lib 31 | end 32 | 33 | if 34 | ver < 0x05000000 // 5.0.0 35 | then 36 | print_help_string {text} "My Mod requires CLEO 5.0.0 or newer to work!" 37 | terminate_this_custom_script 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /examples/Mission_Trigger.txt: -------------------------------------------------------------------------------- 1 | // CLEO5 example script 2 | // Sanny Builder 4 3 | // mode: GTA SA (v1.0 - SBL) 4 | 5 | {$CLEO .cs} 6 | {$USE CLEO+} 7 | 8 | const 9 | Mission_Icon = 34 // RadarSprite.Ryder - https://library.sannybuilder.com/#/sa/script/enums/RadarSprite 10 | Mission_Pos_X = 2468.5 11 | Mission_Pos_Y = -1688.0 12 | Mission_Pos_Z = 13.5 13 | Mission_File = "my_ryder_mission" // my_ryder_mission.cm 14 | end 15 | 16 | script_name 'mis_trg' 17 | 18 | CleoBlip blipHandle = -1 19 | int markerActive = false 20 | while true 21 | wait 0 22 | 23 | if or 24 | is_on_mission // any mission is in progress 25 | not is_player_playing $player1 // wasted or busted 26 | then 27 | if 28 | blipHandle <> -1 29 | then 30 | remove_cleo_blip blipHandle 31 | blipHandle = -1 32 | end 33 | 34 | markerActive = true // in case any mission ends in this mission trigger 35 | wait {time} 1000 // on mission 36 | continue 37 | else 38 | if 39 | blipHandle == -1 40 | then 41 | blipHandle = add_cleo_blip {RadarSprite} Mission_Icon {pos} Mission_Pos_X Mission_Pos_Y {short} true {rgba} 255 255 255 255 42 | end 43 | 44 | if 45 | locate_char_any_means_3d $scplayer {pos} Mission_Pos_X Mission_Pos_Y Mission_Pos_Z {radius} 50.0 50.0 50.0 {drawSphere} false // in proximity? 46 | then 47 | if 48 | //locate_stopped_char_any_means_3d $scplayer {pos} Mission_Pos_X Mission_Pos_Y Mission_Pos_Z {radius} 2.0 2.0 2.0 {drawSphere} true 49 | locate_stopped_char_on_foot_3d $scplayer {pos} Mission_Pos_X Mission_Pos_Y Mission_Pos_Z {radius} 2.0 2.0 2.0 {drawSphere} true 50 | //locate_stopped_char_in_car_3d $scplayer {pos} Mission_Pos_X Mission_Pos_Y Mission_Pos_Z {radius} 2.0 2.0 2.0 {drawSphere} true 51 | then 52 | if and 53 | markerActive == false 54 | can_player_start_mission $player1 55 | then 56 | markerActive = true 57 | load_and_launch_custom_mission Mission_File 58 | continue 59 | end 60 | else 61 | markerActive = false 62 | end 63 | else 64 | wait {time} 1000 // away from trigger 65 | continue 66 | end 67 | end 68 | end 69 | 70 | terminate_this_custom_script // not needed, but good to have 71 | -------------------------------------------------------------------------------- /examples/Sounds_Browser.txt: -------------------------------------------------------------------------------- 1 | // CLEO5 example script 2 | // Sanny Builder 4 3 | // mode: GTA SA (v1.0 - SBL) 4 | {$CLEO .cs} 5 | 6 | script_name {name} "sound_br" 7 | 8 | int soundId = 1000 9 | int keyWasDown = false 10 | while true 11 | wait 0 12 | 13 | print_formatted_now "Sound id: %d~n~Press ~y~<~s~ and ~y~>~s~ to browse,~n~hold ~y~SHIFT~s~ to browse faster.~n~Press ~y~?~s~ to play again." {time} 1 {args} soundId 14 | 15 | // handle browse keys 16 | if or 17 | is_key_pressed {keyCode} KeyCode.OemComma // < 18 | is_key_pressed {keyCode} KeyCode.OemPeriod // > 19 | then 20 | keyWasDown = true 21 | 22 | int step 23 | if 24 | is_key_pressed {keyCode} KeyCode.OemPeriod 25 | then 26 | step = 1 27 | else 28 | step = -1 29 | end 30 | if 31 | is_key_pressed {keyCode} KeyCode.Shift 32 | then 33 | step *= 10 34 | end 35 | soundId += step 36 | 37 | // warp around if out of bounds 38 | if 39 | soundId < 1000 40 | then 41 | soundId = 1190 42 | end 43 | if 44 | soundId > 1190 45 | then 46 | soundId = 1000 47 | end 48 | 49 | // wait for key release or timeout 50 | while true 51 | if and 52 | not is_key_pressed {keyCode} KeyCode.OemComma // < 53 | not is_key_pressed {keyCode} KeyCode.OemPeriod // > 54 | then 55 | break // keys released 56 | end 57 | 58 | if 59 | TimerA > 30 // auto repeat time in miliseconds 60 | then 61 | TimerA = 0 62 | break 63 | end 64 | 65 | wait 0 66 | end 67 | 68 | continue 69 | end 70 | 71 | // handle play key 72 | if 73 | is_key_pressed {keyCode} KeyCode.Oem2 // ? key 74 | then 75 | keyWasDown = true 76 | 77 | wait 50 78 | continue 79 | end 80 | 81 | if 82 | keyWasDown == true 83 | then 84 | float x, y, z 85 | x, y, z = get_char_coordinates $scplayer 86 | 87 | add_one_off_sound {pos} x y z {soundId} soundId 88 | 89 | keyWasDown = false 90 | end 91 | 92 | // keys are up 93 | TimerA = -200 // extra delay before auto repeat activates 94 | end 95 | 96 | terminate_this_script -------------------------------------------------------------------------------- /examples/Vehicle_Flags.txt: -------------------------------------------------------------------------------- 1 | // CLEO5 example script 2 | // Sanny Builder 4 3 | // mode: GTA SA (v1.0 - SBL) 4 | {$CLEO .cs} 5 | 6 | wait 3000 // give game time to start 7 | 8 | while true 9 | wait {time} 250 10 | 11 | if 12 | not is_player_control_on $player1 13 | then 14 | continue // wait for player playing 15 | end 16 | 17 | if 18 | not is_char_sitting_in_any_car $scplayer 19 | then 20 | continue // wait for player in car 21 | end 22 | 23 | int car_handle = store_car_char_is_in_no_save $scplayer 24 | 25 | int pointer = get_vehicle_pointer car_handle 26 | 27 | pointer = read_memory_with_offset {address} pointer {offset} 0x384 {size} 4 // CVehicle::m_pHandlingData 28 | if 29 | pointer == 0 // nullptr 30 | then 31 | continue // error: no handling data 32 | end 33 | 34 | int flags = read_memory_with_offset {address} pointer {offset} 0xCC {size} 4 // tHandlingData::m_nModelFlags 35 | 36 | // https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/tHandlingData.h#L66 37 | if 38 | is_bit_set {number} flags {bitIndex} 13 // m_bDoubleExhaust 39 | then 40 | print_formatted_now "~g~~h~Double exhaust" {time} 250 41 | else 42 | print_formatted_now "~r~~h~Single exhaust" {time} 250 43 | end 44 | end 45 | 46 | terminate_this_script 47 | -------------------------------------------------------------------------------- /setup_env.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | @SET GAME_DIR=C:\Program Files (x86)\Rockstar Games\GTA San Andreas 4 | @SET PLUGIN_DIR=C:\plugin-sdk-master 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | @IF DEFINED GTA_SA_DIR ( 17 | ECHO GTA_SA_DIR already set to: 18 | ECHO "%GTA_SA_DIR%" 19 | ECHO: 20 | ECHO New value: 21 | ECHO "%GAME_DIR%" 22 | ECHO: 23 | CHOICE /C YN /M "Do you want to update?" 24 | If ERRORLEVEL 2 GOTO SET_GAME_END 25 | ) 26 | 27 | @SETX GTA_SA_DIR "%GAME_DIR%" 28 | ECHO GTA_SA_DIR configured as: 29 | ECHO "%GAME_DIR%" 30 | :SET_GAME_END 31 | 32 | ECHO: 33 | ECHO: 34 | 35 | @IF DEFINED PLUGIN_SDK_DIR ( 36 | ECHO PLUGIN_SDK_DIR already set to: 37 | ECHO "%PLUGIN_SDK_DIR%" 38 | ECHO . 39 | ECHO New value: 40 | ECHO "%PLUGIN_DIR%" 41 | ECHO . 42 | CHOICE /C YN /M "Do you want to update?" 43 | If ERRORLEVEL 2 GOTO SET_PLUGIN_END 44 | ) 45 | 46 | @SETX PLUGIN_SDK_DIR "%PLUGIN_DIR%" 47 | ECHO PLUGIN_SDK_DIR configured as: 48 | ECHO "%PLUGIN_DIR%" 49 | :SET_PLUGIN_END 50 | 51 | ECHO: 52 | ECHO: 53 | 54 | pause 55 | exit 56 | -------------------------------------------------------------------------------- /source/CDebug.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CDebug.h" 3 | #include "CleoBase.h" 4 | 5 | 6 | CDebug Debug; 7 | using namespace CLEO; 8 | 9 | void CDebug::Trace(CLEO::eLogLevel level, const char* msg) 10 | { 11 | std::lock_guard guard(mutex); 12 | 13 | // output to console 14 | #ifdef _DEBUG 15 | OutputDebugString(msg); 16 | OutputDebugString("\n"); 17 | #endif 18 | 19 | // censor user name in paths like "C:\Users\xxx\Documents..." 20 | const char* UsersDir = "\\users\\"; 21 | std::string msgStr = msg; 22 | StringToLower(msgStr); 23 | auto usersDirPos = strstr(msgStr.c_str(), UsersDir); 24 | if (usersDirPos != nullptr) 25 | { 26 | size_t userBegin = (size_t)(usersDirPos - msgStr.c_str()) + strlen(UsersDir); 27 | 28 | size_t userEnd = msgStr.find_first_of("\\/*\"<>:|?", userBegin); // till next path separator or any invalid filepath character 29 | if (userEnd == std::string::npos) 30 | { 31 | userEnd = msgStr.length(); 32 | } 33 | 34 | msgStr = msg; // restore original case 35 | msgStr.replace(userBegin, userEnd - userBegin, "[redacted]"); 36 | msg = msgStr.c_str(); 37 | } 38 | 39 | // output to callbacks 40 | if (CleoInstance.IsStarted()) 41 | { 42 | for (void* func : CleoInstance.GetCallbacks(eCallbackId::Log)) 43 | { 44 | typedef void WINAPI callback(eLogLevel, const char*); 45 | ((callback*)func)(level, msg); 46 | } 47 | } 48 | 49 | // output to log file 50 | if (m_hFile.good()) 51 | { 52 | // time stamp 53 | SYSTEMTIME t; 54 | GetLocalTime(&t); 55 | //void(__stdcall * GTA_GetLocalTime)(LPSYSTEMTIME lpSystemTime) = memory_pointer(0x0081E514); // use ingame function instead as GetLocalTime seems to be considered suspicious by some AV software 56 | //GTA_GetLocalTime(&t); 57 | 58 | char timestampStr[32]; 59 | sprintf_s(timestampStr, "%02d/%02d/%04d %02d:%02d:%02d.%03d ", t.wDay, t.wMonth, t.wYear, t.wHour, t.wMinute, t.wSecond, t.wMilliseconds); 60 | m_hFile << timestampStr; 61 | 62 | // add separator line if frame rendered since last log entry 63 | if (lastFrame != CTimer::m_FrameCounter) 64 | { 65 | m_hFile << std::endl << timestampStr; 66 | lastFrame = CTimer::m_FrameCounter; 67 | } 68 | 69 | // message 70 | auto message = std::string(msg); 71 | StringRemoveFormatting(message); 72 | m_hFile << message.c_str(); 73 | 74 | m_hFile << std::endl; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /source/CDebug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class CDebug 5 | { 6 | public: 7 | CDebug() : m_hFile(Filepath_Log) 8 | { 9 | Trace(CLEO::eLogLevel::Default, "Log started."); 10 | 11 | #ifdef _DEBUG 12 | CLEO::Trace(CLEO::eLogLevel::Default, "CLEO v%s DEBUG", CLEO_VERSION_STR); 13 | #else 14 | CLEO::Trace(CLEO::eLogLevel::Default, "CLEO v%s", CLEO_VERSION_STR); 15 | #endif 16 | } 17 | 18 | ~CDebug() 19 | { 20 | CLEO::Trace(CLEO::eLogLevel::Default, ""); // separator 21 | CLEO::Trace(CLEO::eLogLevel::Default, "Log finished."); 22 | } 23 | 24 | void Trace(CLEO::eLogLevel level, const char* msg); 25 | 26 | private: 27 | unsigned int lastFrame = -1; 28 | std::mutex mutex; 29 | std::ofstream m_hFile; 30 | }; 31 | 32 | extern CDebug Debug; 33 | -------------------------------------------------------------------------------- /source/CDmaFix.cpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | #include "CDmaFix.h" 4 | #include "CGameVersionManager.h" 5 | #include "CleoBase.h" 6 | 7 | namespace CLEO 8 | { 9 | void CDmaFix::Inject(CCodeInjector& inj) 10 | { 11 | TRACE("Injecting DmaFix..."); 12 | CGameVersionManager& gvm = CleoInstance.VersionManager; 13 | switch (gvm.GetGameVersion()) 14 | { 15 | case GV_EU10: 16 | case GV_US10: 17 | inj.MemoryWrite(0x463CC5, 0x0824448B); 18 | inj.MemoryWrite(0x463CC9, 0x90); 19 | 20 | inj.Nop(0x4641C6, 3); 21 | inj.Nop(0x4641E8, 3); 22 | inj.Nop(0x4641FE, 3); 23 | 24 | inj.Nop(0x46447F, 3); 25 | inj.Nop(0x4644A1, 3); 26 | inj.Nop(0x4644B7, 3); 27 | break; 28 | case GV_EU11: 29 | inj.MemoryWrite(0x463D45, 0x0824448B); 30 | inj.MemoryWrite(0x463D49, 0x90); 31 | 32 | inj.Nop(0x464246, 3); 33 | inj.Nop(0x464268, 3); 34 | inj.Nop(0x46427E, 3); 35 | 36 | inj.Nop(0x4644FF, 3); 37 | inj.Nop(0x464521, 3); 38 | inj.Nop(0x464537, 3); 39 | break; 40 | case GV_STEAM: 41 | inj.MemoryWrite(0x469390, 0x0824448B); 42 | inj.MemoryWrite(0x469394, 0x90); 43 | 44 | inj.Nop(0x4698F6, 3); 45 | break; 46 | default: 47 | SHOW_ERROR("CDmaFix::Inject(): Unimplemented game version."); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /source/CDmaFix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CCodeInjector.h" 3 | 4 | namespace CLEO 5 | { 6 | class CDmaFix 7 | { 8 | public: 9 | void Inject(CCodeInjector& inj); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /source/CGameMenu.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CGameMenu.h" 3 | #include "CleoBase.h" 4 | #include "CDebug.h" 5 | 6 | namespace CLEO 7 | { 8 | void CGameMenu::Inject(CCodeInjector& inj) 9 | { 10 | TRACE("Injecting MenuStatusNotifier..."); 11 | inj.ReplaceFunction(HOOK_DrawMenuBackground, CleoInstance.VersionManager.TranslateMemoryAddress(MA_CALL_CTEXTURE_DRAW_BG_RECT), &DrawMenuBackground_Orig); 12 | } 13 | 14 | void __fastcall CGameMenu::HOOK_DrawMenuBackground(CSprite2d* texture, int dummy, CRect* rect, RwRGBA *color) 15 | { 16 | CleoInstance.Start(CCleoInstance::InitStage::OnDraw); // late initialization 17 | 18 | CleoInstance.GameMenu.DrawMenuBackground_Orig(texture, dummy, rect, color); 19 | 20 | CFont::SetBackground(false, false); 21 | CFont::SetWrapx(640.0f); 22 | CFont::SetFontStyle(FONT_MENU); 23 | CFont::SetProportional(true); 24 | CFont::SetOrientation(ALIGN_LEFT); 25 | 26 | CFont::SetColor({ 0xAD, 0xCE, 0xC4, 0xFF }); 27 | CFont::SetEdge(1); 28 | CFont::SetDropColor({ 0x00, 0x00, 0x00, 0xFF }); 29 | 30 | const float fontSize = 0.5f / 448.0f; 31 | const float aspect = (float)RsGlobal.maximumWidth / RsGlobal.maximumHeight; 32 | const float subtextHeight = 0.75f; // factor of first line height 33 | float sizeX = fontSize * 0.5f / aspect * RsGlobal.maximumWidth; 34 | float sizeY = fontSize * RsGlobal.maximumHeight; 35 | 36 | float posX = 25.0f * sizeX; // left margin 37 | float posY = RsGlobal.maximumHeight - 15.0f * sizeY; // bottom margin 38 | 39 | auto cs_count = CleoInstance.ScriptEngine.WorkingScriptsCount(); 40 | auto plugin_count = CleoInstance.PluginSystem.GetNumPlugins(); 41 | if (cs_count || plugin_count) 42 | { 43 | posY -= 15.0f * sizeY; // add space for bottom text 44 | } 45 | 46 | // draw CLEO version text 47 | std::ostringstream text; 48 | text << "CLEO v" << CLEO_VERSION_STR; 49 | #ifdef _DEBUG 50 | text << " ~r~~h~DEBUG"; 51 | #endif 52 | CFont::SetScale(sizeX, sizeY); 53 | CFont::PrintString(posX, posY - 15.0f * sizeY, text.str().c_str()); 54 | 55 | // draw plugins / scripts text 56 | if (cs_count || plugin_count) 57 | { 58 | text.str(""); // clear 59 | if (plugin_count) text << plugin_count << (plugin_count > 1 ? " plugins" : " plugin"); 60 | if (cs_count && plugin_count) text << " / "; 61 | if (cs_count) text << cs_count << (cs_count > 1 ? " scripts" : " script"); 62 | 63 | posY += 15.0f * sizeY; // line feed 64 | sizeX *= subtextHeight; 65 | sizeY *= subtextHeight; 66 | CFont::SetScale(sizeX, sizeY); 67 | CFont::PrintString(posX, posY - 15.0f * sizeY, text.str().c_str()); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /source/CGameMenu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CCodeInjector.h" 3 | 4 | namespace CLEO 5 | { 6 | class CGameMenu 7 | { 8 | public: 9 | void Inject(CCodeInjector& inj); 10 | 11 | private: 12 | static void __fastcall HOOK_DrawMenuBackground(CSprite2d* texture, int dummy, CRect* rect, RwRGBA* color); 13 | void(__fastcall* DrawMenuBackground_Orig)(CSprite2d* texture, int dummy, CRect* rect, RwRGBA* color) = nullptr; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /source/CGameVersionManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CCodeInjector.h" 3 | 4 | namespace CLEO 5 | { 6 | // returned by 0DD5: get_platform opcode 7 | enum ePlatform 8 | { 9 | PLATFORM_NONE, 10 | PLATFORM_ANDROID, 11 | PLATFORM_PSP, 12 | PLATFORM_IOS, 13 | PLATFORM_FOS, 14 | PLATFORM_XBOX, 15 | PLATFORM_PS2, 16 | PLATFORM_PS3, 17 | PLATFORM_MAC, 18 | PLATFORM_WINDOWS 19 | }; 20 | 21 | // determines the list of memory adresses, that can be translated 22 | // considering to game version 23 | enum eMemoryAddress 24 | { 25 | // UpdateGameLogics 26 | MA_CALL_UPDATE_GAME_LOGICS, 27 | 28 | // MenuStatusNotifier 29 | MA_CALL_CTEXTURE_DRAW_BG_RECT, 30 | 31 | // ScriptEngine 32 | MA_SCRIPT_OPCODE_HANDLER0_FUNCTION, 33 | MA_GET_SCRIPT_PARAMS_FUNCTION, 34 | MA_TRANSMIT_SCRIPT_PARAMS_FUNCTION, 35 | MA_SET_SCRIPT_PARAMS_FUNCTION, 36 | MA_SET_SCRIPT_COND_RESULT_FUNCTION, 37 | MA_GET_SCRIPT_PARAM_POINTER1_FUNCTION, 38 | MA_GET_SCRIPT_STRING_PARAM_FUNCTION, 39 | MA_GET_SCRIPT_PARAM_POINTER2_FUNCTION, 40 | MA_OPCODE_PARAMS, 41 | MA_SCM_BLOCK, 42 | MA_MISSION_LOCALS, 43 | MA_MISSION_BLOCK, 44 | MA_ON_MISSION_FLAG, 45 | MA_ACTIVE_THREAD_QUEUE, 46 | MA_INACTIVE_THREAD_QUEUE, 47 | MA_STATIC_THREADS, 48 | MA_CALL_INIT_SCM1, 49 | MA_CALL_INIT_SCM2, 50 | MA_CALL_INIT_SCM3, 51 | MA_CALL_SAVE_SCM_DATA, 52 | MA_CALL_LOAD_SCM_DATA, 53 | MA_CALL_PROCESS_SCRIPT, 54 | MA_CALL_DRAW_SCRIPT_TEXTS_BEFORE_FADE, 55 | MA_CALL_DRAW_SCRIPT_TEXTS_AFTER_FADE, 56 | MA_CALL_GAME_SHUTDOWN, 57 | MA_CALL_GAME_RESTART_1, 58 | MA_CALL_GAME_RESTART_2, 59 | MA_CALL_GAME_RESTART_3, 60 | MA_CALL_DEBUG_DISPLAY_TEXT_BUFFER_IDLE, 61 | MA_CALL_DEBUG_DISPLAY_TEXT_BUFFER_FRONTEND, 62 | 63 | // CustomOpcodeSystem 64 | MA_OPCODE_HANDLER, 65 | MA_OPCODE_HANDLER_REF, 66 | 67 | MA_CALL_CREATE_MAIN_WINDOW, 68 | 69 | MA_TOTAL, 70 | }; 71 | 72 | eGameVersion DetermineGameVersion(); 73 | 74 | class CGameVersionManager 75 | { 76 | eGameVersion m_eVersion; 77 | 78 | public: 79 | CGameVersionManager() 80 | { 81 | m_eVersion = DetermineGameVersion(); 82 | } 83 | 84 | ~CGameVersionManager() 85 | { 86 | } 87 | 88 | eGameVersion GetGameVersion() const 89 | { 90 | return m_eVersion; 91 | } 92 | 93 | memory_pointer TranslateMemoryAddress(eMemoryAddress addrId) const; 94 | }; 95 | } 96 | -------------------------------------------------------------------------------- /source/CLEO.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cleolibrary/CLEO5/c1c74036121f4d782d42467f693eb00a61ad81b3/source/CLEO.ico -------------------------------------------------------------------------------- /source/CLEO5.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cleolibrary/CLEO5/c1c74036121f4d782d42467f693eb00a61ad81b3/source/CLEO5.rc -------------------------------------------------------------------------------- /source/CModuleSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace CLEO 4 | { 5 | struct ScriptDataRef 6 | { 7 | char* base = nullptr; // script's base data 8 | int offset = 0; // address within the script 9 | 10 | bool Valid() const 11 | { 12 | return base != nullptr; 13 | } 14 | }; 15 | 16 | class CModuleSystem 17 | { 18 | public: 19 | CModuleSystem() = default; 20 | CModuleSystem(const CModuleSystem&) = delete; // no copying 21 | 22 | void Clear(); 23 | 24 | // registers module reference. Needs to be released with ReleaseModuleRef 25 | const ScriptDataRef GetExport(std::string modulePath, std::string_view exportName); 26 | 27 | bool LoadFile(const char* const path); // single file 28 | bool LoadDirectory(const char* const path); // all modules in directory 29 | bool LoadCleoModules(); // all in cleo\cleo_modules 30 | 31 | private: 32 | static void NormalizePath(std::string& path); 33 | 34 | class CModule 35 | { 36 | friend class CModuleSystem; 37 | 38 | struct ModuleExport 39 | { 40 | std::string name; 41 | int offset = 0; // address within module's data 42 | 43 | void Clear(); 44 | bool LoadFromFile(std::ifstream& file); 45 | 46 | static void NormalizeName(std::string& name); 47 | }; 48 | 49 | std::string filepath; // source file 50 | std::vector data; 51 | std::map exports; 52 | 53 | public: 54 | CModule() = default; 55 | CModule(const CModule&) = delete; // no copying 56 | ~CModule() = default; 57 | 58 | void Clear(); 59 | const char* GetFilepath() const; 60 | bool LoadFromFile(const char* path); 61 | const ScriptDataRef GetExport(std::string name); 62 | }; 63 | 64 | std::map modules; 65 | }; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /source/CPluginSystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace CLEO 7 | { 8 | class CPluginSystem 9 | { 10 | struct PluginEntry 11 | { 12 | std::string name; 13 | HMODULE handle = nullptr; 14 | 15 | PluginEntry() = default; 16 | PluginEntry(std::string name, HMODULE handle) : name(name), handle(handle) {} 17 | }; 18 | std::list plugins; 19 | bool pluginsLoaded = false; 20 | 21 | public: 22 | CPluginSystem() = default; 23 | CPluginSystem(const CPluginSystem&) = delete; // no copying 24 | ~CPluginSystem(); 25 | 26 | void LoadPlugins(); 27 | void UnloadPlugins(); 28 | size_t GetNumPlugins() const; 29 | 30 | void LogLoadedPlugins() const; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /source/FileEnumerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "..\cleo_sdk\CLEO.h" 3 | 4 | template 5 | void FilesWalk(const char* directory, const char* extension, T callback) 6 | { 7 | auto filePattern = std::string(directory); 8 | filePattern += "\\*"; 9 | filePattern += extension; 10 | 11 | auto list = CLEO::CLEO_ListDirectory(nullptr, filePattern.c_str(), false, true); 12 | for (DWORD i = 0; i < list.count; i++) 13 | { 14 | auto fsPath = FS::path(list.strings[i]); 15 | callback(list.strings[i], fsPath.filename().string().c_str()); 16 | } 17 | CLEO::CLEO_StringListFree(list); 18 | } 19 | -------------------------------------------------------------------------------- /source/Mem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define OP_NOP 0x90 4 | #define OP_RET 0xC3 5 | #define OP_CALL 0xE8 6 | #define OP_JMP 0xE9 7 | #define OP_JMPSHORT 0xEB 8 | 9 | template 10 | inline void MemWrite(U p, const T v) { *(T*)p = v; } 11 | template 12 | inline void MemWrite(U p, const T v, int n) { memcpy((void*)p, &v, n); } 13 | template 14 | inline T MemRead(U p) { return *(T*)p; } 15 | template 16 | inline void MemFill(U p, T v, int n) { memset((void*)p, v, n); } 17 | template 18 | inline void MemCopy(U p, const T v) { memcpy((void*)p, &v, sizeof(T)); } 19 | template 20 | inline void MemCopy(U p, const T v, int n) { memcpy((void*)p, &v, n); } 21 | template 22 | inline void MemCopy(U p, const T* v) { memcpy((void*)p, v, sizeof(T)); } 23 | template 24 | inline void MemCopy(U p, const T* v, int n) { memcpy((void*)p, v, n); } 25 | 26 | // Write a jump to v to the address at p and copy the replaced jump address to r 27 | template 28 | inline void MemJump(U p, const T v, T *r = nullptr) 29 | { 30 | if (r != nullptr) 31 | { 32 | *r = MemReadInstrucionDestination::type>(p); 33 | } 34 | 35 | MemWrite(p++, OP_JMP); 36 | MemWrite(p, ((DWORD)v - (DWORD)p) - 4); 37 | } 38 | 39 | // Write a call to v to the address at p and copy the replaced call address to r 40 | template 41 | inline void MemCall(U p, const T v, T *r = nullptr) 42 | { 43 | if (r != nullptr) 44 | { 45 | *r = MemReadInstrucionDestination::type>(p); 46 | } 47 | 48 | MemWrite(p++, OP_CALL); 49 | MemWrite(p, (DWORD)v - (DWORD)p - 4); 50 | } 51 | 52 | // Read and convert a relative offset to absolute address 53 | template 54 | T MemReadOffsetPtr(U p) 55 | { 56 | return (T)((size_t)MemRead(p) + (size_t)p + sizeof(T)); 57 | } 58 | 59 | // Read absolute target address of jump or call instruction 60 | template 61 | T MemReadInstrucionDestination(U p) 62 | { 63 | auto ptr = (BYTE*)p; 64 | BYTE opcode = *ptr; 65 | ptr++; 66 | 67 | T dest = (T)nullptr; 68 | switch (opcode) 69 | { 70 | case OP_CALL: 71 | dest = MemReadOffsetPtr(ptr); 72 | break; 73 | 74 | case OP_JMP: 75 | dest = MemReadOffsetPtr(ptr); 76 | break; 77 | 78 | case OP_JMPSHORT: 79 | dest = MemReadOffsetPtr(ptr); 80 | break; 81 | } 82 | 83 | return dest; 84 | } 85 | 86 | inline void MemGrantAccess(size_t address, size_t size) 87 | { 88 | DWORD oldProtect; 89 | VirtualProtect((LPVOID)address, size, PAGE_EXECUTE_READWRITE, &oldProtect); 90 | } 91 | -------------------------------------------------------------------------------- /source/OpcodeInfoDatabase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | class OpcodeInfoDatabase 8 | { 9 | struct OpcodeArgument 10 | { 11 | std::string name; 12 | 13 | OpcodeArgument() = default; 14 | OpcodeArgument(const char* name) : name(name) 15 | { 16 | } 17 | }; 18 | 19 | struct Opcode 20 | { 21 | uint16_t id; 22 | std::string name; 23 | std::vector arguments; 24 | 25 | Opcode() = default; 26 | Opcode(uint16_t id, std::string name) : id(id), name(name) 27 | { 28 | } 29 | }; 30 | 31 | struct Extension 32 | { 33 | std::string name; 34 | std::map opcodes; 35 | }; 36 | 37 | std::atomic ok = false; 38 | std::map extensions; 39 | 40 | public: 41 | OpcodeInfoDatabase() = default; 42 | 43 | void Clear(); 44 | bool Load(const char* filepath); // triggers asynchronic load 45 | 46 | const char* GetExtensionName(uint16_t opcode) const; // nullptr if not found 47 | const char* GetExtensionName(const char* commandName) const; // nullptr if not found 48 | 49 | uint16_t GetOpcode(const char* commandName) const; // 0xFFFF if not found 50 | const char* GetCommandName(uint16_t opcode) const; // nullptr if not found 51 | 52 | const char* GetArgumentName(uint16_t opcode, size_t paramIdx) const; // nullptr if not found 53 | 54 | std::string GetExtensionMissingMessage(uint16_t opcode) const; // extension "x" missing message if known, empty text otherwise 55 | }; 56 | 57 | -------------------------------------------------------------------------------- /source/ScmFunction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "..\cleo_sdk\CLEO.h" 3 | #include "CDebug.h" 4 | 5 | 6 | namespace CLEO 7 | { 8 | struct ScmFunction 9 | { 10 | static const size_t Store_Size = 0x400; 11 | static ScmFunction* store[Store_Size]; 12 | static size_t allocationPlace; // contains an index of last allocated object 13 | static ScmFunction* Get(unsigned short idx); 14 | static void Clear(); 15 | 16 | unsigned short prevScmFunctionId, thisScmFunctionId; 17 | BYTE callArgCount = 0; // args provided to cleo_call 18 | 19 | // saved nesting context state 20 | void* savedBaseIP; 21 | BYTE* retnAddress; 22 | BYTE* savedStack[8]; // gosub stack 23 | WORD savedSP; 24 | SCRIPT_VAR savedTls[32]; 25 | std::list stringParams; // texts with this scope lifetime 26 | bool savedCondResult; 27 | eLogicalOperation savedLogicalOp; 28 | bool savedNotFlag; 29 | std::string savedScriptFileDir; // modules switching 30 | std::string savedScriptFileName; // modules switching 31 | 32 | void* operator new(size_t size); 33 | void operator delete(void* mem); 34 | ScmFunction(CRunningScript* thread); 35 | 36 | void Return(CRunningScript* thread); 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /source/ScriptDelegate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../cleo_sdk/CLEO.h" 3 | #include 4 | 5 | namespace CLEO 6 | { 7 | struct ScriptDeleteDelegate 8 | { 9 | std::vector funcs; 10 | 11 | template void operator+=(FuncScriptDeleteDelegateT mFunc) 12 | { 13 | funcs.push_back(mFunc); 14 | } 15 | 16 | template void operator-=(FuncScriptDeleteDelegateT mFunc) 17 | { 18 | funcs.erase(std::remove(funcs.begin(), funcs.end(), mFunc), funcs.end()); 19 | } 20 | 21 | void operator()(CRunningScript* script) 22 | { 23 | for (auto& f : funcs) f(script); 24 | } 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /source/Singleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | static bool CleoSingletonChecked = false; 6 | 7 | // search for CLEO.asi modules loaded, terminate game if duplicate found 8 | static void CleoSingletonCheck() 9 | { 10 | if(!CleoSingletonChecked) 11 | { 12 | MODULEENTRY32 module; 13 | module.dwSize = sizeof(MODULEENTRY32); 14 | HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); 15 | 16 | Module32First(snapshot, &module); 17 | if (snapshot != INVALID_HANDLE_VALUE) 18 | { 19 | size_t count = 0; 20 | do 21 | { 22 | if (_strcmpi(module.szModule, "CLEO.asi") == 0) 23 | { 24 | count++; 25 | 26 | if(count > 1) 27 | { 28 | CloseHandle(snapshot); 29 | MessageBox(NULL, "Another copy of CLEO.asi is already loaded!\nPlease remove duplicated files.", "CLEO error", MB_SYSTEMMODAL | MB_TOPMOST | MB_ICONERROR | MB_OK); 30 | exit(1); // terminate the game 31 | break; 32 | } 33 | } 34 | } while (Module32Next(snapshot, &module)); 35 | 36 | CloseHandle(snapshot); 37 | } 38 | 39 | CleoSingletonChecked = true; 40 | } 41 | } 42 | 43 | -------------------------------------------------------------------------------- /source/cleo.def: -------------------------------------------------------------------------------- 1 | LIBRARY 2 | 3 | EXPORTS 4 | _CLEO_GetFloatOpcodeParam@4 @1 5 | _CLEO_GetGameVersion@0 @2 6 | _CLEO_GetIntOpcodeParam@4 @3 7 | _CLEO_GetOperandType@4 @4 8 | _CLEO_GetVersion@0 @5 9 | _CLEO_ReadStringOpcodeParam@12 @6 10 | _CLEO_RecordOpcodeParams@8 @7 11 | _CLEO_RegisterOpcode@8 @8 12 | _CLEO_RetrieveOpcodeParams@8 @9 13 | _CLEO_SetFloatOpcodeParam@8 @10 14 | _CLEO_SetIntOpcodeParam@8 @11 15 | _CLEO_SetThreadCondResult@8 @12 16 | _CLEO_SkipOpcodeParams@8 @13 17 | _CLEO_ThreadJumpAtLabelPtr@8 @14 18 | _CLEO_WriteStringOpcodeParam@8 @15 19 | missionLocals @16 20 | opcodeParams @17 21 | staticThreads @18 22 | _CLEO_GetPointerToScriptVariable@4 @19 23 | _CLEO_ReadStringPointerOpcodeParam@12 @20 24 | _CLEO_GetScriptTextureById@8 @21 25 | _CLEO_GetInternalAudioStream@8 @22 26 | _CLEO_CreateCustomScript@12 @23 27 | _CLEO_GetLastCreatedCustomScript@0 @24 28 | _CLEO_AddScriptDeleteDelegate@4 @25 29 | _CLEO_RemoveScriptDeleteDelegate@4 @26 30 | _CLEO_RegisterCallback@8 @27 31 | _CLEO_UnregisterCallback@8 @28 32 | _CLEO_GetVarArgCount@4 @29 33 | _CLEO_SkipUnusedVarArgs@4 @30 34 | _CLEO_ReadParamsFormatted@16 @31 35 | _CLEO_GetScriptVersion@4 @32 36 | _CLEO_GetScriptInfoStr@16 @33 37 | _CLEO_GetScriptParamInfoStr@12 @34 38 | _CLEO_ResolvePath@12 @35 39 | _CLEO_ListDirectory@16 @36 40 | _CLEO_StringListFree@8 @37 41 | _CLEO_GetScriptDebugMode@4 @38 42 | _CLEO_SetScriptDebugMode@8 @39 43 | _CLEO_Log@8 @40 44 | _CLEO_ReadStringParamWriteBuffer@16 @41 45 | _CLEO_GetOpcodeParamsArray@0 @42 46 | _CLEO_GetParamsHandledCount@0 @43 47 | _CLEO_PeekIntOpcodeParam@4 @44 48 | _CLEO_PeekFloatOpcodeParam@4 @45 49 | _CLEO_PeekPointerToScriptVariable@4 @46 50 | _CLEO_GetScriptByName@16 @47 51 | _CLEO_GetScriptByFilename@8 @48 52 | _CLEO_GetScriptFilename@4 @49 53 | _CLEO_GetScriptWorkDir@4 @50 54 | _CLEO_SetScriptWorkDir@8 @51 55 | _CLEO_RegisterCommand@8 @52 56 | _CLEO_IsScriptRunning@4 @53 57 | _CLEO_TerminateScript@4 @54 58 | _CLEO_GetGameDirectory@0 @55 59 | _CLEO_GetUserDirectory@0 @56 60 | _CLEO_GetVersionStr@0 @57 61 | _CLEO_SetScriptVersion@8 @58 62 | -------------------------------------------------------------------------------- /source/cleo_config.ini: -------------------------------------------------------------------------------- 1 | [General] 2 | ; default debug mode state for all scripts (see opcode debug_on/debug_off): 0 - off, 1 - enabled 3 | DebugMode=0 4 | 5 | ; legacy mode for main script(s): 0 - off, 3 - CLEO3, 4 - CLEO4 6 | MainScmLegacyMode=0 7 | 8 | ; do not load legacy CLEO4 plugins 9 | PluginBlacklist = FileSystemOperations.cleo,GxtHook.cleo,IniFiles.cleo,IntOperations.cleo 10 | 11 | -------------------------------------------------------------------------------- /source/crc32.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | unsigned long crc32(const unsigned char *buf, unsigned long len); 5 | unsigned long crc32FromUpcaseString(const char *str); 6 | unsigned long crc32FromUpcaseStdString(const std::string& str); 7 | unsigned long crc32FromString(const char *str); 8 | unsigned long crc32FromStdString(const std::string& str); 9 | -------------------------------------------------------------------------------- /source/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CleoBase.h" 3 | #include "CDebug.h" 4 | 5 | 6 | using namespace CLEO; 7 | 8 | class Starter 9 | { 10 | static Starter dummy; 11 | Starter() 12 | { 13 | auto gv = CleoInstance.VersionManager.GetGameVersion(); 14 | TRACE("Started on game of version: %s", 15 | (gv == GV_US10) ? "SA 1.0 us" : 16 | (gv == GV_EU11) ? "SA 1.01 eu" : 17 | (gv == GV_EU10) ? "SA 1.0 eu" : 18 | (gv == GV_STEAM) ? "SA 3.0 steam" : 19 | ""); 20 | 21 | if (gv != GV_US10 && gv != GV_EU11 && gv != GV_EU10 && gv != GV_STEAM) 22 | TRACE( 23 | "Unknown game version.\n" 24 | "The list of all known executables:\n\n" 25 | " 1) gta_sa.exe, original 1.0 us, 14 405 632 bytes;\n" 26 | " 2) gta_sa.exe, public no-dvd 1.0 us, 14 383 616 bytes;\n" 27 | " 3) gta_sa_compact.exe, listener's executable, 5 189 632 bytes;\n" 28 | " 4) gta_sa.exe, original 1.01 eu, 14 405 632 bytes;\n" 29 | " 5) gta_sa.exe, public no-dvd 1.01 eu, 15 806 464 bytes;\n" 30 | " 6) gta_sa.exe, 1C localization, 15 806 464 bytes;\n" 31 | " 7) gta_sa.exe, original 1.0 eu, unknown size;\n" 32 | " 8) gta_sa.exe, public no-dvd 1.0eu, 14 386 176 bytes;\n" 33 | " 9) gta_sa.exe, original 3.0 steam executable, unknown size;" 34 | " 10) gta_sa.exe, decrypted 3.0 steam executable, 5 697 536 bytes." 35 | ); 36 | 37 | // incompatible game version 38 | if (gv != GV_US10) 39 | { 40 | const auto versionMsg = \ 41 | "Unsupported game version! \n" \ 42 | "Like most of GTA SA mods, CLEO is meant to work with game version 1.0. \n" \ 43 | "Please downgrade your game's executable file to GTA SA 1.0 US, or so called \"Hoodlum\" or \"Compact\" variant."; 44 | 45 | int prevVersion = GetPrivateProfileInt("Internal", "ReportedGameVersion", GV_US10, Filepath_Config.c_str()); 46 | if (gv != prevVersion) // we not nagged user yet 47 | { 48 | SHOW_ERROR(versionMsg); 49 | } 50 | else 51 | { 52 | TRACE(""); 53 | TRACE(versionMsg); 54 | TRACE(""); 55 | } 56 | 57 | char strValue[32]; 58 | _itoa_s(gv, strValue, 10); 59 | WritePrivateProfileString("Internal", "ReportedGameVersion", strValue, Filepath_Config.c_str()); 60 | } 61 | 62 | CleoInstance.Start(CCleoInstance::InitStage::Initial); 63 | } 64 | 65 | ~Starter() 66 | { 67 | CleoInstance.Stop(); 68 | } 69 | }; 70 | 71 | Starter Starter::dummy; 72 | 73 | extern "C" BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 74 | { 75 | return TRUE; 76 | } 77 | -------------------------------------------------------------------------------- /source/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by CLEO4.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /source/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /source/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define _USE_MATH_DEFINES 4 | #define WIN32_LEAN_AND_MEAN 5 | #undef UNICODE 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "..\cleo_sdk\CLEO.h" 30 | #include "..\cleo_sdk\CLEO_Utils.h" 31 | 32 | #include "simdjson.h" 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | 51 | // global constant paths. Initialize before anything else 52 | namespace FS = std::filesystem; 53 | 54 | static std::string GetGameDirectory() // already stored in Filepath_Game 55 | { 56 | std::string path; 57 | path.resize(MAX_PATH); 58 | GetModuleFileNameA(NULL, path.data(), path.size()); // game exe absolute path 59 | path.resize(CLEO::FilepathGetParent(path).length()); 60 | CLEO::FilepathNormalize(path); 61 | return std::move(path); 62 | } 63 | 64 | static std::string GetUserDirectory() // already stored in Filepath_User 65 | { 66 | static const auto GTA_InitUserDirectories = (char* (__cdecl*)())0x00744FB0; // SA 1.0 US - CFileMgr::InitUserDirectories 67 | 68 | std::string path = GTA_InitUserDirectories(); 69 | CLEO::FilepathNormalize(path); 70 | 71 | return std::move(path); 72 | } 73 | 74 | inline const std::string Filepath_Game = GetGameDirectory(); 75 | inline const std::string Filepath_User = GetUserDirectory(); 76 | inline const std::string Filepath_Cleo = Filepath_Game + "\\cleo"; 77 | inline const std::string Filepath_Config = Filepath_Cleo + "\\.cleo_config.ini"; 78 | inline const std::string Filepath_Log = Filepath_Game + "\\cleo.log"; 79 | -------------------------------------------------------------------------------- /tests/.cleo_tests_runner.txt: -------------------------------------------------------------------------------- 1 | // Sanny Builder 4 2 | // mode: GTA SA (v1.0 - SBL) 3 | 4 | {$CLEO .cs} 5 | 6 | script_name 'CleoTest' 7 | debug_on 8 | 9 | print_big_string {text} "CLEO TESTING" {time} 4000 {style} TextStyle.MiddleSmaller 10 | 11 | wait 3500 // wait for game to fade in 12 | clear_prints 13 | 14 | RUN_TESTS_DIR("cleo:", "cleo_tests") 15 | 16 | trace "" 17 | trace "All tests done" 18 | print_big_string {text} "DONE" {time} 5000 {style} TextStyle.MiddleSmaller 19 | 20 | terminate_this_custom_script 21 | 22 | 23 | function RUN_TESTS_DIR(basePath :string, directory :string) 24 | trace "" // separator 25 | trace "~y~~h~-------- Testing module '~s~~h~%s~y~~h~' --------" directory 26 | 27 | // process all test files 28 | int str = allocate_memory 260 29 | string_format str = "%s\\%s\\*.s" basePath directory 30 | 31 | int searchHandle = 0 32 | int found = allocate_memory 64 33 | 34 | if 35 | find_first_file str {handle} searchHandle {fileName} found 36 | then 37 | repeat 38 | string_format str = "%s\\%s\\%s" basePath directory found 39 | if 40 | does_file_exist str // files only 41 | then 42 | stream_custom_script str 43 | int script = get_script_struct_just_created 44 | 45 | while is_script_running script 46 | wait 0 47 | end 48 | end 49 | until not find_next_file searchHandle {fileName} found 50 | 51 | find_close searchHandle 52 | else 53 | trace "~r~~h~~h~No tests found!" 54 | end 55 | 56 | // process all sub directories 57 | string_format str = "%s\\%s\\*" basePath directory 58 | if 59 | find_first_file str {handle} searchHandle {fileName} found 60 | then 61 | repeat 62 | string_format str = "%s\\%s\\%s" basePath directory found 63 | if and 64 | not is_text_prefix {text} found {prefix} "." {ignoreCase} true 65 | not is_text_prefix {text} found {prefix} ".." {ignoreCase} true 66 | does_directory_exist str // directories only 67 | then 68 | string_format str = "%s\\%s" basePath directory 69 | RUN_TESTS_DIR(str, found) 70 | end 71 | until not find_next_file searchHandle {fileName} found 72 | 73 | find_close searchHandle 74 | end 75 | 76 | free_memory str 77 | free_memory found 78 | end 79 | -------------------------------------------------------------------------------- /tests/cleo_tests/.Compile_All.bat: -------------------------------------------------------------------------------- 1 | @REM Compile all .txt files in the current directory to .s files using Sanny Builder 4 2 | @REM Usage: set SANNY="path\to\sanny.exe" && .Compile_All.bat 3 | 4 | @echo off 5 | SETLOCAL EnableDelayedExpansion 6 | 7 | @REM Delete all .s files in the current directory and subdirectories 8 | for /f "delims=" %%i in ('dir /b /s *.s') do ( 9 | set p=%%i 10 | echo Deleting !p:%__CD__%=! 11 | del "%%i" 12 | ) 13 | echo. 14 | 15 | @REM Compile all .txt files in the current directory and subdirectories 16 | for /f "delims=" %%i in ('dir /b /s *.txt') do ( 17 | if not "%%~nxi" == "cleo_tester.txt" ( 18 | set p=%%i 19 | echo Compiling !p:%__CD__%=! 20 | %SANNY% --compile "%%i" "%%~dpni.s" --no-splash --mode sa_sbl 21 | if not exist "%%~dpni.s" ( 22 | echo ERROR: Failed to build !p:%__CD__%=! 23 | ) 24 | ) 25 | ) 26 | echo. 27 | 28 | echo Done. 29 | pause 30 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0AAC.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | var 0@ : Integer 5 | var 1@ : Integer 6 | var 2@ : Integer 7 | var 3@ : Integer 8 | var 4@ : Integer 9 | var 5@ : Integer 10 | var 6@ : Integer 11 | var 7@ : Integer 12 | var 8@ : Integer 13 | var 9@ : Integer 14 | var 10@ : Integer 15 | 16 | script_name "0AAC" // load_audio_stream 17 | debug_on 18 | 19 | trace "0AAC (load_audio_stream)" 20 | 21 | 22 | // load not existing file 23 | wait 0 24 | if 25 | load_audio_stream ".\invalid name.mp3" store_to 0@ // tested opcode 26 | then 27 | breakpoint "~r~~h~~h~~h~0AAC (load_audio_stream), #0 FAILED!~n~Non existing file loaded? Handle: %d" 0@ 28 | else 29 | trace "~g~~h~~h~0AAC (load_audio_stream), #0 PASSED (with expected warning)" 30 | end 31 | 32 | 33 | // load existing file 34 | wait 0 35 | if 36 | load_audio_stream ".\Ding.mp3" store_to 0@ // tested opcode 37 | then 38 | trace "~g~~h~~h~0AAC (load_audio_stream), #1 PASSED" 39 | else 40 | breakpoint "~r~~h~~h~~h~0AAC (load_audio_stream), #1 FAILED!~n~Failed to load file. Handle: %d" 0@ 41 | end 42 | 43 | 44 | terminate_this_custom_script 45 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0AAD.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | var 0@ : Integer 5 | var 1@ : Integer 6 | var 2@ : Integer 7 | var 3@ : Integer 8 | var 4@ : Integer 9 | var 5@ : Integer 10 | var 6@ : Integer 11 | var 7@ : Integer 12 | var 8@ : Integer 13 | var 9@ : Integer 14 | var 10@ : Integer 15 | 16 | script_name "0AAD" // set_audio_stream_state 17 | debug_on 18 | 19 | trace "0AAD (set_audio_stream_state)" 20 | 21 | 22 | // load the file 23 | wait 0 24 | if 25 | load_audio_stream ".\Ding.mp3" store_to 0@ 26 | then 27 | trace "~g~~h~~h~0AAD (set_audio_stream_state), #0 PASSED" 28 | else 29 | breakpoint "~r~~h~~h~~h~0AAD (set_audio_stream_state), #0 FAILED!~n~Failed to load file. Handle: %d" 0@ 30 | end 31 | 32 | 33 | // set state 34 | wait 0 35 | 0AAD: set_audio_stream_state 0@ state AudioStreamState.Pause // tested opcode 36 | trace "~g~~h~~h~0AAD (set_audio_stream_state), #1 PASSED" 37 | 38 | 39 | terminate_this_custom_script 40 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0AAE.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | var 0@ : Integer 5 | var 1@ : Integer 6 | var 2@ : Integer 7 | var 3@ : Integer 8 | var 4@ : Integer 9 | var 5@ : Integer 10 | var 6@ : Integer 11 | var 7@ : Integer 12 | var 8@ : Integer 13 | var 9@ : Integer 14 | var 10@ : Integer 15 | 16 | script_name "0AAE" // remove_audio_stream 17 | debug_on 18 | 19 | trace "0AAE (remove_audio_stream)" 20 | 21 | 22 | // load the file 23 | wait 0 24 | if 25 | load_audio_stream ".\Ding.mp3" store_to 0@ 26 | then 27 | trace "~g~~h~~h~0AAE (remove_audio_stream), #0 PASSED" 28 | else 29 | breakpoint "~r~~h~~h~~h~0AAE (remove_audio_stream), #0 FAILED!~n~Failed to load file. Handle: %d" 0@ 30 | end 31 | 32 | 33 | // remove stream 34 | wait 0 35 | 0AAE: remove_audio_stream 0@ // tested opcode 36 | trace "~g~~h~~h~0AAE (remove_audio_stream), #1 PASSED" 37 | 38 | 39 | terminate_this_custom_script 40 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0AAF.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | var 0@ : Integer 5 | var 1@ : Integer 6 | var 2@ : Integer 7 | var 3@ : Integer 8 | var 4@ : Integer 9 | var 5@ : Integer 10 | var 6@ : Integer 11 | var 7@ : Integer 12 | var 8@ : Integer 13 | var 9@ : Integer 14 | var 10@ : Integer 15 | 16 | script_name "0AAF" // get_audio_stream_length 17 | 18 | debug_on 19 | 20 | trace "0AAF (get_audio_stream_length)" 21 | 22 | 23 | // load the file 24 | wait 0 25 | if 26 | load_audio_stream ".\Ding.mp3" store_to 0@ 27 | then 28 | trace "~g~~h~~h~0AAF (get_audio_stream_length), #0 PASSED" 29 | else 30 | breakpoint "~r~~h~~h~~h~0AAF (get_audio_stream_length), #0 FAILED!~n~Failed to load file. Handle: %d" 0@ 31 | end 32 | 33 | 34 | // get stream length 35 | wait 0 36 | 0AAF: get_audio_stream_length 0@ store_to 1@ // tested opcode 37 | if 38 | 1@ == 0 // Ding.mp3 duration is about 0.25 second, opcode returns integer with seconds 39 | then 40 | trace "~g~~h~~h~0AAF (get_audio_stream_length), #1 PASSED" 41 | else 42 | breakpoint "~r~~h~~h~~h~0AAF (get_audio_stream_length), #1 FAILED!~n~0 Expected~n~%d Occured" 1@ 43 | end 44 | 45 | 46 | terminate_this_custom_script 47 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0AB9.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0AB9' 5 | test("0AB9 (get_audio_stream_state)", tests) 6 | terminate_this_custom_script 7 | 8 | const Test_File = ".\Speech.mp3" 9 | 10 | function tests 11 | int stream 12 | before_each(@setup) 13 | after_each(@cleanup) 14 | 15 | it("should return set state", test1) 16 | it("should return Stopped when finished", test2) 17 | return 18 | 19 | 20 | :setup 21 | stream = load_audio_stream Test_File 22 | assert_result_true() 23 | return 24 | 25 | 26 | :cleanup 27 | remove_audio_stream stream 28 | stream = -1 29 | return 30 | 31 | 32 | function test1(stream: int) 33 | int state 34 | 35 | // starts as stopped 36 | state = 0x666 37 | state = get_audio_stream_state stream 38 | assert_eq(state, 2) // AudioStreamState.Paused 39 | 40 | // still paused 41 | wait {time} 0 42 | state = 0x666 43 | state = get_audio_stream_state stream 44 | assert_eq(state, 2) // AudioStreamState.Paused 45 | 46 | // play, effective right away 47 | set_audio_stream_state stream {action} AudioStreamAction.Play 48 | state = 0x666 49 | state = get_audio_stream_state stream 50 | assert_eq(state, 1) // AudioStreamState.Playing 51 | 52 | // still playing 53 | wait {time} 0 54 | state = 0x666 55 | state = get_audio_stream_state stream 56 | assert_eq(state, 1) // AudioStreamState.Playing 57 | 58 | // stop, effective right away 59 | set_audio_stream_state stream {action} AudioStreamAction.Stop 60 | state = 0x666 61 | state = get_audio_stream_state stream 62 | assert_eq(state, -1) // AudioStreamState.Stopped 63 | 64 | // still stopped 65 | wait {time} 0 66 | state = 0x666 67 | state = get_audio_stream_state stream 68 | assert_eq(state, -1) // AudioStreamState.Stopped 69 | 70 | // stopped can not turn into paused 71 | set_audio_stream_state stream {action} AudioStreamAction.Pause 72 | state = 0x666 73 | state = get_audio_stream_state stream 74 | assert_eq(state, -1) // AudioStreamState.Stopped 75 | end 76 | 77 | 78 | function test2(stream: int) 79 | set_audio_stream_progress stream {progress} 0.99 80 | set_audio_stream_state stream {action} AudioStreamAction.Play 81 | 82 | wait {time} 200 83 | int state = 0x666 84 | state = get_audio_stream_state stream 85 | assert_eq(state, -1) // AudioStreamState.Stopped 86 | end 87 | end 88 | 89 | 90 | terminate_this_custom_script 91 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0ABB.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | var 0@ : Integer 5 | var 1@ : Integer 6 | var 2@ : Integer 7 | var 3@ : Integer 8 | var 4@ : Integer 9 | var 5@ : Integer 10 | var 6@ : Integer 11 | var 7@ : Integer 12 | var 8@ : Integer 13 | var 9@ : Integer 14 | var 10@ : Integer 15 | 16 | script_name "0ABB" // get_audio_stream_volume 17 | 18 | debug_on 19 | 20 | trace "0ABB (get_audio_stream_volume)" 21 | 22 | 23 | // load the file 24 | wait 0 25 | if 26 | load_audio_stream ".\Ding.mp3" store_to 0@ 27 | then 28 | trace "~g~~h~~h~0ABB (get_audio_stream_volume), #0 PASSED" 29 | else 30 | breakpoint "~r~~h~~h~~h~0ABB (get_audio_stream_volume), #0 FAILED!~n~Failed to load file. Handle: %d" 0@ 31 | end 32 | 33 | 34 | // get stream volume 35 | wait 0 36 | 0ABB: get_audio_stream_volume 0@ store_to 1@ // tested opcode 37 | if 38 | 1@ == 1.0 // default volume 39 | then 40 | trace "~g~~h~~h~0ABB (get_audio_stream_volume), #1 PASSED" 41 | else 42 | breakpoint "~r~~h~~h~~h~0ABB (get_audio_stream_volume), #1 FAILED!~n~%f Expected~n~%f Occured" 1.0 1@ 43 | end 44 | 45 | 46 | terminate_this_custom_script 47 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0ABC.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | var 0@ : Integer 5 | var 1@ : Integer 6 | var 2@ : Integer 7 | var 3@ : Integer 8 | var 4@ : Integer 9 | var 5@ : Integer 10 | var 6@ : Integer 11 | var 7@ : Integer 12 | var 8@ : Integer 13 | var 9@ : Integer 14 | var 10@ : Integer 15 | 16 | script_name "0ABC" // set_audio_stream_volume 17 | 18 | debug_on 19 | 20 | trace "0ABC (set_audio_stream_volume)" 21 | 22 | 23 | // load the file 24 | wait 0 25 | if 26 | load_audio_stream ".\Ding.mp3" store_to 0@ 27 | then 28 | trace "~g~~h~~h~0ABC (set_audio_stream_volume), #0 PASSED" 29 | else 30 | breakpoint "~r~~h~~h~~h~0ABC (set_audio_stream_volume), #0 FAILED!~n~Failed to load file. Handle: %d" 0@ 31 | end 32 | 33 | 34 | // get stream volume 35 | wait 0 36 | get_audio_stream_volume 0@ store_to 1@ 37 | if 38 | 1@ == 1.0 // default volume 39 | then 40 | trace "~g~~h~~h~0ABC (set_audio_stream_volume), #1 PASSED" 41 | else 42 | breakpoint "~r~~h~~h~~h~0ABC (set_audio_stream_volume), #1 FAILED!~n~%f Expected~n~%f Occured" 1.0 1@ 43 | end 44 | 45 | 46 | // set stream volume 47 | wait 0 48 | 0ABC: set_audio_stream_volume 0@ volume 0.25 // tested opcode 49 | trace "~g~~h~~h~0ABC (set_audio_stream_volume), #2 PASSED" 50 | 51 | 52 | // get updated volume 53 | wait 0 54 | get_audio_stream_volume 0@ store_to 1@ 55 | if 56 | 1@ == 0.25 57 | then 58 | trace "~g~~h~~h~0ABC (set_audio_stream_volume), #3 PASSED" 59 | else 60 | breakpoint "~r~~h~~h~~h~0ABC (set_audio_stream_volume), #3 FAILED!~n~%f Expected~n~%f Occured" 0.25 1@ 61 | end 62 | 63 | 64 | terminate_this_custom_script 65 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0AC0.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | {$USE audio} 5 | var 0@ : Integer 6 | var 1@ : Integer 7 | var 2@ : Integer 8 | var 3@ : Integer 9 | var 4@ : Integer 10 | var 5@ : Integer 11 | var 6@ : Integer 12 | var 7@ : Integer 13 | var 8@ : Integer 14 | var 9@ : Integer 15 | var 10@ : Integer 16 | 17 | script_name "0AC0" // set_audio_stream_looped 18 | 19 | debug_on 20 | 21 | trace "0AC0 (set_audio_stream_looped)" 22 | 23 | 24 | // load the file 25 | wait 0 26 | if 27 | load_audio_stream ".\Ding.mp3" store_to 0@ 28 | then 29 | trace "~g~~h~~h~0AC0 (set_audio_stream_looped), #0 PASSED" 30 | else 31 | breakpoint "~r~~h~~h~~h~0AC0 (set_audio_stream_looped), #0 FAILED!~n~Failed to load file. Handle: %d" 0@ 32 | end 33 | 34 | 35 | // enable looping 36 | wait 0 37 | 0AC0: set_audio_stream_looped 0@ flag true // tested opcode 38 | trace "~g~~h~~h~0AC0 (set_audio_stream_looped), #1 PASSED" 39 | 40 | 41 | // start playback 42 | wait 0 43 | set_audio_stream_state 0@ state AudioStreamAction.Play 44 | trace "~g~~h~~h~0AC0 (set_audio_stream_looped), #2 PASSED" 45 | 46 | 47 | // get updated state 48 | wait 0 49 | get_audio_stream_state 0@ store_to 1@ 50 | if 51 | 1@ == 1 // AudioStreamState.Playing 52 | then 53 | trace "~g~~h~~h~0AC0 (set_audio_stream_looped), #3 PASSED" 54 | else 55 | breakpoint "~r~~h~~h~~h~0AC0 (set_audio_stream_looped), #3 FAILED!~n~%d Expected~n~%d Occured" 1 1@ 56 | end 57 | 58 | 59 | // check if still playing 60 | wait 400 // Ding.mp3 is 0.25s long 61 | get_audio_stream_state 0@ store_to 1@ 62 | if 63 | 1@ == 1 // AudioStreamState.Playing 64 | then 65 | trace "~g~~h~~h~0AC0 (set_audio_stream_looped), #4 PASSED" 66 | else 67 | breakpoint "~r~~h~~h~~h~0AC0 (set_audio_stream_looped), #4 FAILED!~n~%d Expected~n~%d Occured" -1 1@ 68 | end 69 | 70 | 71 | // stop playback 72 | wait 0 73 | set_audio_stream_state 0@ state AudioStreamAction.Stop 74 | trace "~g~~h~~h~0AC0 (set_audio_stream_looped), #5 PASSED" 75 | 76 | 77 | terminate_this_custom_script 78 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0AC1.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | var 0@ : Integer 5 | var 1@ : Integer 6 | var 2@ : Integer 7 | var 3@ : Integer 8 | var 4@ : Integer 9 | var 5@ : Integer 10 | var 6@ : Integer 11 | var 7@ : Integer 12 | var 8@ : Integer 13 | var 9@ : Integer 14 | var 10@ : Integer 15 | 16 | script_name "0AC1" // load_3d_audio_stream 17 | debug_on 18 | 19 | trace "0AC1 (load_3d_audio_stream)" 20 | 21 | 22 | // load not existing file 23 | wait 0 24 | if 25 | 0AC1: load_3d_audio_stream ".\invalid name.mp3" store_to 0@ // tested opcode 26 | then 27 | breakpoint "~r~~h~~h~~h~0AC1 (load_3d_audio_stream), #0 FAILED!~n~Non existing file loaded? Handle: %d" 0@ 28 | else 29 | trace "~g~~h~~h~0AC1 (load_3d_audio_stream), #0 PASSED (with expected warning)" 30 | end 31 | 32 | 33 | // load existing file 34 | wait 0 35 | if 36 | load_3d_audio_stream ".\Ding.mp3" store_to 0@ // tested opcode 37 | then 38 | trace "~g~~h~~h~0AC1 (load_3d_audio_stream), #1 PASSED" 39 | else 40 | breakpoint "~r~~h~~h~~h~0AC1 (load_3d_audio_stream), #1 FAILED!~n~Failed to load file. Handle: %d" 0@ 41 | end 42 | 43 | 44 | terminate_this_custom_script 45 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0AC2.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | {$USE audio} 5 | var 0@ : Integer 6 | var 1@ : Integer 7 | var 2@ : Integer 8 | var 3@ : Integer 9 | var 4@ : Integer 10 | var 5@ : Integer 11 | var 6@ : Integer 12 | var 7@ : Integer 13 | var 8@ : Integer 14 | var 9@ : Integer 15 | var 10@ : Integer 16 | 17 | script_name "0AC2" // set_play_3d_audio_stream_at_coords 18 | debug_on 19 | 20 | trace "0AC2 (set_play_3d_audio_stream_at_coords)" 21 | 22 | 23 | // load existing file 24 | wait 0 25 | if 26 | load_3d_audio_stream ".\Ding.mp3" store_to 0@ 27 | then 28 | trace "~g~~h~~h~0AC2 (set_play_3d_audio_stream_at_coords), #0 PASSED" 29 | else 30 | breakpoint "~r~~h~~h~~h~0AC2 (set_play_3d_audio_stream_at_coords), #0 FAILED!~n~Failed to load file. Handle: %d" 0@ 31 | end 32 | 33 | 34 | // test player's actor 35 | wait 0 36 | if 37 | does_char_exist $scplayer 38 | then 39 | trace "~g~~h~~h~0AC2 (set_play_3d_audio_stream_at_coords), #1 PASSED" 40 | else 41 | breakpoint "~r~~h~~h~~h~0AC2 (set_play_3d_audio_stream_at_coords), #1 FAILED!~n~Player character does not exists!" 0@ 42 | end 43 | 44 | 45 | // get left coords 46 | wait 0 47 | get_offset_from_char_in_world_coords $scplayer offset -10.0 0.0 0.0 store_to 1@ 2@ 3@ 48 | trace "~g~~h~~h~0AC2 (set_play_3d_audio_stream_at_coords), #2 PASSED" 49 | 50 | 51 | // set sound coordinates 52 | wait 0 53 | 0AC2: set_play_3d_audio_stream_at_coords 0@ xyz 1@ 2@ 3@ // tested opcode 54 | trace "~g~~h~~h~0AC2 (set_play_3d_audio_stream_at_coords), #3 PASSED" 55 | 56 | 57 | // play the sound 58 | wait 0 59 | print_big_formatted "LEFT________________________" {time} 300 {style} TextStyle.MiddleSmaller 60 | set_audio_stream_volume 0@ volume 10.0 61 | set_audio_stream_state 0@ state AudioStreamAction.Play 62 | wait 250 63 | trace "~g~~h~~h~0AC2 (set_play_3d_audio_stream_at_coords), #4 PASSED" 64 | 65 | 66 | // get right coords 67 | wait 0 68 | get_offset_from_char_in_world_coords $scplayer offset 10.0 0.0 0.0 store_to 1@ 2@ 3@ 69 | trace "~g~~h~~h~0AC2 (set_play_3d_audio_stream_at_coords), #2 PASSED" 70 | 71 | 72 | // set sound coordinates 73 | wait 0 74 | 0AC2: set_play_3d_audio_stream_at_coords 0@ xyz 1@ 2@ 3@ // tested opcode 75 | trace "~g~~h~~h~0AC2 (set_play_3d_audio_stream_at_coords), #3 PASSED" 76 | 77 | 78 | // play the sound 79 | wait 0 80 | print_big_formatted "________________________RIGHT" {time} 300 {style} TextStyle.MiddleSmaller 81 | set_audio_stream_volume 0@ volume 10.0 82 | set_audio_stream_state 0@ state AudioStreamAction.Play 83 | wait 250 84 | trace "~g~~h~~h~0AC2 (set_play_3d_audio_stream_at_coords), #4 PASSED" 85 | 86 | 87 | terminate_this_custom_script 88 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/0AC4.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .cs} 2 | nop 3 | 4 | {$CLEO .s} 5 | {$USE debug} 6 | {$USE memory} 7 | {$USE audio} 8 | var 0@ : Integer 9 | var 1@ : Integer 10 | var 2@ : Integer 11 | var 3@ : Integer 12 | var 4@ : Integer 13 | var 5@ : Integer 14 | var 6@ : Integer 15 | var 7@ : Integer 16 | var 8@ : Integer 17 | var 9@ : Integer 18 | var 10@ : Integer 19 | 20 | script_name "0AC4" // set_play_3d_audio_stream_at_char 21 | debug_on 22 | 23 | trace "0AC4 (set_play_3d_audio_stream_at_char)" 24 | 25 | 26 | // load existing file 27 | wait 0 28 | if 29 | load_3d_audio_stream ".\Ding.mp3" store_to 0@ 30 | then 31 | trace "~g~~h~~h~0AC4 (set_play_3d_audio_stream_at_char), #0 PASSED" 32 | else 33 | breakpoint "~r~~h~~h~~h~0AC4 (set_play_3d_audio_stream_at_char), #0 FAILED!~n~Failed to load file. Handle: %d" 0@ 34 | end 35 | 36 | 37 | // test player's actor 38 | wait 0 39 | if 40 | does_char_exist $scplayer 41 | then 42 | trace "~g~~h~~h~0AC4 (set_play_3d_audio_stream_at_char), #1 PASSED" 43 | else 44 | breakpoint "~r~~h~~h~~h~0AC4 (set_play_3d_audio_stream_at_char), #1 FAILED!~n~Player character does not exists!" 0@ 45 | end 46 | 47 | 48 | // attach to character 49 | wait 0 50 | 0AC4: set_play_3d_audio_stream_at_char 0@ character $scplayer // tested opcode 51 | trace "~g~~h~~h~0AC4 (set_play_3d_audio_stream_at_char), #2 PASSED" 52 | 53 | 54 | // play the sound 55 | wait 0 56 | print_big_formatted "AT PLAYER CHAR" {time} 300 {style} TextStyle.MiddleSmaller 57 | set_audio_stream_state 0@ state AudioStreamAction.Play 58 | wait 250 59 | trace "~g~~h~~h~0AC4 (set_play_3d_audio_stream_at_char), #3 PASSED" 60 | 61 | 62 | terminate_this_custom_script 63 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/2507.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2507' 5 | test("2507 (get_audio_stream_progress)", tests) 6 | terminate_this_custom_script 7 | 8 | const Test_File = ".\Speech.mp3" 9 | 10 | function tests 11 | int stream 12 | before_each(@setup) 13 | after_each(@cleanup) 14 | 15 | it("should get progress", test1) 16 | it("should return 1.0 when finished", test2) 17 | return 18 | 19 | 20 | :setup 21 | stream = load_audio_stream Test_File 22 | assert_result_true() 23 | return 24 | 25 | 26 | :cleanup 27 | remove_audio_stream stream 28 | stream = -1 29 | return 30 | 31 | 32 | function test1(stream: int) 33 | float progress 34 | 35 | progress = -1.0 36 | progress = get_audio_stream_progress stream 37 | assert_eqf(progress, 0.0) 38 | 39 | set_audio_stream_progress stream {progress} 0.5 40 | progress = -1.0 41 | progress = get_audio_stream_progress stream 42 | assert_rangef(progress, 0.499, 0.501) 43 | end 44 | 45 | 46 | function test2(stream: int) 47 | float progress 48 | 49 | set_audio_stream_progress stream {progress} 0.99 50 | set_audio_stream_state stream {action} AudioStreamAction.Play 51 | 52 | wait {time} 200 53 | progress = -1.0 54 | progress = get_audio_stream_progress stream 55 | assert_eqf(progress, 1.0) 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/2508.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2508' 5 | test("2508 (set_audio_stream_progress)", tests) 6 | terminate_this_custom_script 7 | 8 | const Test_File = ".\Speech.mp3" 9 | 10 | function tests 11 | int stream 12 | before_each(@setup) 13 | after_each(@cleanup) 14 | 15 | it("should set progress", test1) 16 | return 17 | 18 | 19 | :setup 20 | stream = load_audio_stream Test_File 21 | assert_result_true() 22 | return 23 | 24 | 25 | :cleanup 26 | remove_audio_stream stream 27 | stream = -1 28 | return 29 | 30 | 31 | function test1(stream: int) 32 | float progress 33 | 34 | // set after loaded 35 | set_audio_stream_progress stream {progress} 0.5 36 | progress = -1.0 37 | progress = get_audio_stream_progress stream 38 | assert_rangef(progress, 0.499, 0.501) 39 | 40 | // still same later 41 | wait {time} 0 42 | progress = -1.0 43 | progress = get_audio_stream_progress stream 44 | assert_rangef(progress, 0.499, 0.501) 45 | 46 | // used when playback started 47 | set_audio_stream_state stream {action} AudioStreamAction.Play 48 | progress = -1.0 49 | progress = get_audio_stream_progress stream 50 | assert_rangef(progress, 0.499, 0.501) 51 | 52 | wait {time} 0 53 | progress = -1.0 54 | progress = get_audio_stream_progress stream 55 | assert_rangef(progress, 0.499, 0.510) 56 | 57 | // still same after stopped 58 | set_audio_stream_state stream {action} AudioStreamAction.Stop 59 | progress = -1.0 60 | progress = get_audio_stream_progress stream 61 | assert_rangef(progress, 0.499, 0.510) 62 | 63 | // sets progress of stopped stream 64 | set_audio_stream_progress stream {progress} 0.25 65 | progress = -1.0 66 | progress = get_audio_stream_progress stream 67 | assert_rangef(progress, 0.249, 0.251) 68 | 69 | // still same after resume 70 | set_audio_stream_state stream {action} AudioStreamAction.Play 71 | progress = -1.0 72 | progress = get_audio_stream_progress stream 73 | assert_rangef(progress, 0.249, 0.260) 74 | 75 | wait {time} 0 76 | progress = -1.0 77 | progress = get_audio_stream_progress stream 78 | assert_rangef(progress, 0.249, 0.260) 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/250B.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '250B' 5 | test("250B (get_audio_stream_progress_seconds)", tests) 6 | terminate_this_custom_script 7 | 8 | const Test_File = ".\Speech.mp3" 9 | 10 | function tests 11 | int stream 12 | before_each(@setup) 13 | after_each(@cleanup) 14 | 15 | it("should get progress", test1) 16 | return 17 | 18 | 19 | :setup 20 | stream = load_audio_stream Test_File 21 | assert_result_true() 22 | return 23 | 24 | 25 | :cleanup 26 | remove_audio_stream stream 27 | stream = -1 28 | return 29 | 30 | 31 | function test1(stream: int) 32 | float progress 33 | 34 | progress = -1.0 35 | progress = get_audio_stream_progress_seconds stream 36 | assert_eqf(progress, 0.0) 37 | 38 | set_audio_stream_progress stream {progress} 0.5 39 | progress = -1.0 40 | progress = get_audio_stream_progress_seconds stream 41 | assert_rangef(progress, 3.6, 3.8) // test file is about 7.4 seconds long 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/250C.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '250C' 5 | test("250C (set_audio_stream_progress_seconds)", tests) 6 | terminate_this_custom_script 7 | 8 | const Test_File = ".\Speech.mp3" 9 | 10 | function tests 11 | int stream 12 | before_each(@setup) 13 | after_each(@cleanup) 14 | 15 | it("should set progress", test1) 16 | return 17 | 18 | 19 | :setup 20 | stream = load_audio_stream Test_File 21 | assert_result_true() 22 | return 23 | 24 | 25 | :cleanup 26 | remove_audio_stream stream 27 | stream = -1 28 | return 29 | 30 | 31 | function test1(stream: int) 32 | float progress 33 | 34 | // set after loaded 35 | set_audio_stream_progress_seconds stream {progress} 3.7 // ~50% 36 | progress = -1.0 37 | progress = get_audio_stream_progress stream 38 | assert_rangef(progress, 0.49, 0.51) 39 | 40 | // still same later 41 | wait {time} 0 42 | progress = -1.0 43 | progress = get_audio_stream_progress stream 44 | assert_rangef(progress, 0.49, 0.51) 45 | 46 | // used when playback started 47 | set_audio_stream_state stream {action} AudioStreamAction.Play 48 | progress = -1.0 49 | progress = get_audio_stream_progress stream 50 | assert_rangef(progress, 0.49, 0.51) 51 | 52 | wait {time} 0 53 | progress = -1.0 54 | progress = get_audio_stream_progress stream 55 | assert_rangef(progress, 0.49, 0.56) 56 | 57 | // still same after stopped 58 | set_audio_stream_state stream {action} AudioStreamAction.Stop 59 | progress = -1.0 60 | progress = get_audio_stream_progress stream 61 | assert_rangef(progress, 0.49, 0.56) 62 | 63 | // sets progress of stopped stream 64 | set_audio_stream_progress_seconds stream {progress} 1.85 // ~25% 65 | progress = -1.0 66 | progress = get_audio_stream_progress stream 67 | assert_rangef(progress, 0.24, 0.26) 68 | 69 | // still same after resume 70 | set_audio_stream_state stream {action} AudioStreamAction.Play 71 | progress = -1.0 72 | progress = get_audio_stream_progress stream 73 | assert_rangef(progress, 0.24, 0.31) 74 | 75 | wait {time} 0 76 | progress = -1.0 77 | progress = get_audio_stream_progress stream 78 | assert_rangef(progress, 0.24, 0.31) 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/Ding.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cleolibrary/CLEO5/c1c74036121f4d782d42467f693eb00a61ad81b3/tests/cleo_tests/Audio/Ding.mp3 -------------------------------------------------------------------------------- /tests/cleo_tests/Audio/Speech.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cleolibrary/CLEO5/c1c74036121f4d782d42467f693eb00a61ad81b3/tests/cleo_tests/Audio/Speech.mp3 -------------------------------------------------------------------------------- /tests/cleo_tests/Cleo/0AB2.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AB2" 5 | test("0AB2 (cleo_return)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should return values", test1) 10 | it("should keep condition result", test2) 11 | it_cs4("should allow too few return params in legacy modes", test3) 12 | it_cs4("should allow too many return params in legacy modes", test4) 13 | return 14 | 15 | function test1 16 | int a = 0xAA 17 | int b = 0xBB 18 | a, b = RETURN_TWO() 19 | assert_eq(a, 0x11) 20 | assert_eq(b, 0x22) 21 | end 22 | 23 | function test2 24 | RETURN_TRUE() 25 | assert_result_true() 26 | 27 | RETURN_FALSE() 28 | assert_result_false() 29 | end 30 | 31 | function test3 32 | int a = 0xAA 33 | cleo_call RETURN_TWO {numParams} 0 {params} {return} a 34 | assert_eq(a, 0x11) 35 | end 36 | 37 | function test4 38 | int a = 0xAA 39 | int b = 0xBB 40 | int c = 0xCC 41 | cleo_call RETURN_TWO {numParams} 0 {params} {return} a b c 42 | assert_eq(a, 0x11) 43 | assert_eq(b, 0x22) 44 | assert_eq(c, 0xCC) 45 | end 46 | end 47 | 48 | function RETURN_TWO(): int, int 49 | cleo_return 2 0x11 0x22 50 | end 51 | 52 | function RETURN_TRUE() 53 | is_pc_version // set condition result true 54 | cleo_return 55 | end 56 | 57 | function RETURN_FALSE() 58 | is_australian_game // set condition result false 59 | cleo_return 60 | end 61 | -------------------------------------------------------------------------------- /tests/cleo_tests/Cleo/2000.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2000' 5 | test("2000 (get_cleo_arg_count)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | :return_arg_count 10 | 0@ = get_cleo_arg_count 11 | cleo_return 1 0@ 12 | 13 | 14 | function tests 15 | it("should return cleo call arguments count", test1) 16 | return 17 | 18 | function test1 19 | cleo_call @return_arg_count {numParams} 0 {params} {result} 0@ 20 | assert_eq(0@, 0) 21 | 22 | cleo_call @return_arg_count {numParams} 1 {params} 123 {result} 0@ 23 | assert_eq(0@, 1) 24 | 25 | cleo_call @return_arg_count {numParams} 2 {params} 123 0@ {result} 0@ 26 | assert_eq(0@, 2) 27 | 28 | cleo_call @return_arg_count {numParams} 3 {params} 123 0@ "some_text" {result} 0@ 29 | assert_eq(0@, 3) 30 | 31 | cleo_call @return_arg_count {numParams} 25 {params} 123 0@ "some_text" 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 {result} 0@ 32 | assert_eq(0@, 25) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0A99.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0A99" 5 | test("0A99 (set_current_directory)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | before_each(@setup) 11 | after_each(@cleanup) 12 | 13 | it("should set param 0", test1) 14 | it("should set param 1", test2) 15 | it("should set virtual paths", test3) 16 | it("should set script path", test4) 17 | it("should enter relative sub-path", test5) 18 | return 19 | 20 | 21 | :setup 22 | 0@ = allocate_memory {size} 512 23 | set_current_directory {path} 0 // game root 24 | return 25 | 26 | 27 | :cleanup 28 | free_memory {address} 0@ 29 | return 30 | 31 | 32 | function test1 33 | set_current_directory {path} 0 // game root 34 | 0@ = resolve_filepath "" 35 | assert_eqs(0@, "") // relative to root, so empty 36 | end 37 | 38 | 39 | function test2 40 | set_current_directory {path} 1 // user files 41 | does_file_exist {path} "gta_sa.set" // game's settings file in user dir 42 | assert_result_true() 43 | end 44 | 45 | 46 | function test3 47 | set_current_directory {path} "root:" // game root 48 | 0@ = resolve_filepath "" 49 | assert_eqs(0@, "") // relative to root, so empty 50 | does_file_exist {path} "gta_sa.set" // game's settings file in user dir 51 | assert_result_false() 52 | 53 | set_current_directory {path} "user:" // user files 54 | does_file_exist {path} "gta_sa.set" // game's settings file in user dir 55 | assert_result_true() 56 | 57 | set_current_directory {path} "cleo:" // cleo directory 58 | 0@ = resolve_filepath "" 59 | assert_eqs(0@, "cleo") // relative to root 60 | 61 | set_current_directory {path} "cleo:\cleo_plugins" // cleo sub-directory 62 | 0@ = resolve_filepath "" 63 | assert_eqs(0@, "cleo\cleo_plugins") // relative to root 64 | end 65 | 66 | 67 | function test4 68 | set_current_directory {path} ".\\" // this script's location 69 | 0@ = resolve_filepath "" 70 | assert_eqs(0@, "cleo\cleo_tests\FilesystemOperations") // relative to root 71 | end 72 | 73 | 74 | function test5 75 | set_current_directory {path} "root:" 76 | set_current_directory {path} "data" 77 | set_current_directory {path} "script" 78 | 79 | 0@ = resolve_filepath "" 80 | assert_eqs(0@, "data\script") // relative to root 81 | 82 | does_file_exist {path} "main.scm" 83 | assert_result_true() 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0A9A.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0A9A" // open_file 5 | test("0A9A (open_file)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | 11 | it("should fail on a non-existing file", test1) 12 | it("should open existing file", test2) 13 | return 14 | 15 | function test1 16 | 0@ = open_file "cleo\not_a_file.txt" {mode} "r" // tested opcode 17 | assert_result_false() 18 | end 19 | 20 | function test2 21 | if 22 | 0@ = open_file "cleo\.cleo_config.ini" {mode} "r" // tested opcode 23 | then 24 | assert(true) 25 | close_file 0@ 26 | else 27 | assert(false) 28 | end 29 | end 30 | 31 | end 32 | 33 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0A9B.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE file} 4 | {$USE bitwise} 5 | var 0@ : Integer 6 | var 1@ : Integer 7 | var 2@ : Integer 8 | var 3@ : Integer 9 | var 4@ : Integer 10 | var 5@ : Integer 11 | var 6@ : Integer 12 | var 7@ : Integer 13 | var 8@ : Integer 14 | var 9@ : Integer 15 | var 10@ : Integer 16 | 17 | script_name "0A9B" // close_file 18 | debug_on 19 | 20 | trace "0A9B (close_file)" 21 | 22 | 23 | wait 0 24 | // open file 25 | if 26 | 0@ = open_file "cleo\.cleo_config.ini" {mode} "r+" 27 | then 28 | trace "~g~~h~~h~0A9B (close_file), #0 PASSED" 29 | else 30 | breakpoint "~r~~h~~h~~h~0A9B (close_file), #0 FAILED! Failed to open file." 31 | end 32 | 33 | 34 | wait 0 35 | // close file 36 | 0A9B: close_file 0@ // tested opcode 37 | trace "~g~~h~~h~0A9B (close_file), #1 PASSED" 38 | 39 | 40 | wait 0 41 | // open file again 42 | if 43 | 0@ = open_file "cleo\.cleo_config.ini" {mode} "r+" 44 | then 45 | trace "~g~~h~~h~0A9B (close_file), #2 PASSED" 46 | else 47 | breakpoint "~r~~h~~h~~h~0A9B (close_file), #2 FAILED! Failed to open file." 48 | end 49 | 50 | 51 | wait 0 52 | // close file again 53 | 0A9B: close_file 0@ // tested opcode 54 | trace "~g~~h~~h~0A9B (close_file), #3 PASSED" 55 | 56 | 57 | terminate_this_custom_script 58 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0A9C.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE file} 4 | {$USE bitwise} 5 | var 0@ : Integer 6 | var 1@ : Integer 7 | var 2@ : Integer 8 | var 3@ : Integer 9 | var 4@ : Integer 10 | var 5@ : Integer 11 | var 6@ : Integer 12 | var 7@ : Integer 13 | var 8@ : Integer 14 | var 9@ : Integer 15 | var 10@ : Integer 16 | 17 | script_name "0A9C" // get_file_size 18 | debug_on 19 | 20 | trace "0A9A (get_file_size)" 21 | 22 | 23 | wait 0 24 | // try open existing file 25 | if 26 | 0@ = open_file "cleo.asi" {mode} "r" // tested opcode 27 | then 28 | trace "~g~~h~~h~0A9C (get_file_size), #0 PASSED" 29 | else 30 | breakpoint "~r~~h~~h~~h~0A9C (get_file_size), #0 FAILED! Failed to open file." 31 | end 32 | 33 | 34 | wait 0 35 | 0A9C: get_file_size 0@ {size} 1@ // tested opcode 36 | if 37 | 1@ > 0 38 | then 39 | trace "~g~~h~~h~0A9C (get_file_size), #1 PASSED" 40 | else 41 | breakpoint "~r~~h~~h~~h~0A9C (get_file_size), #1 FAILED! File size: %d" 1@ 42 | end 43 | 44 | 45 | close_file 0@ 46 | trace "~g~~h~~h~0A9C (get_file_size), #2 PASSED" 47 | 48 | 49 | terminate_this_custom_script 50 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0A9D.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE file} 4 | {$USE bitwise} 5 | var 0@ : Integer 6 | var 1@ : Integer 7 | var 2@ : Integer 8 | var 3@ : Integer 9 | var 4@ : Integer 10 | var 5@ : Integer 11 | var 6@ : Integer 12 | var 7@ : Integer 13 | var 8@ : Integer 14 | var 9@ : Integer 15 | var 10@ : Integer 16 | 17 | 18 | script_name "0A9D" // read_from_file 19 | debug_on 20 | 21 | trace "0A9D (read_from_file)" 22 | 23 | 24 | wait 0 25 | // open the file 26 | if 27 | 0@ = open_file "cleo.asi" {mode} "r" 28 | then 29 | trace "~g~~h~~h~0A9D (read_from_file), #0 PASSED" 30 | else 31 | breakpoint "~r~~h~~h~~h~0A9D (read_from_file), #0 FAILED! Failed to open file." 32 | end 33 | 34 | 35 | wait 0 36 | // read 0 bytes 37 | 1@ = 0xcccccccc 38 | 2@ = 0xdddddddd 39 | 3@ = 0xeeeeeeee 40 | 41 | 0A9D: read_from_file 0@ {size} 0 {destination} 2@ // tested opcode 42 | 43 | if and 44 | 1@ == 0xcccccccc 45 | 2@ == 0x00000000 46 | 3@ == 0xeeeeeeee 47 | then 48 | trace "~g~~h~~h~0A9D (read_from_file), #1 PASSED" 49 | else 50 | breakpoint "~r~~h~~h~~h~0A9D (read_from_file), #1 FAILED!~n~cccccccc 00000000 eeeeeeee Expected~n~%08x %08x %08x Occured" 1@ 2@ 3@ 51 | end 52 | 53 | 54 | wait 0 55 | // read 2 bytes 56 | 1@ = 0xcccccccc 57 | 2@ = 0xdddddddd 58 | 3@ = 0xeeeeeeee 59 | 60 | 0A9D: read_from_file 0@ {size} 2 {destination} 2@ // tested opcode 61 | 62 | if and 63 | 1@ == 0xcccccccc 64 | 2@ == 0x00005A4D // DOS "MZ" header 65 | 3@ == 0xeeeeeeee 66 | then 67 | trace "~g~~h~~h~0A9D (read_from_file), #2 PASSED" 68 | else 69 | breakpoint "~r~~h~~h~~h~0A9D (read_from_file), #2 FAILED!~n~cccccccc 00005A4D eeeeeeee Expected~n~%08x %08x %08x Occured" 1@ 2@ 3@ 70 | end 71 | 72 | 73 | wait 0 74 | close_file 0@ 75 | trace "~g~~h~~h~0A9D (read_from_file), #3 PASSED" 76 | 77 | 78 | wait 0 79 | // open the file 80 | if 81 | 0@ = open_file "cleo.asi" {mode} "r" 82 | then 83 | trace "~g~~h~~h~0A9D (read_from_file), #3 PASSED" 84 | else 85 | breakpoint "~r~~h~~h~~h~0A9D (read_from_file), #3 FAILED! Failed to open file." 86 | end 87 | 88 | 89 | wait 0 90 | // read 2 bytes into array 91 | 1@ = 0xcccccccc 92 | 2@ = 0xdddddddd 93 | 3@ = 0xeeeeeeee 94 | 4@ = 2 // array index 95 | 96 | 0A9D: read_from_file 0@ {size} 2 {destination} 0@(4@,32i) // tested opcode 97 | 98 | if and 99 | 1@ == 0xcccccccc 100 | 2@ == 0x00005A4D // DOS "MZ" header 101 | 3@ == 0xeeeeeeee 102 | then 103 | trace "~g~~h~~h~0A9D (read_from_file), #4 PASSED" 104 | else 105 | breakpoint "~r~~h~~h~~h~0A9D (read_from_file), #4 FAILED!~n~cccccccc 00005A4D eeeeeeee Expected~n~%08x %08x %08x Occured" 1@ 2@ 3@ 106 | end 107 | 108 | 109 | wait 0 110 | close_file 0@ 111 | trace "~g~~h~~h~0A9D (read_from_file), #5 PASSED" 112 | 113 | 114 | terminate_this_custom_script 115 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0AAB.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AAB" 5 | test("0AAB (does_file_exist)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | 11 | it("should fail on a non-existing file", test1) 12 | it("should success on existing file", test2) 13 | it("should handle .\ prefix", test3) 14 | it_cs4("should handle .\ prefix", test4) 15 | return 16 | 17 | function test1 18 | does_file_exist {path} "cleo\not_a_file.txt" // tested opcode 19 | assert_result_false() 20 | end 21 | 22 | function test2 23 | does_file_exist {path} "cleo\.cleo_config.ini" // tested opcode 24 | assert_result_true() 25 | end 26 | 27 | function test3 28 | does_file_exist {path} ".\0AAB.s" 29 | assert_result_true() 30 | 31 | does_file_exist {path} ".\cleo.asi" 32 | assert_result_false() 33 | end 34 | 35 | function test4 36 | does_file_exist {path} ".\0AAB.s" 37 | assert_result_false() 38 | 39 | does_file_exist {path} ".\cleo.asi" 40 | assert_result_true() 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0AD6.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AD6" 5 | test("0AD6 (is_end_of_file_reached)", tests) 6 | terminate_this_custom_script 7 | 8 | const Test_File = ".\test_file.txt" 9 | 10 | function tests 11 | before_each(@setup) 12 | after_each(@cleanup) 13 | 14 | it("should detect EOF", test1) 15 | return 16 | 17 | :setup 18 | if 19 | does_file_exist {path} Test_File 20 | then 21 | delete_file {path} Test_File 22 | end 23 | 24 | 0@ = open_file {filePathName} Test_File {mode} "w" 25 | write_to_file 0@ {size} 4 {var_source} 0x22222222 26 | write_to_file 0@ {size} 3 {var_source} 0x333333 27 | close_file 0@ 28 | 29 | 0@ = open_file {filePathName} Test_File {mode} "r" 30 | return 31 | 32 | :cleanup 33 | close_file 0@ 34 | delete_file {path} Test_File 35 | return 36 | 37 | function test1 38 | 1@ = read_from_file 0@ {size} 4 39 | assert_eq(1@, 0x22222222) 40 | is_end_of_file_reached 0@ 41 | assert_result_false() 42 | 43 | 1@ = read_from_file 0@ {size} 4 44 | assert_eq(1@, 0x00333333) 45 | is_end_of_file_reached 0@ 46 | assert_result_true() 47 | 48 | 1@ = 0x66666666 49 | 1@ = read_from_file 0@ {size} 4 50 | assert_eq(1@, 0x00000000) 51 | is_end_of_file_reached 0@ 52 | assert_result_true() 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0AE4.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AE4" 5 | test("0AE4 (does_directory_exist)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | 11 | it("should fail on a non-existing directory", test1) 12 | it("should success on existing directory", test2) 13 | return 14 | 15 | function test1 16 | does_directory_exist {path} "cleo\not_a_directory" // tested opcode 17 | assert_result_false() 18 | end 19 | 20 | function test2 21 | does_directory_exist {path} "cleo\cleo_tests" // tested opcode 22 | assert_result_true() 23 | end 24 | 25 | end 26 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0AE5.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AE5" 5 | test("0AE5 (create_directory)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | const Test_Path = "cleo\cleo_test_directory" 10 | 11 | function tests 12 | before_each(@cleanup) 13 | after_each(@cleanup) 14 | 15 | it("should create directory", test1) 16 | return 17 | 18 | :cleanup 19 | delete_directory {path} Test_Path {recursive} true 20 | return 21 | 22 | function test1 23 | does_directory_exist {path} Test_Path 24 | assert_result_false() 25 | 26 | create_directory {path} Test_Path // tested opcode 27 | assert_result_true() 28 | 29 | does_directory_exist {path} Test_Path 30 | assert_result_true() 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0B00.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0B00" 5 | test("0B00 (delete_file)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | const Test_Path = "cleo\cleo_test_file.ini" 10 | 11 | function tests 12 | before_each(@cleanup) 13 | after_each(@cleanup) 14 | 15 | it("should fail on a non-existing file", test1) 16 | it("should delete existing file", test2) 17 | return 18 | 19 | :cleanup 20 | delete_file {path} Test_Path 21 | return 22 | 23 | function test1 24 | delete_file {path} "cleo\not_a_file.ini" // tested opcode 25 | assert_result_false() 26 | end 27 | 28 | function test2 29 | write_int_to_ini_file {value} 42 {path} Test_Path {section} "test" {key} "test" 30 | assert_result_true() 31 | does_file_exist {path} Test_Path 32 | assert_result_true() 33 | 34 | delete_file {path} Test_Path // tested opcode 35 | assert_result_true() 36 | does_file_exist {path} Test_Path 37 | assert_result_false() 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0B01.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0B01" 5 | test("0B01 (delete_directory)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | const Test_Path = "cleo\cleo_test_directory" 10 | 11 | function tests 12 | before_each(@cleanup) 13 | after_each(@cleanup) 14 | 15 | it("should fail on a non-existing directory", test1) 16 | it("should delete empty directory", test2) 17 | it("should delete directory with contents", test3) 18 | return 19 | 20 | :cleanup 21 | set_current_directory {path} 0 22 | delete_directory {dirPath} Test_Path {recursive} true 23 | return 24 | 25 | function test1 26 | delete_directory {dirPath} Test_Path {recursive} false // tested opcode 27 | assert_result_false() 28 | end 29 | 30 | function test2 31 | create_directory {path} Test_Path 32 | assert_result_true() 33 | does_directory_exist {dirPath} Test_Path 34 | assert_result_true() 35 | 36 | delete_directory {dirPath} Test_Path {recursive} false // tested opcode 37 | assert_result_true() 38 | does_directory_exist {dirPath} Test_Path 39 | assert_result_false() 40 | end 41 | 42 | function test3 43 | create_directory {path} Test_Path 44 | assert_result_true() 45 | does_directory_exist {dirPath} Test_Path 46 | assert_result_true() 47 | 48 | set_current_directory {path} Test_Path 49 | create_directory {path} "Test_Sub_Dir" 50 | write_int_to_ini_file {value} 42 {path} "Test_File.ini" {section} "test" {key} "test" 51 | set_current_directory {path} 0 52 | 53 | // check if file was actually created in desired location 54 | int str = allocate_memory {size} 260 55 | string_format str = "%s\\Test_File.ini" Test_Path 56 | int value = read_int_from_ini_file {path} str {section} "test" {key} "test" 57 | assert_eq(value, 42) 58 | free_memory str 59 | 60 | delete_directory {dirPath} Test_Path {recursive} false // tested opcode 61 | assert_result_false() 62 | does_directory_exist {dirPath} Test_Path 63 | assert_result_true() 64 | 65 | delete_directory {dirPath} Test_Path {recursive} true // tested opcode 66 | assert_result_true() 67 | does_directory_exist {dirPath} Test_Path 68 | assert_result_false() 69 | end 70 | 71 | end 72 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0B02.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0B02" 5 | test("0B02 (move_file)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | const Test_Path_Src = "cleo\cleo_test_file.ini" 10 | const Test_Path_Dst = "_test_file_B.ini" 11 | 12 | function tests 13 | before_each(@cleanup) 14 | after_each(@cleanup) 15 | 16 | it("should fail on a non-existing file", test1) 17 | it("should move file", test2) 18 | return 19 | 20 | :cleanup 21 | delete_file {path} Test_Path_Src 22 | delete_file {path} Test_Path_Dst 23 | return 24 | 25 | function test1 26 | does_file_exist {dirPath} Test_Path_Src 27 | assert_result_false() 28 | 29 | move_file {path} Test_Path_Src {newPath} Test_Path_Dst // tested opcode 30 | assert_result_false() 31 | end 32 | 33 | function test2 34 | // setup 35 | write_int_to_ini_file {value} 42 {path} Test_Path_Src {section} "test" {key} "test" 36 | assert_result_true() 37 | does_file_exist {dirPath} Test_Path_Src 38 | assert_result_true() 39 | does_file_exist {dirPath} Test_Path_Dst 40 | assert_result_false() 41 | 42 | // act 43 | move_file {path} Test_Path_Src {newPath} Test_Path_Dst // tested opcode 44 | assert_result_true() 45 | does_file_exist {dirPath} Test_Path_Src 46 | assert_result_false() 47 | does_file_exist {dirPath} Test_Path_Dst 48 | assert_result_true() 49 | 50 | int value = read_int_from_ini_file {path} Test_Path_Dst {section} "test" {key} "test" 51 | assert_eq(value, 42) 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0B03.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0B03" 5 | test("0B03 (move_directory)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | const Test_Path_Src = "cleo\cleo_test_dir" 10 | const Test_Path_Dst = "test_directory" 11 | 12 | function tests 13 | before_each(@cleanup) 14 | after_each(@cleanup) 15 | 16 | it("should fail on a non-existing directory", test1) 17 | it("should move directory", test2) 18 | return 19 | 20 | :cleanup 21 | set_current_directory {path} 0 22 | delete_directory {path} Test_Path_Src 23 | delete_directory {path} Test_Path_Dst 24 | return 25 | 26 | function test1 27 | does_directory_exist {dirPath} Test_Path_Src 28 | assert_result_false() 29 | 30 | move_directory {path} Test_Path_Src {newPath} Test_Path_Dst // tested opcode 31 | assert_result_false() 32 | end 33 | 34 | function test2 35 | // setup 36 | create_directory {path} Test_Path_Src 37 | set_current_directory {path} Test_Path_Src 38 | create_directory {path} "Test_Sub_Dir" 39 | write_int_to_ini_file {value} 42 {path} "Test_File.ini" {section} "test" {key} "test" 40 | set_current_directory {path} 0 41 | assert_result_true() 42 | does_directory_exist {dirPath} Test_Path_Src 43 | assert_result_true() 44 | does_directory_exist {dirPath} Test_Path_Dst 45 | assert_result_false() 46 | 47 | // check if file was actually created in desired location 48 | int str = allocate_memory {size} 260 49 | string_format str = "%s\\Test_File.ini" Test_Path_Src 50 | int value = read_int_from_ini_file {path} str {section} "test" {key} "test" 51 | assert_eq(value, 42) 52 | free_memory str 53 | 54 | // act 55 | move_directory {path} Test_Path_Src {newPath} Test_Path_Dst // tested opcode 56 | assert_result_true() 57 | does_directory_exist {dirPath} Test_Path_Src 58 | assert_result_false() 59 | does_directory_exist {dirPath} Test_Path_Dst 60 | assert_result_true() 61 | 62 | // check contents 63 | set_current_directory {path} Test_Path_Dst 64 | does_directory_exist {path} "Test_Sub_Dir" 65 | assert_result_true() 66 | value = read_int_from_ini_file {path} "Test_File.ini" {section} "test" {key} "test" 67 | assert_eq(value, 42) 68 | end 69 | 70 | end 71 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0B04.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0B04" 5 | test("0B04 (copy_file)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | const Test_Path_Src = "cleo\cleo_test_file.ini" 10 | const Test_Path_Dst = "_test_file_B.ini" 11 | 12 | function tests 13 | before_each(@cleanup) 14 | after_each(@cleanup) 15 | 16 | it("should fail on a non-existing file", test1) 17 | it("should copy file", test2) 18 | return 19 | 20 | :cleanup 21 | delete_file {path} Test_Path_Src 22 | delete_file {path} Test_Path_Dst 23 | return 24 | 25 | function test1 26 | does_file_exist {path} Test_Path_Src 27 | assert_result_false() 28 | 29 | copy_file {path} Test_Path_Src {newPath} Test_Path_Dst // tested opcode 30 | assert_result_false() 31 | end 32 | 33 | function test2 34 | // setup 35 | write_int_to_ini_file {value} 42 {path} Test_Path_Src {section} "test" {key} "test" 36 | assert_result_true() 37 | does_file_exist {path} Test_Path_Src 38 | assert_result_true() 39 | does_file_exist {path} Test_Path_Dst 40 | assert_result_false() 41 | 42 | // act 43 | copy_file {path} Test_Path_Src {newPath} Test_Path_Dst // tested opcode 44 | assert_result_true() 45 | 46 | int value = read_int_from_ini_file {path} Test_Path_Src {section} "test" {key} "test" 47 | assert_eq(value, 42) 48 | 49 | value = read_int_from_ini_file {path} Test_Path_Dst {section} "test" {key} "test" 50 | assert_eq(value, 42) 51 | end 52 | 53 | end 54 | -------------------------------------------------------------------------------- /tests/cleo_tests/FilesystemOperations/0B05.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0B05" 5 | test("0B05 (copy_directory)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | const Test_Path_Src = "cleo\cleo_test_dir" 10 | const Test_Path_Dst = "test_directory" 11 | 12 | function tests 13 | before_each(@cleanup) 14 | after_each(@cleanup) 15 | 16 | it("should fail on a non-existing directory", test1) 17 | it("should move directory", test2) 18 | return 19 | 20 | :cleanup 21 | set_current_directory {path} 0 22 | delete_directory {path} Test_Path_Src {recursive} true 23 | delete_directory {path} Test_Path_Dst {recursive} true 24 | return 25 | 26 | function test1 27 | does_directory_exist {dirPath} Test_Path_Src 28 | assert_result_false() 29 | 30 | copy_directory {path} Test_Path_Src {newPath} Test_Path_Dst // tested opcode 31 | assert_result_false() 32 | end 33 | 34 | function test2 35 | // setup 36 | create_directory {path} Test_Path_Src 37 | set_current_directory {path} Test_Path_Src 38 | create_directory {path} "Test_Sub_Dir" 39 | write_int_to_ini_file {value} 42 {path} "Test_File.ini" {section} "test" {key} "test" 40 | set_current_directory {path} 0 41 | assert_result_true() 42 | does_directory_exist {dirPath} Test_Path_Src 43 | assert_result_true() 44 | does_directory_exist {dirPath} Test_Path_Dst 45 | assert_result_false() 46 | 47 | // check if file was actually created in desired location 48 | int str = allocate_memory {size} 260 49 | string_format str = "%s\\Test_File.ini" Test_Path_Src 50 | int value = read_int_from_ini_file {path} str {section} "test" {key} "test" 51 | assert_eq(value, 42) 52 | free_memory str 53 | 54 | // act 55 | copy_directory {path} Test_Path_Src {newPath} Test_Path_Dst // tested opcode 56 | assert_result_true() 57 | does_directory_exist {dirPath} Test_Path_Src 58 | assert_result_true() 59 | does_directory_exist {dirPath} Test_Path_Dst 60 | assert_result_true() 61 | 62 | // check contents 63 | set_current_directory {path} Test_Path_Src 64 | does_directory_exist {path} "Test_Sub_Dir" 65 | assert_result_true() 66 | value = read_int_from_ini_file {path} "Test_File.ini" {section} "test" {key} "test" 67 | assert_eq(value, 42) 68 | set_current_directory {path} 0 69 | 70 | set_current_directory {path} Test_Path_Dst 71 | does_directory_exist {path} "Test_Sub_Dir" 72 | assert_result_true() 73 | value = read_int_from_ini_file {path} "Test_File.ini" {section} "test" {key} "test" 74 | assert_eq(value, 42) 75 | end 76 | 77 | end 78 | -------------------------------------------------------------------------------- /tests/cleo_tests/GameEntities/0AB6.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0AB6' 5 | test("0AB6 (get_target_blip_coords)", tests) 6 | terminate_this_custom_script 7 | 8 | const Target_Blip_GTA_SA = 0x00BA6774 9 | 10 | function tests 11 | it("should get target blip info", test1) 12 | return 13 | 14 | function test1() 15 | int handle 16 | float x, y, z 17 | 18 | // delete target blip if set 19 | handle = read_memory {address} Target_Blip_GTA_SA {size} 4 {vp} false 20 | if 21 | handle <> 0 22 | then 23 | remove_blip handle 24 | write_memory {address} Target_Blip_GTA_SA {size} 4 {value} 0 {vp} false 25 | end 26 | 27 | // test no blip 28 | x = 111.0 29 | y = 222.0 30 | z = 333.0 31 | x, y, z = get_target_blip_coords 32 | assert_result_false() 33 | assert_eqf(x, 111.0) 34 | assert_eqf(y, 222.0) 35 | assert_eqf(z, 333.0) 36 | 37 | // create target blip 38 | handle = add_blip_for_coord {pos} 125.0 -98.0 20.0 // Blue Berry 39 | write_memory {address} Target_Blip_GTA_SA {size} 4 {value} handle {vp} false 40 | 41 | x, y, z = get_target_blip_coords 42 | assert_result_true() 43 | assert_eqf(x, 125.0) 44 | assert_eqf(y, -98.0) 45 | //assert_rangef(z, 1.5, 1.6) // actual ground height 46 | 47 | remove_blip handle 48 | end 49 | end 50 | 51 | -------------------------------------------------------------------------------- /tests/cleo_tests/GameEntities/0AB7.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0AB7' 5 | test("0AB7 (get_car_number_of_gears)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should get car gear count", test1) 10 | return 11 | 12 | function test1() 13 | int carHandle, count 14 | 15 | // Landstalker: 5 gears 16 | carHandle = SpawnCar(#LANDSTAL) 17 | count = 0x666 18 | count = get_car_number_of_gears carHandle 19 | assert_eq(count, 5) 20 | delete_car carHandle 21 | 22 | // Bus: 4 gears 23 | carHandle = SpawnCar(#BUS) 24 | count = 0x666 25 | count = get_car_number_of_gears carHandle 26 | assert_eq(count, 4) 27 | delete_car carHandle 28 | end 29 | end 30 | 31 | 32 | function SpawnCar(modelIdx: int): int 33 | float x, y, z 34 | x = generate_random_float_in_range {min} -5.0 {max} 5.0 35 | y = generate_random_float_in_range {min} 4.0 {max} 6.0 36 | z = -1.0 37 | 38 | x, y, z = get_offset_from_char_in_world_coords $scplayer {offset} x y z 39 | 40 | request_model modelIdx 41 | load_all_models_now 42 | int carHandle = create_car {modelId} modelIdx {pos} x y z 43 | mark_model_as_no_longer_needed modelIdx 44 | 45 | return carHandle 46 | end 47 | -------------------------------------------------------------------------------- /tests/cleo_tests/GameEntities/0AB8.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0AB8' 5 | test("0AB8 (get_car_current_gear)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should get car current gear", test1) 10 | return 11 | 12 | function test1() 13 | int carHandle, gear 14 | 15 | carHandle = SpawnCar(#LANDSTAL) 16 | int pedHandle = create_random_char_as_driver {vehicle} carHandle 17 | 18 | wait {time} 250 19 | gear = 0x666 20 | gear = get_car_current_gear carHandle 21 | assert_eq(gear, 1) 22 | 23 | set_car_temp_action carHandle {actionId} TempAction.Reverse {time} 5000 24 | wait {time} 250 25 | gear = 0x666 26 | gear = get_car_current_gear carHandle 27 | assert_eq(gear, 0) // reverse 28 | 29 | delete_car carHandle 30 | end 31 | end 32 | 33 | 34 | function SpawnCar(modelIdx: int): int 35 | float x, y, z 36 | x = generate_random_float_in_range {min} -5.0 {max} 5.0 37 | y = generate_random_float_in_range {min} 4.0 {max} 6.0 38 | z = -1.0 39 | 40 | x, y, z = get_offset_from_char_in_world_coords $scplayer {offset} x y z 41 | 42 | request_model modelIdx 43 | load_all_models_now 44 | int carHandle = create_car {modelId} modelIdx {pos} x y z 45 | mark_model_as_no_longer_needed modelIdx 46 | 47 | return carHandle 48 | end 49 | -------------------------------------------------------------------------------- /tests/cleo_tests/GameEntities/0ABD.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0ABD' 5 | test("0ABD (is_car_siren_on)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should get car siren state", test1) 10 | return 11 | 12 | function test1() 13 | int carHandle 14 | 15 | carHandle = SpawnCar(#AMBULAN) 16 | //int pedHandle = create_random_char_as_driver {vehicle} carHandle // crashes the game 17 | 18 | wait {time} 0 19 | is_car_siren_on carHandle 20 | assert_result_false() 21 | 22 | switch_car_siren carHandle {state} true 23 | wait {time} 0 24 | is_car_siren_on carHandle 25 | assert_result_true() 26 | 27 | delete_car carHandle 28 | end 29 | end 30 | 31 | 32 | function SpawnCar(modelIdx: int): int 33 | float x, y, z 34 | x = generate_random_float_in_range {min} -5.0 {max} 5.0 35 | y = generate_random_float_in_range {min} 4.0 {max} 6.0 36 | z = -1.0 37 | 38 | x, y, z = get_offset_from_char_in_world_coords $scplayer {offset} x y z 39 | 40 | request_model modelIdx 41 | load_all_models_now 42 | int carHandle = create_car {modelId} modelIdx {pos} x y z 43 | mark_model_as_no_longer_needed modelIdx 44 | 45 | return carHandle 46 | end 47 | -------------------------------------------------------------------------------- /tests/cleo_tests/GameEntities/0ABE.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0ABE' 5 | test("0ABE (is_car_engine_on)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should get car engine state", test1) 10 | return 11 | 12 | function test1() 13 | int carHandle 14 | 15 | carHandle = SpawnCar(#LANDSTAL) 16 | 17 | wait {time} 0 18 | is_car_engine_on carHandle 19 | assert_result_false() 20 | 21 | int pedHandle = create_random_char_as_driver {vehicle} carHandle 22 | wait {time} 0 23 | is_car_engine_on carHandle 24 | assert_result_true() 25 | 26 | delete_car carHandle 27 | end 28 | end 29 | 30 | 31 | function SpawnCar(modelIdx: int): int 32 | float x, y, z 33 | x = generate_random_float_in_range {min} -5.0 {max} 5.0 34 | y = generate_random_float_in_range {min} 4.0 {max} 6.0 35 | z = -1.0 36 | 37 | x, y, z = get_offset_from_char_in_world_coords $scplayer {offset} x y z 38 | 39 | request_model modelIdx 40 | load_all_models_now 41 | int carHandle = create_car {modelId} modelIdx {pos} x y z 42 | mark_model_as_no_longer_needed modelIdx 43 | 44 | return carHandle 45 | end 46 | -------------------------------------------------------------------------------- /tests/cleo_tests/GameEntities/0ABF.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0ABF' 5 | test("0ABF (cleo_set_car_engine_on)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should set car engine state", test1) 10 | return 11 | 12 | function test1() 13 | int carHandle 14 | 15 | carHandle = SpawnCar(#LANDSTAL) 16 | 17 | wait {time} 0 18 | is_car_engine_on carHandle 19 | assert_result_false() 20 | 21 | cleo_set_car_engine_on carHandle {state} true 22 | wait {time} 0 23 | is_car_engine_on carHandle 24 | assert_result_true() 25 | 26 | cleo_set_car_engine_on carHandle {state} false 27 | wait {time} 0 28 | is_car_engine_on carHandle 29 | assert_result_false() 30 | 31 | delete_car carHandle 32 | end 33 | end 34 | 35 | 36 | function SpawnCar(modelIdx: int): int 37 | float x, y, z 38 | x = generate_random_float_in_range {min} -5.0 {max} 5.0 39 | y = generate_random_float_in_range {min} 4.0 {max} 6.0 40 | z = -1.0 41 | 42 | x, y, z = get_offset_from_char_in_world_coords $scplayer {offset} x y z 43 | 44 | request_model modelIdx 45 | load_all_models_now 46 | int carHandle = create_car {modelId} modelIdx {pos} x y z 47 | mark_model_as_no_longer_needed modelIdx 48 | 49 | return carHandle 50 | end 51 | -------------------------------------------------------------------------------- /tests/cleo_tests/GameEntities/0ADD.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0ADD' 5 | test("0ADD (spawn_vehicle_by_cheating)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | before_each(@setup) 10 | after_each(@cleanup) 11 | it("should spawn car like cheat", test1) 12 | return 13 | 14 | 15 | :setup 16 | while not is_player_playing $player1 17 | wait 0 18 | end 19 | 20 | set_player_control $player1 {state} false 21 | set_police_ignore_player {player} $player1 {state} true 22 | set_char_proofs $scplayer {bulletProof} true {fireProof} true {explosionProof} true {collisionProof} true {meleeProof} true 23 | 24 | set_area_visible {areaId} 0 25 | set_char_area_visible $scplayer {areaId} 0 26 | warp_char_from_car_to_coord $scplayer {pos} 2737.8 -1760.3 43.15 27 | set_char_heading $scplayer {heading} 0.0 28 | restore_camera_jumpcut 29 | load_scene {pos} 2737.8 -1760.3 43.15 30 | request_collision {xy} 2737.8 -1760.3 31 | 32 | set_ped_density_multiplier {multiplier} 0.0 33 | set_car_density_multiplier {multiplier} 0.0 34 | clear_area {pos} 0.0 0.0 0.0 {radius} 100000.0 {clearParticles} true 35 | return 36 | 37 | 38 | :cleanup 39 | set_player_control $player1 {state} true 40 | set_police_ignore_player {player} $player1 {state} false 41 | set_char_proofs $scplayer {bulletProof} false {fireProof} false {explosionProof} false {collisionProof} false {meleeProof} false 42 | 43 | clear_area {pos} 0.0 0.0 0.0 {radius} 100000.0 {clearParticles} true 44 | return 45 | 46 | 47 | function test1() 48 | int pedHandle, vehHandle 49 | 50 | wait {time} 250 51 | vehHandle, pedHandle = store_closest_entities $scplayer 52 | assert_eq(vehHandle, -1) 53 | 54 | spawn_vehicle_by_cheating {modelId} #LANDSTAL 55 | wait {time} 250 56 | vehHandle, pedHandle = store_closest_entities $scplayer 57 | assert_neq(vehHandle, -1) 58 | 59 | clear_area {pos} 0.0 0.0 0.0 {radius} 100000.0 {clearParticles} true 60 | end 61 | end 62 | 63 | 64 | function SpawnPed(modelIdx: int): int 65 | float x, y, z 66 | x = generate_random_float_in_range {min} -5.0 {max} 5.0 67 | y = generate_random_float_in_range {min} 4.0 {max} 6.0 68 | z = -1.0 69 | 70 | x, y, z = get_offset_from_char_in_world_coords $scplayer {offset} x y z 71 | 72 | request_model modelIdx 73 | load_all_models_now 74 | int pedHandle = create_char {type} PedType.CivMale {model} modelIdx {pos} x y z 75 | mark_model_as_no_longer_needed modelIdx 76 | 77 | return pedHandle 78 | end 79 | -------------------------------------------------------------------------------- /tests/cleo_tests/IniFiles/0AF4.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AF4" 5 | test("0AF4 (read_string_from_ini_file)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | const Test_Path = "cleo\cleo_test_file.ini" 10 | 11 | function tests 12 | before_each(@setup) 13 | after_each(@cleanup) 14 | 15 | it("should fail on not-existing file", test1) 16 | it("should fail on invalid file", test2) 17 | it("should fail on not existing value", test3) 18 | it("should read string value", test4) 19 | it("should trim whitespaces", test5) 20 | 21 | return 22 | 23 | :setup 24 | delete_file {path} Test_Path 25 | write_int_to_ini_file {value} 42 {path} Test_Path {section} "test" {key} "test_int" 26 | write_int_to_ini_file {value} -42 {path} Test_Path {section} "test" {key} "test_int_neg" 27 | write_string_to_ini_file {value} "0x42" {path} Test_Path {section} "test" {key} "test_int_hex" 28 | write_float_to_ini_file {value} 50.0 {path} Test_Path {section} "test" {key} "test_float" 29 | write_float_to_ini_file {value} -50.0 {path} Test_Path {section} "test" {key} "test_float_neg" 30 | write_string_to_ini_file {value} "value_one" {path} Test_Path {section} "test" {key} "test_string" 31 | write_string_to_ini_file {value} " 12.3four " {path} Test_Path {section} "test" {key} "test_mixed" 32 | return 33 | 34 | :cleanup 35 | delete_file {path} Test_Path 36 | return 37 | 38 | function test1 39 | longstring value = "initial" 40 | value = read_string_from_ini_file {path} "not_a_file.ini" {section} "test" {key} "test_string" 41 | assert_result_false() 42 | assert_eqs(value, "initial") 43 | end 44 | 45 | function test2 46 | longstring value = "initial" 47 | value = read_string_from_ini_file {path} "cleo.asi" {section} "test" {key} "test_string" 48 | assert_result_false() 49 | assert_eqs(value, "initial") 50 | end 51 | 52 | function test3 53 | longstring value = "initial" 54 | value = read_string_from_ini_file {path} Test_Path {section} "test" {key} "invalid_key" 55 | assert_result_false() 56 | assert_eqs(value, "initial") 57 | end 58 | 59 | function test4 60 | longstring value = "initial" 61 | value = read_string_from_ini_file {path} Test_Path {section} "test" {key} "test_string" 62 | assert_result_true() 63 | assert_eqs(value, "value_one") 64 | end 65 | 66 | function test5 67 | longstring value = "initial" 68 | value = read_string_from_ini_file {path} Test_Path {section} "test" {key} "test_mixed" 69 | assert_result_true() 70 | assert_eqs(value, "12.3four") 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /tests/cleo_tests/IniFiles/2800.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "2800" 5 | test("2800 (delete_section_from_ini_file)", tests) 6 | terminate_this_custom_script 7 | 8 | const Test_Path = "cleo\cleo_test_file.ini" 9 | 10 | function tests 11 | before_each(@cleanup) 12 | after_each(@cleanup) 13 | 14 | it("should delete section from ini", test1) 15 | return 16 | 17 | :cleanup 18 | delete_file {path} Test_Path 19 | return 20 | 21 | function test1 22 | write_string_to_ini_file {value} "value1" {path} Test_Path {section} "test" {key} "key1" 23 | assert_result_true() 24 | 25 | write_string_to_ini_file {value} "value2" {path} Test_Path {section} "test" {key} "key2" 26 | assert_result_true() 27 | 28 | delete_section_from_ini_file {path} Test_Path {section} "test" 29 | assert_result_true() 30 | 31 | longstring value1 = read_string_from_ini_file {path} Test_Path {section} "test" {key} "key1" 32 | assert_result_false() 33 | 34 | longstring value2 = read_string_from_ini_file {path} Test_Path {section} "test" {key} "key2" 35 | assert_result_false() 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /tests/cleo_tests/IniFiles/2801.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "2801" 5 | test("2801 (delete_key_from_ini_file)", tests) 6 | terminate_this_custom_script 7 | 8 | const Test_Path = "cleo\cleo_test_file.ini" 9 | 10 | function tests 11 | before_each(@cleanup) 12 | after_each(@cleanup) 13 | 14 | it("should delete key from ini", test1) 15 | return 16 | 17 | :cleanup 18 | delete_file {path} Test_Path 19 | return 20 | 21 | function test1 22 | write_string_to_ini_file {value} "value1" {path} Test_Path {section} "test" {key} "key1" 23 | assert_result_true() 24 | 25 | write_string_to_ini_file {value} "value2" {path} Test_Path {section} "test" {key} "key2" 26 | assert_result_true() 27 | 28 | delete_key_from_ini_file {path} Test_Path {section} "test" {key} "key1" 29 | assert_result_true() 30 | 31 | longstring value1 = read_string_from_ini_file {path} Test_Path {section} "test" {key} "key1" 32 | assert_result_false() 33 | 34 | longstring value2 = read_string_from_ini_file {path} Test_Path {section} "test" {key} "key2" 35 | assert_result_true() 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /tests/cleo_tests/Math/0AEE.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0AEE' 5 | test("0AEE (pow)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should power numbers", test1) 10 | return 11 | 12 | function test1 13 | 0AEE: pow {number} 3.0 {power} 4.0 {var_result} 0@ 14 | assert_eqf(0@, 81.0) 15 | 16 | 0AEE: pow {number} 16.0 {power} 0.25 {var_result} 0@ 17 | assert_eqf(0@, 2.0) 18 | 19 | 0AEE: pow {number} 3.1415 {power} 0.0 {var_result} 0@ 20 | assert_eqf(0@, 1.0) 21 | 22 | 0AEE: pow {number} 3.0 {power} 1.0 {var_result} 0@ 23 | assert_eqf(0@, 3.0) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /tests/cleo_tests/Math/2701.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2701' 5 | test("2701 (set_bit)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should set bits", test1) 10 | return 11 | 12 | function test1 13 | 0@ = 0x12345678 14 | 2701: set_bit {var_number} 0@ {bitIndex} 0 15 | assert_eq(0@, 0x12345679) 16 | 17 | 0@ = 0x12345678 18 | 2701: set_bit {var_number} 0@ {bitIndex} 3 // already set 19 | assert_eq(0@, 0x12345678) 20 | 21 | 0@ = 0x12345678 22 | 2701: set_bit {var_number} 0@ {bitIndex} 13 23 | assert_eq(0@, 0x12347678) 24 | 25 | 0@ = 0x12345678 26 | 2701: set_bit {var_number} 0@ {bitIndex} 14 // already set 27 | assert_eq(0@, 0x12345678) 28 | 29 | 0@ = 0x12345678 30 | 2701: set_bit {var_number} 0@ {bitIndex} 28 // already set 31 | assert_eq(0@, 0x12345678) 32 | 33 | 0@ = 0x12345678 34 | 2701: set_bit {var_number} 0@ {bitIndex} 31 35 | assert_eq(0@, 0x92345678) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /tests/cleo_tests/Math/2702.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2702' 5 | test("2702 (clear_bit)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should clear bits", test1) 10 | return 11 | 12 | function test1 13 | 0@ = 0x12345678 14 | 2702: clear_bit {var_number} 0@ {bitIndex} 0 // was not set 15 | assert_eq(0@, 0x12345678) 16 | 17 | 0@ = 0x12345678 18 | 2702: clear_bit {var_number} 0@ {bitIndex} 3 19 | assert_eq(0@, 0x12345670) 20 | 21 | 0@ = 0x12345678 22 | 2702: clear_bit {var_number} 0@ {bitIndex} 13 // was not set 23 | assert_eq(0@, 0x12345678) 24 | 25 | 0@ = 0x12345678 26 | 2702: clear_bit {var_number} 0@ {bitIndex} 14 27 | assert_eq(0@, 0x12341678) 28 | 29 | 0@ = 0x12345678 30 | 2702: clear_bit {var_number} 0@ {bitIndex} 28 31 | assert_eq(0@, 0x02345678) 32 | 33 | 0@ = 0x12345678 34 | 2702: clear_bit {var_number} 0@ {bitIndex} 31 // was not set 35 | assert_eq(0@, 0x12345678) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /tests/cleo_tests/Math/2703.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2703' 5 | test("2703 (toggle_bit)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should toggle bits", test1) 10 | it("should handle numbers as bool", test2) 11 | return 12 | 13 | function test1 14 | 0@ = 0x12345678 15 | 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} true 16 | assert_eq(0@, 0x12345679) 17 | 18 | 0@ = 0x12345678 19 | 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} false // was not set 20 | assert_eq(0@, 0x12345678) 21 | 22 | 0@ = 0x12345678 23 | 2703: toggle_bit {var_number} 0@ {bitIndex} 3 {state} true // already set 24 | assert_eq(0@, 0x12345678) 25 | 26 | 0@ = 0x12345678 27 | 2703: toggle_bit {var_number} 0@ {bitIndex} 3 {state} false 28 | assert_eq(0@, 0x12345670) 29 | 30 | 0@ = 0x12345678 31 | 2703: toggle_bit {var_number} 0@ {bitIndex} 13 {state} true 32 | assert_eq(0@, 0x12347678) 33 | 34 | 0@ = 0x12345678 35 | 2703: toggle_bit {var_number} 0@ {bitIndex} 13 {state} false // was not set 36 | assert_eq(0@, 0x12345678) 37 | 38 | 0@ = 0x12345678 39 | 2703: toggle_bit {var_number} 0@ {bitIndex} 14 {state} true // already set 40 | assert_eq(0@, 0x12345678) 41 | 42 | 0@ = 0x12345678 43 | 2703: toggle_bit {var_number} 0@ {bitIndex} 14 {state} false 44 | assert_eq(0@, 0x12341678) 45 | 46 | 0@ = 0x12345678 47 | 2703: toggle_bit {var_number} 0@ {bitIndex} 28 {state} true // already set 48 | assert_eq(0@, 0x12345678) 49 | 50 | 0@ = 0x12345678 51 | 2703: toggle_bit {var_number} 0@ {bitIndex} 28 {state} false 52 | assert_eq(0@, 0x02345678) 53 | 54 | 0@ = 0x12345678 55 | 2703: toggle_bit {var_number} 0@ {bitIndex} 31 {state} true 56 | assert_eq(0@, 0x92345678) 57 | 58 | 0@ = 0x12345678 59 | 2703: toggle_bit {var_number} 0@ {bitIndex} 31 {state} false // was not set 60 | assert_eq(0@, 0x12345678) 61 | end 62 | 63 | function test2 64 | 0@ = 0xF 65 | 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} 0 66 | assert_eq(0@, 0xE) 67 | 68 | 0@ = 0x0 69 | 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} 1 70 | assert_eq(0@, 0x1) 71 | 72 | 0@ = 0x0 73 | 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} 2 74 | assert_eq(0@, 0x1) 75 | 76 | 0@ = 0x0 77 | 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} -1 78 | assert_eq(0@, 0x1) 79 | 80 | 0@ = 0x0 81 | 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} 0x00010000 82 | assert_eq(0@, 0x1) 83 | 84 | 0@ = 0x0 85 | 2703: toggle_bit {var_number} 0@ {bitIndex} 0 {state} 0x10000000 86 | assert_eq(0@, 0x1) 87 | end 88 | -------------------------------------------------------------------------------- /tests/cleo_tests/Math/2705.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2705' 5 | test("2705 (pick_random_int)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("should pick single random int", test1) 11 | it("should pick random ints", test2) 12 | return 13 | 14 | function test1 15 | int value = pick_random_int {values} 42 16 | assert_eq(value, 42) 17 | end 18 | 19 | function test2 20 | int aCount = 0 21 | int bCount = 0 22 | int cCount = 0 23 | int dCount = 0 24 | 25 | int i 26 | for i = 1 to 300 27 | int value = pick_random_int {values} -50 100 150 28 | 29 | switch value 30 | case -50 31 | aCount += 1 32 | 33 | case 100 34 | bCount += 1 35 | 36 | case 150 37 | cCount += 1 38 | 39 | default 40 | dCount += 1 41 | end 42 | end 43 | 44 | assert_range(aCount, 80, 120) 45 | assert_range(bCount, 80, 120) 46 | assert_range(cCount, 80, 120) 47 | assert_eq(dCount, 0) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /tests/cleo_tests/Math/2706.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2706' 5 | test("2706 (pick_random_float)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("should pick single random int", test1) 11 | it("should pick random ints", test2) 12 | return 13 | 14 | function test1 15 | int value = pick_random_float {values} 42.0 16 | assert_eq(value, 42.0) 17 | end 18 | 19 | function test2 20 | int aCount = 0 21 | int bCount = 0 22 | int cCount = 0 23 | int dCount = 0 24 | 25 | int i 26 | for i = 1 to 300 27 | float value = pick_random_float {values} -50.0 100.0 150.0 28 | 29 | switch value 30 | case -50.0 31 | aCount += 1 32 | 33 | case 100.0 34 | bCount += 1 35 | 36 | case 150.0 37 | cCount += 1 38 | 39 | default 40 | dCount += 1 41 | end 42 | end 43 | 44 | assert_range(aCount, 80, 120) 45 | assert_range(bCount, 80, 120) 46 | assert_range(cCount, 80, 120) 47 | assert_eq(dCount, 0) 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /tests/cleo_tests/Math/2707.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2707' 5 | test("2707 (pick_random_text)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("should pick single random text", test1) 11 | it("should pick random texts", test2) 12 | return 13 | 14 | function test1 15 | string value = pick_random_text {values} "Test" 16 | assert_eqs(value, "Test") 17 | end 18 | 19 | function test2 20 | int aCount = 0 21 | int bCount = 0 22 | int cCount = 0 23 | 24 | int i 25 | for i = 1 to 300 26 | string value = pick_random_text {values} "A" "Bb" "Cccc" 27 | 28 | if 29 | is_text_equal {text} value {another} "A" {ignoreCase} false 30 | then 31 | aCount += 1 32 | end 33 | 34 | if 35 | is_text_equal {text} value {another} "Bb" {ignoreCase} false 36 | then 37 | bCount += 1 38 | end 39 | 40 | if 41 | is_text_equal {text} value {another} "Cccc" {ignoreCase} false 42 | then 43 | cCount += 1 44 | end 45 | end 46 | 47 | assert_range(aCount, 80, 120) 48 | assert_range(bCount, 80, 120) 49 | assert_range(cCount, 80, 120) 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /tests/cleo_tests/Math/2708.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2708' 5 | test("2708 (random_chance)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("should always be true", test1) 11 | it("should always be false", test2) 12 | it("should produce correct chance", test3) 13 | return 14 | 15 | function test1 16 | int i 17 | float count 18 | 19 | count = 0.0 20 | for i = 1 to 100 21 | if 22 | random_chance {percent} 100.0 23 | then 24 | count += 1.0 25 | end 26 | end 27 | assert_eqf(count, 100.0) 28 | 29 | count = 0.0 30 | for i = 1 to 100 31 | if 32 | random_chance {percent} 200.0 33 | then 34 | count += 1.0 35 | end 36 | end 37 | assert_eqf(count, 100.0) 38 | end 39 | 40 | function test2 41 | int i 42 | float count 43 | 44 | count = 0.0 45 | for i = 1 to 100 46 | if 47 | random_chance {percent} 0.0 48 | then 49 | count += 1.0 50 | end 51 | end 52 | assert_eqf(count, 0.0) 53 | 54 | count = 0.0 55 | for i = 1 to 100 56 | if 57 | random_chance {percent} -10.0 58 | then 59 | count += 1.0 60 | end 61 | end 62 | assert_eqf(count, 0.0) 63 | end 64 | 65 | function test3 66 | float count = 0.0 67 | 68 | int i 69 | for i = 1 to 500 70 | if 71 | random_chance {percent} 33.33333 72 | then 73 | count += 1.0 74 | end 75 | end 76 | count /= 500.0 77 | 78 | assert_rangef(count, 0.2, 0.4) // expected value 0.333(3) 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0A8C.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0A8C' 5 | test("0A8C (write_memory)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | before_each(@before) 11 | 12 | it("should write 0 bytes", test1) 13 | it("should write 1 byte", test2) 14 | it("should write 2 bytes", test3) 15 | it("should write 3 bytes", test4) 16 | it("should write 4 bytes", test5) 17 | it("should write 5 bytes", test6) 18 | it("should write 7 bytes", test7) 19 | it("should write float", test8) 20 | return 21 | 22 | :before 23 | get_var_pointer 2@ {store_to} 0@ 24 | 1@ = 0xcccccccc 25 | 2@ = 0xdddddddd 26 | 3@ = 0xeeeeeeee 27 | return 28 | 29 | function test1 30 | write_memory {address} 0@ {size} 0 {value} 0x11223344 {vp} false 31 | assert_eq(1@, 0xcccccccc) 32 | assert_eq(2@, 0xdddddddd) 33 | assert_eq(3@, 0xeeeeeeee) 34 | end 35 | 36 | function test2 37 | write_memory {address} 0@ {size} 1 {value} 0x11223344 {vp} false 38 | assert_eq(1@, 0xcccccccc) 39 | assert_eq(2@, 0xdddddd44) 40 | assert_eq(3@, 0xeeeeeeee) 41 | end 42 | 43 | function test3 44 | write_memory {address} 0@ {size} 2 {value} 0x11223344 {vp} false 45 | assert_eq(1@, 0xcccccccc) 46 | assert_eq(2@, 0xdddd3344) 47 | assert_eq(3@, 0xeeeeeeee) 48 | end 49 | 50 | function test4 51 | write_memory {address} 0@ {size} 3 {value} 0x11223344 {vp} false 52 | assert_eq(1@, 0xcccccccc) 53 | assert_eq(2@, 0xdd444444) // memset behavior 54 | assert_eq(3@, 0xeeeeeeee) 55 | end 56 | 57 | function test5 58 | write_memory {address} 0@ {size} 4 {value} 0x11223344 {vp} false 59 | assert_eq(1@, 0xcccccccc) 60 | assert_eq(2@, 0x11223344) 61 | assert_eq(3@, 0xeeeeeeee) 62 | end 63 | 64 | function test6 65 | write_memory {address} 0@ {size} 5 {value} 0x11223344 {vp} false 66 | assert_eq(1@, 0xcccccccc) 67 | assert_eq(2@, 0x44444444) 68 | assert_eq(3@, 0xeeeeee44) 69 | end 70 | 71 | function test7 72 | write_memory {address} 0@ {size} 7 {value} 0x11223344 {vp} false 73 | assert_eq(1@, 0xcccccccc) 74 | assert_eq(2@, 0x44444444) 75 | assert_eq(3@, 0xee444444) 76 | end 77 | 78 | function test8 79 | 4@ = 100.0 80 | 0A8C: write_memory {address} 0@ {size} 4 {value} 4@ {vp} false // tested opcode 81 | assert_eq(1@, 0xcccccccc) 82 | assert_eqf(2@, 100.0) 83 | assert_eq(3@, 0xeeeeeeee) 84 | end 85 | 86 | 87 | end 88 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0A8D.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0A8D' 5 | test("0A8D (read_memory)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | before_each(@prepare_tests) 10 | 11 | it("should read 0 bytes", test1) 12 | it("should read 1 byte", test2) 13 | it("should read 2 bytes", test3) 14 | it("should read 3 bytes", test4) 15 | it("should read 4 bytes", test5) 16 | it("should read float", test6) 17 | 18 | return 19 | 20 | :prepare_tests 21 | 0@ = get_label_pointer @DATA 22 | 1@ = 0xcccccccc 23 | 2@ = 0xdddddddd 24 | 3@ = 0xeeeeeeee 25 | return 26 | 27 | function test1 28 | 2@ = read_memory {address} 0@ {size} 0 {vp} false 29 | 30 | assert_eq(1@, 0xcccccccc) 31 | assert_eq(2@, 0x00000000) 32 | assert_eq(3@, 0xeeeeeeee) 33 | end 34 | 35 | function test2 36 | 2@ = read_memory {address} 0@ {size} 1 {vp} false 37 | 38 | assert_eq(1@, 0xcccccccc) 39 | assert_eq(2@, 0x00000044) 40 | assert_eq(3@, 0xeeeeeeee) 41 | end 42 | 43 | function test3 44 | 2@ = read_memory {address} 0@ {size} 2 {vp} false 45 | 46 | assert_eq(1@, 0xcccccccc) 47 | assert_eq(2@, 0x00003344) 48 | assert_eq(3@, 0xeeeeeeee) 49 | end 50 | 51 | function test4 52 | 2@ = read_memory {address} 0@ {size} 3 {vp} false 53 | 54 | assert_eq(1@, 0xcccccccc) 55 | assert_eq(2@, 0x00223344) 56 | assert_eq(3@, 0xeeeeeeee) 57 | end 58 | 59 | function test5 60 | 2@ = read_memory {address} 0@ {size} 4 {vp} false 61 | 62 | assert_eq(1@, 0xcccccccc) 63 | assert_eq(2@, 0x11223344) 64 | assert_eq(3@, 0xeeeeeeee) 65 | end 66 | 67 | function test6 68 | 0@ = 125.0 69 | 2@ = 0 70 | get_var_pointer 0@ {store_to} 1@ 71 | 2@ = read_memory {address} 1@ {size} 4 {vp} false 72 | 73 | assert_eq(2@, 125.0) 74 | end 75 | 76 | :DATA 77 | hex 78 | 44 33 22 11 79 | "some longer testing text" 00 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0A96.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0A96" // get_ped_pointer 5 | test("0A96 (get_ped_pointer)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | 10 | it("should return valid pointer", test1) 11 | return 12 | 13 | function test1 14 | int handle = get_player_char 0 15 | int ptr = get_ped_pointer handle 16 | 17 | assert_ptr(ptr) 18 | end 19 | end -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0A97.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0A97" // get_vehicle_pointer 5 | test("0A97 (get_vehicle_pointer)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | 10 | it("should return a valid pointer", test1) 11 | return 12 | 13 | function test1 14 | request_model 400 15 | load_all_models_now 16 | int handle = create_car 400 {xyz} 0.0 0.0 0.0 17 | 18 | int ptr = 0 19 | ptr = get_vehicle_pointer handle 20 | mark_car_as_no_longer_needed handle 21 | 22 | assert_ptr(ptr) 23 | end 24 | end -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0A98.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0A98" // get_vehicle_pointer 5 | test("0A98 (get_object_pointer)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | 10 | it("should return a valid pointer", test1) 11 | return 12 | 13 | function test1 14 | request_model 333 // golf club 15 | load_all_models_now 16 | int handle = create_object 333 {xyz} 0.0 0.0 0.0 17 | 18 | int ptr = 0 19 | ptr = get_object_pointer handle 20 | mark_object_as_no_longer_needed handle 21 | 22 | assert_ptr(ptr) 23 | end 24 | end -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AA3.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AA3" 5 | test("0AA3 (free_dynamic_library)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | 11 | it("should load and free library", test1) 12 | return 13 | 14 | function test1 15 | int lib = load_dynamic_library {fileName} "cleo.asi" 16 | assert_result_true() 17 | free_dynamic_library lib 18 | 19 | lib = load_dynamic_library {fileName} "cleo.asi" 20 | assert_result_true() 21 | 22 | int lib2 = load_dynamic_library {fileName} "cleo.asi" 23 | assert_result_true() 24 | 25 | assert_eq(lib, lib2) 26 | 27 | free_dynamic_library lib 28 | free_dynamic_library lib2 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AA4.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AA4" 5 | test("0AA4 (get_dynamic_library_procedure)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | 10 | it("should return address of Sleep function from kernel32.dll", test1) 11 | it("should get export by index", test2) 12 | return 13 | 14 | function test1 15 | int load_library_addr = read_memory 0x858070 4 false 16 | trace "Address of LoadLibrary function is %d" load_library_addr 17 | 18 | int kernel_dll_addr = call_function_return {address} load_library_addr {numParams} 1 {pop} 0 {funcParams} "kernel32.dll" // tested opcode 19 | if 20 | // lib address can be any valid pointer, not necessarily one loaded with 0AA2 opcode 21 | int sleep_addr = get_dynamic_library_procedure {procName} "Sleep" {DynamicLibrary} kernel_dll_addr 22 | then 23 | assert(true) 24 | else 25 | assert(false) 26 | end 27 | end 28 | 29 | function test2 30 | int load_library_addr = read_memory 0x858070 4 false 31 | 32 | int kernel_dll_addr = call_function_return {address} load_library_addr {numParams} 1 {pop} 0 {funcParams} "kernel32.dll" // tested opcode 33 | if 34 | // lib address can be any valid pointer, not necessarily one loaded with 0AA2 opcode 35 | int sleep_addr = get_dynamic_library_procedure {procName} 1 {DynamicLibrary} kernel_dll_addr 36 | then 37 | assert(true) 38 | else 39 | assert(false) 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AA8.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AA8" 5 | test("0AA8 (call_method_return)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should call class getter method", test1) 10 | it_cs4("should ignore null 'this' in legacy modes", test2) 11 | it_cs4("should handle misused 'this' in legacy modes", test3) 12 | return 13 | 14 | function test1 15 | int charPtr = get_ped_pointer {char} $scplayer 16 | int result = call_method_return {address} 0x00411990 {struct} charPtr {numParams} 0 {pop} 0 // CEntity.GetMatrix() 17 | int matrixPtr = read_memory_with_offset {address} charPtr {offset} 0x14 {size} 4 // CEntity::m_matrix 18 | assert_eq(result, matrixPtr) 19 | end 20 | 21 | function test2 22 | int result = call_method_return {address} 0x00826330 {struct} 0 {numParams} 1 {pop} 1 {funcParams} "test" // size_t strlen(const char *Str) 23 | assert_eq(result, 4) 24 | end 25 | 26 | function test3 27 | int funcPtr = get_label_pointer @ret_ecx 28 | int result = call_method_return {address} funcPtr {struct} 10 {numParams} 0 {pop} 0 29 | assert_eq(result, 11) 30 | end 31 | end 32 | 33 | :ret_ecx 34 | hex 35 | 89 C8 // mov eax, ecx 36 | 40 // inc eax 37 | C3 // retn 38 | end 39 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AC6.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AC6" // get_label_pointer 5 | test("0AC6 (get_label_pointer)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | 10 | it("should return valid pointer", test1) 11 | return 12 | 13 | function test1 14 | int ptr = 0 15 | ptr = get_label_pointer @DATA 16 | int number = 0xCCCCCCCC 17 | number = read_memory ptr {size} 4 {vp} false 18 | assert_ptr(ptr) 19 | assert_eq(number, 0x11223344) 20 | end 21 | 22 | :DATA 23 | hex 24 | 44 33 22 11 25 | "some longer testing text" 00 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AC7.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AC7" // get_var_pointer 5 | test("0AC7 (get_var_pointer)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | 10 | it("should return valid pointer", test1) 11 | return 12 | 13 | function test1 14 | int val1 = 0x11223344 15 | int val2 = 0xCCCCCCCC 16 | int ptr = get_var_pointer val1 17 | val2 = read_memory ptr {size} 4 {vp} false 18 | 19 | assert_ptr(ptr) 20 | assert_eq(val1, 0x11223344) 21 | assert_eq(val2, 0x11223344) 22 | end 23 | 24 | :DATA 25 | hex 26 | 44 33 22 11 27 | "some longer testing text" 00 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AC8.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AC8" // allocate_memory 5 | test("0AC8 (allocate_memory)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | 10 | before_each(@allocate) 11 | after_each(@free) 12 | 13 | it("should return valid pointer", test1) 14 | it("should point to zero-filled mem in CLEO5", test2) 15 | return 16 | 17 | function test1 18 | // 0@ is set in before_each callback 19 | assert_ptr(0@) 20 | assert_neq(0@, 0x11223344) 21 | end 22 | 23 | function test2 24 | 2@ = 0xCCCCCCCC 25 | 2@ = read_memory 0@ {size} 4 {vp} false 26 | assert_eq(2@, 0) 27 | end 28 | 29 | :allocate 30 | 0@ = 0x11223344 31 | 0@ = allocate_memory {size} 4 32 | return 33 | 34 | :free 35 | free_memory {address} 0@ 36 | return 37 | 38 | 39 | end -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AC9.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AC9" // free_memory 5 | test("0AC9 (free_memory)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | 10 | it("should free allocated memory", test1) 11 | return 12 | 13 | function test1 14 | int ptr = 0x11223344 15 | ptr = allocate_memory {size} 4 16 | free_memory ptr 17 | 18 | // not much to check within script. Did not crashed the game or printed error, so perhaps ok 19 | assert(true) 20 | end 21 | end -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AE9.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AE9" // pop_float 5 | test("0AE9 (pop_float)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | 10 | it("should pop float from stack", test1) 11 | return 12 | 13 | 14 | function test1 15 | 0@s = '42.5' 16 | 2@ = get_var_pointer 0@ 17 | call_function 0x0823CEE {argCount} 1 {pop} 1 {arg} 2@ // double atof(const char *) 18 | 19 | pop_float {result} 3@ 20 | 21 | 3@ == 42.5 22 | assert_result_true() 23 | 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AEA.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AEA" // get_ped_ref 5 | test("0AEA (get_ped_ref)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should return ped handle for pointer", test1) 10 | return 11 | 12 | function test1 13 | int handle = get_player_char 0 14 | int ptr = get_ped_pointer handle 15 | int handle2 = get_ped_ref ptr 16 | 17 | handle == handle2 18 | assert_result_true() 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AEB.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AEB" // get_vehicle_ref 5 | test("0AEB (get_vehicle_ref)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should return vehicle handle for pointer", test1) 10 | return 11 | 12 | function test1 13 | request_model 400 14 | load_all_models_now 15 | int handle = create_car 400 {xyz} 0.0 0.0 0.0 16 | int ptr = get_vehicle_pointer handle 17 | int handle2 = get_vehicle_ref ptr 18 | mark_car_as_no_longer_needed handle 19 | 20 | handle == handle2 21 | assert_result_true() 22 | end 23 | end 24 | 25 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/0AEC.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name "0AEC" // get_object_ref 5 | test("0AEC (get_object_ref)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should return vehicle handle for pointer", test1) 10 | return 11 | 12 | function test1 13 | request_model 333 // golf club 14 | load_all_models_now 15 | int handle = create_object 333 {xyz} 0.0 0.0 0.0 16 | int ptr = get_object_pointer handle 17 | int handle2 = get_object_ref ptr 18 | mark_object_as_no_longer_needed handle 19 | 20 | handle == handle2 21 | assert_result_true() 22 | end 23 | end 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/2403.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | var 0@ : Integer 5 | var 1@ : Integer 6 | var 2@ : Integer 7 | var 3@ : Integer 8 | var 4@ : Integer 9 | var 5@ : Integer 10 | var 6@ : Integer 11 | var 7@ : Integer 12 | var 8@ : Integer 13 | var 9@ : Integer 14 | var 10@ : Integer 15 | 16 | script_name "2403" // forget_memory 17 | debug_on 18 | 19 | trace "2403 (forget_memory)" 20 | 21 | 22 | wait 0 23 | 0@ = 0x11223344 24 | allocate_memory {size} 4 {result} 0@ 25 | 26 | 2403: forget_memory 0@ // tested opcode 27 | 28 | // not much to check within script. Did not crashed the game or printed error, so perhaps ok 29 | trace "~g~~h~~h~2403 (forget_memory), #0 PASSED" 30 | 31 | 32 | terminate_this_custom_script 33 | -------------------------------------------------------------------------------- /tests/cleo_tests/MemoryOperations/2404.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$USE debug} 3 | {$USE memory} 4 | var 0@ : Integer 5 | var 1@ : Integer 6 | var 2@ : Integer 7 | var 3@ : Integer 8 | var 4@ : Integer 9 | var 5@ : Integer 10 | var 6@ : Integer 11 | var 7@ : Integer 12 | var 8@ : Integer 13 | var 9@ : Integer 14 | var 10@ : Integer 15 | 16 | script_name "2404" // get_script_struct_just_created 17 | debug_on 18 | 19 | trace "2404 (get_script_struct_just_created)" 20 | 21 | // no wait! 22 | 2404: get_script_struct_just_created 0@ // tested opcode 23 | 24 | get_this_script_struct 1@ 25 | 26 | if 27 | 0@ == 1@ // this script is last created one 28 | then 29 | trace "~g~~h~~h~2404 (get_script_struct_just_created), #0 PASSED" 30 | else 31 | breakpoint "~r~~h~~h~~h~2404 (get_script_struct_just_created), #0 FAILED!~n~%08x Expected~n~%08x Occured" 1@ 0@ 32 | end 33 | 34 | 35 | terminate_this_custom_script 36 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/0AD3.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0AD3' 5 | test("0AD3 (string_format)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("should format string", test1) 11 | it("should respect short string variable size", test2) 12 | it("should respect long string variable size", test3) 13 | it("should create long text", test4) 14 | 15 | return 16 | 17 | function test1 18 | string_format {buffer} 0@v {format} "" {args} 19 | assert_eqs(0@v, "") 20 | 21 | string_format {buffer} 0@v {format} "test" {args} 22 | assert_eqs(0@v, "test") 23 | 24 | string_format {buffer} 0@v {format} "char %c" {args} 0x41 25 | assert_eqs(0@v, "char A") 26 | 27 | string_format {buffer} 0@v {format} "int %d" {args} 3 28 | assert_eqs(0@v, "int 3") 29 | 30 | string_format {buffer} 0@v {format} "hex %x" {args} 0x123 31 | assert_eqs(0@v, "hex 123") 32 | 33 | string_format {buffer} 0@v {format} "num %0.1f" {args} 1.234 34 | assert_eqs(0@v, "num 1.2") 35 | 36 | string_format {buffer} 0@v {format} "str %s" {args} "text" 37 | assert_eqs(0@v, "str text") 38 | end 39 | 40 | function test2 41 | 0@ = 0xAAAAAAAA 42 | 1@ = 0xBBBBBBBB 43 | 2@ = 0xCCCCCCCC 44 | 45 | string_format {buffer} 0@s {format} "some longer test text" {args} 46 | 47 | assert_eqs(0@s, "some lon") // clamped to size 48 | assert_eq(2@, 0xCCCCCCCC) 49 | end 50 | 51 | function test3 52 | 0@ = 0xAAAAAAAA 53 | 1@ = 0xBBBBBBBB 54 | 2@ = 0xCCCCCCCC 55 | 3@ = 0xDDDDDDDD 56 | 4@ = 0xEEEEEEEE 57 | 58 | string_format {buffer} 0@v {format} "some longer test text" {args} 59 | 60 | assert_eqs(0@v, "some longer test") // clamped to size 61 | assert_eq(4@, 0xEEEEEEEE) 62 | end 63 | 64 | function test4 65 | 0@ = allocate_memory {size} 64 66 | 67 | string_format {buffer} 0@ {format} "some longer test text" {args} 68 | 69 | assert_eqs(0@, "some longer test text") // not clamped 70 | free_memory 0@ 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/0AD4.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0AD4' 5 | test("0AD4 (scan_string)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("should scan numbers", test1) 11 | it("should scan characters", test2) 12 | it("should scan strings", test3) 13 | it("should report arg count missmatch", test4) 14 | it("should respect target string size", test5) 15 | return 16 | 17 | function test1 18 | scan_string {string} "input 1 2 4 8.0 16.0 32.0" {format} "input %d %d %d %f %f %f" {var_nValues} 0@ {var_values} 1@ 2@ 3@ 4@ 5@ 6@ 19 | assert_result_true() 20 | assert_eq(0@, 6) // read values count 21 | assert_eq(1@, 1) 22 | assert_eq(2@, 2) 23 | assert_eq(3@, 4) 24 | assert_eqf(4@, 8.0) 25 | assert_eqf(5@, 16.0) 26 | assert_eqf(6@, 32.0) 27 | end 28 | 29 | function test2 30 | scan_string {string} "ABC" {format} "%c%c%c" {var_nValues} 0@ {var_values} 1@ 2@ 3@ 31 | assert_result_true() 32 | assert_eq(0@, 3) // read values count 33 | assert_eq(1@, 0x41) // A 34 | assert_eq(2@, 0x42) // B 35 | assert_eq(3@, 0x43) // C 36 | end 37 | 38 | function test3 39 | scan_string {string} "some testing text" {format} "%s %s %s" {var_nValues} 0@ {var_values} 1@s 3@s 5@s 40 | assert_result_true() 41 | assert_eq(0@, 3) // read values count 42 | assert_eqs(1@s, "some") 43 | assert_eqs(3@s, "testing") 44 | assert_eqs(5@s, "text") 45 | end 46 | 47 | function test4 48 | 3@ = 0xCCCCCCCC 49 | scan_string {string} "input 1 2" {format} "input %d %d %d" {var_nValues} 0@ {var_values} 1@ 2@ 3@ 50 | assert_result_false() 51 | assert_eq(0@, 2) // read values count 52 | assert_eq(1@, 1) 53 | assert_eq(2@, 2) 54 | assert_eq(3@, 0xCCCCCCCC) // unchanged 55 | end 56 | 57 | function test5 58 | 1@ = 0x77777777 59 | 2@ = 0x88888888 60 | 3@ = 0x99999999 61 | 4@ = 0xAAAAAAAA 62 | 5@ = 0xBBBBBBBB 63 | 6@ = 0xCCCCCCCC 64 | 7@ = 0xDDDDDDDD 65 | 8@ = 0xEEEEEEEE 66 | 67 | scan_string {string} "first_very_long_test_text second_very_long_test_text" {format} "%s %s" {var_nValues} 0@ {var_values} 1@s 4@v, 68 | assert_result_true() 69 | assert_eq(0@, 2) // read values count 70 | assert_eqs(1@s, "first_ve") // clamped to variable size 71 | assert_eq(3@, 0x99999999) // unchanged 72 | assert_eqs(4@v, "second_very_long") // clamped to variable size 73 | assert_eq(8@, 0xEEEEEEEE) // unchanged 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/0ADB.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0ADB' 5 | test("0ADB (get_name_of_vehicle_model)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should return vehicle model name", test1) 10 | it("should store vehicle name in static buffer", test2) 11 | 12 | return 13 | 14 | function test1 15 | 0@v = get_name_of_vehicle_model {modelId} 400 16 | assert_eqs(0@v, "LANDSTK") 17 | end 18 | 19 | function test2 20 | get_name_of_vehicle_model 400 0xC16F98 21 | assert_eqs(0xC16F98, "LANDSTK") 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/0ADE.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0ADE' 5 | test("0ADE (get_text_label_string)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should return into variable", test1) 10 | it("should return source pointer", test2) 11 | it("should return empty", test3) 12 | return 13 | 14 | function test1 15 | 0@v = get_text_label_string {key} 'DEAD' 16 | assert_eqs(0@v, "Wasted") 17 | end 18 | 19 | function test2 20 | 0@ = get_text_label_string {key} 'DEAD' 21 | assert_ptr(0@) 22 | assert_eqs(0@, "Wasted") 23 | end 24 | 25 | function test3 26 | 0@v = get_text_label_string {key} 'CL_INVA' // invalid label 27 | assert_eqs(0@v, "") 28 | 29 | 0@ = get_text_label_string {key} 'CL_INVA' // invalid label 30 | assert_eqs(0@, "") 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/0ADF.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0ADF' 5 | test("0ADF (add_text_label)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should add dynamic GXT", test1) 10 | return 11 | 12 | function test1 13 | // gxt entry not present yet 14 | 0@v = get_text_label_string {key} 'CLE0ADF' 15 | assert_eqs(0@v, "") 16 | 17 | add_text_label {dynamicKey} 'CLE0ADF' {text} "cleo test" 18 | 0@v = get_text_label_string {key} 'CLE0ADF' 19 | assert_eqs(0@v, "cleo test") 20 | 21 | remove_text_label {key} 'CLE0ADF' // cleanup 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/0AE0.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0AE0' 5 | test("0AE0 (remove_text_label)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should remove dynamic GXT", test1) 10 | return 11 | 12 | function test1 13 | // gxt entry not present yet 14 | 0@v = get_text_label_string {key} 'CLE0AE0' 15 | assert_eqs(0@v, "") 16 | 17 | add_text_label {dynamicKey} 'CLE0AE0' {text} "cleo test" 18 | 0@v = get_text_label_string {key} 'CLE0AE0' 19 | assert_eqs(0@v, "cleo test") 20 | 21 | remove_text_label {key} 'CLE0AE0' 22 | 0@v = get_text_label_string {key} 'CLE0AE0' 23 | assert_eqs(0@v, "") // successfully removed 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/0AED.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '0AED' 5 | test("0AED (string_float_format)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("should print float", test1) 11 | return 12 | 13 | function test1 14 | 0@v = string_float_format {number} 1.66666 {format} "Float %0.3f" 15 | assert_eqs(0@v, "Float 1.667") 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/2600.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2600' 5 | test("2600 (is_text_empty)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("short string should be empty", test1) 11 | it("short string should NOT be empty", test2) 12 | it("long string should be empty", test3) 13 | it("long string should NOT be empty", test4) 14 | it("buffer string should be empty", test5) 15 | it("buffer string should NOT be empty", test6) 16 | return 17 | 18 | function test1 19 | 1@s = '' 20 | is_text_empty 1@s 21 | assert_result_true() 22 | end 23 | 24 | function test2 25 | 1@s = 'test' 26 | is_text_empty 1@s 27 | assert_result_false() 28 | end 29 | 30 | function test3 31 | 1@v = "" 32 | is_text_empty 1@v 33 | assert_result_true() 34 | end 35 | 36 | function test4 37 | 1@v = "test" 38 | is_text_empty 1@s 39 | assert_result_false() 40 | end 41 | 42 | function test5 43 | 1@ = allocate_memory {size} 64 // 0 prefill in CLEO5 44 | is_text_empty 1@ 45 | assert_result_true() 46 | end 47 | 48 | function test6 49 | 1@ = allocate_memory {size} 64 50 | string_format {buffer} 1@ {format} "some text" 51 | is_text_empty 1@ 52 | assert_result_false() 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/2601.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2601' 5 | test("2601 (is_text_equal)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | before_each(@prepare_tests) 11 | after_each(@cleanup_tests) 12 | 13 | it("should texts be equal", test1) 14 | it("should texts be NOT equal", test2) 15 | return 16 | 17 | :prepare_tests 18 | 0@s = 'text-A' 19 | 2@s = 'text-B' 20 | 4@v = "text-A" 21 | 8@v = "text-B" 22 | 12@ = allocate_memory {size} 64 23 | string_format {buffer} 12@ {format} "text-A" 24 | 13@ = allocate_memory {size} 64 25 | string_format {buffer} 13@ {format} "text-B" 26 | 14@ = allocate_memory {size} 64 27 | string_format {buffer} 14@ {format} "TEXT-A" 28 | 15@ = allocate_memory {size} 64 29 | string_format {buffer} 15@ {format} "tExT-b" 30 | return 31 | 32 | :cleanup_tests 33 | free_memory {address} 12@ 34 | free_memory {address} 13@ 35 | free_memory {address} 14@ 36 | free_memory {address} 15@ 37 | return 38 | 39 | function test1 40 | is_text_equal {text} 0@s {another} 0@s {ignoreCase} false 41 | assert_result_true() 42 | 43 | is_text_equal {text} 0@s {another} 0@s {ignoreCase} true 44 | assert_result_true() 45 | 46 | is_text_equal {text} 0@s {another} 4@v {ignoreCase} false 47 | assert_result_true() 48 | 49 | is_text_equal {text} 0@s {another} 4@v {ignoreCase} true 50 | assert_result_true() 51 | 52 | is_text_equal {text} 0@s {another} 12@ {ignoreCase} false 53 | assert_result_true() 54 | 55 | is_text_equal {text} 0@s {another} 12@ {ignoreCase} true 56 | assert_result_true() 57 | 58 | // case mismatch 59 | is_text_equal {text} 0@s {another} 14@ {ignoreCase} true 60 | assert_result_true() 61 | 62 | is_text_equal {text} 8@v {another} 15@ {ignoreCase} true 63 | assert_result_true() 64 | end 65 | 66 | function test2 67 | is_text_equal {text} 0@s {another} 2@s {ignoreCase} false 68 | assert_result_false() 69 | 70 | is_text_equal {text} 0@s {another} 2@s {ignoreCase} true 71 | assert_result_false() 72 | 73 | is_text_equal {text} 4@v {another} 8@v {ignoreCase} false 74 | assert_result_false() 75 | 76 | is_text_equal {text} 4@v {another} 8@v {ignoreCase} true 77 | assert_result_false() 78 | 79 | is_text_equal {text} 4@v {another} 13@ {ignoreCase} false 80 | assert_result_false() 81 | 82 | is_text_equal {text} 4@v {another} 13@ {ignoreCase} true 83 | assert_result_false() 84 | 85 | // case mismatch 86 | is_text_equal {text} 0@s {another} 14@ {ignoreCase} false 87 | assert_result_false() 88 | 89 | is_text_equal {text} 8@v {another} 15@ {ignoreCase} false 90 | assert_result_false() 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/2602.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2602' 5 | test("2602 (is_text_in_text)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("should contain sub-text", test1) 11 | it("should NOT contain sub-text", test2) 12 | return 13 | 14 | function test1 15 | is_text_in_text {text} "the_longer test_text" {subText} "the_longer test_text" {ignoreCase} false 16 | assert_result_true() 17 | 18 | is_text_in_text {text} "the_longer test_text" {subText} "the_longer test_text" {ignoreCase} true 19 | assert_result_true() 20 | 21 | is_text_in_text {text} "the_longer test_text" {subText} "long" {ignoreCase} false 22 | assert_result_true() 23 | 24 | is_text_in_text {text} "the_longer test_text" {subText} "long" {ignoreCase} true 25 | assert_result_true() 26 | 27 | is_text_in_text {text} "the_longer test_text" {subText} "_" {ignoreCase} false 28 | assert_result_true() 29 | 30 | is_text_in_text {text} "the_longer test_text" {subText} "_" {ignoreCase} true 31 | assert_result_true() 32 | 33 | is_text_in_text {text} "the_longer test_text" {subText} "" {ignoreCase} false 34 | assert_result_true() 35 | 36 | is_text_in_text {text} "the_longer test_text" {subText} "" {ignoreCase} true 37 | assert_result_true() 38 | 39 | is_text_in_text {text} "" {subText} "" {ignoreCase} false 40 | assert_result_true() 41 | 42 | is_text_in_text {text} "" {subText} "" {ignoreCase} true 43 | assert_result_true() 44 | 45 | // case mismatch 46 | is_text_in_text {text} "the_longer test_text" {subText} "THE" {ignoreCase} true 47 | assert_result_true() 48 | 49 | is_text_in_text {text} "the_longer test_text" {subText} "LonGer" {ignoreCase} true 50 | assert_result_true() 51 | end 52 | 53 | function test2 54 | is_text_in_text {text} "long" {subText} "the_longer test_text" {ignoreCase} false 55 | assert_result_false() 56 | 57 | is_text_in_text {text} "long" {subText} "the_longer test_text" {ignoreCase} true 58 | assert_result_false() 59 | 60 | is_text_in_text {text} "the_longer test_text" {subText} "other" {ignoreCase} false 61 | assert_result_false() 62 | 63 | is_text_in_text {text} "the_longer test_text" {subText} "other" {ignoreCase} true 64 | assert_result_false() 65 | 66 | is_text_in_text {text} "" {subText} "other" {ignoreCase} false 67 | assert_result_false() 68 | 69 | is_text_in_text {text} "" {subText} "other" {ignoreCase} true 70 | assert_result_false() 71 | 72 | // case mismatch 73 | is_text_in_text {text} "the_longer test_text" {subText} "THE" {ignoreCase} false 74 | assert_result_false() 75 | 76 | is_text_in_text {text} "the_longer test_text" {subText} "LonGer" {ignoreCase} false 77 | assert_result_false() 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/2603.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2603' 5 | test("2603 (is_text_prefix)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("should contain text prefix", test1) 11 | it("should NOT contain text prefix", test2) 12 | return 13 | 14 | function test1 15 | is_text_prefix {text} "the_longer test_text" {prefix} "" {ignoreCase} false 16 | assert_result_true() 17 | 18 | is_text_prefix {text} "the_longer test_text" {prefix} "" {ignoreCase} true 19 | assert_result_true() 20 | 21 | is_text_prefix {text} "the_longer test_text" {prefix} "t" {ignoreCase} false 22 | assert_result_true() 23 | 24 | is_text_prefix {text} "the_longer test_text" {prefix} "t" {ignoreCase} true 25 | assert_result_true() 26 | 27 | is_text_prefix {text} "the_longer test_text" {prefix} "the" {ignoreCase} false 28 | assert_result_true() 29 | 30 | is_text_prefix {text} "the_longer test_text" {prefix} "the" {ignoreCase} true 31 | assert_result_true() 32 | 33 | is_text_prefix {text} "the_longer test_text" {prefix} "the_longer " {ignoreCase} false 34 | assert_result_true() 35 | 36 | is_text_prefix {text} "the_longer test_text" {prefix} "the_longer " {ignoreCase} true 37 | assert_result_true() 38 | 39 | is_text_prefix {text} "the_longer test_text" {prefix} "the_longer test_text" {ignoreCase} false 40 | assert_result_true() 41 | 42 | is_text_prefix {text} "the_longer test_text" {prefix} "the_longer test_text" {ignoreCase} true 43 | assert_result_true() 44 | 45 | // case mismatch 46 | is_text_prefix {text} "the_longer test_text" {prefix} "THE" {ignoreCase} true 47 | assert_result_true() 48 | 49 | is_text_prefix {text} "the_longer test_text" {prefix} "tHe_LoNgEr" {ignoreCase} true 50 | assert_result_true() 51 | end 52 | 53 | function test2 54 | is_text_prefix {text} "the_longer test_text" {prefix} "longer" {ignoreCase} false 55 | assert_result_false() 56 | 57 | is_text_prefix {text} "the_longer test_text" {prefix} "longer" {ignoreCase} true 58 | assert_result_false() 59 | 60 | is_text_prefix {text} "the_longer test_text" {prefix} "he" {ignoreCase} false 61 | assert_result_false() 62 | 63 | is_text_prefix {text} "the_longer test_text" {prefix} "he" {ignoreCase} true 64 | assert_result_false() 65 | 66 | is_text_prefix {text} "the" {prefix} "the_longer test_text" {ignoreCase} false 67 | assert_result_false() 68 | 69 | is_text_prefix {text} "the" {prefix} "the_longer test_text" {ignoreCase} true 70 | assert_result_false() 71 | 72 | // case mismatch 73 | is_text_prefix {text} "the_longer test_text" {prefix} "THE" {ignoreCase} false 74 | assert_result_false() 75 | 76 | is_text_prefix {text} "the_longer test_text" {prefix} "tHe_LoNgEr" {ignoreCase} false 77 | assert_result_false() 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/2604.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2604' 5 | test("2604 (is_text_suffix)", tests) 6 | terminate_this_custom_script 7 | 8 | 9 | function tests 10 | it("should contain text suffix", test1) 11 | it("should NOT contain text suffix", test2) 12 | return 13 | 14 | function test1 15 | is_text_suffix {text} "the_longer test_text" {suffix} "" {ignoreCase} false 16 | assert_result_true() 17 | 18 | is_text_suffix {text} "the_longer test_text" {suffix} "" {ignoreCase} false 19 | assert_result_true() 20 | 21 | is_text_suffix {text} "the_longer test_text" {suffix} "t" {ignoreCase} false 22 | assert_result_true() 23 | 24 | is_text_suffix {text} "the_longer test_text" {suffix} "t" {ignoreCase} true 25 | assert_result_true() 26 | 27 | is_text_suffix {text} "the_longer test_text" {suffix} "text" {ignoreCase} false 28 | assert_result_true() 29 | 30 | is_text_suffix {text} "the_longer test_text" {suffix} "text" {ignoreCase} true 31 | assert_result_true() 32 | 33 | is_text_suffix {text} "the_longer test_text" {suffix} " test_text" {ignoreCase} false 34 | assert_result_true() 35 | 36 | is_text_suffix {text} "the_longer test_text" {suffix} " test_text" {ignoreCase} true 37 | assert_result_true() 38 | 39 | is_text_suffix {text} "the_longer test_text" {suffix} "the_longer test_text" {ignoreCase} false 40 | assert_result_true() 41 | 42 | is_text_suffix {text} "the_longer test_text" {suffix} "the_longer test_text" {ignoreCase} true 43 | assert_result_true() 44 | 45 | // case mismatch 46 | is_text_suffix {text} "the_longer test_text" {suffix} "EXT" {ignoreCase} true 47 | assert_result_true() 48 | 49 | is_text_suffix {text} "the_longer test_text" {suffix} "tEsT_TeXt" {ignoreCase} true 50 | assert_result_true() 51 | end 52 | 53 | function test2 54 | is_text_suffix {text} "the_longer test_text" {suffix} "tex" {ignoreCase} false 55 | assert_result_false() 56 | 57 | is_text_suffix {text} "the_longer test_text" {suffix} "tex" {ignoreCase} true 58 | assert_result_false() 59 | 60 | is_text_suffix {text} "text" {suffix} "the_longer test_text" {ignoreCase} false 61 | assert_result_false() 62 | 63 | is_text_suffix {text} "text" {suffix} "the_longer test_text" {ignoreCase} true 64 | assert_result_false() 65 | 66 | // case mismatch 67 | is_text_suffix {text} "the_longer test_text" {suffix} "EXT" {ignoreCase} false 68 | assert_result_false() 69 | 70 | is_text_suffix {text} "the_longer test_text" {suffix} "tEsT_TeXt" {ignoreCase} false 71 | assert_result_false() 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/2606.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2606' 5 | test("2606 (load_fxt)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("GXTs should not exists yet", test1) 10 | it("should load new GXTs", test2) 11 | return 12 | 13 | function test1 14 | int ptr 15 | 16 | ptr = get_text_label_string {key} 'CLEO_T1' 17 | assert_ptr(ptr) 18 | assert_eqs(ptr, "") 19 | 20 | ptr = get_text_label_string {key} 'CLEO_T2' 21 | assert_ptr(ptr) 22 | assert_eqs(ptr, "") 23 | 24 | ptr = get_text_label_string {key} 'CLEO_T3' 25 | assert_ptr(ptr) 26 | assert_eqs(ptr, "") 27 | end 28 | 29 | function test2 30 | 2606: load_fxt {filepath} "cleo\cleo_tests\text\non existing file.fxt" 31 | assert_result_false() 32 | 33 | 2606: load_fxt {filepath} "cleo\cleo_tests\text\test.fxt" 34 | assert_result_true() 35 | 36 | int ptr 37 | 38 | ptr = get_text_label_string {key} 'CLEO_T1' 39 | assert_ptr(ptr) 40 | assert_eqs(ptr, "Test one") 41 | 42 | ptr = get_text_label_string {key} 'CLEO_T2' 43 | assert_ptr(ptr) 44 | assert_eqs(ptr, "Test two") 45 | 46 | ptr = get_text_label_string {key} 'CLEO_T3' 47 | assert_ptr(ptr) 48 | assert_eqs(ptr, "Test three") 49 | 50 | // load again 51 | 2606: load_fxt {filepath} "cleo\cleo_tests\text\test.fxt" 52 | assert_result_true() 53 | 54 | unload_fxt {filepath} "cleo\cleo_tests\text\test.fxt" 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/2607.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2607' 5 | test("2607 (unload_fxt)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("GXTs should not exists yet", test1) 10 | it("should load new GXTs", test2) 11 | it("should unload GXTs", test3) 12 | return 13 | 14 | function test1 15 | int ptr 16 | 17 | ptr = get_text_label_string {key} 'CLEO_T1' 18 | assert_ptr(ptr) 19 | assert_eqs(ptr, "") 20 | 21 | ptr = get_text_label_string {key} 'CLEO_T2' 22 | assert_ptr(ptr) 23 | assert_eqs(ptr, "") 24 | 25 | ptr = get_text_label_string {key} 'CLEO_T3' 26 | assert_ptr(ptr) 27 | assert_eqs(ptr, "") 28 | end 29 | 30 | function test2 31 | load_fxt {filepath} "cleo\cleo_tests\text\test.fxt" 32 | assert_result_true() 33 | 34 | int ptr 35 | 36 | ptr = get_text_label_string {key} 'CLEO_T1' 37 | assert_ptr(ptr) 38 | assert_eqs(ptr, "Test one") 39 | 40 | ptr = get_text_label_string {key} 'CLEO_T2' 41 | assert_ptr(ptr) 42 | assert_eqs(ptr, "Test two") 43 | 44 | ptr = get_text_label_string {key} 'CLEO_T3' 45 | assert_ptr(ptr) 46 | assert_eqs(ptr, "Test three") 47 | 48 | // load again 49 | load_fxt {filepath} "cleo\cleo_tests\text\test.fxt" 50 | assert_result_true() 51 | end 52 | 53 | function test3 54 | 2607: unload_fxt {filepath} "cleo\cleo_tests\text\non existing file.fxt" 55 | assert_result_false() 56 | 57 | 2607: unload_fxt {filepath} "cleo\cleo_tests\text\test.fxt" 58 | assert_result_true() 59 | 60 | int ptr 61 | 62 | ptr = get_text_label_string {key} 'CLEO_T1' 63 | assert_ptr(ptr) 64 | assert_eqs(ptr, "") 65 | 66 | ptr = get_text_label_string {key} 'CLEO_T2' 67 | assert_ptr(ptr) 68 | assert_eqs(ptr, "") 69 | 70 | ptr = get_text_label_string {key} 'CLEO_T3' 71 | assert_ptr(ptr) 72 | assert_eqs(ptr, "") 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/2608.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2608' 5 | test("2608 (get_text_length)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should return text length", test1) 10 | return 11 | 12 | function test1 13 | int length 14 | 15 | shortstring short = 'One' 16 | 2608: get_text_length {text} short {length} length 17 | assert_eq(length, 3) 18 | 19 | string_format short = '' 20 | 2608: get_text_length {text} short {length} length 21 | assert_eq(length, 0) 22 | 23 | longstring long = "Longer string" 24 | 2608: get_text_length {text} long {length} length 25 | assert_eq(length, 13) 26 | 27 | int buff = allocate_memory {size} 255 28 | string_format buff = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc et tellus vehicula, tempus felis malesuada, commodo nunc. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam condimentum porttitor lorem est." 29 | 2608: get_text_length {text} buff {length} length 30 | free_memory {address} buff 31 | assert_eq(length, 220) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/2609.txt: -------------------------------------------------------------------------------- 1 | {$CLEO .s} 2 | {$INCLUDE_ONCE ../cleo_tester.inc} 3 | 4 | script_name '2609' 5 | test("2609 (add_text_label_formatted)", tests) 6 | terminate_this_custom_script 7 | 8 | function tests 9 | it("should add dynamic GXT", test1) 10 | return 11 | 12 | function test1 13 | // gxt entry not present yet 14 | 0@v = get_text_label_string {key} 'CLE2609' 15 | assert_eqs(0@v, "") 16 | 17 | add_text_label_formatted {dynamicKey} 'CLE2609' {format} "cleo %s %d" {args} "test" 42 18 | 0@v = get_text_label_string {key} 'CLE2609' 19 | assert_eqs(0@v, "cleo test 42") 20 | 21 | remove_text_label {key} 'CLE2609' // cleanup 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /tests/cleo_tests/Text/Test.fxt: -------------------------------------------------------------------------------- 1 | CLEO_T1 Test one 2 | CLEO_T2 Test two 3 | CLEO_T3 Test three --------------------------------------------------------------------------------