Skip to content

Документация Mассивы.

Mr.Stalin edited this page Jul 1, 2021 · 1 revision

МАССИВ

Sfall вводит новый метод хранения переменных - массивы.

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


КОНЦЕПЦИЯ МАССИВОВ

Массивы создаются и управляются с помощью функций массива. Для начала массив должен быть создан с помощью функций create_array или temp_array, указав, сколько элементов данных может содержать массив. Вы можете хранить любые типы данных int, float или string в массиве, также можно смешивать все 3 типа в одном массиве.
Идентификатор массива, возвращаемый функциями create_array или temp_array, может использоваться в других функциях для доступа к созданному массиву. Массивы являются общими для всех сценариев (т.е. вы можете вызвать "create_array" в одном сценарии, а затем использовать возвращенный идентификатор в совершенно другом сценарии для доступа к массиву). Массивы также могут быть сохранены в файлах сохранения игры.

Массивы, созданные с помощью temp_array, будут автоматически удалены в конце кадра выполнения сценария. create_array - единственная функция, которая возвращает постоянный массив, все остальные функции, возвращающие массивы (string_split, list_as_array и т.д.), создают временные массивы. Вы можете использовать функцию fix_array, чтобы сделать временный массив постоянным.
Функции массивов полностью безопасны в том смысле, что использование неверного идентификатора или попытки доступа к элементам вне размера массива не приведут к сбою в сценарии.

Доступ к элементам массива осуществляется по индексу или ключу.

Пример:

    // this code puts some string in array "list" at index 5:
    list[5] := "Value";

В настоящее время доступно 2 различных типа массива:

  1. Lists - предоставляет коллекцию значений, определенного размера (количество элементов), где элементы имеют числовые индексы, первый индекс элемента всегда начинается с нуля (0) до конца всей длины массива минус единица.

    Пример:

    // this creates list with 3 elements. Element "A" has index 0, element "B" has index 1, element "C" - 2
    list := ["A", "B", "C"];

    Ограничения:

    • все индексы являются числовыми, и начинаются с 0
    • чтобы присвоить значение элементу списка по определенному индексу, необходимо для сначала изменить размер массива, чтобы список содержал этот индекс
      например, если список имеет размер 3 (индексы от 0 до 2), вы не можете присвоить значение по индексу 4, если сначала не измените размер списка на 5
  2. Maps - ассоциативные массивы содержат наборы пар key=>value, где все элементы (значения) доступны с помощью соответствующих ключей.

    Отличия Maps (карт) от List (списка):

    • ассоциативные массивы не имеют определенного размера (для присвоения значений вам не нужно изменять размер массива)
    • ключи, как и значения, могут быть любого типа (но избегайте использования -1 в качестве ключей массива, иначе вы не сможете надежно использовать некоторые функции)

Оба типа массива имеют свои плюсы и минусы и подходят для решения различных задач.


СИНТАКСИС МАССИВОВ

В основном массивы реализуются с использованием ряда новых операторов (функций сценариев). Но для удобства использования есть некоторые новые элементы синтаксиса:

  1. Доступ к элементам. Используйте квадратные скобки:
    display_msg(arr[5]);
    mymap["price"] := 515.23;
  1. Альтернативный доступ к картам. Используйте точку:
    display_msg(mymap.name);
    mymap.price := 232.23;
  1. Выражения массива. Создавайте и заполняйте массивы просто используя одно выражение:
    // create list with 5 values
    [5, 777, 0, 3.14, "Cool Value"]

    // create map:
    {5: "Five", "health": 50, "speed": 0.252}

NOTES: Обязательно вызовите fix_array, если вы хотите, чтобы новый массив был доступен в следующем фрейме выполнения сценария, или save_array, если вы хотите использовать его в течение более длительного периода (подробнее см. следующий раздел).

  1. Перебор элементов массива в цикле. Используйте ключевое слово foreach следующим образом:
    foreach (item in myarray) begin
        // этот блок выполняется для каждого элемента массива, где "item" содержит текущее значение на каждом шаге итерации
    end

    // альтернативный синтаксис:
    foreach (key: item in myarray) begin
        // "key" будет содержать текущий ключ (или числовой индекс, для списков)
    end

