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

Doom Rate: 2.31

Posts quality: +63
Ссылка на пост №1 Отправлено: 13.02.11 02:06:36
ЧАСТЬ 1. Скрипты. Основы.


Руководство переехало http://wiki.doomgod.com/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>> сдвиг влево
~ — инверсия побитовая. !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.
например :
[code]
function int abs(int val)
{
if (val<0>=0 то "return -val;" не выполняется, и выполняется следующая инструкция, то есть "return val" — число и так больше или равно нуля, ничего изменять в нём не надо.
Следующий тип конструкций, один из типов которых как раз использован в предыдущем примере — это [color=orange]ветвления[/color].
их два типа :
if() /else
if переводится как "если". то есть if (a==0) можно перевести как "если а равно нулю, то" Скобочки возле if обязательны. если выражение в этих скобочках равно нулю (а мы ещё помним, что все инструкции логические и сравнения возвращают числа?) то следующий за if оператор [color=orange]НЕ[/color] ВЫПОЛНИТСЯ. иначе выполнится :)
оператор не обязательно один, может быть сразу много, тогда их надо объединять в [color=orange]блок операторов[/color] :
[code]
int b = Random(0,1);
if (b)
{ // начало блока операторов
SpawnSpot(...)

...
b = 10;
} // конец блока операторов
Door_close(...) // выполнится всегда.
[/code]
если после оператора добавить слово "else", то это создаст альтернативную ветвь выполнения :
[code]
int b = Random(0,1);
if (b)
SpawnSpot(...) // выполнится либо этот оператор
else
{ // или этот блок операторов
b = 10;
Door_open(...)
}
Door_close(...) // выполнится всегда.
[/code]
ещё типичным использованием if являются конструкции "else if"
[code]
b = random(1,4)
if (b==1)
{ // здесь окажемся если b = 1
...
}
else if (b==2)
{
...
}
else if (b==3)
{
...
}
else
{
// здесь b равно 4
}
[/code]
альтернативой "if" и "else if" является конструкция "switch"
[code]
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;
}
[/code]
третий тип конструкций : это [color=orange]циклы[/color].
из три типа :
1)for(инициализация;условие;постоператор) оператор_1;
это работает так.
1.1) выполняется оператор из "инициализация")
1.2) проверяется "условие", если оно рано нулю (то есть ложь), то происходит выход из цикла, оператор_1 не выполняется при этом.
1.3) если "условие" не равно нулю, то выполняется оператор_1 (который может быть блоком операторов или даже отсутствовать ;))
1.4) выполняется "постоператор"
1.5) смотри 1.2, то есть зацикливаемся.
пример :
[code]
for (b=0;b<10>0;b--);
// здесь нет операторов, но цикл запустится и будет корректно работать! смотрите.
// первым делом выставит b в 100
// затем начнёт проверять условие. Для этого он выполнит выражение "условие" и сравнит результат с нулём. выражение — это вызов функции МояФункция(b) и логическое умножение результата на выражение "b>0". есть четыре варианта : МояФункция(b) равна нулю, а b>0, МояФункция(b) не равна нулю, а b=0, МояФункция(b) равна нулю и b=0 и наконец МояФункция(b) не равна нулю и b>0. только в последнем случае цикл будет продолжен, то есть функция МояФункция(b) будет вызвана до тех пор, пока или она сама не вернёт 0, или b не станет меньше нуля. Что именно делает и возвращает функция МояФункция(int b), зависит только от вашего желания. пример привожу, чтобы вы не пугались подобных конструкций.
[/code]
2) цикл while(условие) оператор
если "условие" не равно 0, то будет выполнен оператор (или блок операторов)
например
[code]
while(random(0,100))
{
spawn(...)
b++;
}
// пока случайно не выпадет так, что случайное число от нуля до 100 не окажется нулём, спавнить что-нибудь
while(1)
{
spawn(...)
b++
if (b>c)
break;
}
// пока "один не есть 0", то есть до бесконечности выполнять блок операторов. Но выход из цикла всё-же предусмотрен!
[/code]
3) констукция do оператор while (); аналогична предыдущей, но "оператор" будет выполнен как минимум один раз.
В предыдущем примере есть "бесконечный" цикл. Но благодаря инструкции break из него можно выйти. break завершает выполнение цикла, а инструкция continue заставляет выполнять оператор(имеется в виду блок операторов) сначала. вот здесь-то и становится полезен "постоператор" инструкции for. блок операторв прекращает работать, а постоператор всё-же выполняется.

