500
  • Страница 1 из 1
  • 1
Модератор форума: tupi857  
Форум » Видоизменение » Технологии » Руководство по написанию скриптов ( часть 1)
Руководство по написанию скриптов ( часть 1)
# 108:02 12/06/2019
9
tupi857 (jango)
Cмотритель

 Вне сети
Предпосылок

Наиболее важной предпосылкой, если вы хотите работать над сценарием ИИ, является терпение. По своему опыту я знаю, что без достаточного терпения сценарии ИИ довольно разочаровывают. Большая часть времени будет потрачена на тестирование и отладку. Вам нужно терпение.
Кроме того, у вас должны быть базовые знания компьютера, такие как просмотр определенных папок, копирование / вставка, создание новых файлов и т. Д.
Чтобы работать над сценарием, вам необходим текстовый редактор. Если ваша операционная система Windows, у вас уже есть текстовый редактор: «Блокнот» («Пуск»> «Все»> «Блокнот»). Однако я бы порекомендовал более продвинутый текстовый редактор, такой как Notepad ++. Поиск в Google, вы найдете множество текстовых редакторов.
Для тестирования и отладки необходимо установить Age of Empires III и оба его расширения (The WarChiefs и The Asian Dynasties). Ну, так как вы здесь, я предполагаю, что у вас уже есть игра.

Это очень поможет!

Рабочая область

Каталог, в котором установлена ​​ваша копия AoE3, будет нашей основной рабочей областью. По умолчанию это должно быть в C: \ Program Files \ Microsoft games (x86) \ Age of Empires III. Он должен небыть в моих документах, если вы не выбрали его по какой-либо причине. Этот каталог, я назову его папкой AoE3, чтобы мне не приходилось указывать, куда каждый раз устанавливается ваша копия AoE3 .
Иногда нам может понадобиться попасть туда, где сохранены игры и настройки. Он находится в папке \ Users \ [здесь идет ваше имя пользователя] \ Documents \ My games \ Age of Empires 3. Я назову его папкой My games .
И, наконец, вы должны выбрать определенную папку для резервных копий. Да, самое важное правило для моддеров - всегда делать резервную копию, чтобы ее можно было восстановить на случай, если что-то пойдет не так. Например, создайте папку на рабочем столе, назовите ее «AI Backups».
Теперь вот файлы, которые мы будем использовать. Они расположены в папке AoE3 :
папка AoE3 \ data \ protoy.xml: нам понадобится это для поиска юнитов и зданий
AoE3 folder \ data \ techtreey.xml : нам понадобится это для поиска техников
По желанию нам может понадобиться
AoE3 folder \ data \ stringtabley.xml для поиска юнитов / зданий / технологий на случай, если мы забудем их технические названия.
Файлы сценариев AI находятся в папке AoE3 \ AI3 \.

Наконец, я должен сообщить вам, что каждый раз, когда я говорю, откройте XXX (или что-то в этом роде), это означает, что откройте XXX в вашем текстовом редакторе . Просто для вашего сведения, мой текстовый редактор Notepad ++.

Пожалуйста, помните все эти «условности», чтобы мы могли понять друг друга

AI файлы

Каждый компьютерный проигрыватель связан с файлом, известным как «личный файл», и у каждого из них есть свой личный файл. Личные файлы находятся в папке AoE3 \ AI3. Всего существует 14 личных дел: Акбар, Сумасшедший конь, Куаутемок, Элизабет, Фредерик, Генри, Гайавата, Изабелла, Иван, Канси, Наполеон, Сулейман, Токугава и Уильям. Если мы откроем один из них, мы увидим код XML. Единственная часть, которая нас интересует, это:
Код: выбрать все

Код
<script>aiLoaderStandard</script>

