Гипат.org

MODный форум - Создание рандомных монстров

S@MUR@I - 10 декабря 2005, 04:15
Сразу скажу - юзал поиск долго и терпеливо но ничего не нашел.
В общем решил я делать квесты. И так как квест с убийством квестового босса самый распространенный, то лучше этого босса делать рандомным, т. е. со случайным местонахождением. Так интересней.
Короче начал разбираться со скриптом квеста "Пропал парламентер" в Песках на Гипате. И увидел, что людоед рандомный. Тут вспомнил, что вроде бы да, было когда-то, что-то подобное. Должен быть рандомным, а нифига, чего-то не клеится в скрипте.
Помогите кто знает, в чем тут загадка.
Расписал тут, как я понимаю этот скрипт. Поясните пожалуйста, почему скрипт с рандомом не работает?

GlobalVars (\\глобальные переменные
NULL : object,
VSS#i#val : object,
i : object,
RandBush : object \\Некий абстрактный объект (тоже переменная)
)

DeclareScript VTriger#2#1 ( this : object )\\объявление функций
DeclareScript VTriger#2#2 ( this : object )\\объявление функций
DeclareScript VCheck#2#1 ( this : object )\\объявление функций
DeclareScript VCheck#2#2 ( this : object )\\объявление функций

Script VTriger#2#2
(
if
(
)
then
(
KillScript( )
SetCP( RandBush, Add( 200.0, Random( 3 ) ) , 300 , 0 ) \\перемещает(а откуда перемещать то?) RandBush в точку X=от 200 до 203, Y=300, Z=0
UMSentry( GetObject( 1000001 ), Add( 133.7, Random( 1 ) ) , Add( 267.5, Random( 1 ) ) ) \\обязывает охранять людоеда эту точку(тут зачем-то X и Y, тоже сделаны переменными)
VCheck#2#1( this ) \\Проверка этой функции(?). Что значит (this) ?
)
)

Script VCheck#2#1
(
if
(
IsLess( GetX( RandBush ) , 202.0 ) \\Если случайная координата X объекта RandBush меньше числа 202, то это Истина, то есть выполняется нижеописанное
)
then
(
KillScript( )
Sleep( 2 )\\не знаю что это за хрень (время?)
SetCP( GetObject( 1000001 ), Add( 284.6, Random( 1 ) ) , Add( 302.5, Random( 1 ) ) , 0 )\\перемещает людоеда в эту точку (в другое логово)
UMSentry( GetObject( 1000001 ), Add( 284.6, Random( 1 ) ) , Add( 302.5, Random( 1 ) ) )\\обязывает людоеда охранять эту точку
VCheck#2#2( this )\\проверка этой функции(условия)
)
)

Script VCheck#2#2
(
if
(
IsLess( GetX( RandBush ) , 201.0 )\\Если случайная координата X объекта RandBush меньше числа 201, то это Истина, то есть выполняется нижеописанное
)
then
(
KillScript( )
Sleep( 2 )
SetCP( GetObject( 1000001 ), Add( 193.1, Random( 1 ) ) , Add( 191.1, Random( 1 ) ) , 0 )\\перемещает людоеда в эту точку(в третье логово)
UMSentry( GetObject( 1000001 ), Add( 193.1, Random( 1 ) ) , Add( 191.1, Random( 1 ) ) )\\обязывает охранять людоеда эту точку
)
)

Script VTriger#2#1\\после всего вышеописанного, запускается эта функция
(
if
(
)
then
(
KillScript( )
QStart( "z8q1" )\\старт квеста
QObjSeeUnit( "GetObject(1000001)" )\\цель увидеть людоеда
QObjKillUnit( "GetObject(1000001)" ) \\цель убить людоеда
QFinish( )\\конец квеста
)
)

