~ CLEO Script Tutorial ~ (Page 1) / GTA Modding (2024)

CLEO Script Tutorial

english language

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

deutschsprachig

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
off topic:

CLEO GIRL GFXXX


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

INDEX

-First Steps in Cleo scripting with Sannybuilder
---------------------------------------
-The Editor
-Option: different view of the decompiled code
-Classes and Keywords
-Data types
---------------------------------------
-Scripting/Writing a Thread
-Using conditional checks
-The IF - Variation
- Script structure simple
- Script structure extended
-Script exemble: Slowmotion
-Spawn a 3D model
-Placing cars by using parked_car_generator
---------------------------------------
-Special Particularities in Cleo
---------------------------------------
-Script Exemble by using Special Global Cleo Variable/ Store a car at any place
-Template for Cleo Mission Script
-gosub

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

First Steps in Cleo scripting with Sannybuilder

Download newest version of Sannybuilder from Seemann at http://sannybuilder.com/

Install Sannybuilder and create a folder for your scripts
Therefor youre promt to indicate your GTASA-Install dir.

Then start Sannybuilder,
Open a new blank page, copy the script below and insert it into the new page.

{$CLEO .cs}:DEMOTEXT03A4: name_thread "DEMO"wait 1000:DEMOTEXT_1wait 0if0256: player $PLAYER_CHAR defined 004D: jump_if_false @DEMOTEXT_1if00E1: key_pressed 0 17004D: jump_if_false @DEMOTEXT_100BA: text_styled 'FEM_OK' 1000 ms 10A93: end_custom_thread

Save it in your Sannyscript folder and give it a name.
~ CLEO Script Tutorial ~ (Page 1) / GTA Modding (1)

Compile the script. Click on menue icon with "running man" to choose compile + copy
If the CLEO - Library is installed, the script will be compiled and copied in to GTASA\CLEO - folder

The Cleo script file get then the file extension, which is written in the Cleo Script directive at the beginning of the script

{$CLEO .cs} = Cleo directive will be compiled to *.cs
As DEMOTEXT.txt saved and compiled as DEMOTEXT.cs

______________________________________________________________________________________

If CLEO is not installed, then sannybuilder will prompt you to do it and at the lower right corner of the editor
appears the CLEO - box with a red border. Click on it and Sannybuilder installs Cleo immediately.
Or download the cleo auto install exe at http://cleo.sannybuilder.com
______________________________________________________________________________________

If the compiling process was successful you get then a report message
~ CLEO Script Tutorial ~ (Page 1) / GTA Modding (2)
click on OK to confirm
the lower value "Largest Script" shows the script file size
the other values belongs to a compiling process of a main.scm

Test then the script ingame, press fire button to display the text message "OK"
The script ends then, will be deactivated because it ends with opcode 0A93: end_custom_thread

______________________________________________________________________________________
______________________________________________________________________________________

The Editor

The main functions can be found as icon button in the menue bar

1. Decompile: sanny opens script files with extensions .CS, .CM or .SCM

2. Compile: sanny compiles by default to a [Name]main.SCM

Sanny compiles automaticly to Cleoscript files, if the script have a Cleo-Direktive as entry

{$CLEO .cs} = Cleo-Direktive, will be compiled to Name.CS
{$CLEO .cm} = Cleo-Direktive, will be compiled to Name.CM

~ CLEO Script Tutorial ~ (Page 1) / GTA Modding (3)

Useful tools

Choose TOOLS on menue, then IDE Tools >> Coords Manager
to read the x,y,z coordinate and the z-angle of the current player position if the game is running

Choose TOOLS on menue, then IDE Tools >> Opcode Search
to search for opcodes
type any keyword to find a codeline which include this word
or type an opcode to find the description
the foundings are allways existing lines of original main.scm

~ CLEO Script Tutorial ~ (Page 1) / GTA Modding (4)

Line numbers
Choose TOOLS, then options
in option menu EDITOR you can find the feature to switch Line numbers off/on
The line number is part of the editor, not of the script

The Sannybuilder HELP

Choose HELP on menue, then Content to find informations,
such like key_press numbers, weapon numbers, bodyparts etc..

~ CLEO Script Tutorial ~ (Page 1) / GTA Modding (5)

______________________________________________________________________________________
______________________________________________________________________________________

Option: different view of the decompiled code

Choose TOOLS, then options
in option menu GENERAL you can find the feature to switch between 2 ways for decompiling

either decompile by writing opcodes
or decompiling without opcodes

~ CLEO Script Tutorial ~ (Page 1) / GTA Modding (6)

1. Writing Opcodes
All entries are shown with their opcodes
The opcodes are the real programm codes of the script functions
and by showing them is like to see the name of the command
Script with opcodes:

:CARSL_643900D6: if 00E1: player 0 pressed_key 16 004D: jump_if_false @CARSL_6535 010B: 5@ = player $PLAYER_CHAR money 00D6: if 002D: 5@ >= 14@ // (int) 004D: jump_if_false @CARSL_6512 0012: 14@ *= -1 0109: player $PLAYER_CHAR money += 14@ 0002: jump @CARSL_6700

2. Without Opcodes
The script is more slim, maybe more clear (but not for me)
especially 004D: jump_if_false will be now jf
But not all opcodes are disappeared. Many codes must be used furthermore by applying their opcodes.
Script without opcodes:

:CARSL_6439if 00E1: player 0 pressed_key 16 jf @CARSL_6535 5@ = Player.Money($PLAYER_CHAR)if 002D: 5@ >= 14@ // (int) jf @CARSL_6512 14@ *= -1 Player.Money($PLAYER_CHAR) += 14@jump @CARSL_6700

