Welcome to U.A.C. [O.S.A.]
login / register
Status: Guest
Архивы форума | iddqd.ru
Wolf 3D
ПравилаПравила ПоискПоиск
Написание скриптов для ZDoom. Общие идеи, принципы, методы. 1, 2  След.
   Список разделов - Местечко мапперов и моддеров - Написание скриптов для ZDoom. Общие идеи, принципы, методы.Ответить
АвторСообщение
Nil
= Commissar =
Next rank: - UAC Commissar - after 18 points
2842

Doom Rate: 2.34
Ссылка на пост №1 Отправлено: 13.02.11 02:06:36

ЧАСТЬ 1. Скрипты. Основы.


Руководство переехало http://wiki.doom.tc/index.php/Введение_в_ACS
Эта версия не обновляется.


Начнём с классификации скриптов.
1) скрипты без классификатора

script 1 (void)

этот скрипт вызывается командами типа ACS_Execute. может получать максимум ТРИ параметра :

script 1 (int param1, int mul,int a)
{
SetResultValue(param1+mul*a);
}

данный скрипт перемножает второй и третий параметры и добавляет к произведению первый параметр, после чего возвращает значение, которое можно использовать при вызове ACS_ExecuteWithResult, про это попозже.
2) Скрипты вызываемые при запуске карты

script 1 Open

Такие скрипты вызываются один раз для каждой карты. их вызывает не объект, поэтому нельзя использовать TID=0 в качестве ссылки на вызвавший объект или на игрока.
3) Скрипты входа игрока

script 1 enter

Вызывается при входе на карту ДЛЯ КАЖДОГО ИГРОКА. обычно игрок один, поэтому вызывается тоже один раз. Отличается от предыдущего тем, что этот скрипт запускает как-бы сам игрок, поэтому здесь TID=0 ссылается на самого игрока, поэтому, например, игроку можно сразу задать новый тег :

script 1 enter
{
Thing_changeTID(0,6000);
}

Есть ещё некоторые другие типы скриптов, например, Death, который вызывается при смерти игрока, но это я пропущу.
Итак, с типом скрипта определились, теперь надо понять, из чего состоит тело скрипта. ЛЮБОЙ скрипт состоит из смеси трёх типов конструкций : операторов, ветвлений и циклов. Операторы и последовательности операторов — это любые команды, например, по изменению высот полов, потолков, изменению переменных и прочее, например


{
int b;
Thing_Raise(5);
Floor_RaiseByValue(...)
{ //начало блока операторов
int a = 5;
b  += a;
print(i:a,s:" ",i:b);
}
}

операторы бывают следующие :
1) арифметические + - * /
% - взятие остатка
<< сдвиг вправо (умножение на 2^x, например, 4 << 3 = 4 * 2^3 = 4*8 = 32)
>> сдвиг влево
~ — инверсия побитовая. !0x00FF00FF = 0xFF00FF00 (0x это префикс 16-ричного числа)
| побитовое ИЛИ. 0x00FF0000 | 0xFF00FF00 = 0xFFFFFF00
& побитовое И. 0xFF00FF00 & 0x00FFFF00 = 0x0000FF00
^ это не возведение в степень, а операция XOR. если в каких-то разрядах (бинарных) стоят разные значения (1 и 0 или 0 и 1), то в результате в том-же разряде будет 1, иначе 0. операция забавная, но если вы о ней ничего не знаете, то вряд-ли она вам понадобится. 0x00FF00FF ^ 0x0000FFFF = 0x00FFFF00
+= -= *= /= %= |= &= — агрегаты (a+=2 эквивалентно a = a + 2)
++ инкремент. a++ эквивалентно a +=1 или a = a+1. есть префиксный и постфиксный инкремент, но это тонкости, потом расскажу.
-- декремент.
2) логические
2.1) сравнения
< <= > >= == != (последние два — равно и не равно)
тут всё забавно. Результатом выполнения этих конструкция является ЧИСЛО. Это число равно 0, если результат ложный (a = (3==2) - а будет рано 0, так как 3 не равно двум, а значит, результатом сравнения будет число 0). Если же результат сравнения истинный (a = 0; a = (a == 0)), то результутом будет "не ноль". например, 1. или -14543. Но не 0.
2.2 логические операции
&& логическое И. если оба операнда не равны нулю(то есть "правда"), то и результат не будет равен нулю. если хоть один равен нулю, то результат — ноль ("ложь")
|| логическое ИЛИ. если хоть один из операндов не равен нулю, то и результат не будет равен нулю.
! — логическое отрицание. Превращает правду в ложь, ложь в правду. не ноль в ноль, ноль — в не ноль.
3) вызов функции
ИмяФункции()
ИмяФункции(параметры)
например
int a = sin(0.5) // вызов функции sin
int b = ACS_ExecuteWithResult(1,0,1,2,3) // вызовет функцию ACS_ExecuteWithResult(), которая выполнит скрипт номер 1 с параметрами 1,2 и 3 и вернёт значение. Для функции из примера выше будет 1 + 2*3 = 7, то есть b станет равно 7.
Пользовательские функции объявляются следующим образом :