WorldScript\\вызов функций, работающих постоянно(?)
(
Sleep( 2 )
RandBush = GetObjectByID( "1000000" )\\присвоение объекту RandBush идентификатора 1000000 (у людоеда 1000001)
VTriger#2#1( NULL )\\старт квеста, цель и финиш квеста.
VTriger#2#2( NULL )\\перемещение RandBush в точку со случайной координатой X, охрана людоедом первой точки и проверка условия "VCheck#2#1"
VCheck#2#1( NULL )\\эта функция почему то не вызывается
VCheck#2#2( NULL )\\эта функция почему то не вызывается
)
Снайпер - 10 декабря 2005, 16:27
Я б объяснил - это нетрудно... Только мне ещё столько всего надо сделать, что стопудняк не успею :( Потом как-нибудь просвещу на эту тему... Только по мелочам:
Цитата:
RandBush : object \\Некий абстрактный объект (тоже переменная)

Нифига он не абстрактный, точнее абстрактный только пока ему не присвоен объект.
Цитата:
DeclareScript VTriger#2#1 ( this : object )\\объявление функций
DeclareScript VTriger#2#2 ( this : object )\\объявление функций
DeclareScript VCheck#2#1 ( this : object )\\объявление функций
DeclareScript VCheck#2#2 ( this : object )\\объявление функций

Это нивальский мапэдитор(сцуконах) даёт скриптам такие нечеловеческие названия(VCheck#2#1,VTrigger#2#1). Нормальные квестописатели придумают скриптовой процедуре понятное название.
Цитата:
SetCP( RandBush, Add( 200.0, Random( 3 ) ) , 300 , 0 ) \\перемещает(а откуда перемещать то?) RandBush в точку X=от 200 до 203, Y=300, Z=0

Неважно откуда. Откуда угодно, где этот обжект стоял до перемещения.
Цитата:
VCheck#2#1( this ) \\Проверка этой функции(?). Что значит (this) ?

Накуя проверка?!? Это нивал гад, что он сделал такие названия, что кажется, что это проверка. Не проверка это! это вызов скрипта с переменной this, которая была у этого скрипта! Посмотри в объявление функций ;) Кстати эта переменная тоже this называется... Кому-то из ГГ казалось поначалу, что это, как в ООП, ссылка на этот скрипт. Никуа. Переменная с по-дурацки подобранным именем.
Цитата:
IsLess( GetX( RandBush ) , 202.0 ) \\Если случайная координата X объекта RandBush меньше числа 202, то это Истина, то есть выполняется нижеописанное

Кстати, тупо там сделано - проверять рандомность через координату. Координату может понадобиться не один раз менять. Инициализировали бы уж для понятности float-переменную, или память берегут? :) Или им вообще лень было... ХЗ.
Цитата:
Sleep( 2 )\\не знаю что это за хрень (время?)

Пардон, это не хрень. Да, это время. Это значит, что ниженаписанное начнёт выполняться только через 2 единицы измерения времени, равные 1/15 секунды. То есть пдождать, прежде чем продолжить.
Цитата:
VCheck#2#2( this )\\проверка этой функции(условия)

Рррррр! :mad: НИВАЛ!!!
Цитата:
IsLess( GetX( RandBush ) , 201.0 )\\Если случайная координата X объекта RandBush меньше числа 201, то это Истина, то есть выполняется нижеописанное

О чем я и говорил ;) Нет чтобы числовую переменную юзать... :(
Цитата:
Script VTriger#2#1\\после всего вышеописанного, запускается эта функция
...
WorldScript\\вызов функций, работающих постоянно(?)
(
...
VTriger#2#1( NULL )\\старт квеста, цель и финиш квеста.

Перед всем вышеописанным ;)
Цитата:
WorldScript\\вызов функций, работающих постоянно(?)

Вызывается при входе в зону или load'е.
Цитата:
VCheck#2#1( NULL )\\эта функция почему то не вызывается
VCheck#2#2( NULL )\\эта функция почему то не вызывается

Это с какой же это радости она не вызывается? :eek: По моему тут написано её имя и передаваемая ей переменная(NULL, которая просто не инициализирована ничем), поэтому оно вызовется ;)