By compiling it doesnt matter if you use codes with opcodes or without opcodes
You can merge everything and sanny compile it as well,
provided that the code is correct and codelines which includes opcodes by decompiling without opcodes
must be used furthermore by using opcodes

A special feature by decompiling without opcodes is to translate opcode based commands into
Classes and Keywords

For a couple of codes can be used CLASSES
Read more about classes in Sannybuilder-HELP theme: Coding >> Classes

This code by decompiling with writing opcodes
00AB: put_car 22@ at -1577.942 52.6333 40.0

will by shown by decompiling with without opcodes in this kind:

[b]Car[/b].PutAt(22@, -1577.942, 52.6333, 40.0)

the meaning of the code is defined by the class entries

Car= class-name
PutAt= class-member
name and member are combined with a dot in the middle
22@ = class-owner
class-owner and parameters are placed in brackets and separated with comma
(parameter = needed information for the command)

Sanny allows to use some KEYWORDS instead using opcodes

Opcode = Keyword
_____________
0001: = wait
00d6: = if
004d: = else_jump
004d: = jf
0002: = jump
0051: = return
0050: = gosub
016a: = fade
01B6: = set_weather
03a4: = thread
04BB: = select_interior
0417: = start_mission
00d8: = mission_cleanup
0317: = increment_mission_attempts

Instead writing
004D: jump_if_false @MAIN_6
can be written
jf @MAIN_6
or
else_jump @MAIN_6
you also can merge it
004D: jf @MAIN_6

______________________________________________________________________________________
______________________________________________________________________________________

Data types

: (doublepoint) marks a Label (adress)

:MAIN_1

@ is used for 2 different functions

1. in jump instruction to mark the label which should be reached

004D: jump_if_false @SAVE_50050: gosub @SAVE_140002: jump @SAVE_1

2. to mark LOCAL VARIABLES

The stuff in the game needs a identity for registration to can handle with it
The identities can be variable, for exemble by calculating something

The local variable is builded with the @ sign and a number
0@, 1@, ... 30@ from 0@ up to 31@ is possible, 32@ and 33@ are for timers, thats maximum in an .cs file

1@ defines a parked_car generator

014B: 1@ = init_parked_car_generator #PCJ600 0 17 1 alarm 0 door_lock 0 0 10000 at 2490.0 -1682.0 13.5 angle 90.0

1@ can then be used furthermore as variable name of the parked_car generator

014C: set_parked_car_generator 1@ cars_to_generate_to 101

$ is used to mark a GLOBAL VARIABLE

The stuff in the game needs a identity for registration to can handle with it
The identities can be variable, for exemble by calculating something

The global variable is builded with the $ sign and a a letter or a word or a number or both
But using global variables in Cleo scripts can cause heavy bugs or crashs
only $PLAYER_CHAR, $PLAYER_ACTOR, $ONMISSION are valid

global, local, whats that ?
Global variables are used in the main.scm to communicate between different threads
Local variables are also used in the main.scm but they can not communicate between different threads
You can create a car with a LOCAL variable in a thread as 1@ and also with 1@ in an other thread of main.scm
1@ = create_car
You have then 2 different cars, commanded from 2 different threads

You can create a car with GLOBAL variable in a thread but dont use again the same global to create it again in an other thread.
$mycar5 = create_car
But you can command the car from an other thread of the main.scm by using a GLOBAL variable
At least:
The GLOBAL variables are storable, the LOCAL variables not

But dont using global variables in Cleo scripts because they can cause heavy bugs or crashs
only $PLAYER_CHAR, $PLAYER_ACTOR, $ONMISSION are valid

# marks the connected entry as filename of a loadable model

0247: load_model #BMYCG0247: load_model #HMYCM0247: load_model #SWATVAN0247: load_model #M40247: load_model #COLT45

For Cleo can only be used models which are defined in vehicles.ide, peds.ide or default.ide
Other models needs to use their ID number

'...' short string to insert letters or numbers like GXT entrynames or names of special IPL entries

03A4: name_thread 'MAIN'0917: audio_zone 'BEACH' enable_sound 000BA: show_text_styled GXT 'INTRO_1' time 1000 style 20299: activate_garage 'MODLAST'07FB: set_interior 'GYM1' access 1 // Ganton Gym0390: load_txd_dictionary 'LD_BEAT'076C: set_zone 'GAN1' gang 1 density_to 25

"..." long string to insert letters or numbers like animation- and IFP file names, bodypart names, particel names, etc...

087B: set_player $PLAYER_CHAR clothes_texture "PLAYER_FACE" model "HEAD" body_part 1038F: load_texture "DOWN" as 1 // Load dictionary with 0390 first0605: actor -1 perform_animation_sequence "DAN_LOOP_A" IFP_file "DANCING" 4.0 loop 1 0 0 0 time -1 // versionA0674: set_car_model #GREENWOO numberplate "GROVE4L_"0245: set_actor 5@ walk_style_to "GANG2"064B: 25@ = create_particle "EXPLOSION_MOLOTOV" at 2010.0 -1610.0 16.5 type 1

To set entries of strings equal to variable names must be used special opcodes and extended variable signs
05AA:
05A9:
06D2:
06D1:
furthermore can strings also replaced with variables by using extended variable signs

@s - local-string-variable

05AA: 5@s = 'FEM_OK'00BC: show_text_highpriority GXT 5@s time 10000 flag 1

s$ - global-string-variable
Attension by using Global vars in cleo scripts, it can cause bugs or crashes!

05A9: s$Actor_Speech_GXT_Reference = 'CATX_UA' // ~z~Carl, you are a f*cking idiota! 00BC: show_text_highpriority GXT s$Actor_Speech_GXT_Reference time 10000 flag 105AA: 5@s = s$Actor_Speech_GXT_Reference00BC: show_text_highpriority GXT 5@s time 10000 flag 1