function int ИмяФункции(список параметров)
{
return значение;
}
или
function void ИмяФункции(список параметров)
{
}
или
function void ИмяФункции(void)
{
}
или
function int ИмяФункции(void)
{
return значение;
}

void значит "пусто", нет параметров или нет возвращаемого значения. если возвращаемое значение есть, то его надо "вернуть" с помощью инструкции return.
например :

function int abs(int val)
{
if (val<0)
{
    return -val;
}
return val;
}

функция "модуль" или "АБСолютное значение". принимает один параметр и сравнивает его с нулём. если значение меньше нуля, то возвращает "минус val", ну тут понятно — два минуса дают плюс. Если же val>=0 то "return -val;" не выполняется, и выполняется следующая инструкция, то есть "return val" — число и так больше или равно нуля, ничего изменять в нём не надо.
Следующий тип конструкций, один из типов которых как раз использован в предыдущем примере — это ветвления.
их два типа :
if() /else
if переводится как "если". то есть if (a==0) можно перевести как "если а равно нулю, то" Скобочки возле if обязательны. если выражение в этих скобочках равно нулю (а мы ещё помним, что все инструкции логические и сравнения возвращают числа?) то следующий за if оператор НЕ ВЫПОЛНИТСЯ. иначе выполнится :)
оператор не обязательно один, может быть сразу много, тогда их надо объединять в блок операторов :

int b = Random(0,1);
if (b)
{ // начало блока операторов
SpawnSpot(...)

...
b = 10;
} // конец блока операторов
Door_close(...) // выполнится всегда.

если после оператора добавить слово "else", то это создаст альтернативную ветвь выполнения :

int b = Random(0,1);
if (b)
    SpawnSpot(...) // выполнится либо этот оператор
else
{ // или этот блок операторов
    b = 10;
    Door_open(...)
}
Door_close(...) // выполнится всегда.

ещё типичным использованием if являются конструкции "else if"

b = random(1,4)
if (b==1)
{ // здесь окажемся если b = 1
...
}
else if (b==2)
{
...
}
else if (b==3)
{
...
}
else
{
// здесь b равно 4
}

альтернативой "if" и "else if" является конструкция "switch"

int b = random(0,5)
switch(b)
{
case 0:
case 1:
Door_open(...)
Spawn(...)
break; если b рано 0 или 1, то будут выполнены оба оператора и break тут-же переместит выполнение скрипта за блок switch
case 2:
c = 1;
case 3:
Door_close(...) // если b равно 2, то выполнится и "c = 1", и "Door_close", если b рано 3, то только Door_close. Это потому, что перед "case 3" не стоит "break".
break;
default:
SpawnSpot(...)
break;
}