Короче что успел - объяснил. Будут вопросы - пишите все, кому не лень(*сонным голосом продолжает вербовку скриптеров)...
Farlander - 10 декабря 2005, 17:13
Гы... вообще, ВСЕ квесты в Песках были сделаны ГГ (а квест "пропал парламентер" - в песках).... тааааак... кто из ГГовцев был таким извращенцем и садомазохистом что называл все скрипты именами Нивальского редактора?
S@MUR@I - 10 декабря 2005, 20:46
Кстати на зоне "Развалины" труп исправно рандомится. Ну, труп с деньгами. Скрипт такой же и с теми же садомазоскриптами :roll:

Взял за основу этот скрипт и сделал квест "Убить Каку". Кака у меня нормально рандомится. А, как ни извращался с людоедом, ни хотит он, ну не рандомится и все тут!

Если убрали рандом людоеда сознательно, для облегчения квеста, то просьба вернуть эту фишку. Так как щас есть телепорт. И не забудьте сообщить в чем прикол.
Снайпер - 11 декабря 2005, 00:16
По приколу, я не знаю, кто из ЕИ-Модовцев ответственный за скрипт, но могу предположить, что это сделано специально - с целью защиты мобов от взлома. Но названия препаршивейшие...
S@MUR@I - 11 декабря 2005, 00:30
Да ну! Защищать то зачем? От кого? Просто привык чел так набирать, для порядка (и я так обзываю функции и че? и многие так делают).
К тому же ниче это не защищает.
А где действительно есть защита, это моб квеста "Волчья стая". Там ни подменить монстров, ни че сделать нельзя. Структура ветвлений какая-то не такая. Нет ни идентификаторов монстров, ни много чего еще. Есть зато "лишняя" пустая ветка.
Снайпер - 12 декабря 2005, 22:10
Цитата (S@MUR@I):
Просто привык чел так набирать, для порядка

:D
_________________
P.S.: Сорри, сорри за флуд... Нимагу, ржу я... порядок есть не это, порядок есть вооон то. Но я людское "имхо" не трогаю, пусть оно будет у каждого своё :) Особенно по философским вопросам.
S@MUR@I - 13 декабря 2005, 00:40
Создал квест с рандомным волком в Развалинах. Волк рандомился в 5 разных местах. Затем в файле zone3-lmp.mob сделал так, чтоб труп с деньгами на этой зоне рандомился в 4-х разных местах. И волк у меня перестал рандомится. Ошибка была моя и я ее исправил.

Я это к чему. Оказывается мой волк берет случайную координату Х из другого моба! Более того, сам скрипт рандомности волка(RandBush) не пашет. Хотя скрипт такой же, как у трупа. Пашет тока тот участок кода, который отвечает за перемещение волка в соответствие с координатой Х переменной RandBush.
Снайпер - 13 декабря 2005, 00:43
То есть, как выяснилось, я был прав - и не надо было привязывать рэндом к координатам. На то есть приличный 4-байтовый тип float, который всё ладненько и устроил бы. Главное - вовремя обнулять переменную, и всё путём. А координату обнулить не получится :D Ибо она не для того дана ;)
S@MUR@I - 13 декабря 2005, 02:38
Говоришь координата не обнуляется?
Тут что то не сходится.
Например, в Песках сделано так. Для ящика с деньгами создается переменная RandBush2, а для людоеда - RandBush. Мало того, их ID-номера различаются. То есть случайные координаты Х создаются для разных переменных, с разными ID-шниками. И мне кажется, что обнулять тут бессмысленно. Проблема в том, что в основном мобе(мобе карты) RandBush пашет, а в мобе квеста нет.
Кстати, а почему абстрактному объекту(RandBush) присваивается ID?
Может потому, что он далеко не абстрактный? Может в мобе он, как-то прописан? Надо будет проверить. Хотя вряд ли.

Кстати, по моему ящик с деньгами в Песках тоже не пашет :)
Нету его. А это уже серъезно. Верните мои деньги :abuse:
Снайпер - 13 декабря 2005, 03:33
Пример:
Код:
//Скрипт позволит рассеивать рандомные позиции обжектов по разным точкам
GlobalVars(
  NULL : object,  //Нулл - просто переменная-затычка. Для прикола можно ей чтонить присвоить.
  i : object,      //Нужная переменная. Вдруг цикл какой, с полным перебором?
  rnd : float,    //Наша случайная переменная. Без камиинтариивъ
  cond : float,  //Это просто для сокращения места - чтоб условие 100 раз не писать
  Monster1 : object, //Первый обжект
//... список...
  MonsterN : object  //Последний обжект
)