[size=18][center][color=orange]ЧАСТЬ 2. Еденицы измерений и их перевод[/color][/center][/size]
Эта часть будет посвящена арифметике с фиксированной точкой, углам, расстояниям и проблемам перевода.
самым фундаментальным типом является тип 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>> 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().

[size=18][center][color=orange]ЧАСТЬ 3. Массивы, строки. Облать видимости[/color][/center][/size]
сначала хотелось-бы начать с конца заголовка и объяснить такую вещь, как область видимости переменных. их несколько типов :
1) локальная область видимости. Переменная объявлена внутри функции или скрипта. объявление выглядит следующим образом :
[code]
script 1 (void)
{
int i;
int j = 10;
int k = j + sin(j*0.05);
print(i:k);
}
[/code]
здесь локально объявляются три переменных, причём две из них ещё и определяются. значения этих переменных потеряются после выполнения скрипта и их нельзя использовать в других скриптах — в других скриптах эти переменные не определены. А если их и определить, то это будут другие переменные :
[code]
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
}
[/code]
В отличие от c++ и с, после объявления локальной переменной она доступна везде в теле скрипта или функции ниже по тексту.
Следующий уровень — уровень карты. Эти переменные объявляются ВНЕ тела цикла :
[code]

int myvar = 1;
script 1 (void)
{
print (i:myvar++);
}
[/code]
такая переменная доступна во всех скриптах и её значение не теряется после выхода из скриптов. При хождении по хабу из карты в карту все локальные переменные сохраняются, но не могут быть использованы в других картах.
Критически важной особенностью переменных уровня карты является то, что можно объявлять МАССИВЫ таких переменных.
[code]
int arrayofint[100];
script 1 (void)
{
for (int i=0;i<100;i++)
arrayofint = 100-i;
}
[/code]
Здесь объявлен массив из 100 элементов — с нулевого по 99. В скрипте мы производим его ннициализацию числами со 100 до 1, то есть arrayofint[0] == 100, а arrayofint[50] = 50. Массивы бывают не только одномерные, но и многомерными, например
[code]
int coordinates[10][2];
script 1 (void)
{
for (int i=0;i<10>var1)
print(s:"ok");
}
[/code]
В этом примере объявлены три глобальных переменных : два int и один массив. обратите внимание, что его размер не указан. При этом размер этого массива действительно не определён и в него можно записать много(не знаю точно сколько именно, возможно десятки и сотни мегабайт) значений типа int. Также надо обратить внимание на конструкцию типа "номер":"имя переменной". Именно номер определяет, что это за переменная, а имя только используется в скриптах. При переходе на другую карту в этой другой карте доступ к переменным можно будет получить, ещё раз ив определив с тем-же номером(не обязательно с тем-же именем :
[code]
global int 1:var2;
global int 2:sdata;
script 1 (void)
{
print(i:var2); // если на преведущей карте script 1 отработал, то выведет "10"
}
[/code]
Есть ещё тип world, он аналогичен global, но распространяется только на хаб, между хабами эти переменные обнуляются.
[color=orange]Строки.[/color]
строки в ACS — это номера строк в массиве строк, который(массив) формируется из всех строк, встреченных в тексте :
[code]
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.
[/code]
Поскольку при таком подходе доступа к содержимому строк нет, то и изменять такие строки нельзя.
[code]
script 1 (void)
int a = "Hello";
Spawn("DoomImp",...);
int b = "world";
int c = a + b; // 0 + 2
print(s:c); // выведет "world", поскольку переменная c содержит индекс 2, который соответствует этой строке.
[/code]
тем не менее длинну такой строки в символах можно узнать при помощи функции strlen(), а значение каждого конкретного символа — при помощи функции getchar(string,pos).
Однако в ZDoom всё-же есть возможность печати произвольно составленных, неконстантных строк. Для этого существует классификатор "a", который печатает массив символов, заканчивающийся нулём. Символы являются символами ASCII, допускаются символы из обеих половин таблицы, в том числе и русские буквы, если конечно они есть в текущем шрифте.
[code]
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"
}
[/code]
Выведет то-же, но вот только изменять такие массивы уже можно, добавляя слова, меняя буквы, сдвигая, модифицирую как вам захочется итд.

[size=18][center][color=orange]Часть 4. Функции вывода на экран текста и изображений[/color][/center][/size]
ещё не написанно.

[size=18][center][color=orange]Жду ваши комментарии, вопросы, предложения[/color][/center][/size]
а я продолжу завтра.
1 2 1
Memfis
= Colonel =
Next rank: - Commissar - after 137 points
4753