Эта строка кода загружает скрипт, который будет управлять плеером компьютера. Здесь компьютерный плеер будет управляться скриптом aiLoaderStandard . Мы можем найти aiLoaderStandard в той же папке, что и личные файлы. Вы можете открыть его, если хотите, но пока он нам не понадобится. Позже мы создадим наш собственный файл сценария и загрузим его в файлы личных данных, но теперь это не будет.

Основами XS.

Вы можете спросить, что такое «XS». XS - это своего рода язык программирования, который используется во многих частях AoE3 для AI, случайных карт, триггеров, пользовательского интерфейса, домашнего города (для управления людьми, которые бродят по домашнему городу). Поскольку вы собираетесь создавать ИИ, вам придется выучить некоторые вещи на языке XS, здесь и сейчас.

Комментарии
Комментарии являются частью сценария, который ничего не делает. Они ничего не влияют на ИИ. Оставлять комментарии - все равно, что ничего не ставить. Для чего нужны комментарии? Вам нужны комментарии, чтобы объяснить те части сценария, которые кажутся трудными для понимания тем, кто будет читать ваш сценарий. Другими словами, комментарии помогают понять коды. Даже вам, автору скрипта, понадобятся комментарии, если вы не откроете скрипт в течение определенного периода. Есть два типа комментариев:
однострочные комментарии: //
Код: выбрать все

Код
// This whole line will be ignored by AoE3

Многострочные комментарии: / * * /

Код
/* Commentary on the use of multi-line comments.
Multi-line comments are usually used to write
bigger blocks of text*/

Не пренебрегайте комментариями!

1. Переменные

Переменные - это разновидность именованных блоков, которые могут содержать информацию, которая может быть изменена во время выполнения программы (в нашем случае это скорее выполнение скрипта). Использование переменных просто важно, так как эта информация понадобится во время выполнения скрипта. В XS типизированы переменные, т.е. информация, содержащаяся в этих переменных, имеет тип. Каждая переменная занимает определенную память в ОЗУ, а объем памяти зависит от типа данных. Прежде чем использовать переменную, мы должны сначала определить (создать) ее . Чтобы определить переменную, мы пишем:
type name = value ;
Замените тип на нужный тип (указан ниже)
Замените имя на желаемое имя для переменной (правило именования следует после списка типов)
= (равно) обязательно. Это означает, что мы присваиваем значение переменной.
Замените значение на желаемое значение. Предупреждение: он должен быть того же типа, что и переменная (целочисленная переменная не может содержать десятичное значение)
; (точка с запятой) является обязательным. Это означает, что мы закончили определение переменной.

Пример:

Код
int myIntegerVariable = -1;

После определения переменной вам больше не нужно ставить тип перед ее именем

Код
int myIntegerVariable = -1;
myIntegerVariable = 10;

И я настаиваю: прежде чем использовать переменную, мы должны сначала определить (создать) ее .
Правильно:
int myVar = 0;
myVar = 2;

Неверно:
myVar = 0;
int myVar = 2;

Вот наиболее часто используемые типы в XS: Целочисленные

(
целые ) переменные типа Integer содержат числовые, недесятичные значения, например 100, -100, 8463.

Числа с плавающей запятой (с плавающей запятой)
Эти переменные могут содержать числовые значения с десятичной частью, например 3.141592, 2.718281, -1.0

Booleans (bool)
Эти переменные имеют только два возможных значения: true или false .

Логические значения полезны, когда вы хотите сравнить два значения (или значения двух переменных). Вот известные операторы для сравнения:
> больше чем
<меньше чем
> = больше или равно
<= меньше или равно
== равно (Внимание: не путайте это с "=")
! = Не равно

Вот несколько примеров того, как использовать логические переменные:

bool a = (1 == 4);
Поскольку 1 не равно 4, это неверно .

bool b = (1 <4);
Поскольку 1 меньше 4, это правда .

bool a = (1 == 4);
bool b = (1 <4);
bool c = (a == b);
Поскольку а ложно, а б верно иложь не верно, тогда с ложно .