//Скрипт предназначен для расставляния чего-то в случайных комбинациях
DeclareScript SetRandomPositions( this : object )

Script SetRandomPositions
//Задаём случайные точки N-му числу монстров
(
  if
  (
  )
  then
  (
    KillScript(  ) //Чтоб по окончании скрипта не пошло по 2 кругу
    //Monster1 - 3 точки размещения
    rnd = Random(3) //дробь типа float от 0 до трёх
    //Обнуление
    SetCP(Monster1,0,0,0)
    //Случай номер 1: от 0 до 1, точка (200;300)
    cond = Not(IsGreater(rnd,1))//rnd<=1
    //Проверяем условие с помощью банальной операции умножения
    //Для арифметических операций не надо писать длиннных блоков ветвлений...
    //Булевские операции в ПЗ выражены типом float - true = 1, false = 0
    //Mul - умножение, Add - сложение, Sub - вычитание, Div - Деление
    //Выставляем первый случай:
    SetCP(Monster1,Add(GetX(Monster1),Mul(cond,200)),Add(GetY(Monster1),Mul(cond,300)),0)
    //Второй случай: (1;2], точка (150;100)
    cond = Mul(IsGreater(rnd,1),Not(IsGreater(rnd,2)))
    SetCP(Monster1,Add(GetX(Monster1),Mul(cond,150)),Add(GetY(Monster1),Mul(cond,100)),0)
    //Итак, если предыдущее условие не выполнилось - то координаты объекта до операции№2 равны (0,0,0). Если условие не верно - координаты не меняются: x + a*0 = x
    //Операция 3: (2;+<бесконечность>), (50;200)
    cond = IsGreater(rnd,2)
SetCP(Monster1,Add(GetX(Monster1),Mul(cond,50)),Add(GetY(Monster1),Mul(cond,200)),0)
    //Аналогично. На каждый случай уходит 2 действия, на растасовку потрачены сверх объектной 2 переменные - rnd и cond. Форма записи легкая - в мобэдиторе лучше видно, например в МРТ экран белый, а не тут ото...
    //...
    //...
    //MonsterN - 2 точки(например!) Можно сделать его независимым от первого, и повторить всю процедуру с момента rnd = Random..., а можно сделать в зависимости от первого, но тогда бы лучше писать сразу там же ;)
    rnd = Random(2)
    cond = Not(IsGreater(rnd,1))  //(-<б.>;1]; (10;15)
    SetCP(MonsterN,Add(GetX(MonsterN),Mul(cond,10)),Add(GetY(MonsterN),Mul(cond,15)),0)
    //Тру-ля-ля... Думаю, все, кому надо, уже разобрались...
    cond = IsGreater(rnd,1)  //(1;+<б.>); (20;30)
    SetCP(MonsterN,Add(GetX(MonsterN),Mul(cond,20)),Add(GetY(MonsterN),Mul(cond,30)),0)
  )
)

WorldScript
(
  Sleep( 2 ) //Чуток подождать, чтоб не сглючило
  Monster1 = GetObjectById("12345")
  MonsterN = GetObjectById("67890")
  SetRandomPositions( NULL )
  //Переменная NULL не содержит ничего, но нам она и не нужна. Это просто заглушка.
)


