Nexus: The Jupiter Incident

Nexus: The Jupiter Incident

Not enough ratings
Advanced scripting manual (RU)
By TehnoMag
Данное руководство предназначено для углубленного изучения структуры и возможнотей скриптов Nexus: TJI. Здесь я буду описывать все найденные, но недокументированные функции; отмечать функции и события, которые не работают в последней версии; указывать особенности работы ряда функций, которые плохо документированы в официальном руководстве, или не документированы вовсе. Часть информации взята с Wiki http://nexusthegame.net/wiki/Nexus_-_The_Jupiter_Incident и я не претендую на авторство. Такой контент отмечен как цитата или приведена ссылка на оригинальную статью.

Если у Вас есть замечания или исправления по данному руководству, пожалуйста, дайте мне знать.
   
Award
Favorite
Favorited
Unfavorite
Необходмый контент и инструментарий
Для работы со скриптами Nexus Вам понадобится 3 вещи:
  • Текстовый редактор для работы со скриптами
    Я рекомендую использоовать Notepad++ (Официальный сайт[notepad-plus-plus.org]).

  • Microsoft Exel для удобного редактирования параметров кораблей и устройств.
    Также можно использовать LibreOffice.Calc, если сможете адаптировать под него макрос (у меня, например, не получилось).

  • Набор вспомагательных модов.
    Конечно, они не обязательны, и вы можете создать свою реализацию, но в данном руководстве я буду постоянно обращаться к ним, поэтому для лучшего понимания процесса лучше иметь эти моды под рукой.
    http://gtm.steamproxy.vip/sharedfiles/filedetails/?id=1139261112
Пространства переменных и их видимость
Оригинальная статья[nexusthegame.net]

  • Пространство "D."
    Оно представлено в руководстве, как пространство диалогов, но на самом деле не работает.

  • Пространство "T."
    Представлено в руководстве, как пространоство тактических подпрограмм (Subroutines), и работает, но бесполезно, т.к. в подпрограммы передавать переменные лучше через пространство "E."
Структура скриптов
Оригинальная статья[nexusthegame.net]

Дополнительно, блок 'RULE' может принимать следующий синтаксис, в случае, если указано усолвие:

На самом деле описание тела ':else' присутсвует в официальном руководстве, но по какой-то причине отсутсвует в Wiki и не используется в исходной кампании

RULE event DoSomething condition somevar=1 :action Debug("somevar eq 1"); :end :else Debug ("somevar not eq 1"); :end END

В случае если условие выполнется, будут выполнены команды в теле :action
Если нет, то в блоке :else

Также, Вы можете указать несколько тел :action в блоке RULE

RULE event DoSomething condition somevar=1 :action Debug("somevar eq 1"); :end :else Debug ("somevar not eq 1"); :end condition somevar2=1 :action Debug("somevar2 eq 1"); :end :else Debug ("somevar2 not eq 1"); :end END

В этом случае вначале будет проверено первое условие и выполненное выбранное тело, а потом второе.
Список uTypeObject
Список айди типов, которые могут быть проверены через функцию uType()