третий тип конструкций : это циклы.
из три типа :
1)for(инициализация;условие;постоператор) оператор_1;
это работает так.
1.1) выполняется оператор из "инициализация")
1.2) проверяется "условие", если оно рано нулю (то есть ложь), то происходит выход из цикла, оператор_1 не выполняется при этом.
1.3) если "условие" не равно нулю, то выполняется оператор_1 (который может быть блоком операторов или даже отсутствовать ;))
1.4) выполняется "постоператор"
1.5) смотри 1.2, то есть зацикливаемся.
пример :

for (b=0;b<10;b+=2)
SpawnSpot("DoomImp",100+b);
// здесь оператор_1 — это SpawnSpot(...) который будет выполнен 5 раз, в результате будут отспавнены импы в спавнспотах 100,102,104,106,108

for (b=100;МояФункция(b) && b>0;b--);
// здесь нет операторов, но цикл запустится и будет корректно работать! смотрите.
// первым делом выставит b в 100
// затем начнёт проверять условие. Для этого он выполнит выражение "условие" и сравнит результат с нулём. выражение — это вызов функции МояФункция(b) и логическое умножение результата на выражение "b>0". есть четыре варианта : МояФункция(b) равна нулю, а b>0, МояФункция(b) не равна нулю, а b=0, МояФункция(b) равна нулю и b=0 и наконец МояФункция(b) не равна нулю и b>0. только в последнем случае цикл будет продолжен, то есть функция МояФункция(b) будет вызвана до тех пор, пока или она сама не вернёт 0, или b не станет меньше нуля. Что именно делает и возвращает функция МояФункция(int b), зависит только от вашего желания. пример привожу, чтобы вы не пугались подобных конструкций.

2) цикл while(условие) оператор
если "условие" не равно 0, то будет выполнен оператор (или блок операторов)
например

while(random(0,100))
{
spawn(...)
b++;
}
// пока случайно не выпадет так, что случайное число от нуля до 100 не окажется нулём, спавнить что-нибудь
while(1)
{
spawn(...)
b++
if (b>c)
break;
}
// пока "один не есть 0", то есть до бесконечности выполнять блок операторов. Но выход из цикла всё-же предусмотрен!

3) констукция do оператор while (); аналогична предыдущей, но "оператор" будет выполнен как минимум один раз.
В предыдущем примере есть "бесконечный" цикл. Но благодаря инструкции break из него можно выйти. break завершает выполнение цикла, а инструкция continue заставляет выполнять оператор(имеется в виду блок операторов) сначала. вот здесь-то и становится полезен "постоператор" инструкции for. блок операторв прекращает работать, а постоператор всё-же выполняется.

ЧАСТЬ 2. Еденицы измерений и их перевод