См.: sslc_readme.txt файл для получения полной информации о новых функциях синтаксиса SSL.


ХРАНЕНИЕ МАССИВОВ

Часть массивов списков и карт разделена по способу их хранения.

Существует 3 типа массивов:

  • Temporary: Они создаются с помощью функции temp_array или при использовании выражений массива. Массивы этого типа автоматически удаляются в конце кадра выполнения сценария. Так, например, если у вас есть глобальный сценарий, который выполняется через регулярные промежутки времени, где вы создаете temp_array, то массив не будет доступен при следующем выполнении вашего глобального сценария.

  • Permanent: Они создаются с помощью функций create_array или fix_array (из уже существующего временного массива). Массивы этого типа всегда доступны (по их идентификатору) до тех пор, пока вы не начнете новую игру или не загрузите сохраненную игру (после чего они будут удалены).

  • Saved: Если вы хотите, чтобы ваш массив действительно оставался на некоторое время, используйте функцию save_array, чтобы сделать любой массив "сохраняемым". Однако они, как и постоянные массивы, "удаляются" из памяти при загрузке игры. Чтобы правильно их использовать, вы должны загружать их из сохраненной игры с помощью "load_array" всякий раз, когда вы хотите их использовать.
    Пример:

    variable savedArray;
    procedure start begin
        if game_loaded then begin
            savedArray := load_array("traps");
        end else begin
            foreach trap in traps begin
                ....
            end
        end
    end

ПРАКТИЧЕСКИЕ ПРИМЕРЫ

Используйте массивы для реализации процедур с переменными аргументами:

    // define it
    procedure give_item(variable critter, variable pidList) begin
        foreach (pid: qty in pidList) begin
            give_pid_qty(critter, pid, qty);
        end
    end

    // call it:
    call give_item(dude_obj, {PID_SHOTGUN: 1, PID_SHOTGUN_SHELLS: 4, PID_STIMPAK: 3});

Создание массивов объектов (карт) для продвинутого скриптинга:

    variable traps;
    procedure init_traps begin
        // just a quick example, there is a better way of doing it...
        traps := load_array("traps");
        if (traps == 0) then begin
            traps := [];
            save_array("traps", traps);
        end
        foreach k: v in traps begin
            traps[k] := load_array("trap_"+k); // каждый объект хранится отдельно
        end
    end

    procedure add_trap(variable trapArray) begin
        variable index;
        index := len_array(traps);
        save_array("trap_"+k, trapArray);
        array_push(traps, trapArray);
    end

    // use them:
    foreach trap in traps begin
        if (self_elevation == trap["elev"] and tile_distance(self_tile, trap["tile"]) < trap["radius"]) then
            // kaboom!!!
        end
    end

ФУНКЦИИ МАССИВОВ

int create_array(int size, int flags)

  • Создает постоянный массив (тип Permanent)
  • если аргумент size больше или равен 0, то это создает список заданного размера
  • если аргумент size равен -1, то это создает карту (ассоциативный массив)
  • если аргумент size равен -1 а аргумент flags равен 2, то это создает lookup карту (ассоциативный массив), в котором значения существующих ключей доступны только для чтения и не могут быть обновлены. Только этот тип массива позволяет хранить ноль (0) в значение ключа.
    ПРИМЕЧАНИЕ: в более ранних версиях (до 4.1.3/3.8.13) аргумент flags не используется, просто используйте 0
  • Возвращает идентификатор созданного массива arrayID (действует до тех пор, пока массив не будет удален)

int temp_array(int size, int flags)

  • Работает точно так же, как функция create_array, только создает временный массив (тип Temporary)

