# Переменные

Переменная - это именованная область памяти со значением, которое может быть многократно прочитано и/или изменено. Существует два вида переменных - *глобальные* и *локальные*.

## Глобальные переменные

Глобальная переменная начинается со знака `$`, после которого следует комбинация латинских букв, цифр и `_`:

`$variable1`\
`$100`\
`$____`

Значения глобальных переменных доступны из любого места в коде.

### **Сохраняемые переменные**

Сохраняемые переменные - это особый вид глобальных переменных, добавленный в `LCS` и `VCS` [режимах](https://docs.sannybuilder.com/ru/edit-modes). Перед их именем стоит `$_`, например `$_var`. Значение такой переменной восстанавливается при загрузке сохраненной игры. Глобальные переменные, которые начинаются только с `$` (например, `$var`), не сохраняют свое значение и обнуляются при загрузке сохранения в LCS или VCS.

### DMA переменные

Во время компиляции имена переменных заменяются на числа. Эти числа являются индексами в специальном массиве, который используется игрой для хранения значений глобальных переменных. Индекс является уникальным числом, присваиваемым конкретной переменной.

Глобальная переменная, чье имя состоит из цифр, называется`DMA`-переменная (**D**irect **M**emory **A**ddress - прямой доступ к памяти). Это имя и будет индексом, который использует игра.

См. [Alloc](https://docs.sannybuilder.com/ru/built-in-commands#alloc).

## Локальные переменные

Именем локальной переменной служит число, после которого стоит знак `@`.

```pascal
0@ 
999@ 
56@
```

Значения локальных переменных доступны только в пределах текущего скрипта или миссии.

{% hint style="warning" %}
Количество локальных переменных в одном скрипте/миссии строго [ограничено](https://docs.sannybuilder.com/ru/scm-documentation/gta-limits).
{% endhint %}

### Переменные-таймеры

Каждый скрипт или миссия также имеют две особые локальные переменные, которые называются `TIMERA` и `TIMERB`. Значение переменной-таймера постоянно увеличивается с ходом игры, поэтому они обычно используются, чтобы измерять время, пройденное с определенного момента (сброса таймера).

```pascal
0006: TIMERA = 0 // сброс таймера

:WAIT_2S
0001: wait 0 ms
00D6: if
0019:   TIMERA > 2000 // если таймер увеличился до 2000, т.е. прошло 2 секунды
004D: jump_if_false @WAIT_2S
0662: printstring "2 seconds has passed" // показать текст
```

{% hint style="info" %}
Имена `TIMERA`и`TIMERB`доступны начиная с Sanny Builder v3.3.0. В более ранних скриптах таймеры использовались как обычные локальные переменные `16@, 17@` (в GTA3 и VC) либо `32@, 33@` (SA).
{% endhint %}

## Объявление типа переменной <a href="#declaring-a-variable-type" id="declaring-a-variable-type"></a>

Переменные обычно используются в арифметических или условных выражениях. Если в выражении правая часть является числом, опкод указывать не обязательно:

```pascal
$var = 0
$myarray($index, 10i) >= 150
```

Если же обе части выражения являются переменными, компилятор не сможет подобрать нужный опкод, т.к. типы переменных неизвестны.

Например, существует два опкода, которые складывают значения двух переменных: `0058` для целых чисел и `0059` для дробных.

```pascal
0058: $Var1 += $Var2 // (целые числа)
0059: $Var1 += $Var2 // (дробные числа)
```

Если убрать опкод, как скомпилировать такое выражение?

```pascal
$Var1 += $Var2 // ??
```

Чтобы сообщить компилятору тип переменной, используется ключевое слово `var`.

```pascal
var <переменная>: <тип>
```

`Переменная` - это любая допустимая глобальная или локальная переменная (см. выше).

`Тип` может быть одним из нижеперечисленных значений:

* `Integer`, `Int` - целые числа
* `Float` - дробные числа
* `String`, `ShortString` - переменная, содержащая [короткий строковый литерал](https://docs.sannybuilder.com/ru/data-types#strokovye-literaly) (используется только при объявлении массивов, для одиночных переменных используются префикс `s$` или суффикс `@s`)
* `LongString` - переменная, содержащая [длинный строковый литерал](https://docs.sannybuilder.com/ru/data-types#strokovye-literaly) (используется только при объявлении массивов, для одиночных переменных используются префикс `v$` или суффикс `@v`)
* `<Имя класса>` - переменная или массив переменных [членов класса](https://docs.sannybuilder.com/ru/classes#chleny-klassa)

Пример:

```pascal
var $size: integer
```

Можно объявить несколько переменных в одной строке, разделяя их запятой:

```pascal
var $x: float, $y: float, $z: float    
```

Если вы предпочитаете многострочные определения, используйте конструкцию `VAR..END`:

```pascal
var
   $x: float
   $y: float
   $z: float
end
```

Когда обе переменные имеют известный компилятору тип, выражение компилируется без опкода:

```pascal
var
    $Var1 : Integer
    $Var2 : Integer
end
$Var1 += $Var2 // здесь будет опкод 0058
```

{% hint style="info" %}
Как только тип переменной объявлен, он используется везде ниже по коду. Тип переменной может быть изменен, если она используется по-другому:

```
script_name 'Food'
var
    10@ : Float
    $Var : Float
end
$var = 1
10@ = $Var
end_thread

thread 'Loop'
var
    10@ : Int
    $Var : Int
end
$var = 1
10@ = $Var
end_thread
```

В скрипте`'Food'` `10@` является дробной переменной. В скрипте`'Loop'` `10@` уже целочисленная переменная.

Тип переменной может быть переобъявлен многократно.
{% endhint %}

## Короткая форма объявления переменных

Начиная с версии 3.2.0 можно объявлять переменные, используя только имя типа (доступно для типов `Int`, `Float`, `String`, `LongString`).

Синтаксис:

```pascal
<type> <variable name>
```

Пример:

<pre class="language-pascal"><code class="lang-pascal"><strong>int 0@ // 0@ объявлена как целочисленная переменная
</strong></code></pre>

Начиная с версии 3.4.0 появилась возможность объявить переменную с собственным именем:

```pascal
int a
float distance
string name

a = 1
distance = 15.5
name = 'CJ'
```

Одновременно с объявлением такой переменной можно присвоить ей начальное значение, чтобы уменьшить количество строк кода:

```pascal
int a = 1
float distance = 15.5
string name = 'CJ'
```

Компилятор связывает каждое имя с новой локальной переменной. В примере выше код будет скомпилирован примерно следующим образом:

```pascal
0006: 0@ = 1 
0007: 1@ = 15.5 
05AA: 2@ = 'CJ'
```

{% hint style="info" %}
Из-за [архитектурных ограничений](https://github.com/sannybuilder/dev/issues/32) эта возможность доступна только в CLEO скриптах.
{% endhint %}

## Начальное значение переменной

Одновременно с объявлением переменной можно задать ей начальное значение. Для этого напишите `=` и значение:

```pascal
var $fVar: float = 1.0
```

или

```pascal
float $fVar = 1.0
```

Теперь переменная `$fVar` объявлена как `Float`, и компилятор добавит в скрипт опкод `0005`:

```pascal
0005: $fVar = 1.0
```

Инициализация доступна только для переменных, но не массивов.