Doom Rate: 1.8

Posts quality: +700
Ссылка на пост №2 Отправлено: 13.02.11 02:43:16
Было бы интересно узнать откуда взялось ограничение на именно три параметра. Как-то необычно.
1 2 1
Nil
= 2nd Lieutenant =
Next rank: - 1st Lieutenant - after 127 points
1513

Doom Rate: 2.31

Posts quality: +63
Ссылка на пост №3 Отправлено: 13.02.11 02:57:35
В Hexen (да и в UDMF) на линию или предмет можно было повесить так называемый Action specials. каждый экшен имел максимум пять параметров. Одним из экшенов стал ACS_Execute. У него следующие параметры - номер скрипта, номер карты, и три передаваемых скрипту параметра. Поскольку ACS_Execute и производные ACS_ExecuteAlvays и ACS_ExecuteWithResult — единственные способы вызвать скрипт, и у всех их есть возможность передать МАКСИМУМ три параметра. отсюда и ограничение. В ПОЛЬЗОВАТЕЛЬСКИЙ ФУНКЦИЯХ такого ограничения нет.
1 2 1
Arsenikum
= Warrant Officer =
Next rank: - 2nd Lieutenant - after 14 points
1276

Doom Rate: 1.54

Posts quality: +29
Ссылка на пост №4 Отправлено: 13.02.11 03:41:36
Nil
Перед второй частью настоятельно рекомендую описать типы данных - основу основ любого языка программирования. Сюда же идут массивы, константы, переменные и область действия переменных, т.н. scope.

В одной из своих частей не забудь, пожалуйста, ACS операторы задержки и связанные с ними подводные камни.
6 3
cybermind
- Warrant Officer -
Next rank: = Warrant Officer = after 95 points
1045

Doom Rate: 1.99

Posts quality: +163
Ссылка на пост №5 Отправлено: 13.02.11 08:36:32
Ну первое что броилось в глаза, это случайные грамматические ошибки ("преведущем","суловие"...). По крайней мере надо через спеллчекер прогнать.
Ну второй довольно сильный недостаток - для легкого понимания человек должен более-менее разбираться в программировании и вообще знать какой-то минимум по АЦС(где редактировать, как и т.д.) Было бы неплохо, если статья была выполнена примерно как Декорейт для чайников от зер0, а то как то суховато.
Ну и предложение - хотелось бы раздел "Тонкие особенности(типа "А вы знаете, что..."), примеры реализации чего-то особенного и т.д.", думаю за время твоего программирования в АЦС у тебя накопилось много-много секретов и триков :)
1 2 1
Archi]ASTS[
= Commissar =
Next rank: - UAC Commissar - after 395 points
5405

Doom Rate: 1.9

Posts quality: +61
Ссылка на пост №6 Отправлено: 13.02.11 11:37:33
Nil:
данный скрипт перемножает второй и третий параметры и добавляет к произведению первый параметр, после чего возвращает значение, которое можно использовать при вызове ACS_ExecuteWithResult, про это попозже.

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

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

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

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

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

Doom Rate: 2.31

Posts quality: +63
Ссылка на пост №7 Отправлено: 13.02.11 12:33:22
Archi [B0S], с одной стороны в функции проще и такой скрипт бессмысленен. А с другой — ждать (delay() / tagwait()) в функциях нельзя. А если очень надо, то приходится оформлять функцию как скрипт, ничего с этим не поделаешь. Ошибки там есть, причём много и разных, кое-что сейчас исправлю, спасибо.
Написал вторую часть кстати.
И 3 тоже. Потом добавлю часть 4 и на этом мой кратный обхор основных средств ACS можно заканчивать.
1 2 1
nprotect
- 2nd Lieutenant -
Next rank: = 2nd Lieutenant = after 97 points
1343

Doom Rate: 2.45

Ссылка на пост №8 Отправлено: 03.03.11 15:43:52
хороший гид, может хоть количество вопросов "как создать скрипт" поуменьшится :)
1 2 1
Shadowman
= UAC Marshal =
Next rank: UAC General after 161 points
8039

Doom Rate: 2.09

Posts quality: +1768
Ссылка на пост №9 Отправлено: 04.03.11 18:21:23
Offtop
nprotect
С возвращением!
Будешь ли продолжать свой проект? :)
//offtop
1 7 2
bardysya
- Lance Corporal -
Next rank: = Lance Corporal = after 18 points
142

Doom Rate: 1

