Массивы

Скрипт для GTA San Andreas позволяет использовать массивы. Эту возможность я добавил и в генератор. Я рекомендую научится ими пользоваться, так как это существенно ускоряет разработку миссий и позволяет сократить количество ручного кода.

Генератор поддерживает практически все типы данных. Чтобы создать массив, нам нужно определиться будет ли он глобальным и какой тип он будет представлять. Базовый синтаксис такой:

[Thread]
public void TEST() {

    var pedArray = Array<Actor>.local( 0, 10 ); // 0@ - 9@

    end_thread();
}

Генератор теперь будет знать, что "pedArray" - это массив, который начинается с индекса 0 и имеет 10 элементов. Тип данных будет "Actor". Это значит, что количество переменных, которые ему будут доступны - 10.

После этого мы можем обращаться к массиву по индексу и давать команды, которые есть у указанного типа данных:

[Thread]
public void TEST() {

    var pedArray = Array<Actor>.local( 0, 10 ); // 0@ - 9@

    pedArray[ 0 ].create_random( 0.0, 1.0, 2.0 );
    pedArray[ 1 ].create_random( 1.0, 1.0, 2.0 );
    pedArray[ 2 ].create_random( 2.0, 1.0, 2.0 );
    // ...
    pedArray[ 9 ].create_random( 9.0, 1.0, 2.0 );

    end_thread();
}

Если тип требует более одной переменной, то генератор это будет учитывать и делать нужные отступы. Это требуют только два типа данных: "sString" и "vString":

[Thread]
public void TEST() {

    var pedArray = Array<Actor>.local( 0,  2 ); // 0@ - 1@
    pedArray[ 0 ].create_random( 0.0, 1.0, 2.0 );
    pedArray[ 1 ].create_random( 1.0, 1.0, 2.0 );

    var stringArray = Array<vString>.local( 2, 3 ); // 2@,3@,4@,5@    6@,7@,8@,9@    10@,11@,12@,13@
    stringArray[ 0 ].value = "str 0";
    stringArray[ 1 ].value = "str 1";
    stringArray[ 2 ].value = "str 2";
    end_thread();
}

Мы увидим смещение в результате:

:TEST
03A4: name_thread 'TEST'
0376: 0@ = create_random_actor_at 0.0 1.0 2.0
0376: 1@ = create_random_actor_at 1.0 1.0 2.0
06D2: 2@v = "str 0" // @v = ? (vstring)
06D2: 6@v = "str 1" // @v = ? (vstring)
06D2: 10@v = "str 2" // @v = ? (vstring)
004E: end_thread

Заметно, что никаких массивов не используется на выходе. Здесь активно внедрён трюк с переменными, который позволяет объединять переменные в массивы. Мы можем вызвать метод "each", который будет делать указанное действие с каждым элементом массива:

[Thread]
public void TEST() {

    var index = Int.local( 0 ); // 0@
    var strArray = Array<sString>.local( 1,  5 ); // 1@,2@    3@,4@    5@,6@    7@,8@    9@,10@
    strArray.each( index, elem => {
        elem.value = sString.DUMMY;
    } );

    end_thread();
}

Внутри этой команды "вшит" цикл, который требует перменную-счётчик. Парматер "elem" нужно для того, чтобы работать с элементом массива. Мы можем использовать и ручной цикл, передав переменную счётчик в индекс массива:

[Thread]
public void TEST() {

    var index = Int.local( 0 ); // 0@
    var strArray = Array<sString>.local( 1,  5 ); // 1@,2@    3@,4@    5@,6@    7@,8@    9@,10@
    strArray.each( index, elem => {
        elem.value = sString.DUMMY;
    } );

	// ручной перебор массива
    to( index, 0, strArray.count, delegate {
        strArray[ index ].value = "DUMMY";
    } );

    end_thread();
}

Оба варианта будут генерировать одно и тоже. Только первый делает это быстрее. Вот результат:

//------------- TEST ---------------

:TEST
03A4: name_thread 'TEST'

for 0@ = 0 to 5
05AA: 1@(0@,5s) = 'DUMMY' // @s = ? (sstring)
end


int 0@
for 0@ = 0 to 5
05AA: 1@(0@,5s) = 'DUMMY' // @s = ? (sstring)
end

004E: end_thread

Мы можем изменть размер массива. Но это надо делать осторожно и лучше использовать это не более 1 раза за скрипт:

[Thread]
public void TEST() {

    var index = Int.local( 0 ); // 0@
    var strArray = Array<sString>.local( 1,  5 ); // 1@,2@    3@,4@    5@,6@    7@,8@    9@,10@
    strArray.each( index, elem => {
        elem.value = sString.DUMMY;
    } );

    strArray.Resize( 4 ); // 1@,2@    3@,4@    5@,6@    7@,8@

    strArray.each( index, elem => {
        elem.value = sString.DUMMY;
    } );

    end_thread();
}

На самом деле изменения как такового нету. Просто в циклах изменится размер:

//------------- TEST ---------------

:TEST
03A4: name_thread 'TEST'

for 0@ = 0 to 5 // изначальный размер
05AA: 1@(0@,5s) = 'DUMMY' // @s = ? (sstring)
end

for 0@ = 0 to 4 // после изменения размера
05AA: 1@(0@,4s) = 'DUMMY' // @s = ? (sstring)
end

004E: end_thread

Изменения размера хорошо использовать в миссиях, где часто нужно создавать разное количество врагов и маркеров над ними. Тогда достаточно перед началом миссии изменить размер.