@v - local-long-string-variable

06D2: 28@v = "LAPDAN1" // @v = string0812: AS_actor $PLAYER_ACTOR perform_animation "LAPDAN_P" IFP_file 28@v 1000.0 loopA 0 lockX 0 lockY 0 lockF 1 time -1

v$ - global-long string-variable
Attension by using Global vars in cleo scripts, it can cause bugs or crashes!

06D1: v$1225 = "Bat_block"// 16-byte strings 0605: actor $PLAYER_ACTOR perform_animation_sequence v$1225 from_file "BASEBALL" 4.0 1 0 0 0 -1 ms

______________________________________________________________________________________
______________________________________________________________________________________

Scripting/Writing a Thread

The scripts which are running in GTA are called THREAD
They are defined in the main.scm as thread with the create_thread command or a mission script as mission
As well the Extern scripts of script.img are also threads.

The cleo programm checks if there is .cs file in the Cleo folder
and if yes, it start this script as thread

Script structur / short version:

At first, the head, it beginns with the Cleo directive

{$CLEO .cs}

First Label (adress)

:Akt

Then give the thread a name

03A4: name_thread 'AKT'

now put a code inthere which will doing something and then end_custom_thread as last code
its ready then to test it ingame

{$CLEO .cs}:Akt03A4: name_thread 'AKT'08B2: toggle_thermal_vision 10A93: end_custom_thread

Script above activates the Infrarot view unless in cutscenes
The script ends then, will be deactivated because it ends with opcode 0A93: end_custom_thread
The script will be started by each loading of savegame or by start new game

______________________________________________________________________________________

Next step / using conditional checks

A conditional check requires minimum 3 opcodes

1. the IF-variation
2. the real question
3. the jump instruction by negation

1. if

2. 0AB0: key_pressed 8

3. 004D: jump_if_false @akt_01

We use the previous script again but now we wonna be able to switch into normal view
Therefore we use a conditional check and build a "LOOP"

Loop means that a jump instruction can send the reading process to a previous adress
I call such an adress "Loop-adress"
Important:
The first opcode after such a Loop-adress must be the wait opcode
mostly wait 0 millisecond

the jump instruction can be a jump instruction by negation
or also a normal jump instruction

004D: jump_if_false @akt_01

or

0002: jump @akt_01

The conditional check of a key press in the script below should be passed by pressing BACKSPACE

{$CLEO .cs}:Akt03A4: name_thread 'AKT'08B2: toggle_thermal_vision 1:Akt_01//----------------------------Loop adresse0001: wait 0 msif0AB0: key_pressed 8004D: jump_if_false @Akt_01//--------jump instruction by negation08B2: toggle_thermal_vision 00A93: end_custom_thread

Script above activates the Infrarot view and toggle back to normal view by key_press
The reading process is looping as long as BACKSPACE is not pressed
the jump instruction by negation sends the reading process allways to the label :Akt_01
1000 times per second

______________________________________________________________________________________

The IF - Variation


if00FF: actor $PLAYER_ACTOR 1 (in-sphere)near_point_on_foot 2493.5 -1682.5 13.35 radius 1.0 1.0 1.0004D: jump_if_false @Teleport_2

By more than one question in an conditional check requires to determine,
if it means if oror if and

if and00DF: actor $PLAYER_ACTOR driving8119: NOT car 0@ wrecked004D: jump_if_false @AD_5
if or00E1: key_pressed 0 000E1: key_pressed 0 100E1: key_pressed 0 1400E1: key_pressed 0 18004D: jump_if_false @AD_7
if or8118: NOT actor 7@ dead8118: NOT actor 8@ dead004D: jump_if_false @AD_250002: jump @AD_12

The most question codes can be changed into the opposite question
by changing the ciro of the opcode into 8 and insert "not" into the code line

exemble:

00E1: key_pressed 0 10

and

80E1: NOT key_pressed 0 11

______________________________________________________________________________________

Next Step/ Script structure simple

The previous scripts ended because of the opcode 0A93: end_custom_thread
Instead let the script ending we use a jump instruction at script end to the 1.Loop adress
So the reading process is permanent looping

0002: jump @Akt_01

And since now we add a check in our loop which we add allways after a Loop adress.
It is:

if0256: player $PLAYER_CHAR defined004D: jump_if_false @Akt_01

It should prevent crashes if the player dies or gets arrested
The "IF Player- Defined-check" should allway be the first check in a loop

Script structure simple with 1 Loop:
-Script head
-1.Loop-Adress
-wait code
-IF player_defined-check
-Conditional Check
-Event
-Normal jump instruction to 1.LoopAdress

{$CLEO .cs}:Akt03A4: name_thread 'AKT':Akt_010001: wait 0 msif0256: player $PLAYER_CHAR defined004D: jump_if_false @Akt_01if0AB0: key_pressed 8//-----------------key = Backspace004D: jump_if_false @Akt_0108B2: toggle_thermal_vision 10001: wait 3000 ms08B2: toggle_thermal_vision 00002: jump @Akt_01//--------Normal jump instruction to 1.LoopAdress

Script above activates the Infrarot view after key_press
and toggle back to normal view after 3 seconds

______________________________________________________________________________________

Next Step/ Script structure extended

To start an event with our script will change the game state and the conditions.
This needs to redirect the reading process to prevent that the same code will be read again.
Therefore we add a second Loop in the script
Loop 1 - before the event
Loop 2 - after the event

Script structure extended with 2 Loops:
-Script head
-1.Loop-Adress
-wait code
-IF player_defined-check
-Conditional Check
-Event
-2.Loop-Adress
-wait code
-IF player_defined-check
-Conditional Check
-Normal jump instruction to 1.LoopAdress