Эта часть будет посвящена арифметике с фиксированной точкой, углам, расстояниям и проблемам перевода.
самым фундаментальным типом является тип int. Он может принимать любые значения от -2147483648 до 2147483647 то есть 32 битное целое со знаком. Все остальные типы есть производные от int : fixed, str. Это не самостоятельные типы, это переименованный int. Кстати, в связи с этим есть забавное ограничение — пользовательские функции могут принимать и возвращать "только int". Ну и смысла писать что-либо ещё просто нет, везде используйте int и не парьтесь.
Итак, у нас есть только int. Как же получить всякие дроби, градусы, радианы, строки в конце концов? В ACS используется арифметика с фиксированной точкой. старшая половина двоичных разрядов считается целой частью, младшая — дробной. точность — гарантируется 4 десятичных знака после запятой, и ещё чуть-чуть больше. Работает это следующим образом (буду использовать десятичные разряды для наглядности) — допустим, у нас есть разрядная сетка на 4 разряда+ знак, куда мы можем записать числа -9999, -9998, ..., 0000,0001, ..., +9999 теперь мы говорим, что старшие два разряда — целая часть, а младшая — дробная часть. то есть +99.99, но это точка нарисованная, физически на уровне типа int её нет. сложение и вычитание производятся обычным образом : 01.15 + 02.85 = 0115 + 0285 = 0400 = 04.00, то есть четыре в смысле "fixed point". или 400 в смысле int. Функции сами разбираются, что им передали — фиксированную точку или целое. Если функция просит "Map units" или "byte angle", то она требует простого int, иначе — фиксированную точку.
продолжу обзор операций с плавающей точкой. Умножение и деление ,взятие остатка работают несколько иначе. есть число 02.00 умножить на 02.00 оператором "*", то получится 4 0000, то есть ноль, с переполнением разрядной сетки. не влез такой большой результат, хотя вроде два на два умножили. если бы мы умножали два в фиксированной точке на два целых, то всё было-бы нормально : 02.00 * 00.02 = 200 * 2 = 400 = 04.00. Если же нам надо обязательно умножить два числа в виде с фиксированной точкой, то надо использовать функции fixedmul(a,b) и fixeddiv(a,b), соответственно умножает или делит а на b. fixedmul(02.00,02.00) = 04.00
Кстати, вы ещё не забыли, что наши десятичные выкладки над четырёхразрядными числами являются модельными? и на самом деле в ACS числа имеют 32 двоичных разряда? один из которых — знак числа, в расчётах участвует опосредовано?
Теперь немного вернёмся к ACS.
если написать "int a = 1", то мы получим "1" в значении целое, а в смысле fixed point это будет "0.0000152587890625". если же мы напишем "int i = 1.0", то целое представление будет "65536", а дробное — "1.0". ещё раз напомню, что нигде не написано, в каком именно виде хранится ваше число, а точнее, оно хранится в однозначном наборе битов, которое можно интерпретировать двумя (точнее тремя, но об этом попозже, третий тип — номер строки в таблице строк) разными способами. Какой именно выберет программа зависит от того, в какой функции вы используете ваши числа. sin(), cos(), SetActorPosition() используют фиксированную точку, GetSectorFloorZ() использует целые числа, а FadeRange() например использует для разных параметров разное представление. Цветовые составляющие принимает в целых числах от 0 до 255, а интенсивность — в фиксированной точке от 0.0 до 1.0 (или от 0 до 65535).
перевести число из фиксированной точки в целое можно, если сдвинуть его вправо на 16 разрядов : 1.0 >> 16 == 1. обратное преобразование очевидно : 1 << 16 == 1.0.
Получить целую и дробную части дробного числа можно несколькими способами :
1) операцией % - взятие остатка и делением. 245.12 % 1.0 = 0.12; 245.12 / 1.0 = 245 (целое значение)
2) побитовыми операциями (наложение маски) 245.12 & 8000FFFF = 0.12, 245.12 & FFFF0000 = 245.0
Углы бывают двух видов — byte angle и fixed point angle. первые могут принимать 255 разных значений, где 0 — восток (0 градусов) 64 — север (90 градусов) 128 — запад (180 градусов) 192 — юг (270 градусов). Вторые принимают значения от 0.0 до 1.0. К сожалению, я бы предпочёл в радианах, но что есть, то есть. перевод из первого во второе выглядит так :
int fixedangle = byteangle << 8;
а fixed angle в byte angle так:
int fixedangle = byteangle >> 8;
Эти операции всего-лишь "растягивают" или "сжимают" наши значения углов из диапазона 0..255 в диапазон 0.65535. Чтобы окончательно развеять всякую магию, запишу это так :
int fixedangle = byteangle * 256; //256 = 2^8
то есть при байтовом угле = 64 (90 градусов) fixed будет равен 16384 или "0.25", то есть четверть окружности или 90 градусов. Все верно.
важнейшим математическим объеком является вектор. Это либо два числа (X и Y), или длина и угол. Длину можно получить по теореме Пифагора, правда, там фигурирует корень квадратный, а такой встроенной функции в ACS нет. Возьмите из
http://zdoom.org/wiki/Sqrt любую на выбор. точнее, последние две там работают с fixed point числами, остальные — с целыми. Угол можно узнать при помощи функции VectorAngle(). за обратные преобразования угла в и длинны в координаты X и Y отвечают sin() и cos() : X = cos(angle) * length; Y = sin(Angle) * length; Если длина у вас в виде фиксированной точки, то вместо "*" используйте функции fixedmul().

