A small TypeScript library providing helpful utilities for CLEO Redux scripts. Works with GTA III, Vice City and San Andreas.
Copy scm.mts next to your main script and then import necessary functions:
import { SCM, Timer, Counter, VehiclePool, PedPool, ObjectPool, TextDraw } from "./scm.mts";scm.mts requires mem permission. Your script name should include [mem], or the CLEO config should allow mem.
A helper class to create and manipulate onscreen counters (can be one of the two types: bars and numbers).
const counter = new Counter(350).type(0).display(); // create a new bar counter with initial value of 350
wait(1000);
counter.value -= 100; // decrement counter's value by 100
wait(1000);
counter.clear(); // delete counterCounter constructor accepts a number or an object:
new Counter(number)- creates a new Counter with the initial valuenew Counter({ type: number, slot: number, text: string, key: string, noFlash: boolean, initialValue: number})- creates a new Counter with the one or many given options.
Also Counter object has methods that can be chained to customize the visual style and behavior of the counter:
.type(number)- 0 is a number (default), 1 is a bar.slot(number)- position on screen (1, 2, 3, or 4). Supported since VC..text(string)- custom text for the counter label (empty by default).key(string)- a GXT key for the counter label.noFlash()- don't flash the counter on appear (only in SA)
The following calls are equivalent:
const counter = new Counter(50).type(1).slot(3).noFlash().display();
const counter = new Counter({ initialValue: 50, type: 1, slot: 3, noFlash: true }).display();Customization methods can only be used before .display(). When .display() method is invoked it returns a new object with the following properties:
.value- a getter/setter for the counter. Can be increased or decreased.
counter.value += 1;
counter.value = 5;
counter.value--;.clear()- delete the counter
A helper class to create and manipulate onscreen timers.
const timer = new Timer(10000).text("My Timer").display(); // create a new timer with initial time of 10 seconds and custom label
wait(1000);
timer.freeze(true); // temporarily pause the timer
wait(1000);
timer.freeze(false); // continue timer
wait(1000);
timer.clear(); // delete timerTimer constructor accepts a number or an object:
new Timer(number)- creates a new Timer with the initial time in msnew Timer({ direction: number, beepTime: number, text: string, key: string, initialValue: number})- creates a new Timer with the one or many given options.
Also Timer object has methods that can be chained to customize the visual style and behavior of the counter:
.direction(number)- 0 is a countup timer, 1 is a countdown timer (default). Supported since VC..beepTime(number)- time when the timer makes a noise. Only in SA..text(string)- custom text for the counter label (empty by default).key(string)- a GXT key for the counter label
The following calls are equivalent:
const timer = new Timer(5000).direction(0).text("TIME").display();
const timer = new Timer({ initialValue: 5000, direction: 0, text: "TIME" }).display();Customization methods can only be used before .display(). When .display() method is invoked it returns a new object with the following properties:
.value- a getter/setter for the timer. Can be increased or decreased. Note that in each frame the game automatically updates the timer value.
timer.value += 1000;
timer.value = 5000;
timer.value -= 1000;.freeze(boolean)- pause/unpause the timer.clear()- delete the timer
A static object with the following methods:
-
SCM.readVar(number)- reads the value of the global variable with the given index -
SCM.writeVar(number, number)- writes a new value of the global variable with the given index -
SCM.bind(object)- binds object keys to SCM variables
Example:
const $ = SCM.bind({
PLAYER1: 2,
SCPLAYER: 3,
ONMISSION: 409,
SOME_BLIP: new Blip(123)
});
$.ONMISSION = 1;
$.SOME_BLIP.remove();
A static object with the following methods:
VehiclePool.getHandle(number)- returns a Car handle for the given CVehicle instance addressVehiclePool.getAt(number)- returns a CVehicle instance address for the given Car handleVehiclePool.getEntities()- returns an array of existing CVehicle instance addresses. Can be used to iterate over all existing cars
A static object with the following methods:
PedPool.getHandle(number)- returns a Char handle for the given CPed instance addressPedPool.getAt(number)- returns a CPed instance address for the given Char handlePedPool.getEntities()- returns an array of existing CPed instance addresses. Can be used to iterate over all existing peds
A static object with the following methods:
ObjectPool.getHandle(number)- returns a ScriptObject handle for the given CObject instance addressObjectPool.getAt(number)- returns a CObject instance address for the given ScriptObject handleObjectPool.getEntities()- returns an array of existing CObject instance addresses. Can be used to iterate over all existing objects
A helper class to display custom text on screen.
const text = new TextDraw().color("Red").pos(320, 200);
while (true) {
wait(0);
text.draw("Hello World!");
}All methods (except .draw()) can be chained:
new TextDraw()
.color("Yellow")
.bg("Black")
.alignCenter()
.font(2)
.scale(1.0, 1.5)
.uppercase()
.pos("50%", "10%")
.draw("MISSION PASSED");.color(r, g, b, a)- set text color with RGBA values (0-255).color(name)- set color by name:"Red","Blue","Yellow","White","Black", etc..color("#RRGGBB")or.color("#RRGGBBAA")- set color with hex string.bg(r, g, b, a)- set background color with RGBA values (0-255).bg(name)- set background color by name:"Red","Blue","Yellow","White", `"Black", etc..bg("#RRGGBB")or.bg("#RRGGBBAA")- set background color with hex string.noBg()- disable background.randomColor()- set a random color.opacity(value)- set text alpha (0-255or"0%"-"100%")
.color(fn)- set color with callback(prevR, prevG, prevB, prevA) => [newR, newG, newB, newA].opacity(fn)- opacity with callback(prevAlpha) => newAlpha.bg(fn)- background color with callback(prevR, prevG, prevB, prevA) => [newR, newG, newB, newA]
.pos(x, y)- set position in units (0-640for X,0-448for Y) or percentage ("50%","25%").x(value)- set X position.y(value)- set Y position
.pos(fn)- dynamic position with callback(prevX, prevY) => [newX, newY].x(fn)- dynamic X position with callback(prevX) => newX.y(fn)- dynamic Y position with callback(prevY) => newY
.alignLeft()- align text to left (default).alignCenter()- center text.alignRight()- align text to right.maxWidth(value)- set max width in units (0-640) or percentage (e.g..maxWidth("100%"))
.font(number)- set font style (0-3), corresponds to GTA fonts https://library.sannybuilder.com/#/sa?q=SET_TEXT_FONT.scale(x, y)- set text size. can be absolute (.scale(0.48, 1.12)) or relative to the default size (.scale("75%", "150%")).scaleX(value)/.scaleY(value)- set individual scale.uppercase()- transform text to UPPERCASE.lowercase()- transform text to lowercase.normalCase()- keep original case
.scale(fn)- dynamic scale with callback(prevScaleX, prevScaleY) => [newScaleX, newScaleY].scaleX(fn)- dynamic X scale with callback(prevScaleX) => newScaleX.scaleY(fn)- dynamic Y scale with callback(prevScaleY) => newScale
.draw(text)- render text on screen. Must be called every frame withwait 0.
Fade out effect:
const fadeOut = new TextDraw().color("White").opacity((prev) => Math.max(0, prev - 1));
fadeOut.draw("Fading Out...");Fade in effect:
const fadeIn = new TextDraw()
.color("White")
.opacity(0)
.opacity((prev) => Math.min(255, prev + 1));
fadeIn.draw("Fading In...");Centered text:
const centered = new TextDraw().x("50%").y("50%").alignCenter();
centered.draw("Centered!");Bouncing DVD logo:
let xVelocity = 1.0;
let yVelocity = 1.0;
const bouncer = new TextDraw()
.x((prev) => {
if (prev > 640 || prev < 0) xVelocity *= -1;
return prev + xVelocity;
})
.y((prev) => {
if (prev > 448 || prev < 0) yVelocity *= -1;
return prev + yVelocity;
});
bouncer.draw("DVD");News ticker:
const ticker = new TextDraw().y("95%").color("Red").maxWidth("100%").uppercase().bg("Black");
ticker.draw("Breaking news...");Rainbow text effect:
const rainbow = new TextDraw().color((_, __, ___, a) => {
const time = Date.now() / 1000;
const r = Math.floor((Math.sin(time + 0) + 1) * 127);
const g = Math.floor((Math.sin(time + 2) + 1) * 127);
const b = Math.floor((Math.sin(time + 4) + 1) * 127);
return [r, g, b, a];
});
rainbow.draw("RAINBOW TEXT EFFECT");