{$CLEO .cs}:akt03A4: name_thread 'AKT' :akt01//----------------------------1.Loop Adress0001: wait 0 ms if0256: player $PLAYER_CHAR defined 004D: jump_if_false @akt01if00DF: actor $PLAYER_ACTOR driving004D: jump_if_false @akt0103C0: 1@ = actor $PLAYER_ACTOR car 0229: set_car 1@ color_to 17 0 02AC: set_car 1@ immunities BP 1 FP 1 EP 1 CP 1 MP 1 053F: set_car 1@ tires_vulnerability 0 :akt03//----------------------------2.Loop Adress0001: wait 0 ms if0256: player $PLAYER_CHAR defined 004D: jump_if_false @akt03if80DF: not actor $PLAYER_ACTOR driving004D: jump_if_false @akt0301C3: remove_references_to_car 1@0002: jump @akt01//--------Normal jump instruction to 1.LoopAdress

The script above makes the player_car undestructable as soon as a car is entered
Therefore we must registrate the instance of the car and define it with a variable name
03C0: 1@ = actor $PLAYER_ACTOR car
Then we can use this variable name 1@ to make the car immun

After player has left the car, the reading process jumps back into the first Loop.

Youre not restricted by 2 Loops and there are also other kinds of script structure
But I recommand to build your scripts with this structure as long as you have not much experience

______________________________________________________________________________________

Script exemble: Slowmotion

The script toggle by key_press between slowmotion and normal speed
set_gamespeed .3 make the game slow and also the reading process
wait 50 milliseconds needs ca. 1 second
A "if_player_defined"-check is not nessesary because the script dont have any codes which belongs to the player
After a passed key_press check it makes sense to set a wait of one second otherwise the key_press check will be repeated to fast.

{$CLEO .cs}:slow_003A4: name_thread 'SLW':slow_10001: wait 0 msif0AB0: key_pressed 8//-----------------key = Backspace004D: jump_if_false @slow_1015D: set_gamespeed .30001: wait 50 ms:slow_20001: wait 0 msif0AB0: key_pressed 8//-----------------key = Backspace004D: jump_if_false @slow_2015D: set_gamespeed 1.00001: wait 1000 ms0002: jump @slow_1

______________________________________________________________________________________

Next Step/ Spawn a 3D model

Using models requires 5 steps by applying with models and their definition in its variable name

1. first step to load the model

0247: request_model #INFERNUS

2. second step to prove if the model is loaded in an extra "load-model-check-Loop"

:Load_Model_Check0001: wait 0 ms00D6: if 00248: model #INFERNUS available004D: jump_if_false @Load_Model_Check

3. The model can be created as soon as the model file is loaded and define it with a variable name

00A5: 1@ = create_car #INFERNUS at 2487.5 -1660.5 13.350175: set_car 1@ z_angle_to 90.0

4. release the loaded model file if it not needed anymore

0249: release_model #INFERNUS

5. Release the defined item from script when the script has done its work
The script can then go to the status quo by jumping back into the first Loop

01C3: remove_references_to_car 1@ // Like turning a car into any random car

Releasing a spawned car by using 01C3: remove_references_to_car deletes the instance of the car for our script
but its still available in the game but can not used anymore in our script.

An other way to release the car is to delete it complete:

00A6: destroy_car 1@

This 2 different kinds for releasing exist for vehicles, actors and objects each with own opcodes

{$CLEO .cs}:3dModels_103A4: name_thread 'MODL':3dModels_20001: wait 0 ms00D6: if 00256: player $PLAYER_CHAR defined004D: jump_if_false @3dModels_200D6: if 000FF: actor $PLAYER_ACTOR 1 (in-sphere)near_point_on_foot 2491.5 -1667.5 13.35 radius 1.0 1.0 1.0004D: jump_if_false @3dModels_20247: request_model #INFERNUS:Load_Model_Check0001: wait 0 ms00D6: if 00248: model #INFERNUS available004D: jump_if_false @Load_Model_Check00A5: 1@ = create_car #INFERNUS at 2487.5 -1660.5 13.350175: set_car 1@ z_angle_to 90.00249: release_model #INFERNUS:3dModels_30001: wait 0 ms00D6: if 00256: player $PLAYER_CHAR defined004D: jump_if_false @3dModels_300D6: if 080FF: NOT actor $PLAYER_ACTOR 0 ()near_point_on_foot 2491.5 -1667.5 13.35 radius 2.0 2.0 2.0004D: jump_if_false @3dModels_301C3: remove_references_to_car 1@ // Like turning a car into any random car0002: jump @3dModels_2

Script above spawns the car Infernus in Grovestreet if player goes into red marker(sphere)
If player leave the spot the car will be released from script and the reading process jumps back into 1.Loop

# marks the connected entry as filename of a loadable model
For Cleo can only be used models which are defined in vehicles.ide, peds.ide or default.ide
Other models needs to use their ID number

For exemble to spawn the object 1655, waterjumpx2 of data\maps\generic\multiobj.ide

{$CLEO .cs}:JumpR0003A4: name_thread 'JPR':JumpR010001: wait 0 ms00D6: if 00256: player $PLAYER_CHAR defined004D: jump_if_false @JumpR0100D6: if 000E1: key_pressed 0 10//--------- No key 004D: jump_if_false @JumpR010247: request_model 1655:JumpR020001: wait 0 ms00D6: if 00248: model 1655 available004D: jump_if_false @JumpR020172: 2@ = actor $PLAYER_ACTOR z_angle04C4: create_coordinate 11@ 12@ 13@ from_actor $PLAYER_ACTOR offset 0.0 14.5 -1.80107: 1@ = create_object 1655 at 11@ 12@ 13@0177: set_object 1@ z_angle_to 2@0001: wait 0 ms0249: release_model 16550001: wait 1000 ms01C4: remove_references_to_object 1@ // This object will now disappear when the player looks away0002: jump @JumpR01