ЧАСТЬ 3. Массивы, строки. Облать видимости

сначала хотелось-бы начать с конца заголовка и объяснить такую вещь, как область видимости переменных. их несколько типов :
1) локальная область видимости. Переменная объявлена внутри функции или скрипта. объявление выглядит следующим образом :

script 1 (void)
{
int i;
int j = 10;
int k = j + sin(j*0.05);
print(i:k);
}

здесь локально объявляются три переменных, причём две из них ещё и определяются. значения этих переменных потеряются после выполнения скрипта и их нельзя использовать в других скриптах — в других скриптах эти переменные не определены. А если их и определить, то это будут другие переменные :

script 1 (void)
{
int i;
int j = 10;
int k = j + sin(j*0.05);
print(i:k);
}

script 2 (void)
{
i = 10; // ошибка : переменная i не определена
int j;
print(i:j); // скорее всего будет выведен ноль, хотя в преведущем скрипте переменная с таким же именем могла быть выставлена в 10
}

В отличие от c++ и с, после объявления локальной переменной она доступна везде в теле скрипта или функции ниже по тексту.
Следующий уровень — уровень карты. Эти переменные объявляются ВНЕ тела цикла :


int myvar = 1;
script 1 (void)
{
print (i:myvar++);
}

такая переменная доступна во всех скриптах и её значение не теряется после выхода из скриптов. При хождении по хабу из карты в карту все локальные переменные сохраняются, но не могут быть использованы в других картах.
Критически важной особенностью переменных уровня карты является то, что можно объявлять МАССИВЫ таких переменных.

int arrayofint[100];
script 1 (void)
{
for (int i=0;i<100;i++)
    arrayofint = 100-i;
}

Здесь объявлен массив из 100 элементов — с нулевого по 99. В скрипте мы производим его ннициализацию числами со 100 до 1, то есть arrayofint[0] == 100, а arrayofint[50] = 50. Массивы бывают не только одномерные, но и многомерными, например

int coordinates[10][2];
script 1 (void)
{
for (int i=0;i<10;i++)
    coordinates[0]= GetActorX(50+i);
    coordinates[1]= GetActorY(50+i);
}

В этом примере есть двумерный массив 10x2, который мы интерпретируем как массив из 10 элементов, каждый из которых — пара чисел X и Y. мы инициализируем его координатами объектов с 50 по 59. Потом запомненные координаты можно будет использовать в другом скрипте, например, телепортировав над этими координатами бомбы или ракеты :)
следующий уровень видимости — глобальный.
объявление переменных в нём несколько отличается :

global int 1:var1;
global int 2:data;
global int 3:array[];
script 1 (void)
{
var1 = 10;
print(i:data);
if (array[data]>var1)
print(s:"ok");
}