Есть также еще два оператора: AND (&&) и OR (||)
AND:
true && true это правда
true && false это false
false && false это false

OR:
true || правда это правда
правда || ложь верно
ложь || false is false

Не беспокойтесь, на практике мы будем конкретным образом использовать логические значения, и тогда это станет более понятным.

Строки (string)
Эти переменные содержат буквенно-цифровые значения. Строковые значения должны быть между двумя »(цитата). Пример:

Код
string myName = "Alistair";

Можно объединить значения:

Код
string name1 = "Edward";
string name2 = "Thatch";
string actualName = name1+" "+name2;

Поскольку name1 и name2 не находятся между двумя кавычками, они рассматриваются как переменные, поэтому вместо «name1 name2» мы получаем «Edward Thatch».

Это все для переменных типов. Теперь давайте посмотрим правила именования переменных:
* Имена переменных содержат только символы от a до z, от A до Z, от 0 до 9 и _ (подчеркивание).
* Имена не могут начинаться с цифры, но могут начинаться с подчеркивания.
* Имена не могут быть зарезервированными словами:
точка останова, точка останова, регистр, константа, продолжение, значение по умолчанию, double, else, extern, float, for, goto, если, int, long, return, static, string, switch, vector, void, while
* Каждая переменная имеет уникальное имя , т.е. вы не можете определить две переменные с одинаковым именем:
int thisIsAnIntVar = 0;
int thisIsAnIntVar = 0; // ОШИБКА!!! Эта переменная уже была определена.
XS чувствителен к регистру, поэтому A отличается от a, AA не является aa и т. Д. Это тогда правильно:
int thisIsAnIntVar = 0;
int THISISANINTVAR = 0;
int thisisanintvar = 0;
Однако я бы не советовал называть это так.

Теперь вот несколько примеров для определения переменных:

Код
int myIntegerVariable = 3;
float myFloatVariable = 3.141592;
bool thisMapIsNaval = false;
vector mapOrigin = vector(0.0, 0.0, 0.0);
string unitName = "Musketeer";

Также возможно сделать некоторые основные математические:
Код
int a = 1;
int b = 6;
int c = a + b; // The value of c is 6

Возможные операции: сложение (+), вычитание (-), умножение (*), деление (/),
приращение: ++, как a ++, что аналогично a = a + 1;
декремент: - как a--, который похож на a = a - 1;
Примечание: отрицание (-) * не * поддерживается при применении к переменным: -a неверно. Таким образом, вы должны сделать так: a = 0 - a;

Константы Константа
- это переменная, значение которой никогда не меняется после определения. Константы похожи на простые выражения, но с именем:

Код
int score = 300;
float distance = 30.0;
const int penalty = 5;
// If distance is bigger than 30.0, decrease the score
score = score - penalty;

Написание счета = оценка - штраф - это то же самое, что написание счета = оценка - 5
Разница в том, что вы хотите изменить штрафную точку. Если вы написали « оценка = оценка - 5» , вы должны изменить все 5 на новое желаемое значение, и это может быть очень раздражающим, в зависимости от количества случаев. Если вы написали счет = оценка - штраф , вам просто нужно изменить значение в определении:
const int penalty = 10

2. Управляющие структуры.

Итак, вы теперь поняли понятие переменных, но это определенно не единственное, что делает скрипт - это было бы просто сумасшествием. ИИ должен решить, что делать в зависимости от ситуации / обстоятельств. Управляющие структуры служат для указания того, что должно быть выполнено сценарием, если выполняется определенное условие.

Блок инструкций
Блок - это последовательность инструкций, которые сгруппированы и обычно выполняются как одна инструкция. Несколько инструкций, заключенных в фигурные скобки {}, образуют блок.

Условные структуры: если, еще
Помните о логических значениях? Ну, это будет использовано здесь.
Структура условий выглядит следующим образом

Код
if (condition)
{
    instructions A;
}
else
{
    instructions B;
}