Вот так то ;)
Я вполне допускаю, что в 2 часа ночи я мог допустить опечатку, например, со скобками, и при помещении в .моб-файл то, что в "КОД"е работать не будет(хотя это ещё проверить надо ;) ), но по устранении всех опечаток - алгоритм будет разбрасывать столько объектов, сколько туда не поленятся вбить.
P.S.: Счас забэкаплю текст, а то мало ли что, перепад вольта...
P.P.S.: Кроме того, таким же задовым способом можно делать случайную выдачу квестов, награды, пальбу скриптовыми молниями по случайной точке заданного прямоугольника... :D Давайте, квестоделы, подключайтесь к ЕИ-моду - балансом займётся Читтер, а вы квестов сделаете, и будет у нас, кроме прочего, ещё и хороший мульти<эх, ме4ты...>. ;)
S@MUR@I - 13 декабря 2005, 08:25
Почитал, разобрался и восхитился. Горд так, как будто сам это написал :)
Вроде должно все работать. Завтра проверю на людоеде.
S@MUR@I - 13 декабря 2005, 08:47
Цитата (Снайпер):
Цитата:
VCheck#2#1( NULL )\\эта функция почему то не вызывается
VCheck#2#2( NULL )\\эта функция почему то не вызывается

Это с какой же это радости она не вызывается? :eek: По моему тут написано её имя и передаваемая ей переменная(NULL, которая просто не инициализирована ничем), поэтому оно вызовется ;)


Может это уже не важно, но все таки скажу. Это я написал, чтобы прокомментировать. На самом деле эти функции в коде скрипта не прописаны. Потому я и сказал - не вызываются.
Может, так и надо, потому что в коде со скриптом рандомного трупа на Развалинах, они тоже не вызываются. Тем не менее труп рандомится. Кстати о трупе. Вы знаете, что иногда трупа нет? Ну нет и все. Он должен по идее появлятся в двух местах. Скорее всего, дело опять же в координате Х. Там условие начинается с определенной цифры. И если значение координаты получилось выше этой цифры, то трупа с деньгами нет.
А также прикол. Я увеличил кол-во рандомных мест(возможно поэтому?или не проставил где-то sleep?) и иногда труп, хотя и мертвый, стоит себе и почесывается :) . Как людоед в Геноциде :)
S@MUR@I - 14 декабря 2005, 00:57
Ну что ж, проверил - работает.
Только зачем объявлять монстров в качестве глобальных переменных? :drug:
Соответственно не нужно в Ворлдскрипте присваивать монстрам ID-шники, это физические объекты, прописанные в мобе. Правда не знаю, что будет, если вызвать монстров не имеющих "прописки". Может, как раз им и нужно будет присваивать ID, каждому в WorldScript. Но если так, то надо ли их(монстров) объявлять, как переменные?
В общем, такие дела, даже не знаю...

Вот, работающий скрипт рандомного людоеда. Любой, кто умеет обращаться с МРТ, если захочет, может поправить этот баг с людоедом.

GlobalVars (
NULL : object,
i : object,
rnd : float,
cond : float
)

DeclareScript OgreChest ( this : object )
DeclareScript SetRandomPositions ( this : object )


Script SetRandomPositions
(
if
(
)
then
(
KillScript( )
rnd = Random( 3 )
SetCP( GetObject( 1000001 ), 0, 0, 0 )
cond = Not( IsGreater( rnd, 1 ) )
SetCP( GetObject( 1000001 ), Add( GetX( GetObject( 1000001 ) ), Mul( cond, 133.7 ) ), Add( GetY( GetObject( 1000001 ) ), Mul( cond, 267.5 ) ), 0 )
UMSentry( GetObject( 1000001 ), 133.7, 267.5 )
cond = Mul( IsGreater( rnd, 1 ), Not( IsGreater( rnd, 2 ) ) )
SetCP( GetObject( 1000001 ), Add( GetX( GetObject( 1000001 ) ), Mul( cond, 284.6 ) ), Add( GetY( GetObject( 1000001 ) ), Mul( cond, 302.5 ) ), 0 )
UMSentry( GetObject( 1000001 ), 284.6, 302.5 )
cond = IsGreater( rnd, 2 )
SetCP( GetObject( 1000001 ), Add( GetX( GetObject( 1000001 ) ), Mul( cond, 193.1 ) ), Add( GetY( GetObject( 1000001 ) ), Mul( cond, 191.1 ) ), 0 )
UMSentry( GetObject( 1000001 ), 193.1, 191.1 )
)
)

Script OgreChest
(
if
(
)
then
(
KillScript( )
QStart( "z8q1" )
QObjSeeUnit( "GetObject( 1000001 )" )
QObjKillUnit( "GetObject( 1000001 )" )
QFinish( )
)
)