В этом примере объявлены три глобальных переменных : два int и один массив. обратите внимание, что его размер не указан. При этом размер этого массива действительно не определён и в него можно записать много(не знаю точно сколько именно, возможно десятки и сотни мегабайт) значений типа int. Также надо обратить внимание на конструкцию типа "номер":"имя переменной". Именно номер определяет, что это за переменная, а имя только используется в скриптах. При переходе на другую карту в этой другой карте доступ к переменным можно будет получить, ещё раз ив определив с тем-же номером(не обязательно с тем-же именем :

global int 1:var2;
global int 2:sdata;
script 1 (void)
{
print(i:var2); // если на преведущей карте script 1 отработал, то выведет "10"
}

Есть ещё тип world, он аналогичен global, но распространяется только на хаб, между хабами эти переменные обнуляются.
Строки.
строки в ACS — это номера строк в массиве строк, который(массив) формируется из всех строк, встреченных в тексте :

script 1 (void)
int a = "Hello";
Spawn("DoomImp",...);
int b = "world";
print(s:a;s:", ",s:b); //выведет "Hello, world"
print(i:a,s:" ",i:" ",s:" ",i:b); // выведет "0 3 2", то есть используются строки с индексами 0, 3 и 2.

Поскольку при таком подходе доступа к содержимому строк нет, то и изменять такие строки нельзя.

script 1 (void)
int a = "Hello";
Spawn("DoomImp",...);
int b = "world";
int c = a + b; // 0 + 2
print(s:c); // выведет "world", поскольку переменная c содержит индекс 2, который соответствует этой строке.

тем не менее длинну такой строки в символах можно узнать при помощи функции strlen(), а значение каждого конкретного символа — при помощи функции getchar(string,pos).
Однако в ZDoom всё-же есть возможность печати произвольно составленных, неконстантных строк. Для этого существует классификатор "a", который печатает массив символов, заканчивающийся нулём. Символы являются символами ASCII, допускаются символы из обеих половин таблицы, в том числе и русские буквы, если конечно они есть в текущем шрифте.

int array[100];
script 1 (void)
{
int s = "Hello, world";
int len = strlen(s);
for (int i=0;i<len;i++)
    array[i] = getchar(s,i);
print(a:array); // выведет те-же "Hello, world"
}

Выведет то-же, но вот только изменять такие массивы уже можно, добавляя слова, меняя буквы, сдвигая, модифицирую как вам захочется итд.

Часть 4. Функции вывода на экран текста и изображений

ещё не написанно.

Жду ваши комментарии, вопросы, предложения

а я продолжу завтра.
1 2 1
Memfis
UAC General
Next rank: Unavailable after 0 points
5780

Doom Rate: 1.77
Ссылка на пост №2 Отправлено: 13.02.11 02:43:16

Было бы интересно узнать откуда взялось ограничение на именно три параметра. Как-то необычно.
1 1 3
Nil
= Commissar =
Next rank: - UAC Commissar - after 18 points
2842

Doom Rate: 2.34
Ссылка на пост №3 Отправлено: 13.02.11 02:57:35

В Hexen (да и в UDMF) на линию или предмет можно было повесить так называемый Action specials. каждый экшен имел максимум пять параметров. Одним из экшенов стал ACS_Execute. У него следующие параметры - номер скрипта, номер карты, и три передаваемых скрипту параметра. Поскольку ACS_Execute и производные ACS_ExecuteAlvays и ACS_ExecuteWithResult — единственные способы вызвать скрипт, и у всех их есть возможность передать МАКСИМУМ три параметра. отсюда и ограничение. В ПОЛЬЗОВАТЕЛЬСКИЙ ФУНКЦИЯХ такого ограничения нет.
1 2 1
Arsenikum
= 1st Lieutenant =
Next rank: - Captain - after 56 points
1584

Doom Rate: 1.48
Ссылка на пост №4 Отправлено: 13.02.11 03:41:36

Nil
Перед второй частью настоятельно рекомендую описать типы данных - основу основ любого языка программирования. Сюда же идут массивы, константы, переменные и область действия переменных, т.н. scope.

В одной из своих частей не забудь, пожалуйста, ACS операторы задержки и связанные с ними подводные камни.
3 1
cybermind
Chief Petty Officer
Next rank: Chief Petty Officer after 79 points
911

Doom Rate: 1.86
Ссылка на пост №5 Отправлено: 13.02.11 08:36:32

Ну первое что броилось в глаза, это случайные грамматические ошибки ("преведущем","суловие"...). По крайней мере надо через спеллчекер прогнать.
Ну второй довольно сильный недостаток - для легкого понимания человек должен более-менее разбираться в программировании и вообще знать какой-то минимум по АЦС(где редактировать, как и т.д.) Было бы неплохо, если статья была выполнена примерно как Декорейт для чайников от зер0, а то как то суховато.
Ну и предложение - хотелось бы раздел "Тонкие особенности(типа "А вы знаете, что..."), примеры реализации чего-то особенного и т.д.", думаю за время твоего программирования в АЦС у тебя накопилось много-много секретов и триков :)
1
Archi
UAC General
Next rank: Unavailable after 0 points
10967