если условие является истинным , инструкции А будет выполняться. В противном случае инструкция B будет выполнена.

Существует также другое if , которое позволяет нам проверять различные условия, если первое условие ложно . Мы можем использовать как можно больше :

Код
if (condition)
{
    instructions;
}
else if (condition)
{
    instructions;
}
else if (conditions)
{
    instructions;
}
else
{
    instructions;
}


Пример:

Код
string chat = "Ugh... I don't know what to say";
if (a < 0)
{
    chat = "a is negative";
}
else if (a > 0)
{
    chat = "a is positive";
}
else
{
    chat = "a is 0";
}

Итерационные структуры: циклы
Цель циклов - повторять блок инструкций определенное количество раз или при выполнении условия.

в то время как
Код
while (condition)
{
    instructions;
}


В то время как условие является истинным , инструкции будут выполнены. Будьте осторожны, это может привести к проблемам с производительностью и даже к сбоям. Чтобы разорвать цикл, вы можете изменить условия:
Код
int a = 0;
int b = 100;
string chat = "Nothing";

while (a < 100)
{
    chat = "a="+a;
    a++;
}

Опять же , будьте осторожны, избегайте всех рисков , чтобы сделать бесконечный цикл - когда условие всегда истинно .
Код
for (initialization; condition)
{
    instructions;
}

Этот цикл выполняет блок инструкций определенное количество раз.
инициализация : определяет целочисленную переменную, устанавливает начальное значение для счетчика (для подсчета количества итераций).
условие : если это правда , инструкции выполняются, значение переменной при инициализации увеличивается на 1 (увеличивается), и цикл продолжается. Если значение равно false , цикл прерывается и инструкции не выполняются.
Пример:
Код
string info = "Info";
for (i=0;<10)
{
    if (i==0)
    {
  info = "i is 0";
    }
    else
    {
  info = "i is now "+i;
    }
}

Код
info = "i is 0"
info = "i is now 1"
info = "i is now 2"
info = "i is now 3"
info = "i is now 4"
info = "i is now 5"
info = "i is now 6"
info = "i is now 7"
info = "i is now 8"
info = "i is now 9"


Настоятельно рекомендуется использовать для когда вы знаете , сколько раз должен быть выполнен блок инструкций.

Операторы Jump: break
Иногда нам может потребоваться завершить цикл, даже если условие истинно . Для этого мы используем перерыв .
Код
string info = "Info";
for (i=0;<10)
{
    if (i==4)
    {
  info = "i is 4 so let's stop";
  break;
    }
    info = "i="+i;
}

Код
info = "i=0"
info = "i=1"
info = "i=2"
info = "i=3"
info = "i is 4 so let's stop"

Операторы перехода: продолжить
Иногда нам может потребоваться пропустить выполнение блока инструкций, даже если условие истинно . Для этого мы используем продолжить .

Код
string info = "Info";
for (i=0;<10)
{
    if (i==4)
    {
  continue;
    }
    info = "i="+i;
}

Код
info = "i=0"
info = "i=1"
info = "i=2"
info = "i=3"
// (4 is skipped)
info = "i=5"
info = "i=6"
info = "i=7"
info = "i=8"
info = "i=9
"
Селективная структура: switch
Цель с помощью switch - проверить несколько возможных значений для выражения, аналогично if ... else if ... else.

Код
switch(expression)
{
    case constant1:
    {
  instructions A;
  break;
    }
    case constant2:
    {
  instructions B;
  break;
    }
    .
    .
    .
    default:
    {
  default instructions;
    }
}


Ну, это работает так:
switch вычисляет выражение и проверяет, если выражение == constant1 . Если это так, инструкция A выполняется. Когда разрыв обнаружен, структура переключателя заканчивается. Если выражение! = Константа1 , оно проверяет, является ли выражение == константа2 и является ли оно истинным, инструкции B выполняются и т. Д. Если значение выражения не соответствует ни одной из констант, выполняются инструкции по умолчанию . Обратите внимание, что значение по умолчанию не является обязательным - блок инструкций по умолчанию является необязательным. Также обратите внимание, что выражениесравнивается только с константами: вы не можете поместить переменные вместо константы1, константы2, ...