Ссылка на пост №10 Отправлено: 13.03.11 09:31:59
А какой оператор нужно использовать, чтобы когда игрок атакует противника, был определенный шанс впасть в состояние Берсерка, только без хила?
Archi]ASTS[
= Commissar =
Next rank: - UAC Commissar - after 395 points
5405

Doom Rate: 1.9

Posts quality: +61
Ссылка на пост №11 Отправлено: 13.03.11 09:38:39
eltorrio
Внимательно прочитай название темы. Тебе не кажется что ты адресом ошибся?
1 2 1
bardysya
- Lance Corporal -
Next rank: = Lance Corporal = after 18 points
142

Doom Rate: 1

Ссылка на пост №12 Отправлено: 13.03.11 09:47:11
Archi [B0S]
Мое тоже относится к скрипту. Я просто не до конца все понимаю.
Nil
= 2nd Lieutenant =
Next rank: - 1st Lieutenant - after 127 points
1513

Doom Rate: 2.31

Posts quality: +63
Ссылка на пост №13 Отправлено: 13.03.11 10:25:26
eltorrio
Товарищ, вы тупите, причём очень, прямо таки провокационно сильно. У нас за такое предусмотрена награда за троллинг, но у вас ещё есть возможность исправится и ещё пару десятков раз прочитать то, что написанно в первом посте. Авось сможете разобрать слова и предложения.
1 2 1
Striker
- Corporal -
Next rank: = Corporal = after 15 points
85

Doom Rate: 2.02

Posts quality: -4
Ссылка на пост №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 - тапками не кидать, если не работает... там тэги и еще ченибудь укажете сами
Devived]ASTS[
= Master Corporal =
Next rank: - Sergeant - after 21 points
269

Doom Rate: 1.1

Posts quality: +5
Ссылка на пост №15 Отправлено: 04.07.11 12:10:34
San9 berserK
Это слишком простой скрипт для того, чтобы его выкладывать. А если учесть, что есть формат UDMF - то даже не нужен этот скрипт, в свойствах сектора это можно настроить...
1
Striker
- Corporal -
Next rank: = Corporal = after 15 points
85

Doom Rate: 2.02

Posts quality: -4
Ссылка на пост №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: - 2nd Lieutenant - after 79 points
1211

Doom Rate: 1.38

Posts quality: +235
Ссылка на пост №17 Отправлено: 25.12.11 00:13:46
Думаю в скором времени лучше будет описывать скриптами, а не свойствами секторов... кстати задался вопросом: возможно ли описать на acs кривую безье, как это делалось с помощью С++ в Quake3? Нестандартный вопрос знаю, но помоему это позволи-ло бы при сокращении лайндефов увеличить детализацию выпуклых и вогнутых поверхностей...
2 2 1
Nil
= 2nd Lieutenant =
Next rank: - 1st Lieutenant - after 127 points
1513

Doom Rate: 2.31

Posts quality: +63
Ссылка на пост №18 Отправлено: 25.12.11 01:17:59
BFG2407[B0S], Вопрос лишен смысла.
1) Описать на ACS можно что угодно, он полон по тьюрингу.
2) Движок Doom работает при рисовании только с лайндефами, сайдефами и дальше по ниспадающему BSP. Динамически что-либо изменять на карте в отношении построенного BSP нельзя, кроме одного исключения — полиобъектов, они обрабатываются совершенно по особому и должны быть заданы до запуска уровня (то есть в редакторе карт).
Тем более, вопрос лишен смысла в этой теме.
1 2 1
c4tnt
UAC Sergeant Major
Next rank: Chief Petty Officer after 54 points
796

Doom Rate: 1.92

Posts quality: +5
Ссылка на пост №19 Отправлено: 25.12.11 12:18:18

ACS_ExecuteWithResult


По мне так у неё есть гораздо более практичное применение - отмена анимации нажатия кнопки\использования итема. Тем более что результат нужно вернуть всё равно до первого ожидания в скрипте, иначе ничего не произойдёт.
1 1
Nil
= 2nd Lieutenant =
Next rank: - 1st Lieutenant - after 127 points
1513

Doom Rate: 2.31

Posts quality: +63
Ссылка на пост №20 Отправлено: 25.12.11 12:41:27
c4tnt, А что, я эту функцию где-то разбирал в руководстве? Неа, не разбирал, претензий поэтому не принимаю.
1 2 1
Страница 1 из 2Перейти наверх 1, 2  След.
   Список разделов - Флуд и устаревшие темы - Написание скриптов для ZDoom. Общие идеи, принципы, методы.