Script above spawns a jumpramp by key_press

You can allways use the ID number to spawn models, also for cars and actors
As next we use 120 intead #TRIBOSS to spawn an actor

{$CLEO .cs}:Actor_103A4: name_thread 'Actor':Actor_20001: wait 0 ms00D6: if 00256: player $PLAYER_CHAR defined004D: jump_if_false @Actor_200D6: if 000FF: actor $PLAYER_ACTOR 1 (in-sphere)near_point_on_foot 2491.5 -1667.5 13.35 radius 1.0 1.0 1.0004D: jump_if_false @Actor_20247: request_model 1200247: request_model #AK47:Load_models_check0001: wait 0 ms00D6: if and0248: model 120 available0248: model #AK47 available004D: jump_if_false @Load_models_check009A: 1@ = create_actor 24 120 at 2486.5 -1664.5 13.450173: set_actor 1@ z_angle_to 180.001B2: give_actor 1@ weapon 30 ammo 99999 // Load the weapon model before using this02E2: set_actor 1@ weapon_accuracy_to 1000223: set_actor 1@ health_to 100005E2: AS_actor 1@ kill_actor $PLAYER_ACTOR0249: release_model 120:Loop_10001: wait 0 ms00D6: if 08118: NOT actor 1@ dead004D: jump_if_false @Cleanup_100D6: if 00104: actor $PLAYER_ACTOR near_actor 1@ radius 80.0 80.0 10.0 sphere 0004D: jump_if_false @Cleanup_10002: jump @Loop_1:Cleanup_101C2: remove_references_to_actor 1@ // Like turning an actor into a random pedestrian0002: jump @Actor_2

Script above spawns the actor Triboss with gun in Grovestreet
If player leave the area with radius 80.0 80.0 or if the actor is dead,
the actor will be released from script and the reading process jumps back into 1.Loop

To give the actor or the player a weapon requires also to load first the model file
But to give it then really into his hands needs to insert a special weapon number which is not documented in any game file.
To find the right weapon number look in Sannybuilder HELP: SCM Documentation >> GTA SA >> Weapon numbers

Weapon given to actors are not created in same sense like the other models,
so it dont it to release them from script like other items

The spawned actors have predefined execodet behaviors which is dependent by the pedtype parameter of the create_actor opcode.
Look for pedtypes in Sannybuilder HELP: SCM Documentation >> GTA SA >> PedTypes

An actor with pedtype 8 is recruitable like a homie

009A: 1@ = create_actor 8 #TRIBOSS at 2486.5 -1664.5 13.45

An actor with pedtype 7 is agressive like an enemy gangmember

009A: 1@ = create_actor 7 #TRIBOSS at 2486.5 -1664.5 13.45

______________________________________________________________________________________

Placing cars by using parked_car_generator

Init parked_car_generators or pickups need to insert the Cleo opcode:

0A95: enable_thread_saving

Read the discription about enable_thread_saving in the theme:
Special Particularities in Cleo >> Registrate (store) the Script State

The placing of cars by using parked_car_generator dont allows the using of its variable name in vehicle associated opcodes
because its not a car but a car_generator

{$CLEO .cs}:PaCar_103A4: name_thread "PACR"0001: wait 1000 ms0A95: enable_thread_saving014B: 1@ = init_parked_car_generator #BANSHEE -1 -1 1 alarm 0 door_lock 0 0 10000 at 920.1994 2020.546 11.79 angle 100.0014C: set_parked_car_generator 1@ cars_to_generate_to 101032B: 2@ = create_weapon_pickup #MINIGUN 15 ammo 5000 at 2113.373 1520.674 10.820A93: end_custom_thread

Script above adds a parked_car_generator to spawn the car Banshee
and a weapon pickup with MINIGUN

generate_to 101 means that the car will be spawned again and again
generate_to 0 deactivates the car_generator

the two parameters after the model name -1 -1 gives the secondary and primary color
by setting -1 -1the game choose the colors randomly

by setting 0 17 it give black (0) to primary and red (17) to secondary color

alarm 0 can be a value between 0 and 100 and means the probable chance to execute an alarm

door_lock 0 can be a value between 0 and 100 and means the probable chance to execute a door lock

For pickups exist 2 different opcodes for 2 different kinds of pickups
032B: for weapons with ammo and for the Jetpack
0213: for melee weapons and objects like parachute (GUN_PARA) or bodyarmour (1242, bodyarmour)
the parameter after the model ID #MINIGUN 15 is the pickup-typ
Typ 15 is a pickup, which appears again and again
Typ 3 is a pickup, which appears only for one time

______________________________________________________________________________________
______________________________________________________________________________________

Special Particularities in Cleo

The extra-Cleo opcodes can be found in Sannybuilder-HELP
CLEO 3 Code Library >> CLEO 3: opcodes CLEO 3 Code Library>> CLEO 3: opcodes

______________________________________________________________________________________

Two major codes to start scripts are those which already exist in the main.scm and have been re-created for Cleo:

1.) 004F: create_thread @SAVEGAME starts an ordinary thread in the main.scm.
We dont need it in Cleo because it will be allready started from Cleo programm
To start an other thread of a cleo script, started from a cleo script needs following opcode:

0A92: create_custom_thread "New_Test_thread.cs"

The code needs to insert the name of the script file which should get started inclusiv dot and extension

The Cleo script file get then the file extension, which is written in the Cleo Script directive at the beginning of the script
{$CLEO .cs} = Cleo directive will be compiled to *.cs
As New_Test_thread.txt saved and compiled as New_Test_thread.cs