3. Функции
Хорошо, до сих пор все, что мы можем сделать, это определить переменные и сделать некоторые вычисления, которые ничего не сделают для ИИ. Тем не менее, мы увидели ключевую структуру XS и теперь готовы увидеть / сделать более конкретные вещи.
Какие функции? Ну, представьте себе кнопку с именем, которая выполняет определенные задачи, когда мы нажимаем на нее. Функции похожи на эту кнопку: функция - это группа инструкций или блок инструкций, которые выполняются при вызове из некоторой точки скрипта. Создание функций может быть чрезвычайно полезным и сокращает сценарий. Пока же мы увидим нативные функции, то есть функции, которые уже являются частью игры.

Определение
В XS определение функции выглядит так:
Код
returnType functionName(type1 parameter1=defaultValue1, type2 parameter2=defaultValue2)
{
    instructions;
    return returnValue;
}


returnType представляет тип данных, который должна возвращать функция (int, string, ...). Если функции ничего не возвращают, returnType должен быть void .
functionName - это имя функции. Правила именования аналогичны правилам именования переменных.
параметр1, параметр2 ... параметры - это переменные, над которыми (или благодаря которым) функция может выполнять операцию. Когда вы вызываете функцию, вы вводите нужные данные в соответствующий параметр - не беспокойтесь, в примерах это будет понятнее. Обратите внимание, что он не ограничен двумя параметрами, а также можно вообще не задавать никаких параметров.
defaultValue1, defaultValue1 ... когда мы вызываем функцию, но не указываем значение в параметре, функция использует значение этого параметра по умолчанию.
return - возвращает значение, рассчитанное функцией (returnValue). Если функция пуста, это завершает выполнение функции.
returnValue - это то, что функция возвращает после выполнения своего блока инструкций. Значение должно быть того же типа, что и returnType. Если функция пуста, не помещайте returnValue.

Вызов
Если функция не является пустым , вы должны вызывать функцию следующим образом:
variable = functionName (параметр1, параметр2);

Тип данных переменной должен совпадать с типом возвращаемого значения functionName . Ну, иногда нет необходимости присваивать его переменной, вы можете просто вызвать функцию.

Нативные функции в AoE3
В AoE3 есть несколько типов функций:

xs: это что-то вроде элементов XS, которых нет в других языках, или как полезные инструменты, например, для работы с векторами или для работы с массивами.
ai: эти функции напрямую связаны с поведением ИИ во время игры: экономика, вооруженные силы, планы и т. д.
kb: kb означает «базу знаний» и полезны для получения / установки данных из / в игре. Откройте ссылку и узнайте некоторые функции kb. Прочитав их имена, вы сможете понять, что они могут делать. функции т.п.н. работать для игрока , которого вы выбрали, так что , например, если вы используете kbGetPop () , он возвращает общее население контекста игрока , которого вы находитесь.

Функции пользователя
Почти все нативные функции перечислены в справочнике, поэтому я не буду больше тратить на это время (пока). Теперь поговорим о пользовательских функциях.

Ну, мы уже видели, как определить функцию. Вот пример функции с целочисленным типом возврата:
Код
int fact(int n=1)
{
    int temp = 1;
    for(i=1;<n+1)
    {
  temp = temp*i;
    }
    return(temp);
}

Эта функция вычисляет факториал числа. И вот как мы это используем:
int justAnIntVariable = fact (3); // Возвращает факт функции 6

Код
float function1()
{
    int a = 0;
    int b = 0;
}

float function2()
{
    int a = 0;
    int b = 0;
}

Помните, ранее я говорил вам, что вы не можете определить две переменные с одинаковым именем, но я не говорил о концепции локальной и глобальной переменной. Я сделаю, прямо сейчас.
Посмотрите на эту часть кода:

Код
int numInfToTrain = 30; // Number of infantry to train

int getRemainingInfToTrain()
{
    int currentNumInfantry = kbUnitCount(cMyID, cUnitTypeAbstractInfantry, cUnitStateABQ); // The number of infantry we currently have
    int remaining = numInfToTrain - currentNumInfantry;
    if (remaining < 0)
  remaining = 0;
    return(remaining);
}

void updateInfToTrain()
{
    if (kbGetAge() == cAge3)
    {
  numInfToTrain = 60;
    }
}

Переменная numInfToTrain определяется вне функции getRemainingInfToTrain () . Поэтому это глобальная переменная. Глобальные переменные могут быть доступны в любом месте всего скрипта, если он определен первым .

Все остальные переменные в этом коде определены внутри функции getRemainingInfToTrain () . Поэтому они являются локальными переменными. Доступ к локальным переменным возможен только в той функции, в которой они определены . Таким образом функция updateInfToTrain () не имеет доступа к переменным currentNumInfantry и остальным, Поэтому вы можете присвоить одно и то же имя двум или более переменным, если они все находятся в разных функциях.

Небольшое примечание, которое вы должны помнить: в AoE3 функция и переменная могут не иметь одинакового имен

Код
int counter = 10;
int counter()
{

}


Этот код вызовет ошибку, так как функция и переменная имеют одно и то же имя.

Функция main ()
Эта функция является единственной функцией, которая выполняется без вызова в сценарии. Он вызывается самой программой. Да, если нет функции main (), то ни одна из функций и инструкций не будет выполнена, поэтому вам нужно начать с нее.
Код
void main(void)
{
    
}


4. Наш первый AI-скрипт!

Ну, на данный момент, мы можем сделать полностью рабочий сценарий. В заключение!

Перейдите в папку AoE3 \ AI3 и сделайте резервную копию файла aiLoaderStandard . Затем откройте aiLoaderStandard и удалите все коды.

Наш первый скрипт будет таким:
Код
nt find(int utid=-1, int prID=cMyID, int index=0)
{
    static int queryID = -1;
    
    if (queryID < 0)
    {
  queryID = kbUnitQueryCreate("Find");
  kbUnitQuerySetIgnoreKnockedOutUnits(queryID, true);
  kbUnitQuerySetState(queryID, cUnitStateAlive);
    }
    
    if (index==0)
    {
  kbUnitQueryResetResults(queryID);
  if (prID > 1000)
  {
   kbUnitQuerySetPlayerID(queryID, -1, false);
   kbUnitQuerySetPlayerRelation(queryID, prID);
  }
  else
  {
   kbUnitQuerySetPlayerRelation(queryID, -1);
   kbUnitQuerySetPlayerID(queryID, prID, false);
  }
  kbUnitQuerySetUnitType(queryID, utid);
  kbUnitQueryExecute(queryID);
    }
    
    return(kbUnitQueryGetResult(queryID, index));
}

void main(void)
{
    aiChat(1, "Hello!");
    int explorer = find(cUnitTypeHero);
    aiTaskUnitMove(explorer, kbGetMapCenter());
}

Пока вы не должны понимать этот сценарий. Просто скопируйте и вставьте его в пустой aiLoaderStandard и сохраните файл.
Теперь запустите игру («Азиатские династии») и начните перестрелку. Когда карта загружена, AI (ы) скажут: «Привет!» и переместите их исследователь в центр карты. Ну, это крошечный, но здорово сделать наш собственный сценарий! Поверьте мне, лучше знать все эти основы XS, чем просто копировать и вставлять случайные коды, настраивать и играть.
LOVEAOE
Форум » Видоизменение » Технологии » Руководство по написанию скриптов ( часть 1)
  • Страница 1 из 1
  • 1
Поиск:
Пятёрка форумщиков