Doom Rate: 1.92
Ссылка на пост №6 Отправлено: 13.02.11 11:37:33

Nil :
данный скрипт перемножает второй и третий параметры и добавляет к произведению первый параметр, после чего возвращает значение, которое можно использовать при вызове ACS_ExecuteWithResult, про это попозже.

Это все же проще сделать функцией, на мой взгляд. Да и параметров будет больше. Все равно подобные скрипты запускать с линии бессмысленно.

Nil :
& побитовое И. 0xFF00FF00 | 0x00FFFF00 = 0x0000FF00

Тут кажется ошибка.

А пример функции for жосткий.

Кстати говоря, многие функции в думе возвращают значения. Я даже один раз умудрился сделать цикл while, условием выполнения которого было движение полиобъекта. Его можно было заклинить, но пока он не дойдет до конца, дальше скрипт продолжаться не будет.
2 1 1
Nil
= Commissar =
Next rank: - UAC Commissar - after 18 points
2842

Doom Rate: 2.34
Ссылка на пост №7 Отправлено: 13.02.11 12:33:22

Archi [B0S], с одной стороны в функции проще и такой скрипт бессмысленен. А с другой — ждать (delay() / tagwait()) в функциях нельзя. А если очень надо, то приходится оформлять функцию как скрипт, ничего с этим не поделаешь. Ошибки там есть, причём много и разных, кое-что сейчас исправлю, спасибо.
Написал вторую часть кстати.
И 3 тоже. Потом добавлю часть 4 и на этом мой кратный обхор основных средств ACS можно заканчивать.
1 2 1
nprotect
- Colonel -
Next rank: = Colonel = after 47 points
2413

Doom Rate: 2.45
Ссылка на пост №8 Отправлено: 03.03.11 15:43:52

хороший гид, может хоть количество вопросов "как создать скрипт" поуменьшится :)
1 2 1
Shadowman
UAC General
Next rank: Unavailable after 0 points
4981

Doom Rate: 2.84
Ссылка на пост №9 Отправлено: 04.03.11 18:21:23

Offtop
nprotect
С возвращением!
Будешь ли продолжать свой проект? :)
//offtop
1 6 2
bardysya
- Master Corporal -
Next rank: = Master Corporal = after 8 points
332

Doom Rate: 1
Ссылка на пост №10 Отправлено: 13.03.11 09:31:59

А какой оператор нужно использовать, чтобы когда игрок атакует противника, был определенный шанс впасть в состояние Берсерка, только без хила?
Archi
UAC General
Next rank: Unavailable after 0 points
10967

Doom Rate: 1.92
Ссылка на пост №11 Отправлено: 13.03.11 09:38:39

eltorrio
Внимательно прочитай название темы. Тебе не кажется что ты адресом ошибся?
2 1 1
bardysya
- Master Corporal -
Next rank: = Master Corporal = after 8 points
332

Doom Rate: 1
Ссылка на пост №12 Отправлено: 13.03.11 09:47:11

Archi [B0S]
Мое тоже относится к скрипту. Я просто не до конца все понимаю.
Nil
= Commissar =
Next rank: - UAC Commissar - after 18 points
2842

Doom Rate: 2.34
Ссылка на пост №13 Отправлено: 13.03.11 10:25:26

eltorrio
Товарищ, вы тупите, причём очень, прямо таки провокационно сильно. У нас за такое предусмотрена награда за троллинг, но у вас ещё есть возможность исправится и ещё пару десятков раз прочитать то, что написанно в первом посте. Авось сможете разобрать слова и предложения.
1 2 1
Striker
= Corporal =
Next rank: - Lance Corporal - after 13 points
197