void fix_array(int arrayID)

  • Изменяет Temporary массив на Permanent массив (постоянные массивы автоматически не сохраняются в сохраненных играх)

void set_array(int arrayID, mixed key, mixed value)

  • Устанавливает значение для элемента массива
  • если используется массив типа List, то аргумент key должен быть числовым и находиться в допустимом диапазоне индексов (0..size-1)
  • если используется массив типа Maps, в этом случае аргумент key может быть любого типа
  • чтобы "снять" значение с карты, просто установите для ключа его значение равным нулю (0)
    ПРИМЕЧАНИЕ: чтобы установить для ключа значение 0, используйте значение 0.0 с плавающей точкой (тип float)
  • это работает точно так же, как оператор: array[key] := value;

mixed get_array(int arrayID, mixed key)

  • Возвращает значение массива по ключу или индексу
  • если ключ не существует или индекс не находится в допустимом диапазоне, возвращается 0
  • работает точно так же, как выражение: value := array[key];

void resize_array(int arrayID, int size)

  • changes array size
  • applicable to maps too, but only to reduce elements
  • there are number of special negative values of "size" which perform various operations on the array, use macros sort_array, sort_array_reverse, reverse_array, shuffle_array from sfall.h header

void free_array(int arrayID)

  • deletes any array
  • if array was "saved", it will be removed from a savegame

mixed scan_array(int arrayID, mixed value)

  • searches for a first occurence of given value inside given array
  • if value is found, returns it's index (for lists) or key (for maps)
  • if value is not found, returns -1 (be careful, as -1 can be a valid key for a map)

int len_array(int arrayID)

  • returns number of elements or key=>value pairs in a given array
  • if array is not found, returns -1 (can be used to check if given array exist)

mixed array_key(int arrayID, int index)

  • don't use it directly; it is generated by the compiler in foreach loops
  • for lists, returns index back (no change)
  • for maps, returns a key at the specified numeric index (don't rely on the order in which keys are stored though)
  • can be checked if given array is associative or not, by using index (-1): 0 - array is list, 1 - array is map

int arrayexpr(mixed key, mixed value)

  • don't use it directly; it is used by compiler to create array expressions
  • assigns value to a given key in an array, created by last create_array or temp_array call
  • always returns 0

void save_array(mixed key, int arrayID)

  • makes the array saveable; it will be saved in sfallgv.sav file when saving the game
  • arrayID is associated with given "key"
  • array becomes permanent (if it was temporary) and "saved"
  • key can be of any type (int, float or string)
  • if you specify 0 as the key for the arrayID, it will make the array "unsaved"

int load_array(mixed key)

  • load array from savegame data by the same key provided in save_array
  • arrayID is returned or zero (0) if none found

*mixed - means any type


ПРИМЕЧАНИЯ ПО ОБРАТНОЙ СОВМЕСТИМОСТИ

Для тех, кто использовал массивы в своих модах до sfall 3.4:

  1. Существует INI параметр ArraysBehavior в Misc разделе файла "ddraw.ini". Если его значение установлено в 0, то все сценарии, которые ранее использовали массивы sfall, должны работать. Это в основном меняет то, что create_array создает постоянные массивы, которые "сохраняются" по умолчанию, и их идентификатор также является постоянным. По умолчанию этот параметр равен 1.

  2. Как обрабатывается совместимость с сохраненными играми?.
    Сохраненные массивы хранятся в файле sfallgv.sav (в сохраненной игре) в новом (более гибком) формате сразу после старых массивов. Таким образом, в принципе, когда вы загружаете старую сохраненную игру, sfall загрузит массивы из старого формата и сохранит их в новом формате при следующем сохранении игры. Если вы загрузите сохраненную игру, созданную с помощью sfall 3.4, используя sfall 3.3 (например), игра не должна завершиться сбоем, но все массивы будут потеряны.

  3. Ранее вам приходилось указывать размер в байтах для элементов массива. Этот параметр теперь игнорируется, и вы можете хранить строки произвольной длины в массивах.