The script get then started at second once. Once from Cleo programm and once from the 0A92: create_custom_thread
It needs to set a conditional check at script beginn to let the script ending when it was started from Cleo programm.

An other chance is to give the script the extension .s
This needs to insert following:

0A92: create_custom_thread "New_Test_thread.s"

The Cleo script file which should get started, must have {$CLEO .cs} as directive and will be compiled as *.cs
You must change the extension manual by renaming from *.cs into *.s
In this case the Cleo script will only run if it was started with 0A92: create_custom_thread from an other Cleo script.

The opcode 0A92: create_custom_thread can transport more information to the script which should be started
This opcode can be extended with up to 30 values or variables as parameters
exemble:

0A92: create_custom_thread "PimpmyCarFULL2A1.cs" 1 2 0 3@ 4@ 5@ 6@ 29@ 8@ 9@ 10@

The started thread recieves these parameter values with following rule
0@ get value of 1.parameter
1@ get value of 2.parameter
2@ get value of 3.parameter
3@ get value of 4.parameter
4@ get value of 5.parameter
etc...
Its also possible to start much threads in one and the same Cleo script, started from the same script which recieve the create_thread commands.

2.)

0417: start_mission 3
starts a mission script of the main.scm. It needs to insert the number which the mission script get from the listing of the mission table

In Cleo dont exist a mission table and its listing.
But it needs allways a Cleo mission starter script with following command:

0A94: start_custom_mission "DriftMission"

The code needs to insert the name of the script file which should get started but without extension

The Cleo script file get then the file extension, which is written in the Cleo Script directive at the beginning of the script
{$CLEO .cm} = Cleo directive will be compiled to *.cm
As DriftMission.txt saved and compiled as DriftMission.cm

______________________________________________________________________________________

0A93: end_custom_thread let a script ending. Its disabled then.

The original version of this code of the main.scm is 004E: end_thread

And this original version must be used furthermore in Cleo mission scripts (*.cm)

004E: end_thread

Again:

0A93: end_custom_thread in normal Cleo scripts, compiled to a *.cs file

{$CLEO .cs}0A93: end_custom_thread

004E: end_thread in mission scripts, compiled to a *.cm file

{$CLEO .cm}004E: end_thread

______________________________________________________________________________________

Cleo creates extra save files if a save was done,
stored in folder CLEO\Cleo_save

By loading a save file must taken care to check that the presence of the scripts in Cleo folder
is the same as it was as the save was done.
Special attention in this case are going to those scripts which includes the Cleo opcode
to registrate and store the Script State

______________________________________________________________________________________

Registrate (store) the Script State

The Cleo scripts with extension .cs are started allways from new by loading a save game or start new game,
If such a script includes for exemble a parked car generator and execute it and after this a save game is made,
and then this save game is loaded,
will be created a duplicate of the item, in this case a duplicate of a parked car generator.
This happens with parked car generator, pickups as well as placed objects.

To prevent this or to read the script state by using special special Cleo-variable
must be used following Cleo opcode:

0A95: enable_thread_saving

This instruct Cleo to store the script state by making a savegame

______________________________________________________________________________________

Special Global Cleo Variable

This theme requires the understanding of the description about Local Variables and Global Variables
of the previous theme Datatype
especially this part which tells why there exist Local Variables and Global Variables
Global Variables are used in main.scm to communicate between different scripts and they are storable.
Using Global Variables in Cleo scripts can cause bugs and crashes

To realize Global Variables for Cleo scripts exist following Cleo opcode connected with a special expression:

Opcode 0AB3: and 0AB4:

The expression var together with a number, <var><space><number> is builing the Special Global Cleo Variable

0AB3: var 0 = 10or0006: 13@ = 10 // integer values0AB3: var 0 = 13@and0AB4: 0@= var 0

var 0 up to var 999 will be stored, in exemble var 0 is stored with 10

to get then stored value into your script needs to submit into a local:

0AB4: 13@ = var 44if0039: 13@ == 1 // integer values004D: jump_if_false @nextlabel

______________________________________________________________________________________
______________________________________________________________________________________

Script Exemble by using Special Global Cleo Variable/ Store a car at any place
(requires to understand all previous themes of this tut)

Script below saves a car at any place
If player is in car and key F7 is pressed, it stores x,y,z coords and angle, also the car ID, its primary and secondary color and its paintjob.

The player exit then the car and car will be locked and made immun
If player leave the location and the distance to the car will be greater then 100.0
the car will be released from script and the reading process jumps back into an other Loop

If player then comes back to the location, near 80.0 the car will be spawned as new
Only to store the car settings by making savegame needs to give the values into the Special Global Cleo Variable

As I wrote in the theme "Registrate (store) the Script State"
is the Carstore script running from new by loading a save game or start new game"...

...and checks first if var 955 is ciro
its only not ciro if a car was stored in the loaded savegame

If var 955 is ciro, the script starts with the 1.Loop
If var 955 is not ciro, the reading process jumps into the 3.Loop with the check if player is near the car store location

A special side effect of this kind of car store is that the storable entries then available in memory for all savefiles.
Only by shut down the game and start again is the stored car only stored in the savegame which was done to store the car.