WorldScript
(
Sleep( 2 )
OgreChest( NULL )
SetRandomPositions( NULL )
)

Спасибо Снайпер! Буду теперь смотреть, каким макаром реализован рандом некой вещи, в квесте "Предатель в поселке".
Снайпер - 14 декабря 2005, 01:20
Цитата:
Только зачем объявлять монстров в качестве глобальных переменных? :drug:

Раз уж заговорили о таких высоких материях, как прописывание глобальных переменных... :D То, что написано в объекте - вроде бы - имя объекта, то есть реагирует на команду GetObjectByName("Name"), а в чистом виде использоваться не может ;) Так что объявлять надо. А вот труп - это фича известная. После SetCP все юниты юзают анимацию Idle, отчего и стоят так. Надо перемещать его, пока он ещё жив, либо по перемещении убить вторично :D либо проиграть анимацию смерти, он должен после этого так и остаться... :rolleyes:
P.S.: С переменными правда удобнее работать ;) И глобальные - имеется ввиду по мобу, а не по игре. Глобальные по игре задаются не так, через =, а GsSetVar(nPlayer,"Var",Value) ;)

P.S2.:
Цитата:
GetObject( 1000001 )...повторить N раз
Ууу! *зуб ноет. Так только нивальский мобэдитор пишет! Самое лучшее - переменная, да ещё и чтоб имя было понятное. Например, 1000002 - людоед, а 1000003 - лягушка. В мобе отличишь? Не уверен, будет сбивать. А вот если
Код:
Ogre = GetObjectByID("1000002")
Toad = GetObjectByID("1000003")

Всё для чего делается, и переменные, и нормальные названия функций? Для удобства :) Так что переменные 4еver!
PS3: Лучше GetObjectById, потому что просто гетобжект в некоторых случаях работает некорректно(например, с НеПиСяями), и лучше 1 раз написать правильно, чем 10 раз правильно, а 1 неправильно :)
S@MUR@I - 14 декабря 2005, 04:09
Мдяя...
Кстати, я по моему допустил ошибку одну :) несущественную
Но тем не менее скрипт пашет :)
Снайпер - 14 декабря 2005, 04:54
Учитесь, пока я жив :D (с)Народныя присказка
Sagrer - 15 декабря 2005, 20:38
вообще это геморр каждый раз инициализовать переменную для обжекта если он юзается 1-2 раза.... Вот если очень часто нужен - то да....

А с NPC-ёвыми вообще проще всего работать через GetObjectByName
Снайпер - 16 декабря 2005, 00:04
Да, воистину. Хотя я для порядка на все объекты инициализирую - на случай повторного редактирования моба, чтоб не путаться с Id.

Тут мне в приват поступил вопрос,
Q: "а чем можно добавлять и удалять юнитов, и где енту прогу скачать?".
A: Mob Reversing Tool. http://gipat.ru Все добавления и удаления можно без геммороя обставить через скрипт. Кто в бронетазике, тот поймёт ;)
S@MUR@I - 16 декабря 2005, 00:49
В МРТ заметил одну вещь. Статы монстров нельзя изменить. При нажатии кнопки "apply" все изменения сбрасываются.
Но это можно обойти, проставив значение ID_UNIT_NEED_IMPORT=0.
Тогда настройка статов через моб отключена и монстр берется из ресурсов без изменений.
При переодевании юнитов на базе например, следует поставить им 1, чтобы можно было переодевать их через моб.
Снайпер - 16 декабря 2005, 01:02
Цитата (S@MUR@I):
В МРТ заметил одну вещь. Статы монстров нельзя изменить. При нажатии кнопки "apply" все изменения сбрасываются.

Это меня спрашивали тоже :) Какие у людей извечные вопросы
Цитата:
Но это можно обойти, проставив значение ID_UNIT_NEED_IMPORT=0

То есть чтоб параметры брались из моба.
Часовой пояс: GMT +4:00
Форумы Поселка созданы на базе phpBB2 2.0.4 © phpBB Group