uType
id
string
0
entity/*
1
system/
100
effect/
103
nexus/
106
location/**
200
station/
201
asteroidfield/
203
fleet/
204
location/***
205
celestial/
206
navigationpoint/
207
ship/
302
device/
305
asteroidscene/
310
npc/
400

* - Story depot
** - Небесные объекты типа комет
*** - врата Nexus
Пример: uSelect(0, uGetUniverse(), S:uType() = 207) вернет все навигационные точки
Недокументированные функции
  • uGetUniverse
    Возвращает основной объект игры

    Синтаксис
    uGetUniverse()
    Особенности
    Нет

  • uCamera_Enter
    Запускает процедуру входа в тактический режим с анимацией.
    В отличии от uEnterMission не требует отдельного файла миссии.

    Синтаксис
    uCamera_Enter(uTypeObject)
    Поддерживаемые типы аргумента
    • system/*
    • nexus/*
    • celesital/*
    • fleet/*
    • navigationpoint/*
    • asteroidfield/*
    • station/*
    • location/*
    Особенности
    • Работает только в модификациях кампании
    • В моде должна быть определена миссия 99
    • Не требует вызова функции uSetNextMission
    • Не стабильна в тактическом режиме. Пользуйтесь с осторожностью.

  • uCamera_PutInto
    Запускает процедуру входа в тактический режим без анимацией.
    В отличии от uEnterMissionQuick не требует отдельного файла миссии.

    Синтаксис
    uCamera_PutInto(uTypeObject)
    Поддерживаемые типы аргумента
    • system/*
    • nexus/*
    • celesital/*
    • fleet/*
    • navigationpoint/*
    • asteroidfield/*
    • station/*
    • location/*
    Особенности
    • Работает только в модификациях кампании
    • В моде должна быть определена миссия 99
    • Не требует вызова функции uSetNextMission
    • Не стабильна в тактическом режиме. Пользуйтесь с осторожностью.

  • QuitMission
    Запускает процедуру выхода из тактического режима с анимацией.
    В отличии от uQuitMission не требует аргумента. При выходе из тактического режима не будет показан экран дебрифинга, а так-же не произойдет выход в главное меню, если функция uSetNextMission не была вызвана. Переменные U.ActMission и U.ActEpisode не будут инкрементированы.

    Синтаксис
    QuitMission()
    Особенности
    • Работает только в модификациях кампании
    • Стабильна только, если вход в тактический режим был осуществлен с помощью функций uCamera_Enter или uCamera_PutInto
    • Не требует вызова функции uSetNextMission
    • Требует ручного вызова функции GuiSelect(2)
    • Не вызывает событие MissionQuit, поэтому вызов не может быть перехвачен в скриптах истории

  • isat
    Возвращает 1 в случае, если вызвавший функцию объект является дочерним. В противном случае 0.

    Синтаксис
    uTypeObject:isat(uTypeObject)
    Поддерживаемые типы аргумента
    Любой uTypeObject
    Особенности
    Нет

  • uGetC
    Возвращает объект, если тот является дочерним к указанному.

    Синтаксис
    uTypeObject:uGetC(string)
    Особенности
    Нет

  • get
    Псевдоним GetSceneObj

    Синтаксис
    get(string)
    Особенности
    Те же, что и для GetSceneObj

  • makeMainShip
    Неизвестно

    Синтаксис
    MakeMainShip(Ship, string)
    Особенности
    Неизвестно
Хаки
  • Переход в тактический режим через меню карты (стратегический режим)
    Чтобы этот хак заработал нам нужно для всех требуеых объектов системы выставить DetectionLevel в 5 (#UDET_SPYCAM)

    Пример:
    RULE event EpisodeStart condition ActEpisode=1 :action sel := GetFreeSel(); uSelect(sel, uGet("sys_sol"), S:celestial()|S:colony()); ExecList(sel, S:uSetDetectionLevel(#UDET_SPYCAM)); :end END

    Теперь на панели описания объекта появится дополнительная кнопка.
    При ее нажатии будет вызвана функция uCamera_Enter и мы окажемся в тактическом режиме.






  • Анимация прыжка через червоточину
    В мисси 16 оригинальной кампании мы видим анимацию прыжка Ангелады при входе в червоточину. Я думаю многие замечали, что эта анимация больше нигде не работает. Это не совсем так.

    У классов кораблей (файл Universe/tactics/tacticstypes.ini) есть параметр HPRegen (он указан только у класса Ангелады). Если этот параметр больше нуля, то при входе в червоточену будет показана анимация (при этом достаточно указать значение 0.001 или похожее, чтобы не разрушить баланс). Более того, после проигрывания анимации сцена будет выгружена и можно смело использовать функцию uCamera_Enter или uCamera_PutInto в событие MissionQuit для переключения сцены. Однако, к сожалению, это работает только с объектами типа nexusgate/* и мы должны проиграть некий bink ролик для завершения разрушения сцены (пустого ролика будет достаточно).
Объектно ориентированный скриптинг
Устарело!. Раздел будет обновлен после выхода Universe Script Library 2.0

В больших комплексных модах возникает необходимость использовать объекты с одним и тем же набором функций и переменных, но с разными состояниями. К сожалению, в оригинальной игре не предоставлено подобного функционала, поэтому мной был написан модуль для расширения возможностей стандартной StateMachine и включен в состав мода uSL.
  • Основные понятия
    • Класс - StateMachine, созданная через модуль Class библиотеки uSL
    • Ссылка - Номер листа инстанции класса
    • Инстанция - Экземпляр класса
    • Объект - Переменная, являющаяся непосредственно классом

  • Определения
    Каждый класс может иметь одну или несколько инстанций со своим уникальным состоянием переменных. Доступ к инстанции можно получить через объект класса, или через метод __changeInstance.

  • Макросы
    Макросы задаются через директиву #include.
    • uSL/class/declaration
      Данный макрос говорит игре, что данная StateMachine является классом.
      Он должен быть определен сразу после определения MACHINE
      .

    • uSL/class/instance
      Данный макрос определяет метод, как метод инстанции.
      Он должен быть указан сразу после определения RULE event
      .

    • uSL/class/end_instance
      Данный макрос определяет конец метода инстанции.
      Он должен быть указан сразу после определения :end
      .

    • uSL/class/end
      Данный макрос определяет конец класса.
      Он должен быть указан после всех методов
      .

Пример Класса
MACHINE "uSL/Class/Example" #include "uSL/class/declaration" RULE event __Constructor #include "uSL/function/private" :action //Init variables var1 := 3; var2 := 2; var3 := 1; //Doing something :end END //This function need for instancing RULE event __var #include "uSL/function/private" :action if (!E.flag, E.flag := #uSL_CLASS_SETGET); var1 := this:localEvent(__instvar, E.flag := P.flag; E.id := 1; E.value := var1); var2 := this:localEvent(__instvar, E.flag := P.flag; E.id := 2; E.value := var2); var3 := this:localEvent(__instvar, E.flag := P.flag; E.id := 3; E.value := var3); :end END //Simple instanced function RULE event ExampleFunc #include "uSL/class/instance" :action var3:= var1+var2; Return(var3); :end #include "uSL/class/end_instance" END #include "uSL/class/end" END

Пример использования

//Создадим первый экземпляр класcа Example object := U.uSL.Class:localEvent(New,E.class := "Example"); //Получим объект этого класса для последующей работы example:=U.uSL.Class:last; //Создадим второй экземпляр object2 := U.uSL.Class:localEvent(New, E.class := "Example"); //Изменим состояние переменной var1 в инстанции object2 example:var1:=4; //Вызовем метод для инстанции object example:localEvent(ExampleFunc, E.ref := M.object); //Функция возвратит нам 5 //Проверим переменную var3 в инстанции object2 Debug(example:var3); //Вызов вернет нам 1, т.к. для класса основной инстанцией является object2 Вызовем функцию для object2 example:localEvent(ExampleFunc, E.ref:=M.object2); //Функция вернет нам 6 //Еще раз проверим переменную var3 и убедимся, что в ней хранится значение 7 Debug(example:var3); //Поменяем инстанцию класса, передав нужную ссылку в аргументе example:localEvent(__changeInstance,E.ref:=M.object); //Убедимся, что в var3 теперь хранится значение 5 Debug(example:var3); //Удалим созданные классы U.uSL.Class:localEvent(Del, E.ref := M.object); U.uSL.Class:localEvent(Del, E.ref := M.object2);
Галактическая библиотека Скриптов вер.2
Работа библиотеки версии 2 будет описана ниже.
Структура Вашего мода
Точка входа
Точка входа эта рутина, вызов которой приведет к инициализации вашего мода. В Случае с Библиотекой скриптов, это будет главное меню (особенность скриптового движка Nexus Black Ruller заключается в том, что он сбрасывает в сохранение все нужные значение, а также точку останова скрипта, поэтому при загрузке игры мы получим сразу инициализированные скрипты).
Также, отдельно отмечу, что мод, обязан быть модификацией компании, чтобы Библиотека Скриптов могла полноценно загрузиться. Дополнительно ей понадобится указатель на основную стейт машину мода в определенном формате, поэтому дополнительно нужно будет написать небольшую функцию для его передачи.

ЧекЛист
  • Модификация - это модификация компании
В директории мода необходимо создать директорию Universe (если ее нет) и в ней создать пустой файл с именем .campaign (точка campaign)
  • На кнопку "Новая Игра" назначена точка входа Библиотеки Скриптов
В директории Universe вашего мода нужно создать файл main.ini, в котором будет указан следующий код:
Title "My Mod" MAINMENU "Start It!" uCall(ModMain, 0) "Load A Saved Game" loadgame END
, где
Title - название вашего мода
блок MAINMENU описывает все кнопки, которые появятся в нем.
Первый параметр текст кнопки, второй - событие, которое будет вызвано при нажатии на нее.
uCall(ModMain, 0) - Точка входа в Библиотеку Скриптов
  • Присутствует правильно оформленная главная стейт машина мода
Главная стейт машина мода это стейт машина, которая производит управление всеми дальнейшими событиями мода. В ней вы должны указать всю необходимую вам логику, все необходимые переходы, итд. Подробнее о ней будет рассказано далее в руководстве.

Эта машина должны располагаться в рутинах стратегии. Поэтому, необходимо в вашем соде создать необходимые поддиректории в директории Universe вашего мода, а именно, Strategy\Subroutines\. В ней, вам нужно создать файл в формате Mod.ModName.ini, где ModName имя вашего мода.

В этот файл необходимо поместить код стейт машины и рутины, которая будет передать ее указатель в библиотеку скриптов.
RULE event ModMain :action //Get Main Mod Machine e:mod := getMachine("/MdName"); //We want use ScriptLibrary, so lets init it. //As argument we sending Mod main machine uCall(UniverseScriptLibrary, e:mod := p:mod); :end END MACHINE "/ModName" STATE _INIT_ RULE event In :action //If you whant use some modules. You can include them here. _class := usl:localEvent(Use, e:module := "Class"); :end END END STATE _MAIN_ RULE event In :action //Real mod start. All staff already initialized and you can do whatever you whant :end END END END
Ваш модуль (Опциональный мод)
Встроенный модуль "Класс"