{$CLEO .cs}:CARSTORE03A4: name_thread 'CARSTOR'0001: wait 1000 ms0AB4: 7@ = var 95500D6: if8039: not 7@ == 0004D: jump_if_false @CARSTOR_1500AB4: 3@ = var 9510AB4: 4@ = var 9520AB4: 5@ = var 9530AB4: 6@ = var 9540AB4: 7@ = var 9550AB4: 8@ = var 9560AB4: 9@ = var 9570AB4: 10@ = var 9580093: 3@ = integer 3@ to_float0093: 4@ = integer 4@ to_float0093: 5@ = integer 5@ to_float0093: 6@ = integer 6@ to_float0001: wait 1000 ms0002: jump @CARSTOR_555:CARSTOR_1500001: wait 0 ms00D6: if0256: player $PLAYER_CHAR defined004D: jump_if_false @CARSTOR_15000D6: if and00DF: actor $PLAYER_ACTOR driving0AB0: key_pressed 118//-------------------key F7004D: jump_if_false @CARSTOR_15001B4: set_player $PLAYER_CHAR can_move 003C0: 2@ = actor $PLAYER_ACTOR car00AA: store_car 2@ position_to 3@ 4@ 5@0174: 6@ = car 2@ Z_angle0441: 7@ = car 2@ model0988: get_car 2@ paintjob 8@03F3: get_car 2@ primary_color_to 9@ secondary_color_to 10@020A: set_car 2@ door_status_to 002AC: set_car 2@ immunities BP 1 FP 1 EP 1 CP 1 MP 10519: set_car 2@ locked 10633: AS_actor $PLAYER_ACTOR exit_car0092: 13@ = float 3@ to_integer0092: 14@ = float 4@ to_integer0092: 15@ = float 5@ to_integer0092: 16@ = float 6@ to_integer0AB3: var 951 = 13@0AB3: var 952 = 14@0AB3: var 953 = 15@0AB3: var 954 = 16@0AB3: var 955 = 7@0AB3: var 956 = 8@0AB3: var 957 = 9@0AB3: var 958 = 10@0001: wait 2000 ms01B4: set_player $PLAYER_CHAR can_move 10002: jump @CARSTOR_403:CARSTOR_4030001: wait 0 ms00D6: if0256: player $PLAYER_CHAR defined004D: jump_if_false @CARSTOR_55000D6: if82BF: not car 2@ sunk004D: jump_if_false @CARSTOR_73800D6: if8119: not car 2@ wrecked004D: jump_if_false @CARSTOR_55000D6: if0202: actor $PLAYER_ACTOR near_car 2@ radius 100.0 100.0 flag 0004D: jump_if_false @CARSTOR_55000D6: if00DF: actor $PLAYER_ACTOR driving004D: jump_if_false @CARSTOR_40300D6: if00DB: actor $PLAYER_ACTOR in_car 2@004D: jump_if_false @CARSTOR_40302AC: set_car 2@ immunities BP 0 FP 0 EP 0 CP 0 MP 00519: set_car 2@ locked 00002: jump @CARSTOR_738:CARSTOR_55001C3: remove_references_to_car 2@ // Like turning a car into any random car:CARSTOR_5550001: wait 0 ms00D6: if0256: player $PLAYER_CHAR defined004D: jump_if_false @CARSTOR_55500D6: if00FE: actor $PLAYER_ACTOR sphere 0 in_sphere 3@ 4@ 5@ radius 80.0 80.0 50.0004D: jump_if_false @CARSTOR_5550002: jump @CARSTOR_624:CARSTOR_6240247: load_model 7@:CARSTOR_6290001: wait 0 ms00D6: if0248: model 7@ available004D: jump_if_false @CARSTOR_6290001: wait 0 ms00A5: 2@ = create_car 7@ at 3@ 4@ 5@0175: set_car 2@ Z_angle_to 6@06ED: set_car 2@ paintjob 8@0229: set_car 2@ primary_color_to 9@ secondary_color_to 10@020A: set_car 2@ door_status_to 002AC: set_car 2@ immunities BP 1 FP 1 EP 1 CP 1 MP 10519: set_car 2@ locked 10249: release_model 7@0002: jump @CARSTOR_403:CARSTOR_73801C3: remove_references_to_car 2@ // Like turning a car into any random car0AB3: var 955 = 00002: jump @CARSTOR_150

______________________________________________________________________________________
______________________________________________________________________________________

Template for Cleo Mission Script
(requires to understand all previous themes of this tut)

To run a Cleo mission script requires allways 2 Cleo script files
1. A .cs file to start the Cleo mission script file
2. The Cleo mission script file itself with extension .cm

The mission starter thread below is done with a conditional check to check if the player is near a specified point,
which must passed to start the mission.

The coordinates of the near_point check are the location in San Fierro/Carlton Heights near savehouse
Edit the coordinates to set your own location for starting

The parameter 1 of the near_point opcode 00FE: actor $PLAYER_ACTOR 1 (in-sphere)near_point
is displaying a red marker (sphere).
If the parameter is ciro 00FE: actor $PLAYER_ACTOR 0 (in-sphere)near_point does not displaying a red marker.
To display a red marker in this way needs to set 0ms as maximum in the wait code of this Loop

{$CLEO .cs}:Test_M_Start_103A4: name_thread 'TSTM':Test_M_Start_20001: wait 0 ms00D6: if 00256: player $PLAYER_CHAR defined004D: jump_if_false @Test_M_Start_200D6: if 00038: $ONMISSION == 0 // integer values004D: jump_if_false @Test_M_Start_2:Test_M_Start_600D6: if 000FE: actor $PLAYER_ACTOR 1 (in-sphere)near_point 2480.1343 -1665.475 13.3348 radius 3.5 3.5 5.5004D: jump_if_false @Test_M_Start_200BA: text_styled 'STAD_02' 1000 ms 20004: $ONMISSION = 1 // integer values0A94: start_custom_mission "TestMission" //0002: jump @Test_M_Start_2

The mission starter script includes the following Cleo opcode to start the Cleo mission script:
0A94: start_custom_mission "TestMission"

The code needs to insert the name of the script file which should get started but without extension

The Cleo script file get then the file extension, which is written in the Cleo Script directive at the beginning of the script
{$CLEO .cm} = Cleo directive will be compiled to *.cm
As TestMission.txt saved and compiled as TestMission.cm