Doom Rate: 1.81
Ссылка на пост №14 Отправлено: 04.07.11 10:25:31

Если кому-то надо скрипт Deep water - пожалуйста -

1 #include "zcommon.acs"
2
3 script 1 OPEN
4 {
5 //make water blue
6 sector_setColor(2, 0,50,219);
7 }

P.S - тапками не кидать, если не работает... там тэги и еще ченибудь укажете сами
[BoMF]Devived
Chief Petty Officer
Next rank: Chief Petty Officer after 63 points
927

Doom Rate: 0.91
Ссылка на пост №15 Отправлено: 04.07.11 12:10:34

San9 berserK
Это слишком простой скрипт для того, чтобы его выкладывать. А если учесть, что есть формат UDMF - то даже не нужен этот скрипт, в свойствах сектора это можно настроить...
Striker
= Corporal =
Next rank: - Lance Corporal - after 13 points
197

Doom Rate: 1.81
Ссылка на пост №16 Отправлено: 09.08.11 08:21:23

:( Опять я никому не помог... Слушайте! я вот на днях Speed of doom проходил и заметил скрипт на 12 и 30 уровне на точке старта. Игрок "едет" к телепорту. Не можете ли вы объяснить - как это сделать

Ответ на вопрос

ThrustThing (angle, force, nolimit, tid);
//angle - угол
//force - сила
//nolimit - лимит на расстояние
//tid - тид


Еще один вопрос не туда - пеняй на себя - Vemod
BFG2407
- Warrant Officer -
Next rank: = Warrant Officer = after 80 points
1080

Doom Rate: 2.01
Ссылка на пост №17 Отправлено: 25.12.11 00:13:46

Думаю в скором времени лучше будет описывать скриптами, а не свойствами секторов... кстати задался вопросом: возможно ли описать на acs кривую безье, как это делалось с помощью С++ в Quake3? Нестандартный вопрос знаю, но помоему это позволи-ло бы при сокращении лайндефов увеличить детализацию выпуклых и вогнутых поверхностей...
2 1
Nil
= Commissar =
Next rank: - UAC Commissar - after 18 points
2842

Doom Rate: 2.34
Ссылка на пост №18 Отправлено: 25.12.11 01:17:59

BFG2407[B0S], Вопрос лишен смысла.
1) Описать на ACS можно что угодно, он полон по тьюрингу.
2) Движок Doom работает при рисовании только с лайндефами, сайдефами и дальше по ниспадающему BSP. Динамически что-либо изменять на карте в отношении построенного BSP нельзя, кроме одного исключения — полиобъектов, они обрабатываются совершенно по особому и должны быть заданы до запуска уровня (то есть в редакторе карт).
Тем более, вопрос лишен смысла в этой теме.
1 2 1
c4tnt
Chief Petty Officer
Next rank: Chief Petty Officer after 56 points
934

Doom Rate: 2.13
Ссылка на пост №19 Отправлено: 25.12.11 12:18:18


ACS_ExecuteWithResult


По мне так у неё есть гораздо более практичное применение - отмена анимации нажатия кнопки\использования итема. Тем более что результат нужно вернуть всё равно до первого ожидания в скрипте, иначе ничего не произойдёт.
1
Nil
= Commissar =
Next rank: - UAC Commissar - after 18 points
2842

Doom Rate: 2.34
Ссылка на пост №20 Отправлено: 25.12.11 12:41:27

c4tnt, А что, я эту функцию где-то разбирал в руководстве? Неа, не разбирал, претензий поэтому не принимаю.
1 2 1
Страница 1 из 2Перейти наверх 1, 2  След.
   Список разделов - Местечко мапперов и моддеров - Написание скриптов для ZDoom. Общие идеи, принципы, методы.

Игнор-лист
© iddqd.ru