{$CLEO .cm}:TestMiss_103A4: name_thread "TESTM" 0050: gosub @TestMiss_main_1 00D6: if 00112: wasted_or_busted004D: jump_if_false @TestMiss_end_10050: gosub @TestMiss_fail_1 :TestMiss_end_10050: gosub @TestMiss_clep_1004E: end_thread:TestMiss_main_10317: increment_mission_attempts//here starts the missionscript0004: $ONMISSION = 1054C: use_GXT_table 'MENU2P'00BC: text_highpriority 'MENU_18' 5000 ms 1:TestMiss_110001: wait 0 msif and02D8: actor $PLAYER_ACTOR currentweapon == 0 00E1: key_pressed 0 17 004D: jump_if_false @TestMiss_11:TestMiss_pass_100BA: text_styled 'M_PASS' 5000 ms 10051: return:TestMiss_fail_100BA: text_styled 'M_FAIL' 5000 ms 10051: return:TestMiss_clep_10004: $ONMISSION = 000D8: mission_cleanup0051: return

When the mission script from above is running it can be completed by pressing fire key while player have weapon 0/naked fist.

The secret of the onmission mode

$ONMISSION is not only a variable to check if a mission script is running or not.
Set $ONMISSION to 1 activates a special mission mode if some important conditions are accomplished.
R*s mission scripts run allways in a subroutine which will be cancled from the exe if player is wasted or busted like reading a return code in the script.

1. At first it needs to set $ONMISSION equal to on_mission_flag

0180: set_on_mission_flag_to $ONMISSION// Note: your missions have to use the variable defined here

This code is set by default in the main part of the original main.scm

2. By starting the mission script must sended the reading precess with a gosub command into a subroutine for the main part of the mission script.
It must be the first gosub of the mission script.

0050: gosub @TestMiss_main_1

3. By starting the mission script must be activated the onmission mode with

0004: $ONMISSION = 10317: increment_mission_attempts//here starts the missionscript

Then the mission is running in a subroutine and dont needs to check if player is defined or dead or busted.
If player dies or get busted, the exe cancels the subroutine as like as a return code of our script is readed

The rest of the mission script is just a cunning gosub construct.

______________________________________________________________________________________
______________________________________________________________________________________

gosub

The gosub command leads the reading process to an excluded subscript.
Excluded means the codes of the subscript are not binded in code following of our thread.

0050: gosub @MODLSUBROUTINE

The subscript must end with return

0051: return

If the subscript ends with 0051: return, our thread then continues with reading the codes after the 0050: gosub command

Exemble:

{$CLEO .cs}:MODLSUB_103A4: name_thread 'MODLSUB':MODLSUB_20001: wait 0 ms00D6: if 00256: player $PLAYER_CHAR defined004D: jump_if_false @MODLSUB_200D6: if 000FF: actor $PLAYER_ACTOR 1 (in-sphere)near_point_on_foot 2491.5 -1667.5 13.35 radius 1.0 1.0 1.0004D: jump_if_false @MODLSUB_20050: gosub @MODLSUBROUTINE :Loop_10001: wait 0 ms00D6: if 08118: NOT actor 1@ dead004D: jump_if_false @Cleanup_100D6: if 00104: actor $PLAYER_ACTOR near_actor 1@ radius 80.0 80.0 10.0 sphere 0004D: jump_if_false @Cleanup_10002: jump @Loop_1:Cleanup_101C2: remove_references_to_actor 1@ // Like turning an actor into a random pedestrian0002: jump @MODLSUB_2:MODLSUBROUTINE0005: 1@ = 2473.250005: 2@ = -1657.790005: 3@ = 13.40005: 4@ = 2501.120005: 5@ = -1676.50005: 6@ = 13.40208: 7@ = random_float_in_ranges 1@ 4@0208: 8@ = random_float_in_ranges 2@ 5@0208: 9@ = random_float_in_ranges 3@ 6@0247: request_model #TRIBOSS0247: request_model #AK47:Load_MODLSUB_Check0001: wait 0 ms00D6: if and0248: model #TRIBOSS available0248: model #AK47 available004D: jump_if_false @Load_MODLSUB_Check009A: 1@ = create_actor 24 #TRIBOSS at 7@ 8@ 9@0173: set_actor 1@ z_angle_to 180.001B2: give_actor 1@ weapon 30 ammo 99999 // Load the weapon model before using this02E2: set_actor 1@ weapon_accuracy_to 1000223: set_actor 1@ health_to 100005E2: AS_actor 1@ kill_actor $PLAYER_ACTOR0249: release_model #TRIBOSS0051: return

Script above spawns the actor Triboss with gun in Grovestreet at different places
The coords are generated random
The part with the coords generation and actor spawn is excluded in a subscript

If player leave the area with radius 80.0 80.0 or if the actor is dead,
the actor will be released from script and the reading process jumps back into 1.Loop

______________

Last edited by ZAZ (17-03-2023 17:21)

~ CLEO Script Tutorial ~ (Page 1) / GTA Modding (2024)

References

Top Articles
Latest Posts
Article information

Author: Maia Crooks Jr

Last Updated:

Views: 5850

Rating: 4.2 / 5 (63 voted)

Reviews: 94% of readers found this page helpful

Author information

Name: Maia Crooks Jr

Birthday: 1997-09-21

Address: 93119 Joseph Street, Peggyfurt, NC 11582

Phone: +2983088926881

Job: Principal Design Liaison

Hobby: Web surfing, Skiing, role-playing games, Sketching, Polo, Sewing, Genealogy

Introduction: My name is Maia Crooks Jr, I am a homely, joyous, shiny, successful, hilarious, thoughtful, joyous person who loves writing and wants to share my knowledge and understanding with you.