Форум Oni

Русскоязычный форум поклонников игры «Они» от Bungie

  • Здравствуйте, Гость

#1 22-07-2008 11:04:49

Мih@ 
Регистрация: 27-08-2006
Сообщений: 824
Профиль

Oni Scripts: FAQ-пособие

Побыв прошлую ночь в культурном шоке от темы "Учебник по скриптированию" и так не сумев её отредактировав, оставив хоть какую-нибудь часть в изначальном виде, решил всё-таки выложить хотя бы то, что есть. И что есть уже довольно-таки давно. )
________________________________________________________________________________

1. Общая информация

1.1. О скриптах

1.1.1. Что такое скрипты, для чего они нужны?
Это командные сценарии, выполняемые в игре. С помощью них вы сможете изменять и разнообразить геймплей.

1.1.2. Где они находятся?
В текстовых файлах с расширением bsl (BungieFrameWork Scripting Language), которые хранятся в директории ...\GameDataFolder\IGMD, где разложены по директориям с названиями уровней.

EnvWarehouse ? Тренировка и Склад Синдиката
manplant ? Завод Масаши
lab ? Лаборатория Ваго Биотек
Airport ? Нападение на аэропорт
Airport_III ? Грузовые ангары аэропорта
tctf ? Штаб-квартира TCTF
power ? Атмосферный комплекс (снаружи)
power_II ? Атмосферный комплекс (внутри)
state ? Региональное управление
roof ? Крыши
dream_lab ? Лаборатория доктора Хасегавы
neuro ? Закрытая лаборатория TCTF
tctf_ii ? Штаб-квартира TCTF (redux)
compound ? Горная резиденция Синдиката

Кроме того, существует директория global, обрабатываемая для абсолютно всех уровней. По умолчанию в IGMD она отсутствует, но при надобности её можно создать.

Оригинальные файлы скриптов обычно бывают трёх типов:
main (суффикс _main) ? файл, содержащий основную (вызываемую сразу при запуске уровня) функцию, main.
cutscene (суффикс _cutscene) ? содержит все катсцены (анимированные вставки) уровня.
logic (суффикс _level_logic или отсутствие суффикса) ? всё остальное (от музыки, создания персонажей и start до консолей да всевозможных триггеров).
Иногда встречаются и другие "тематические" скрипты - например, particle_scripts, или _spawn.

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

1.1.3. С помощью чего их можно редактировать?
Подойдет любой текстовый редактор, например, обычный виндовский Блокнот или WordPad. В идеале - любой удобный и привычный редактор с поддержкой C-подобного синтаксиса.
(!) Прежде чем редактировать bsl-файл, снимите у него в свойствах галочку "только для чтения".

1.1.4. Я испортил все скрипты, а оригиналы не сохранил. Что делать?
Переустановить игру ;) Или скачать этот бэкап.

1.2. Язык скриптов

1.2.1. Скриптовые команды
Примеры скриптовых команд в данном пособии будут приводиться следующим ("Shell-style") образом:
    название_команды [параметры]
Пример:
    chr_givepowerup [персонаж] [предмет] [количество]
На практике это должно писаться без квадратных скобок, например:
    chr_givepowerup Muro hypo 2

Существует более строгий (C-style) синтаксис:
    название_команды([параметры]);
Параметры перечисляются через запятую. Пример такого вида:
    chr_givepowerup(Muro, hypo, 2);
Таким образом, разделяя команды точкой с запятой, можно писать несколько команд в строчку. Кроме того, только в таком виде можно использовать в качестве параметра переменную.

Помимо вызовов функций, часто будут встречаться обычные присвоения переменным, то есть просто:
    название_переменной=[значение]

Во избежание недоразумений, обязательно учитывайте тип переменных - ошибки в этом плане ни к чему хорошему не приведут. Чаще всего проблемы возникают при обращении к персонажам: одним функциям нужны string-имена, другим - int-номера, а третьим подходят оба варианта. Следует понимать, что такое поведение чётко определено и, например, добиться чего-то от функции, требующей номера, зная только имя персонажа, нельзя.
В данном пособии пока что типы не указаны (разве что подразумеваются в виде имя/номер/персонаж, или [0/1]), но их всегда можно посмотреть в script_commands.txt (dump_docs), а также они будут указаны здесь в будущем. Когда-нибудь.

(!) Обязательно имейте ввиду, что все команды, функции, переменные и их значения чувствительны к регистру. "Konoko" нельзя менять на "konoko", "konoko" нельзя менять на "Konoko", "main" нельзя менять на "Main", "GrifElite02" нельзя менять на "grifelite02", "chr_set_health" нельзя менять на "chr_Set_Health", и так далее и тому подобное. Даже если очень хочется.

1.2.2. Функции

Традиционная структура всех функций такова:
func void [название] ([параметры])
{
    [команды]
}

При отсутствии параметров в скобках указывается void. Или ничего не указывается, даже сами скобки: в таком случае функция будет работать не хуже. Но лучше на всякий случай указывать void, иначе есть вероятность каких-нибудь глюков.
Если параметров несколько, то они отделяются запятыми; перед каждым параметром указывается его тип. Например:
func void function_name (int parameter_eins, float parameter_zwei, string parameter_drei)

(*) Все команды обязательно должны быть написаны внутри функций, иначе они не выполнятся или вовсе вызовут нефункциональность скрипта. Будьте внимательны с фигурными скобками, достаточно одной незакрытой, чтобы перестал работать весь скрипт.

В первую очередь в игре всегда обрабатывается главная функция, func void main (void). Попробуйте с помощью нее сделать простейший пример своего первого скрипта. Удалите все содержимое, скажем, папки Airport и создайте в ней файл bsl с любым названием. Напишите в нем:
func void main (void)
{
    chr_teleport 0 7010
    sleep 120
    win
}

Загрузите любую сохранку Аэропорта. Вы увидите, как Маи окажется на самолете в ремонтном ангаре, а через пару секунд уровень будет автоматически выигран. Т.е. вы написали подряд три команды, и они выполнились друг за другом. Теперь попробуйте разбить этот "сценарий" на несколько функций, которые вызываются одна из другой. Например:
func void main (void)
{
    start 120
}

func void start (int time_to_sleep)
{
    chr_teleport 0 7010
    sleep(time_to_sleep);
    win_level
}

func void win_level (void)
{
    win
}

Думаю, принцип понятен. Все функции можно писать как в одном файле, так и в нескольких (смотря как вам удобнее и нагляднее). Названия файлов, как уже говорилось, значения не имеют.

1.2.3. Вилки
Кроме того, функции можно вызывать параллельно, без прерывания текущей функции. Для этого достаточно воспользоваться строчкой:
    fork [название функции]
Таким образом, создаётся вилка, и игра обрабатывает уже две (или больше, если вилок много) функции одновременно: начинает новую, и продолжает выполнять текущую.

Хотя эту возможность можно использовать каждый раз, когда нужно запустить какую-то функцию, не теряя хода нынешней, чаще всего вилки используются для того, чтобы запустить ожидание какого-либо события. Например:
func void wait_to_help(void)
{
    chr_wait_health Muro 200

    ai2_boss_battle = 0;
    muro_in_danger = 1;
    ai2_attack GrifElite01 char_0
    ai2_attack GrifElite02 char_0
    ai2_attack GrifElite03 char_0
    ai2_attack GrifElite04 char_0
    ai2_attack GrifElite05 char_0
    ai2_attack GrifElite06 char_0
}

Такая функция (это из последнего уровня, к финальной битве) позволяет по наступлении нетриггерного события (уменьшение здоровья Муро до 200) совершать какие-либо действия и вообще менять, в данном случае, стратегию боя.

Аналогично же можно, например, ждать выполнения какого-то приёма от игрока (да и от других персонажей ? тоже), и прописывать соответствующие действия в вилочной функции.

1.2.4. Переменные
В скриптах есть возможность создавать, редактировать и действовать относительно различных переменных. Их всего четыре вида: bool (двоичная), int (численная), float (с плавающей точкой, она же дробная, она же вещественная) и string (символьная). Двоичные переменные могут принимать всего два значения ? 0 или 1. Численные переменные ? целые (в основном используются натуральные) числа. С ними и можно выполнять всякие разные математические действия. Символьные же переменные могут принимать вид любой последовательности символов (как-то: слово), и могут использоваться для некоторых особых случаев, например, для dmsg. Также, тип string имеют имена персонажей (char_0, MutantMuro, и т.д.), названия предметов и оружий (w1_tap, hypo), и некоторые другие сущности. Никакие действия, кроме присвоения нового значения, к ним неприменимы. Присвоение переменной значения переменной другого типа пока что невозможно.

Для работы с переменной, в первую очередь её следует создать, с указанием типа. Это делается во внефункциональной области скрипта (то есть, пишется не в функциях, а за пределами фигурных скобок) следующей командой:
    var [тип] [название];
или
    var [тип] [название] = [значение];
(*) Каждое действие с переменными вне функций обязательно должно завершаться точкой с запятой (;). Иначе будут фатальные ошибки.

Где тип ? это bool, int, float или string, название ? то, как переменная будет обозначаться в скрипте, а значение ? это значение. =) Значение можно не указывать при создании, и тогда оно будет равняться нулю (для строковых переменных - пустой строке). Но лучше указывать всегда. В названии можно использовать почти любые символы, кроме функциональных (; , # " { } ( ) + - = ! < >). Например, некоторые буквы кириллицы (имеющие аналоги в английском языке, например, "о") работают и в названиях переменных, и в названиях функций, причём даже в английской версии игры. Но лучше не извращаться и обойтись английскими буквами, прочерком (_) и циферками. )

Например:
var string peremennaya = znachenie;
Изменять переменные можно обыкновенным присвоением, строчкой:
    [название переменной] = [новое значение];
Где значением может быть как константа, так и выражение. Например:
    peremennaya = peremennaya + 2;
Применяются переменные как напрямую, так и, чаще, в косвенном виде. Напрямую переменную можно использовать, во-первых, в командах dmsg и dprint (пока что только строковую переменную без каких бы то ни было излишеств), а во-вторых, для int-переменных, для установления численных параметров переменных: в chr_set_health, в количестве даваемых игроку предметов, в задержке, etc.

Косвенно переменные применяются if-конструкциях, для проверки: больше-меньше, равна-неравна переменная числу такому-то...
Например:
    if (hypo_counter ne 0) chr_givepowerup 0 hypo
    if (hypo_counter > 1) chr_givepowerup 0 hypo
    if (hypo_counter > 2) chr_givepowerup 0 hypo
    if (hypo_counter > 3) chr_givepowerup 0 hypo
    if (hypo_counter > 4)
    {
        dprint done
        chr_givepowerup 0 shield
    }
    if (hypo_counter eq 7) chr_givepowerup 0 invis


В такой системе игроку будут даваться гипо-спреи, до четырёх штук, в зависимости от переменной hypo_counter. Если счётчик равен пяти или более, то игроку даётся силовой щит. Если он равен ровно семи, даётся ещё и невидимость.
Также этот пример худо-бедно иллюстрирует работу if: выполнение следующей инструкции при истинности условия в скобках. условие - обычно сравнение двух значений (<, >, >=, <=, eq, ne), либо логическое выражение (and, or), в том числе отрицание (!).
Например, if (!hypo_counter) должно быть эквивалентно if (hypo_counter ne 0)

1.2.5. Строчки, начинающиеся с #
Итак, одна из важнейших составляющих скриптов... Это строчки, начинающиеся с волшебного символа "решётка" (#). Строки эти вообще не обрабатываются игрой. =) В них можно писать комментарии, закосяченные или "мягко" удалённые команды, анекдоты и свои мысли в адрес движка, который ни в какую не хочет нормально обработать, казалось бы, правильно написанный код: всё, что угодно. Движок этого читать, понимать и обрабатывать вообще не будет.
Единственное, что противопоказано в отношении этих строк (условно называемых комментариями) ? это писать символ # не в начале, а в каком-то другом месте строки, в которой написано что-то ещё (например, если хочется поставить свой комментарий не выше и не ниже, а сразу за комментируемой строкой). Сами эти строки (ту часть, что написана до #) движок обрабатывает без особых проблем, но последующую строку пропускает. Если строки завершать точкой с запятой (;), этой проблемы быть не должно, но лучше не морочиться.

1.2.6. Обозначение игрока
Для обозначения Маи лучше использовать индекс 0 (он везде прокатит), а не имя (например, char_0 или konoko - они работают не на всех уровнях). Более точно:
char_0 работает в уровнях: Тренировка, Склады Синдиката, Нападение на аэропорт, Штаб-квартира TCTF, Атмосферный комплекс (снаружи), Атмосферный комплекс (внутри), Крыши, Горная резиденция Синдиката.
konoko работает в уровнях: Завод Масаши, Лаборатория Ваго Биотек, Грузовые ангары аэропорта, Региональное управление, Лаборатория доктора Хасегавы.
На уровне Закрытая лаборатория TCTF игрок именуется Konoko (с заглавной буквы).
На уровне Штаб-квартира TCTF (redux) Маи обозначена как A_player. =)
Сам движок обычно показывает и обрабатывает словесные обозначения, да и в оригинальных скриптах они часто используются, но (особенно в глобальных скриптах, распространяющихся на все уровни) лучше всегда использовать 0.

2. Основы команд

2.1. Неклассифицируемые команды

2.1.1. Сообщения
Игра поддерживает два вида вывода сообщений (изначально предназначенных для отладки -_-) на экран:

    dmsg "[сообщение]"
либо
    dmsg [строковая переменная]
Выводит сообщение внизу экрана, посередине. С течением времени (зависит от активности движения игрока) сообщения плавно исчезают, одновременно может выводиться не более четырёх сообщений. Кроме того, сообщения можно раскрасить: для этого нужно часть сообщения представить в виде "[ц.текст]", где "ц" - буква, отвечающая за выбор цвета. Цветов всего восемь: b, c, g, l, o, r, u, y. Если указать иную букву, сообщение пропечатается вместе с квадратными скобками, буквой и точкой; если букву не указывать, цвет будет белым, также, как текст вне скобок.
Для наглядности приложено отображение команды
    dmsg "[b.B][c.C][g.G][l.L][o.O][r.R][u.U][y.Y][.W]"
http://onimia.ru/forum/attachment.php?item=1549&amp;download=1

    dprint [сообщение]
При включенном режиме разработчиков, отображает сообщение в консоли - снизу слева. Никакого оформления не предусмотрено, команда предназначена для отладки. Все кавычки в сообщении не печатаются. Команда очень часто встречается в оригинальных скриптах.

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

    cinematic_start [название картинки] [ширина] [высота] [начальная позиция] [конечная позиция] [скорость] [отражённость]
Мгновенно создаёт в начальной позиции заданную картинку, которая сразу с заданной скоростью начинает движение к позиции конечной. Картинка может быть любой текстурой из данного или нулевого уровня - хоть мордашка, хоть вид неба, хоть текстура стенки или любого другого объекта. Ширину и высоту (в пикселях) лучше указывать те же, что и у самой текстуры, либо пропорционально меньше (растяжение обычно выглядит не очень красиво). "Стандартный" размер из оригинальных скриптов всегда 180х180. Скорость, кажется, указывается в пикселях во фрейм (1/60 секунды при соответствующем fps). Отражённость слева направо задаётся двоичным числом - или отражается, или нет. Несмотря на то, что в оригинальных скриптах всегда пишется текстовое true или false (или ничего не пишется, что соответствует false), вместо них прекрасно работают, соответственно, единичка и нулик. Текстовое представление здесь - такой же стереотип, как и написание команды по синтаксису со скобками и запятыми. Два равнозначных примера:
    cinematic_start (MUTANTMUROface, 180, 180, 19, 7, 20, false)
    cinematic_start MUTANTMUROface 180 180 19 7 20 0

    cinematic_stop [название картинки] [конечная позиция] [скорость]
С заданной скоростью ведёт уже созданную картинку к конечной позиции, по достижении которой картинка пропадает.

Начальные и конечные позиции - числа от 1 до 25, номера расположенных в строгом порядке позиций на экране и за ним. Их порядок также есть в прилагаемой иллюстрации, где белым прямоугольником обозначена видимая на экране область, а чёрным закрашено окружающее пространство. При указании позиции с номером более 25, кинематика работать не будет. Позиция с нулевым номером расположена в левом верхнем углу видимой области.
http://onimia.ru/forum/attachment.php?item=1550&amp;download=1

Более точно расположение кинематики можно определять следующими переменными:
    cinematic_xoffset=[число]
    cinematic_yoffset=[число]
Горизонтальный и вертикальный отступы от края (т.е. к каждому краю прилегают три видимые позиции; нижний край кинематики расположен чуть выше "настоящего") соответственно. По умолчанию горизонтальный отступ равен 20, вертикальный - 65.

2.1.3. Границы видимости

    gs_farclipplane_set [расстояние]
Выставляет расстояние абсолютной обрезки. Выглядит как плоскость, перпендикулярная линии взгляда (aiming vector), за которой ничего нет. Обычно это не очень красиво (хоть и экономит ресурсы), поэтому в большинстве случаев стоит либо выставить очень большое расстояние, либо использовать его совместно с плавностью тумана.

    gl_fog_start=[число]
    gl_fog_end=[число]
Данные переменные определяют густоту тумана, выражаются числами на отрезке [0,1]. обычно end равен единичке (то бишь, абсолютный туман на расстоянии farclipplane), а start - что-нибудь вида 0.9**. Стоит взглянуть на практике, чтобы оценить масштабы: даже 0.99 - отнюдь не идеальная видимость. чем больше start в данном случае, тем менее густой будет туман. Если выставить end меньше, чем start, то лучшем случае получится затуманивание в другую сторону - плохая видимость модели самого игрока.
Также стоит учитывать, что некоторые части некоторых тел (например, в случае Маи это голова: видимо, это касается "блестящих" поверхностей и частиц) не затуманиваются, и при слишком большом затуманивании будут очень некрасиво смотреться. Кроме того, жестокий туман сейчас менее актуален, так как современные машины довольно свободно отрисовывают весь уровень при отсутствии тумана и пятимиллионном farclipplane... Но это уже зависит от вкуса и ситуации. И вообще атмосферы.

    gl_fog_start_changeto [число] [время]
    gl_fog_end_changeto [число] [время]
Плавно меняют вышеуказанные величины в течение заданного времени.

    gl_fog_red=[число]
    gl_fog_green=[число]
    gl_fog_blue=[число]
Определяют цвет тумана по трём составляющим. Числа из отрезка [0,1]. Чем туман более густ, тем больше в нём проявляется данный цвет (опять же, масштабы могут быть довольно неожиданны, стоит подбирать на практике).

Помимо тумана, есть любимая почти всеми квакерами и не только функция угла обзора:
    gs_fov_set [угол]
Не так мило с учётом вида от третьего лица, но всё же... Для некоторых размазанные края слишком привычны, чтобы испытывать дискомфорт. Кроме того, малые углы можно использовать как зум... В специфичных случаях.

2.1.4. Спецэффекты

    splash_screen [текстура]
Показывает заданный сплэш-скрин. Как обычно, при начале и конце уровня. Не забываем, что это не хухры-мухры, а большие TXMB. Можно, например, фон меню показать. ) Но, в отличие от кинематики, не какую попало текстуру.

    fade_out [red] [green] [blue] [время]
В течение заданного времени "затемняет" весь экран до указанного цвета: red - красная составляющая, green - зелёная, blue - синяя, все на отрезке [0,1]. Кинематика рисуется поверх фейдинга, сообщений при нём нет вообще.

    fade_in [время]
В течение заданного времени возвращает видимость из фейдинга. Причём если fade_in вызван, пока экран окончательно за затемнился от fade_out, то экран мгновенно зальёт итоговым цветом, и уже из этого положения начнёт просветляться.

    ui_show_element [элемент] [0/1]
При нуле прячет указанный элемент (left с оружием, компасом и боеприпасами или right со всем остальным) интерфейса.

    ui_fill_element [элемент] [0/1]
Заполняет указанный элемент интерфейса. То бишь, показывает все шесть обойм/гипо, заполняет показатель здоровья (вплоть до даодановой области: однако, цвет будет соответствовать реальному количеству), все стороны повреждений, всю окружность компаса, стрелочку, и т.д.
Все доступные варианты: health, damage, invis, shield, hypo, weapon, ammo, compass, arrow, ballistic, energy, lsi.

    ui_flash_element [элемент] [0/1]
При единице указанный элемент интерфейса начинает мигать.

    ui_show_help [0/1]
Показывает подсказки к интерфейсу. =)

    ui_suppress_prompt=[число]
При единице отключает всплывающие подсказки (о новых заданиях, сохранениях, и т.п.)

    letterbox [0/1]
Включает катсценообразные чёрные полоски (но не катсцену!). Когда они есть, не отображаются сообщения (типа dmsg) и элементы интерфейса.

    begin_cutscene
Включает катсцену. Катсцена подразумевает сразу ряд функций (ai2_allpassive 1, cm_detach, letterbox 1, ai2_allpassive 1, input 0 и т.п.), и в оригинале не позволяет выйти в меню, например.
Считается функцией без аргументов, однако при указании параметра weapon игрок ещё и прячет оружие.

    end_cutscene
Завершает катсцену.

2.1.5. Конец
За выигрывание уровня отвечает команда:
    win

За проигрыш:
    lose

Обычно в ресурсах к смерти игрока привязана обыкновенная скриптовая функция "you_lose", которую, наверное, можно было бы даже сделать глобальной. Туда пишется фиксация камера в одном месте (cm_detach), затемнение экрана (fade_out), и уже потом, спустя несколько секунд - собственно lose. Разумеется, всё это можно менять каким угодно образом.

2.2. Читы

Чтобы включить некоторые из читов (применительно к игроку), можно воспользоваться строкой:
    [название чита]=[0/1]
Где единица означает включение, нуль ? отключение. Пример:
    invincible=1
Названия читов отличаются от тех, что пишутся в F1:
invincible ? неуязвимость (liveforever)
unstoppable ? неостановимость (canttouchthis)
omnipotent ? смертельный удар (touchofdeath)
chr_big_head ? большая голова (bighead)
chr_mini_me ? мини-режим (minime, он же behemoth)

Кроме того, для режимов mini_me и big_head имеются специальные переменные для их регулирования:
    chr_big_head_amount=[множитель к размерам головы]
Множитель размеров головы по умолчанию равен 4. Нормальный размер ? 1.
Также есть и множитель к mini_me: при его увеличении игрок становится больше (как при behemoth), при уменьшении ? меньше (minime). Стандартное значение для чита minime равно 0.5. Нормальный размер, разумеется, 1:
    chr_mini_me_amount=[множитель размера игрока]
Кроме того, читы можно применять и на конкретных персонажей (как на игрока, так и на АИ). Для этого применяется строка такого вида:
    chr_[название чита] [персонаж] [0/1]
Пример:
    chr_unstoppable Muro 1
Названия читов:
invincible ? неуязвимость (liveforever)
unstoppable ? неостановимость (canttouchthis)
super ? свечение Даодана (chenille*)
ultra_mode ? ультра режим (killmequick)
boss_shield ? щит боссов (bigbadboss, chenille*)
*чит chenille включает в себя и chr_super, и chr_boss_shield

Чит slow motion (carousel) работает вообще по-другому, и пишется так:
    slowmo [время действия]
Время считается во фреймах. Например, для десяти секунд ("обычных" секунд):
    slowmo 600
Включить этот чит на бесконечное количество времени невозможно. Можно только поставить очень-очень большое время. =) например, 5000000 ? это почти сутки "нормального" времени.

2.3. Предметы и оружие

Предметы даются строчкой:
    chr_givepowerup [имя персонажа] [предмет] [количество]
или
    give_powerup [предмет] [количество] [номер персонажа]
Например:
    chr_givepowerup OutroNinja invis -1

Оружие:
    chr_giveweapon [имя персонажа] [оружие]
или
    chr_weapon [номер персонажа] [оружие]
Пример:
    chr_giveweapon MutantMuro w11_ba1

Обязательно различайте функции, требующие имена и функции, требующие номер. Если в give_powerup не указать номер персонажа, предметы будут выданы игроку.
Оружие в каждом случае можно указывать по названию (см. ONWC), либо по номеру. Но из-за неочевидной нумерации лучше обойтись названиями.
В обоих случаях с предметами, количество можно не писать: тогда оно будет принято за единицу. "Количество" фазовой маски измеряется во времени действия: по стандарту оно равно 1800 (во фреймах 30 секунд). "Количество" полного силового щита равно 100, что и является стандартом при выдаче. Если ставить для этих предметов бОльшие числа, то они будут правильно обрабатываться, однако в правом ui-элементе (где указываются гипо, щит, фазовая маска, здоровье...) будут возникать графические глюки. =) Можно указывать и отрицательные значения, тогда предметы будут "отбираться". Если и само количество предметов окажется ниже нуля, то оно будет считаться по модулю 65536. Например, (-1 mod 65536) = 65535. Но если у персонажа Наличие специального предмета (lsi) определяется булевой переменной и выдаётся единожды в количестве одной штуки.

Можно создавать предмет/оружие прямо "на земле", для предметов это строчка:
    powerup_spawn [предмет] [место]
Для оружия:
    weapon_spawn [оружие] [место]
Заспавненное таким образом оружие, если его подобрать и затем бросить, исчезает как после чита munitionfrenzy (оружие, которое не трогали, будет лежать там сколько угодно), что можно изменить строчкой:
    wp_disable_fade=[0/1]
При нуле всё останется, как было, а при единице оружие не будет исчезать. Вообще. Другой вариант ? можно повысить значение следующей переменной, она отвечает за время, по прошествии которого оружие и будет исчезать. Время указывается во фреймах. По стандарту значение этой переменной равно 360 (6 секунд):
    wp_fadetime=[время]
Названия предметов:
hypo ? гипо-спрей
ammo ? баллистическая (красная) обойма
cell ? батарейка (зелёная обойма)
shield ? силовой щит
invis ? фазовая маска
lsi - специальный предмет (блокнот, ключи и т.п.)

При количестве гипо/обойм больше шести, они не отображаются на индикаторах, но существуют "в уме". Максимальное значение для всех предметов, кроме специального, составляет 65535.

Названия оружий:
w1_tap ? пистолет Кемпбелла Mk4
w2_sap ? пистолет-пулемёт Чёрная Гадюка
w3_phr ? плазменная винтовка
w4_psm ? фазовый потоковый излучатель
w5_sbg ? шаромёт
w6_vdg ? электрошок
w7_scc ? ракетница
w8_mbo ? ртутный арбалет
w9_scr ? пушка-Крикун
w10_sni ? оружие Мукада
w11_ba1 ? пушка Барабаса
w12_ba2 ? точка-фигушка, не стреляет

Нижеследующая команда заставляет персонажа спрятать/вынуть оружие:
    chr_forceholster [персонаж] [0/1]
Где при нуле оружие вынуто, при единице ? спрятано.

Для очищения инвентаря используется команда:
    chr_inv_reset [персонаж]

2.4. Двери

Номера дверей выражаются натуральными числами, которые можно найти в оригинальных скриптах. Обычно двери в каждом уровне пронумерованы "послойно", реже ? по порядку прохождения/открытия.

Собственно, команды:
    door_open [номер двери]
и
    door_close [номер двери]
Первая строчка открывает дверь, вторая ? закрывает.
Не путать с:
    door_unlock [номер двери]
и
    door_lock [номер двери]
Где на дверь видимого воздействия нет. Первая строка позволяет как игроку, так и AI, открывать "закрытую" дверь (по приближению/кнопке "действие"), вторая ? запрещает. В игре большинство этих команд (в оригинальных скриптах ? практически всех) сопровождается зелёным-красным огоньком.
Управлять этими зелёными/красными лампочками у дверей можно и нужно независимо от дверей: можно открыть/закрыть дверь, не меняя цвета индикатора, или менять цвет, не изменяя состояния двери. А можно даже честно показывать индикатором состояние двери. Так или иначе, команда:
    particle [название индикатора] do [start/stop]
Где start ? зелёный цвет, stop ? красный.
Названия партиклей тоже ищутся вручную по оригинальным скриптам. Выглядят названия примерно так: lock[номер двери]_locklight01 (последние две цифры меняются, если есть несколько индикаторов к одной двери).

И, наконец,
    door_jam [номер двери]
и
    door_unjam [номер двери]
Первая команда ? фиксация двери. Если дверь была открытой к наступлению команды ? она и останется открытой. Аналогично с закрытой. Дверь может фиксироваться даже тогда, когда она наполовину закрыта (специально для оптимистов ? наполовину открыта ^_^). В этом случае пройти её можно лишь с помощью кувырка/подката.
Вторая, соответственно, снимает эффект этой команды.

Пример:
    door_unlock 12
    door_open 12
    sleep 120
    door_close 12
    door_lock 12
    sleep 15
    door_jam 12


Список дверей по уровням с номерами, названиями, скриншотами, изначальными положениями и названиями сопутствующих индикаторов можно взять на OniStuff.

2.5. Консоли

Когда в игре нажимается какая-либо консоль, в скрипте запускается определённая функция, везде выглядящая по-разному. Например: console200, level_4a, console_truckinfo, grifftext. К некоторым консолям, впрочем, привязано сразу несколько функций.
По нажатии на консоль она запускает функцию единожды: далее изображение на консоли превращается в иллюстрацию "белого шума".
В функции, помимо предназначенных для дебага команд dprint (и, в некоторых консолях, проверок на нажатие других консолей, etc.), встречаются следующие строчки:
    text_console [название текста]
Открывает окошко информационных консолей (выводит текст). Название текста можно искать по скрипту, либо непосредственно в ресурсах.
Название текста обычно выглядит так:
    level_[номер уровня][буква, выражающая номер, чаще всего можно видеть "a"]
Например: level_4a, level_11a, level_19e.

Эта команда (как и остальные консольные команды далее) работает не только в функции консоли, но и в любом месте скрипта ? достаточно прописать эту строчку, и (в случае с этой командой) окно с информацией появится. В любое время.
    console_reset [номер консоли]
Перезагружает консоль ? изображение ненастроенного телевизора исчезает, консолью снова можно воспользоваться. Те консоли, которые работают постоянно (информационные), всего лишь имеют в конце своей функции такую строчку.
В данной команде нужен номер консоли (число, ищется по скриптам вручную. не путать с названием консоли). Ищется он обычно легко ? достаточно посмотреть на число, стоящее после одного из оригинальных console_reset'ов. Так как в оригинальных скриптах эта команда обычно стоит в конце консольных функций, к которым она относится, это и есть искомый номер.
    console_deactivate [номер консоли]
Деактивирует консоль.
    console_activate [номер консоли]
Активирует консоль обратно.

Кроме того, в функцию консоли можно написать любые команды. ^_^
Список консолей во всех уровнях с номерами, скриншотами и вызываемыми функциями можно взять на OniStuff.

2.6. Камера

    cm_reset
Ставит камеру в надлежащее ей место за игроком и снимает все другие команды (типа интерполейта или детача). Чем чаще будет прописана эта команда (или хотя бы чем меньше будет прочих cm_ команд), тем удобней играющему.

    cm_detach
Фиксирует камеру там, где она находилась на момент запуска команды. В оригинальных скриптах обычно использовалась при смертельном падении и самой смерти (без этой команды можно было бы крутить камеру вокруг трупа или наблюдать падение во всех деталях).

    cm_distance=[число]
Задаёт дистанцию от камеры до игрока. В единицах длины. По стандарту равняется 33. Если поставить много (в районе пятисот или даже тысячи), то можно будет осматривать сразу почти весь уровень. Если выставить gl_fog_start=1 и большой gs_farclipplane_set, конечно.

    cm_height=[число]
Задаёт высоту точки, на которую ориентирована камера. По стандарту равняется 15 (уровень головы Маи). Уровень ног/пола ? 0.

    cm_canter_unarmed=[число]
    cm_canter_weapon=[число]
Задают высоту камеры относительно фокусной точки (в безоружном и вооружённом состоянии соответственно). По умолчанию без оружия 8 (камера чуть выше), с оружием 7 (обзор ближе к горизонтальному).
В случае, если камера не фиксирована относительно игрока (например, командой cm_orbit), и игрок сам может крутить головой в вертикальной плоскости, просто определяет угол наклона камеры относительно собственного горизонтального "взгляда" персонажа.

    cm_jello [0/1]
Включает/выключает режим камеры jello?. Суть режима в том, что все препятствия между камерой и наблюдаемым объектом (обычно игрок) становятся полупрозрачными. По стандарту этот режим включен, но его можно и выключить ? тогда стены будут успешно скрывать от камеры всё разворачивающееся за ними действие.

    cm_jello_amt=[число]
Задаёт уровень видимости "просвечиваемых" через jello?-режим объектов, в процентах. По стандарту равняется 20, чем больше, тем виднее мешающийся объект. 0 ? совсем не видно, зато улучшается видимость игрока.

    cm_jello_radius=[число]
Этой переменной задаётся расстояние от наблюдаемого объекта, на котором в действие вступает режим jello?. По стандарту равняется 12 (разумеется, меньше, чем cm_distance).

    cm_wait
Заставляет движок задерживаться перед дальнейшим выполнением команд, пока не закончится текущая манипуляция с камерой.

    cm_orbit [скорость] [угол]
    cm_orbit_block [скорость] [угол]
Вертит камеру вокруг имеющейся точки (обычно ? игрок) с заданной скоростью до заданного угла. скорость задаётся числом от -360 до 360, но уже после |10| верчение камеры может отрицательно сказаться на желудке. Отрицательное число вертит камеру по часовой стрелке, положительное ? против.
Угол можно не указывать (или указать -1, что является эквивалентом бесконечности), и тогда камера будет вертеться бесконечно. Если же задать его, то камера опишет с заданной скоростью лишь часть окружности, заданную этим углом. измеряется он в градусах (360 полная окружность, 180 полуокружность, 90 прямой угол, и т.п.) и отсчитывается против часовой стрелки. При указании угла больше 360 градусов, угол всё равно равен именно 360 градусам.
Команда с суффиксом _block заставит движок ожидать конца поворота, перед тем как дальше выполнять скрипт.
Важный момент: команда жёстко фиксирует вышеописанное положение камеры, в частности, не позволяя игроку самостоятельно шевелить взглядом по вертикали. Пока не наступит cm_reset.

    cm_interpolate [камера] [время]
    cm_interpolate_block [камера] [время]
За заданное время (во фреймах, обычно 60=1сек) камера перемещается в некоторую конкретно заданную статичную позицию. Позиции все заданы разработчиками и названы словесными обозначениями (например, OutroCamDisk, BomberCam00, и т.п.). Если задать достаточно большое время, то переход к этой камере будет оч.плавным. Если задать маленькое, вплоть до 0 ? порезче.
Обычно эта команда используется лишь в катсценах, хотя можно найти ей и некоторые другие применения...
Команда с суффиксом _block заставит движок ожидать конца поворота, перед тем как дальше выполнять скрипт.

    cm_anim both [фильм]
    cm_anim_block both [фильм]
Эта команда вызывает что-то вроде динамичного интерполейта. Или последовательности интерполейтов, идущих в одной совокупности. Используется обычно для красоты катсцен. За что отвечает _block, полагаю, понятно. )

2.7. Звуки

Вообще, со всеми вызываемыми звуками есть очень строгое распределение по типам (ambient, impulse, и т.п.), смотреть в OSBD.

Музыка расписана здесь. =)

    sound_music_start [музыка] [громкость]
Запускает заданную музыку с заданной громкостью. Музыка обычно обозначается тем же названием, что и системное, причём без циферков, обозначающих сэмплы. Например: mus_asianb, mus_main03_hd, atm_gr09.
Громкость обозначается числом от 0 до 1. например, 0.6.

    sound_music_volume [музыка] [громкость] [время]
Изменяет громкость играемой музыки до заданной в этой команде в течение заданного же (в секундах) времени. Если время указано и достаточно велико, то изменение будет плавным. Если равно нулю или вовсе не указано ? мгновенным.

    sound_music_stop [музыка]
Останавливает играемую музыку. За счёт деления музыки на несколько участков, остановка ведётся плавно (по завершении играемого сэмпла начинает играть сэмпл эндинга, а затем и останавливается).

    sound_dialog_play [диалог]
Проигрывает один диалоговый звук (одну реплику).

    sound_dialog_play_interrupt [звук]
Прерывает текущий звук диалога (если таковой имеется), и запускает новый также, как и обыкновенный sound_dialog_play.

    sound_dialog_play_block pause
Проигрывает несуществующие звук pause, задерживая течение скрипта вплоть до окончания проигрывания стоящей перед этой командой sound_dialog_play. Позволяет расписывать диалоги, непосредственно рассчитывая задержки относительно окончаний реплик.

    sound_impulse_play [импульс]
Проигрывает звук класса импульсов (короткие звуки, например, c04_14_02konoko).

    sound_ambient_start [амбиент] [громкость]
Проигрывает звук класса эмбиентов. Они бывают как зацикленные, так и нет. и вообще разными бывают. Но команда от этого всё равно не меняется, так что неважно... Громкость задаётся также, как и в музыке ? дробным числом от 0 до 1.

    sound_ambient_volume [амбиент] [громкость] [время]
Меняет громкость проигрываемого эмбиента за заданный промежуток времени. Плавно.

    sound_ambient_stop [амбиент]
Форсирует остановку играемого эмбиента. Обычно они, как и музыка, расписаны по сэмплам, поэтому остановка будет такой же плавной и красивой.

Также к звукам можно отнести следующую садистскую штуку:
    chr_pain [персонаж] [уровень]
Заставляет персонажа кричать от боли заданного уровня (light, medium, heavy, death).

2.8. Таймеры

Таймеры задаются и действуют предельно просто.
    timer_start [время] [функция]
Время указывается в секундах (не во фреймах!). И, собственно, через этот промежуток времени запускается заданная функция.

Используются таймеры не для обычного аналога вилочного слипа с указанием времени в правом нижнем углу экрана, а для отключаемого (по какому-либо событию) вызова функции (чаще всего ведущей к lose).

Останавливается таймер не менее простой командой:
    timer_stop
По её вызову, таймер мгновенно останавливается и отключается, не вызывая той функции.

В любой момент времени в игре может быть лишь один таймер, не больше.


Прикрепленные файлы:
Аттачмент cinematic.png, Размер: 589 байт, Скачано: 588
Аттачмент dmsgc.png, Размер: 1,991 байт, Скачано: 641

Оффлайн

 

#2 22-07-2008 11:04:50

Мih@ 
Регистрация: 27-08-2006
Сообщений: 824
Профиль

Re: Oni Scripts: FAQ-пособие

3. Персонажи

3.1. Основные команды

Каждый персонаж в игре имеет свой индекс (номер), имя и стартовое расположение. Персонажей из одного уровня нельзя переместить в другой уровень или подредактировать его вид, приёмы, реплики - во всяком случае, лишь скриптами, без редактирования ресурсов игры, что стало возможным лишь с относительно недавнего времени. По крайней мере, перенос и глобализация. =) Ныне есть АЕ, и можно об этой проблеме забыть.
Когда персонаж создаётся, он находится именно на своей стартовой позиции, которая, опять же, прописана не в скриптах, а в файле уровня (Character.BINA).
В данной главе должна довольно чётко обозначаться граница между индексом и именем персонажа. Для некоторых операций индекс более приемлем, но он зависит от порядка спавна, и, например, при нелинейном прохождении скрипта с созданием персонажей по ходу выполнения, он может оказаться разным. Едва персонаж появился, номер фиксируется за ним до самой смерти и даже на некоторое время после неё, после чего может быть занят персонажем, созданным уже после его исчезновения.
Индекс игрока (Маи) - всегда нулик (0), имя же варьируется от уровня к уровню, см. пункт 1.2.6. Имя лучше особо не использовать, а для глобальных функций это вообще противопоказано. Разве что использовать их вызов, предварительно кидая из функции конкретного уровня переменную, определяющую уровень и/или имя. Либо определить единое имя в ресурсах игры. -_- Либо пользоваться chr_name, когда оно появится.
Также у многих персонажей в ресурсах прописано название функции, которая будет вызываться при смерти этого персонажа. Иногда к ним добавляются функции, вызываемые вступлением в диалог с персонажем, нанесением ему первого урона, и т.п.
Список персонажей по уровням с указанием имени, внешнего вида, класса, команды, оружия и прочих предметов, а также всех привязанных функций можно взять на OniStuff.

3.1.1. Создание

    ai2_spawn [имя персонажа] [force]
Собственно создаёт персонажа на его стандартной стартовой позиции и со стандартными параметрами (команда, здоровье, оружие).
force позволяет спавнить одного и того же персонажа более одного раза, после чего, впрочем, могут возникнуть проблемы с дальнейшим управлением этими персонажами. Используйте с осторожностью - порой лучше обойтись командой chr_set_class, если необходимо создать иллюзию большого количестве одинаковых персонажей; и в любом случае старайтесь избегать слишком больших толп врагов, делайте упор на качество, а не количество. Больше 16 противников за раз, имхо, никогда не бывает нужно в принципе, иначе это уже моветон. Да видел, видел я свои скрипты, и rh3 тоже видел, вот потому и предостерегаю...
Также есть команда, позволяющая создать сразу всех персонажей, какие только есть на данном уровне. Кстати, ещё имейте ввиду, что на некоторых видеокартах (особенно от NVidia -_-) могут возникать критические ошибки из-за наличия слишком большого количества активных персонажей (таковыми становятся персы, находящиеся примерно в поле зрения игрока). Проблема pathfinding сетки была исправлено в последних версиях daodan'а, да и нижняя планка нвидии лежала на 32 противниках, чего уже предостаточно.

    ai2_spawnall
Страшная штука. Спавнит всех. Всех, кто перечислен в Character.BINA.

    chr_create [индекс персонажа] [start]
Создаёт тело. Тело имеет все "физические" свойства нормального персонажа, но обделено мозгом - АИ в нём отсутствует. Тела обычно используются только для различных полу катсценовых эффектов (start как раз отсылает тело на дело, для которого оно предназначено). Например, в "Региональном управлении" АИ не имеют Мукад в самом начале уровня, Мукад, тыкающий терминал во время катсцены и Мукад с ещё одним ниндзей, удирающие в самом конце. Подобных тел можно создавать сколь угодно много, пока не будут достигнуты лимиты прорисовывания и памяти. И важно не путать индексы этих тел с номерами персонажей (которые присваиваются по порядку спавна).

3.1.2. Первичная настройка

    chr_set_health [имя персонажа] [количество здоровья]
    chr_health [номер персонажа] [количество здоровья]
Даёт заданному персонажу заданное количество здоровья. Здоровье прибавляется и отнимается плавно, как при использовании гипо-спрея и при ударе, особенно сильном. Полное здоровье Маи без эффекта Даодана равно 200 единицам на среднем и сложном уровнях, и 260 на простом. Если быть точным, по умолчанию на простом уровне у игрока установлено 130% от "обычного" здоровья (а на сложном - 125% у врагов).
В принципе, количество здоровья не ограничивается никакими разумными рамками, но всё здоровье, превышающее верхнюю границу даоданавой силы, отображается как равное верхней границе, и соответствует аналогичной даодановой силе. С течением времени избыток здоровья уменьшается - с той же скоростью, что и обычный даодановый излишек.

    chr_full_health [имя персонажа]
Задаёт персонажу максимум здоровья. Команда не изменяет численное количество здоровья, которое является максимум для данного персонажа, а просто даёт ему ровно столько здоровья, сколько можно до вызова эффекта Даодана. И отображает в консоли его численное количество. Причём здесь плавность отключена: здоровье выставляется мгновенно.

    chr_changeteam [имя персонажа] [название команды]
Задаёт принадлежность персонажа к какой-либо команде. Принадлежность к командам влияет как на поведение персонажа (ИИ, за исключениям мирного люда, дерётся с "чужими", не трогает "своих" в соответствии с командными принадлежностями, а также по-разному ведёт себя с "нейтральными" персонажами), так и на сами боевые контакты ("своих" невозможно ударить).
Названия команд и их взаимоотношения строго (с точки зрения скриптов) прописаны в ресурсах, и делятся на TCTF, Syndicate, Konoko, Neutral, Switzerland (катсценовые персонажи), SyndicateAccessory (девушко в начале второго уровня и синдикатские нейтралы последнего уровня), RogueKonoko (в Лаборатории Хасегавы, порой и сама Маи), SecurityGuard (Региональное управление). Будьте внимательны: названия команд, как и всё остальное, чувствительны к регистру, написания вроде "neutral" или "Tctf" работать не будут.
Менять команду можно и самому игроку.

    chr_teleport [имя персонажа] [номер точки]
Мгновенно переносит персонажа к заданному флагу на уровне.

    chr_location [номер персонажа] [абсцисса] [ордината] [аппликата]
Мгновенно переносит персонажа в заданную координатами точку на уровне. Более точная штука, чем телепорт, но требует именно номера, а не имени.
Если Вы не имеете примерного представления о том, куда направленны оси абсцисс и аппликат (ордината всегда направлена вверх) и где находится точка отсчёта - это очень просто определить в консоли:
    where
Напишет в консоли, где Вы находитесь в данный момент, а
    chr_location 0 0 0 0
или
    goto 0 0 0
Мгновенно перенесёт в точку отсчёта. Всё дальнейшее легко расчитать и проверить опытным путём, либо можно попросту бегать (иногда с использованием примерного chr_location для экономии времени, либо с использованием обильного количества девмодовских возможностей по перемещению) по уровню между всеми нужными точками, запрашивая для них where.
Кстати, chr_location без аргументов тоже показывает текущее местоположение игрока, а при перемещении - и старую, и новую координату. Просто where более предназначена для этого, и угол поворота персонажа заодно показывает - мелочь, а приятно. )
Есть и функция, прорисовывающая отрезок, соединяющий игрока с заданной точкой:
    chr_draw_dot [абсцисса] [ордината] [аппликата]

    chr_facetoflag [персонаж] [флаг]
Поворачивает данного персонажа в направлении, на которое ориентирован данный флаг (не "поворачивает к флагу"). Возможно использование, например, сразу после телепортации, чтобы персонаж не смотрел куда попало. Перед использованием стоитт ознакомиться с направлением facing vector'а данного флага, чтобы направление не оказалось неожиданным. =)

    chr_set_class [номер персонажа] [класс]
Задаёт персонажу класс - ONCC в ресурсах, содержащий все физические данные и ссылки на них, включая модель, текстуры, набор анимаций, звуки и т.п. Имя, номер, независимые от класса свойства АИ и всё прочее остаётся прежним.

    chr_nocollision [персонаж] [0/1]
Читообразная функция, отключающая коллизии с архитектурой. Позволяет ходить сквозь стены и прочие предметы, а также ходить по воздуху. Впрочем, комфорта в этом не так уж и много: персонаж без коллизий фиксируется на своём горизонтальном уровне и не может перемещаться по вертикали. Только прыгнуть, но после этого он "зависнет" на новой горизонтальной плоскости в полёте, пока не превысит лимит "падения" и не погибнет. Коллизии с персонажами и подверженность ударам (в отличие от оружия) при этом остаётся.

    chr_enable_collision=[0/1]
Что-то вроде противоположности вышеуказанной функции. Это не функция, а переменная, отключает коллизии не при единице, а при нуле, отключает не одному персонажу, а всем сразу, и  коллизии в данном случае имеются ввиду между персонажами, можно бить и пробегать насквозь (только броски работают из-за иной механики). С архитектурой и оружием коллизии остаются.

    chr_unkillable [персонаж] [0/1]
Делает персонажа неубиваемым. Отличается от invincible тем, что здоровье отнимается без проблем, при достижении нуля возникают соответствующие смерти эффекты (вспышка, звуки, падение), но смерть совсем не фиксируется и персонаж спокойно может встать и отомстить.

    chr_weapon_immune [персонаж]
Делает персонажа неуязвимым к оружию. Необратимо.

3.1.3. Удаление

    ai2_kill [имя персонажа]
Убивает персонажа - так, как если бы он умер обыкновенной насильственной смертью - с анимацией и звуками смерти, выпадением имущества, наличием трупика и вызовом соответствующей функции.
Убитые таким (как и традиционным) способом персонажи не удаляются полностью (вернее, преодолевают стандартное разложение - постепенное удаление различных свойств, физического присутствия, и т.д.), и впоследствии их можно накачать здоровьем, поднять на ноги и анимировать всяческой скриптовой некромантией, но полноценно оживить его вряд ли получится: как АИ, так и боевые настройки после смерти улетают на небеса. >_< Проще создать персонажа заново, предварительно удалив прошлого следующей командой:

    chr_delete [персонаж]
Удаляет персонажа. Безо всяких эффектов, следов и вызова функции смерти (впрочем, chr_wait_health при удалении срабатывает). Может удалить и мёртвое тело. После удаления персонажа можно создать заново - через ai2_spawn или хотя бы chr_create.

Есть и оружие массового поражения:
    chr_kill_all_ai
Убивает всё живое, что уже заспавнилось.

Также стоит упомянуть о блокировании полного удаления:
    chr_death_lock [персонаж] [0/1]
При включенном блоке, персонаж не будет после смерти проходить все стадии разложения (вплоть до удаления), а оставит бесполезное тело со всеми вытекающими. Например, при этом не освободится его порядковый номер, что позволит более точно контролировать эту самую нумерацию.

3.2. ИИ

Для того, чтобы персонажи оправдывали расшифровку "искусственный интеллект" и не были "искусственными идиотами", существует довольно широкие возможности по контролю их поведения. Без скриптового контроля, персонаж умеет только участвовать в драке, завидев противника, либо выполнять данную ему заранее работу.

    ai2_passive [персонаж] [0/1]
При единице делает персонажа пассивным. В таком состоянии персонаж не принимает участия в драке, не встаёт, если его уронили (исключение - автоматическое поднятие, если персонаж был за областью видимости временно не обсчитывался), и не выполняет некоторые задачи - патрулирование, включение консоли тревоги, и т.п. Традиционно более распространена команда, управляющая пассивностью сразу всех персонажей:
    ai2_allpassive [0/1]
По сути, обезвреживает и останавливает всех, что незаменимо для дебага и сценок.

    ai2_active [персонаж]
Делает персонажа активным. То бишь, прорисовываемым, анимируемым, обсчитываемым движком. Обычно активность/неактивность автоматически переключается при наличии/отсутствии данного персонажа вблизи поля зрения. Обратная команда:
    ai2_inactive [персонаж]

Для фиксации персонажа в активном состоянии, чтобы он не переключился автоматически:
    chr_lock_active [персонаж]
Для расфиксации, соответственно:
    chr_unlock_active [персонаж]

    ai2_attack [персонаж_1] [персонаж_2]
Заставляет персонажа_1 атаковать персонажа_2, по возможности игнорируя всё остальное. можно таким образом заставить персонажа атаковать того, кто с ним в одной команде, но при отсутствии оружия цели достигнут лишь броски (которые у АИ работают не совсем как у людей). Не работает при пассивности агрессора.

    ai2_movetoflag [персонаж] [номер точки]
Посылает персонажа идти к заданному флагу.

    ai2_comehere [персонаж]
    ai2_followme [персонаж]
Посылают персонажа идти к точке, где стоял игрок на момент вызова этой функции. ai2_followme должна была бы регулярно уточнять текущее расположение игрока, но не делает этого из-за небольшой скосяченности. Для не самых замороченных случаев можно воспользоваться аналогом типа:
var bool follow;
func followme(string ai_name, int step)
{
    ai2_comehere(ai_name);
    sleep(step);
    if(follow) fork followme(ai_name,step);
}

Где follow=1; followme [персонаж] [период обновления координат] позволяет включить следование, а follow=0; - выключить.

При задании движения важно уточнить, как именно персонажу следует двигаться - шагом, бегом, красться, вприпрыжку или боком/задом. Для этого используется следующая команда:
    ai2_setmovementmode [персонаж] [тип движения]
Где тип движения может быть creep, walk, walk_noaim, run, run_noaim.

    ai2_lookatchar [персонаж_1] [персонаж_2]
Заставляет персонажа_1 повернуться в сторону персонажа_2. Есть её более короткий аналог, поворачивающий персонажа к игроку:
    ai2_lookatme [персонаж]

Команды ai2_lookatchar, ai2_movetoflag и ai2_setmovementmode можно применить и к самому игроку, но при одном условии - передаче контроля ИИ следующей командой:
    ai2_takecontrol [0/1]
Где 1 включает эту возможность.

    ai2_makedeaf [персонаж] [0/1]
    ai2_makeblind [персонаж] [0/1]
Глушит и слепит персонажа соответственно. глухой персонаж не реагирует на посторонние звуки (бег-прыг) вне видимости. Слепой, очевидно, ничего не видит (но может поворачиваться на звук, а в боевом настрое даже бегать за источником шума). Слепой персонаж способен драться, если его на это спровоцировать, но только пока провокатор находится в непосредственной близости от слепого: малейшее удаление ведёт к потере цели.
Есть и независимые переменные, делающие глухими/слепыми сразу всех персонажей:
    ai2_deaf=[0/1]
    ai2_blind=[0/1]

    ai2_makeignoreplayer [персонаж] [0/1]
Персонаж игнорирует игрока. Аналогично, для массового игнорирования переменная:
    ai2_ignore_player=[0/1]

    ai2_idle [персонаж]
Даёт установку бездельничать. Обычно стоит перед следующей командой:

    ai2_setjobstate [персонаж]
Назначает текущее действие персонажа его работой. Используется для сброса всего остального в idle и для фиксирования, например, следующей вещи:

    ai2_dopath [персонаж] [путь]
Заставляет персонажа следовать данному пути (обычно патрульный обход по точкам в качестве работы, либо просто пробежка в заданной последовательности).

    ai2_doalarm [персонаж] [номер консоли]
Посылает персонажа нажимать указанную консоль. Не имеет значения, "тревожная" это консоль или "обычная" (на самом деле это почтиодни и те же консоли, просто в "тревожных" функциях, скриптовых же, характерное содержание. ну, и флажок для ИИ для поиска имеется). Более того, функции консоли имеют аргумент в имени имени нажавшего (что в оригинальных скриптах не используется), что можно использовать любым образом.

    chr_animate [персонаж] [название анимации]
Всё просто - персонаж выполняет заданную анимацию. Список анимаций равен списку TRAM. при этом нет никаких ограничений, на каком уровне анимация проигрывается, и соответствует ли данному персонажу, и т.д. Единственная неприятность - при проигрывании _tgt анимаций (жертвы бросков) иногда случается блам. Если ещё не исправлено. )
Суффикс _block традиционно приостанавливает выполнение функции до завершения анимации.

Для исполнения анимаций, циклично исполняющихся в течение переменного времени, следует воспользоваться более полным вариантом:
    chr_animate [персонаж] [название анимации] [длительность]
или
    chr_animate [персонаж] [название анимации] [длительность] [фактическое время]
В первом случае анимация просто будет длиться указанное время (нецикличные анимации тоже повторяются), во втором - анимация будет замедленной, чтобы исполниться в фактическое время (оно должно быть больше или равно длительности). При этом возникают различные побочные эффекты: например, персонаж может переместиться дальше, чем следует.

4. Прочее

4.1. Применительное к игроку

4.1.1. Геймплей
    lock_keys [клавиши]
Блокирует/разблокирует определённые клавиши, используемые игроком. Блокирует при отсутствии аргументов, разблокирует следующие типы: keys_reload, keys_hypo, keys_walk, keys_inventory, keys_action, keys_pause, keys_attack, keys_crouch, keys_jump, keys_movement. Для разблокирования всего сразу - keys_all.

    input [0/1]
Выключает/включает ввод игроком. В отличие от lock_keys, блокируется заодно и реакция на движение мыши.

    chr_aim_width=[число]
Угол (в градусах) поворота камеры (и головы игрока), по достижении которого игрок поворачивается всем телом. При 0~1 повоторов головы практически нет (лишь лёгкое подрагивание при повороте), при отрицательном значении модель будет постоянно потряхивать, при достаточно большом (>180) доступен практически полный оборот камеры вокруг вертикальной оси, однако при полуобороте возникает резкий поворот в "отражение" анимации. Стандарт - 70.

    chr_auto_aim_dist=[число]
Опредяет расстояние до противника, с которого работает "самонаведение" (практически мгновенный поворот точно в сторону цели) ударов. По умолчанию 40.

    chr_auto_aim_arc=[число]
Максимальный угол (в градусах) действия вышеуказанного наведения. По умолчанию 90, что, имхо, не очень удобно. Особенно страшно замечать за собой привычку предугадывать поворот и пытаться компенсировать эту функцию.

    chr_weapon_auto_aim=[0/1]
Отвечает за самонаведение оружия. Имеется ввиду автоматическое удержание прицела на противнике на ближней дистанции, но не "подсветка" прицела, когда он наведён на что-то живое.

    wp_force_no_scale=[0/1]
    wp_force_half_scale=[0/1]
    wp_force_scale=[0/1]
Отвечают за масштабирование прицела. =) При no_scale не масштабируется вообще (кажется, что вдали прицел большой, а вблизи не очень), при scale - сильно масштабируется (оч.большой прицел вблизи), half_scale - среднее и оптимальное.

4.1.2. Не геймплей
    gs_screen_shot_reduce=[число]
Уменьшает делаемые игрой скриншоты в 2^[число] раз. И правильно делает, для полноэкранных режимов.

    fall_back
Игрок падает назад.

    fall_front
Игрок падает вперёд.

    diary_page_unlock [номер]
Выблокировывает страницу данного номера в дневнике.

    chr_focus [номер персонажа]
Передаёт игроку заданного персонажа вместо 0. Не забывайте, что при подобной рокировке нужно тщательно контролировать ai2_takecontrol: и для прошлого персонажа (в частности, для самой 0 ИИ не предусмотрено), и для нового (чтобы не остаться в его теле под его контролем... или остаться)

4.2. Сохранения

    save_game [номер сохранения]
Сохраняет игру (местоположение, здоровье, инвентарь и т.п.) в соответствующий слот. Имеем ввиду, что слотов сохранения в каждом уровне можно иметь до десяти штук, и их вполне можно сделать динамическими (самое простое - по нажатию консоли).

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

4.3. Получение констант

Переменной можно присвоить значение, возвращаемое функцией, но не наоборот. -_-
Помимо самописных функций с return, которые должны-таки работать, есть следующие встроенные функции:

    difficulty
Возвращает сложность игры (0 для простой, 1 для средней, 2 для сложной).

    did_kill_griffen (sic!)
Возвращает (из persist.dat) 1, если Гриффин был убит, 0, если нет.
Этот пункт можно вписать в persist.dat следующей командой:
    killed_griffen [0/1] (sic!)

    chr_is_player [персонаж]
Возвращает истинность того, является ли данный персонаж игроком (для баловства с chr_focus, например).

    chr_has_empty_weapon [персонаж]
Указывает на наличие у данного персонажа пустого оружия в руках (если оружие спрятано или его нет совсем, 0).

    chr_has_lsi [персонаж]
Отвечает за наличие у данного персонажа (не только 0) специального предмета (резак, ключи, и т.д.).

4.4. Ожидание.

Пока что нет возможности привязать функцию к какой-либо клавише и явно следить за какими-то очень конкретными событиями, но можно (обычно с помощью вилок) приостановить выполнение функции нижеследующими командами, дабы дальнейшее началось сразу по выполнении условия.

    chr_wait_health [персонаж] [количество здоровья]
Ждёт, пока здоровье персонажа не пересечёт заданное значение. Так как удары, падения, лечения гипами и chr_set_health работают плавно, ожидание довольно верное.

    chr_wait_animation [персонаж] [названия анимаций]
Ждёт, пока данный персонаж не начнёт выполнять данную анимацию (или любую из нескольких перечисленных). Традиционный аналог скриптового бинда и вообще интерфейса (а до появления консоли - ещё и её замена).

    chr_wait_animtype [персонаж] [типы анимаций]
Ждёт любую анимацию из целого класса (или даже нескольких классов) анимаций. Варианты: punch, kick, run, jump, flip, crouch, crouch_back, standing_turn_left, standing_turn_right, Pickup_Object, Pickup_Object_Mid, Pickup_Pistol, Pickup_Rifle, Pickup_Pistol_Mid, Pickup_Rifle_Mid, Autopistol_Recoil, reload_pistol, reload_rifle.

    wait_for_key
Ожидает нажатия чего-нибудь (что убирает начальную заставку уровня).
________________________________________________________________________________
В дальнейшем всё это будет дополняться и тем, что уже есть, но ещё не оформлено сюда, и тем, что надо просто перевести, и то, о чём будете спрашивать. -_-
На фактические ошибки, опечатки и просто спорные места указывайте, плиз. Они ведь есть, наверное, в немалом количестве...
Кинематику, катсцены, win-lose, dmsg-dprint и прочую неклассифицируемую фигню, которой хватать не будет, тоже перечисляйте. За алфавитным перечнем и на английские источники можно слазить, а тут вопрос в надобности команд... )

Огромное спасибо Амэ за огромное в составлении пособия участие. *_* И за мудрое руководство, пересилившее-таки мою лень. -_- Ну, и вообще... За всё. =)
И спасибо geyser'у за нижеоказываемую помощь и участие в составлении аналогичных англоязычных вещей.

Оффлайн

 

#3 24-07-2008 16:17:32

iljaos 
Полицейский TCTF
Откуда: Городишка под названием Асбест
Регистрация: 21-07-2008
Сообщений: 71
Профиль

Re: Oni Scripts: FAQ-пособие

Спасибо всем людям которые писали это руководство, с ним-жить легче стало!

Mix@ ты писал о команде переносящей и грока в заданную точку на уровне. А где можно найти планы уровней с нужными единицами измерения?

Отредактировал(а) Мih@ (24-07-2008 16:45:49)


Только не говорите, что у меня глаза на заднице, чего нет того нет

Оффлайн

 

#4 24-07-2008 16:56:18

Мih@ 
Регистрация: 27-08-2006
Сообщений: 824
Профиль

Re: Oni Scripts: FAQ-пособие

iljaos, во-первых, в последний раз прощаю даблпостинг. В следующий раз буду стирать, не читая.
Во-вторых, подобные вопросы следует задавать в соответствующую тему, или хотя бы создавать новую, с перечислением претензий по недоработкам пособия, которых тут пока что предостаточно, но писаться дополнения будут в единую статью, а не рассредотачиваться по длинной теме, которых уже накопилось несколько штук.
В-третьих, планы уровней есть только в ресурсах игры.
Как описать векторы отсчёта на словах, или даже со скриншотом, без путаницы (а ведь уровни большие), я плохо себе представляю.
Сейчас допишу под chr_location простейший метод определения координат.

Оффлайн

 

#5 26-07-2008 09:44:04

geyser (муж.)
Учёный Синдиката
Откуда: угадайте
Регистрация: 25-06-2007
Сообщений: 1352
Профиль  Вебсайт

Re: Oni Scripts: FAQ-пособие

1.2.1
Mih@: "Скриптовые команды"
geyser: Фактически эти "команды" являются не чем иным, как вызовами функций (см. ниже). Слово "команда" я не люблю.
Mih@: chr_givepowerup [персонаж] [предмет] [количество]
geyser: Я бы и здесь ввёл понятие о типе параметров, то бишь: chr_givepowerup [string:персонаж] [string:предмет] [int:количество] / chr_givepowerup [int:script_ID] [string:предмет] [int:количество]
Mih@: "Собственно, принципиальной разницы я не вижу, но предпочитаю более традиционное написание - без скобок и с переносом строки в качестве разделяющего символа."
geyser: "Традиционный" синтаксис, он же "шелловый", не позволяет использовать в качестве параметра переменную.А это бывает нужно даже в Банькиных скриптах, не то, что в ОТА.

Остальное потом, по порядочку. Есть неточности, грубых ошибок пока не заметил.


Если у тебя есть фонтан, заткни его; дай отдохнуть и фонтану.

Оффлайн

 

#6 26-07-2008 11:45:02

Мih@ 
Регистрация: 27-08-2006
Сообщений: 824
Профиль

Re: Oni Scripts: FAQ-пособие

geyser написал(а):

Слово "команда" я не люблю.

geyser написал(а):

тип параметров

Угу, это всё поправлю и дополню потихоньку.
Насколько я помню, например, sleep ведь относится к синтаксису и ключевым словам, а не к прочим "функциям"? Его "командой" можно обозвать? ) А то более подходящего слова не вижу... Как и ко всем "внутренним" функциям, которые хотелось отделить от тех функций, которые собственно и задаются в скриптах. Может, это не совсем правильно (но, имхо, и не совсем неправильно), да и вшитые функции можно переписывать в скриптах... Но, возможно, стоит просто уточнить в начале, что именно в контексте подразумевается под "командой", "строкой" и т.п.?

geyser написал(а):

"Традиционный" синтаксис, он же "шелловый", не позволяет использовать в качестве параметра переменную.

А вот это вот действительно забыл написать. О_о Хоть и собирался... Пасиба.

geyser написал(а):

Есть неточности, грубых ошибок пока не заметил.

И на том хорошо. +) Относительно... Дальше по ходу дела дописывать-исправлять буду...

Оффлайн

 

#7 26-07-2008 12:57:36

geyser (муж.)
Учёный Синдиката
Откуда: угадайте
Регистрация: 25-06-2007
Сообщений: 1352
Профиль  Вебсайт

Re: Oni Scripts: FAQ-пособие

sleep - единственное из ключевых слов, которое тянет на "команду" т.к. по употреблению похож на вызов функции.. У остальных - очень специфическое употребление, мало чего общего имеющее с "приказом". А поскольку оно одно такое, то не вижу причины использовать слово "команда" вообще. А ssg - вообще неправ.
Функции, предопределённые в движке, мало чем отличаются от пользовательских. Главное отличие - в движке разрешено некое подобие "перегрузки", т.е., тот же chr_givepowerup первым параметром может брать строку или целое число, и ведёт себя в обоих случаях по-разному. Пользователь такую функцию определить не может (а в C это равносильно определению двух одноимённых функций, что BSL опять же не позволяет). Плюс некоторые глюки в самом BSL, из-за чего пользовательские функции могут работать не совсем как надо (есть глюки с else, с return, и с обработкой строк - входных параметров функции). А так я бы не различал предопределённые функции и пользовательские. Философия вызовов, передачи параметров и т.п. для них для всех общая.

2.7
амбиент/музыка/диалог/импульс вызывается по имени OSBDkukareku.amb (амбиент/музыка/диалог) OSBDkukareku.imp (импульс)
Музыка и амбиент ничем не отличаются, кроме того, что у них разные регистры, поэтому если стартануть музыку как sound_ambient_start mus_fitec, то её и стопать надо как sound_ambient_stop mus_fitec
Диалог отличается от музыки и амбиента главным образом тем, что его нельзя "стоп". Общее у этих трёх то, что звук не локализован (то есть это всё по сути "амбиент").

Кстати о "стопе", вот пример "грубой неточности":

А тут еще кот выскочил к рампе и вдруг рявкнул на весь театр человеческим голосом:
? Сеанс окончен! Маэстро! Урежьте марш!!
Ополоумевший дирижер, не отдавая себе отчета в том, что делает, взмахнул палочкой, и оркестр не заиграл, и даже не грянул, и даже не хватил, а именно, по омерзительному выражению кота, урезал какой-то невероятный, ни на что не похожий по развязности своей марш.

Как видно в контексте, "урезать" (т.е. "врезать") - значит вовсе не оборвать на полуноте, а наоборот - "грянуть".

"Проигрывает некоторый блок реплик из диалога. Честно говоря, ни разу не видел блоков, кроме pause. =)"
Ни фига. Никаких "блоков". "pause" - это просто название диалогового звука, которого нет. Или разрабы лоханулись, или просто считали, что несуществующий звук писать лучше, чем никакого звука вообще. Короче, вызов sound_dialog_play kukareku откладывает воспроизведение диалогового звука kukareku до окончания текущего диалогового звука, только и всего.


1.2.4.
"Численные переменные ? любые числа, включая дробные (в меру: для очень дробных лучше использовать переменные с плавающей точкой) и отрицательные."
Ой. Мих, ты чё? Если твои "численные" - это инты, то какие на фиг умеренные дробные? Целые числа и ничего кроме. Причём чаще всего неотрицательные целые.


Если у тебя есть фонтан, заткни его; дай отдохнуть и фонтану.

Оффлайн

 

#8 26-07-2008 13:38:21

Мih@ 
Регистрация: 27-08-2006
Сообщений: 824
Профиль

Re: Oni Scripts: FAQ-пособие

geyser написал(а):

Функции

Ну, с точки зрения представления в скрипте, строка ≈ команда ≈ вызов функции. А вызов функции и сама функция - вещи уже разной природы.
То бишь, имхо, про функции можно написать, например, так:
Функция
func void you_lose(string ai_name)
{
    sleep 240
    fade_out 0 0 0 180
    sleep 240
    lose
}

отвечает за эффект затухания экрана и проигрыш уровня.
А про вызов функции, соответственно, уже иначе:
Строка
    you_lose
отвечает за [то же самое].

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

geyser написал(а):

Музыка и амбиент ничем не отличаются, кроме того, что у них разные регистры, поэтому если стартануть музыку как sound_ambient_start mus_fitec, то её и стопать надо как sound_ambient_stop mus_fitec

Угу. А какого-нить списка в сети о том, что .imp, что .amb, нету? Или просто отправлять всех читать OSBD в ресурсах?..

geyser написал(а):

Кстати о "стопе", вот пример "грубой неточности"

Угу. )

geyser написал(а):

Ни фига. Никаких "блоков".

Угу. Хотя не совсем угу. _block ведь вроде должен тормозить выполнение всего, что после этой строки? А не только диалоговых функций?

geyser написал(а):

Ой. Мих, ты чё?

Воистину ой. А ещё там про float вообще ни слова не было изначально. )) Щас пофиксю всю эту ересь...

Оффлайн

 

#9 26-07-2008 15:08:47

geyser (муж.)
Учёный Синдиката
Откуда: угадайте
Регистрация: 25-06-2007
Сообщений: 1352
Профиль  Вебсайт

Re: Oni Scripts: FAQ-пособие

Слово "строка" я тоже не люблю, т.к. из-за него у народа путаница между "строчками" кода и значениями типа string. Советую употреблять слова "инструкция" (statement) и "выражение" (expression) для базовых элементов кода.
Слово "инструкция" - по сути та же "команда", но под это понятие подпадают и сложные инструкции (фигурные скобки), и условные инструкции (if ... else), и декларации/определения переменных/функций, и присвоения переменных, и вызовы функций.
"выражение" - слово менее общее. Это нечто, имеющее значение. У присвоения значение как бы есть, и у вызова функции - тоже, а вот у сложной инструкции, или у определения - скорее нет.

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

"А какого-нить списка в сети о том, что .imp, что .amb, нету? Или просто отправлять всех читать OSBD в ресурсах?"
1007 *.amb, 298 *.imp ... Дамп имён всей этой толпы нисколько не удобнее читать, чем просто перечень .oni-файлов в Windows Explorer или Total Commander... особенно если грамотно рассовать звуки по папочкам и подпапочкам. OniSplit позволяет. Всем рекомендую. Музыку продокументировал здесь, когда был маленький и глупый: http://wiki.oni2.net/Music/Ingame

"_block ведь вроде должен тормозить выполнение всего, что после этой строки? А не только диалоговых функций?"
Тормозит-то он тормозит, но именно что "блокирует" данную инструкцию (и естественно всё, что после неё - это просто последовательное выполнение BSL), а "блок инструкций" здесь ни при чём.


Если у тебя есть фонтан, заткни его; дай отдохнуть и фонтану.

Оффлайн

 

#10 26-07-2008 15:49:34

Мih@ 
Регистрация: 27-08-2006
Сообщений: 824
Профиль

Re: Oni Scripts: FAQ-пособие

geyser написал(а):

Советую употреблять слова "инструкция" (statement) и "выражение" (expression) для базовых элементов кода.

Ок.

geyser написал(а):

Вызов функции - он вызов функции и есть. Ничего неловкого, всё строго и справедливо. Есть функция, и мы её вызываем.

Говоря строго и справедливо, вызов - это вообще скорее процесс. Есть набор символов в скрипте, который инициирует (ну, вернее, заставляет инициировать того, кто этот набор символов исполняет) вызов функции. Есть функция, которая вызывается тем набором символов. А сам вызов - это нечто между ними, или то, во что они входят. Инструкция > вызов > функция. Инструкция пишется в консоль, функция вызывается, а сам вызов - это нажатие ентера и последующие процессы. Либо инструкция пишется в .bsl файл и мирно дожидается своей минуты, а вызов происходит, когда скриптовый движок эту инструкцию читает и выполняет. Обозвать кучу буковок вызовом у меня как-то в принципе язык не поворачивается... Только то, что эта куча буковок делает при своём исполнении. Как-то так.

geyser написал(а):

Дамп имён всей этой толпы нисколько не удобнее читать, чем просто перечень .oni-файлов в Windows Explorer или Total Commander...

Зато, может, чуть удобнее, чем по dir | more... Проблема устарела уже, это во времена IRF_Oni в куче SNDD было почти невозможно ориентироваться...  Да и сейчас, имхо, закономернее и логичнее будет текстовый список читать, нежели только ради этого списка вываливать кучу мусора в какую-нить директорию и затем постоянно к ней обращаться. Файлы ж всё равно никуда не денутся. По крайней мере, из более-менее оригинальных ресурсов...

geyser написал(а):

http://wiki.oni2.net/Music/Ingame

Угу, заодно ссылку сюда вставлю эту... )

geyser написал(а):

"блок инструкций" здесь ни при чём.

Я в курсе, только проникся смыслом всех _block'ов немножко позже, чем написал единственную пришедшую в голову догадку относительно этого суффикса, так как ни chr_animate_block, ни cm_[...]_block особо не пользовался, отдавая всё всемогущему sleep'у. А при вызове отдельной инструкции из консоли разницы с и без _block как бы и нету... При переписывании в cm_ эти блоки поправил, а вот диалог проглядел почему-то...

Оффлайн

 

#11 26-07-2008 16:47:09

geyser (муж.)
Учёный Синдиката
Откуда: угадайте
Регистрация: 25-06-2007
Сообщений: 1352
Профиль  Вебсайт

Re: Oni Scripts: FAQ-пособие

"вызов - это вообще скорее процесс" Тоже мне философ нашёлся...  Все програмисты называют такой вид инструкции вызовом (call), и ничего, никакой путаницы. Если ты отвлечёшься от BSL или C и глянешь в машинный код, то там ты может и по-другому заговоришь: там вызовы имеют свою трактовку, на другом уровне. Но в рамках языка BSL:  dmsg("пусть меня покрасят") есть не что иное, как инструкция - вызов функции dmsg с параметром/аргументом - строкой "пусть меня покрасят".

"Да и сейчас, имхо, закономернее и логичнее будет текстовый список читать, нежели только ради этого списка вываливать кучу мусора в какую-нить директорию и затем постоянно к ней обращаться."
Всё равно не понимаю. Есть OniSplit. Он разворачивает ресурсы так, что OSBD аккуратно лежат рядышком, причём их можно аккуратно разложить по папочкам: музыку туда, диалоги сюда, шаги ещё куда-нибудь, шумы всякие... При паковке OniSplit это всё съест и не поморщится, а у пользователя возникает удобная классификация этих самых звуков. Люди смотрят на такую директорию, и сразу видят, какие бывают OSBD. Если они хотят копнуть поглубже - открывают OSBD в редакторе или через OniBrowser и сразу имеют инфу о том, с чем данный OSBD едят.
Кому будет лучше от того, что я всё это высеку на мраморе? Не лучше ли просматривать директории или использовать OniBrowser, и иметь реальную информацию о текущем ассортименте OSBD?

"Файлы ж всё равно никуда не денутся. По крайней мере, из более-менее оригинальных ресурсов..."
Я бы на это не сильно рассчитывал. Мне в последнее время влом документировать "каноническое" содержание Они (всякие вот эти списки), потому что при мало-мальски мотивированных моддерах это всё станет давно и неправда (да уже неправда, посмотреть хоть на самые базовые фиксы в Эдишне). А обслуживать леймеров, которые будут в своём углу моддить исходную версию - не вижу причины =)


Если у тебя есть фонтан, заткни его; дай отдохнуть и фонтану.

Оффлайн

 

#12 26-07-2008 17:24:28

Мih@ 
Регистрация: 27-08-2006
Сообщений: 824
Профиль

Re: Oni Scripts: FAQ-пособие

geyser написал(а):

Тоже мне философ нашёлся...  Все програмисты называют такой вид инструкции вызовом (call), и ничего, никакой путаницы.

Ну, значит, вызов как процесс есть calling от statement'а к function'у, и call ≠ statement. Иначе выходит, что сам вызов и вызывает вызываемое. @_@ Не инструкция есть вызов, а инструкция означает, подразумевает, характеризует вызов. В машинном коде, может, это и одно и то же, но ведь речь-то о bsl. ) Впрочем, ладно, уболтал, вызов так вызов, всё равно команды теперь будут называться инструкциями. )

Про OSBD - тоже угу. Примерно поэтому же и пособие это волочилось еле-еле и едва ли не завяло в начале, что возник вопрос - а зачем вообще расписывать обыкновенные скрипты, функции и особенности наряду с наиболее приближёнными частями оригинальных ресурсов, если всё это скоро начнёт мутировать от гораздо более глубоких модификаций? Когда будут новые оружия и противники, когда почти все ресурсы станут доступны из любого уровня, кинематических мордашек станет в пять раз больше, появятся два новых кавайных цвета для dmsg, новые виды предметов, новые уровни, новые скриптовые функции, наконец, новый движок и новый вид скриптов, например, на том же lua? С одним только девмодом львиная доля скриптовых ухищрений стала выполняться в два счёта прямо из игры, если не нажатием одной-двух хоткеев. Не говоря уж о всплывающих подсказках и консольной ругани, по которой можно заиметь представление о немалой части функций... Другое дело, что в крайности впадать не следует, раз пока что хотя бы часть из этого кому-нибудь да понадобится... )

Оффлайн

 

#13 26-07-2008 17:47:54

geyser (муж.)
Учёный Синдиката
Откуда: угадайте
Регистрация: 25-06-2007
Сообщений: 1352
Профиль  Вебсайт

Re: Oni Scripts: FAQ-пособие

"Ну, значит, вызов как процесс есть calling от statement'а к function'у, и call ≠ statement." Нда, неглупый малый, но педант.
Вызов есть частный случай инструкции, наряду с: определением, присвоением, блоком {}, sleep-ом, if-ом, return-ом...

"С одним только девмодом львиная доля скриптовых ухищрений стала выполняться в два счёта прямо из игры" Именно поэтому я рекомендую преподавать BSL в первую очередь на примере консольного ввода. Уж зашитые-то функции с консоли вызывать - самое милое дело... Всё можно наглядно так объяснить.

"а зачем вообще расписывать обыкновенные скрипты, функции и особенности наряду с наиболее приближёнными частями оригинальных ресурсов, если всё это скоро начнёт мутировать от гораздо более глубоких модификаций?"

Это не совсем одно и то же. BSL - вещь мощная и как язык гораздо более элементарная и неизменная чем коллекция данных - ресурсов. Если ресурсы вроде OBJC подлежат массовому апгрейду, который лишает смысла дотошную документацию - то BSL уже сейчас практически достаточен для Эдишна. Не хватает марафета для сингл-плеера, ну и кое-каких вкусностей для арены. А так всё есть, и конечно же никто не собирается на фиг переопределять или отменять знакомые ключевые слова или функции. Вот так вот... даже совсем не одно и то же.


Если у тебя есть фонтан, заткни его; дай отдохнуть и фонтану.

Оффлайн

 

#14 26-07-2008 18:11:20

Мih@ 
Регистрация: 27-08-2006
Сообщений: 824
Профиль

Re: Oni Scripts: FAQ-пособие

geyser написал(а):

Вызов есть частный случай инструкции

Что он есть частный случай, само собой, вопрос был в том, сама ли это инструкция, или то, что она делает, за что отвечает и для чего вообще нужна. Т.е. не инструкция-вызов, инструкция-присвоение, инструкция-возврат, а инструкции вызова, присвоения и возврата. Ладно, не надо берданку, я понял уже всё. %)

geyser написал(а):

Именно поэтому я рекомендую преподавать BSL в первую очередь на примере консольного ввода.

А в таком случае не теряется большая часть смысла скриптов?.. Ну, то есть, это уже получается пособие к консоли, а для скриптов, напротив, надо будет упор сделать на том, что можно и нужно делать только ими, используя консоль максимум как дебаггер с dprint'ами и руганью об ошибках, или как инициатор каких-нибудь функций, без извращений с chr_wait_anim*...

geyser написал(а):

BSL уже сейчас практически достаточен для Эдишна.

Хм, ну раз он ещё таким долго будет, то хорошо. о_О Значит, есть в этом какой-то смысл. ) И даже немалый... О_о

Оффлайн

 

#15 26-07-2008 21:11:18

geyser (муж.)
Учёный Синдиката
Откуда: угадайте
Регистрация: 25-06-2007
Сообщений: 1352
Профиль  Вебсайт

Re: Oni Scripts: FAQ-пособие

Смысл консольного скриптинга в том, чтобы быстро и непринуждённо прочувствовать, как конкретно работают ключевые функции. Сложные конструкции, конечно, никто с консоли вбивать не будет (хотя заскриптить заготовку и вызывать с консоли - тоже вполне педагогический ход). Главное - чтобы у народа было как можно меньше мистики по поводу эффекта той или иной функции/переменной. Чтоб параметрами владели свободно. С каждой функцией на ты. А это как раз очень естественно достигается путём консольного скриптинга.

@ вызов: :"неглупый малый, но..." Говорю же тебе - между вызовом-процессом и вызовом-инструкцией никогда не было никакой путаницы. Потому, что говорить об абстрактном "процессе вызова" редко кому приходится - и наоборот, синтаксическое понятие вызова как структуры языка - точно определено и широко употребляемо. Если уж на то пошло, то Онька первым делом убирает из скрипта все комменты, табы, энтеры и пробелы, кое-что разворачивает, кое-что подставляет... Мы же не будем и для этой промежуточной стадии отдельную терминологию придумывать? правильно - в гробу мы её видали... Поскольку всё тождественно, какая разница: имеем мы дело с "процессом вызова" или его причиной/отображением в скрипте? есть ведь разница? правильно - если мы глядим в скрипт и соответственно имеем дело с человекочитабельными буковками, то нам естественно всю жизнь движка описывать в рамках этого самого языка из буковок, а не каких-то там последствий, которыми эти буковки чреваты, т.е., не выходить за рамки нашего главного инструмента - языка. И поэтому мы будем называть вызовом функции соответствующую инструкцию в текстовом файле, а не соответствующее движение сфер в рантайме. Рантаймовые мистерии - не скриптерого ума дело, и не хрен мозги сушить.


Если у тебя есть фонтан, заткни его; дай отдохнуть и фонтану.

Оффлайн

 

#16 25-08-2008 22:33:52

demos_kratos (муж.)
Рядовой чатланин
Откуда: Волжский
Регистрация: 25-07-2008
Сообщений: 694
Профиль  Вебсайт

Re: Oni Scripts: FAQ-пособие

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


I would put a tax... on all people... who stand... in water.
........
OOH!

Оффлайн

 

#17 26-08-2008 05:30:04

Мih@ 
Регистрация: 27-08-2006
Сообщений: 824
Профиль

Re: Oni Scripts: FAQ-пособие

demos_kratos написал(а):

насколько я понимаю, всё, что здесь обозвано "командами" - не что иное, как процедуры, а вот функции, возвращающие какое либо значение в игре есть?

В bsl (как и много где ещё) принципиальных отличий между функциями, которые что-то возвращают, имеют аргументы и пр. от void нету. В синтаксисе самих функций. Так, на всякий случай. )
Возврат значений существует, конечно, но особого в нём смысла я не вижу, ибо безжалостен к памяти и не брезгую создавать временные переменные (кто видел rh3, тот особенно хорошо поймёт, гы-гы). Но, если хочется шибко красивого кода, то вполне возможна строчка вида:
    [переменная] = [функция]([аргументы]);
С тем, как и чего именно происходит возврат, я пока толком не разбирался, экспериментальные наблюдения (в функции, значение которой присваивалось переменная, только три операции присвоения из трёх обычных переменных, включая искомую, и одной внутренней) таковы:
1) на выход идёт значение от последнего присвоения (var1 = var2 + 56 => var1, он же (var2 + 56), на выход).
2) если есть return(varx);, то на выход идёт varx, а функция дальше return'а не едет.
3) если есть просто return без аргументов, то его как бы и нет (функция едет до конца, выход по пункту 1).
Из возвращалок в игре мне казалось, например, что did_kill_griffen - не константа read-only, а bool-функция...

Оффлайн

 

#18 26-08-2008 23:51:32

geyser (муж.)
Учёный Синдиката
Откуда: угадайте
Регистрация: 25-06-2007
Сообщений: 1352
Профиль  Вебсайт

Re: Oni Scripts: FAQ-пособие

Если мне не изменяет безжалостно затраханная Михой память,
движок определяет только 5 "функций" (в паскалевом смысле):

bool did_kill_griffen()
bool chr_has_lsi()
bool chr_is_player()
bool chr_has_empty_weapon()
int difficulty()

Остальные влияют на состояние игры либо выводят что-то на печать.
Как видишь, demos_kratos, раздолье весьма умеренное... Се ля ви.

Кроме того, ключевое слово return принадлежит к больным местам BSL.
Целые числа возвращать получается, а вот строки - скорее как бы нет.
Другое больное место - else, а также парсинг строк в условиях для if.


Если у тебя есть фонтан, заткни его; дай отдохнуть и фонтану.

Оффлайн

 

#19 12-01-2009 16:16:52

iljaos 
Полицейский TCTF
Откуда: Городишка под названием Асбест
Регистрация: 21-07-2008
Сообщений: 71
Профиль

Re: Oni Scripts: FAQ-пособие

Извините конечно, что поднимаю старую тему но в пособии написано "В принципе, количество здоровья не ограничивается никакими разумными рамками, но всё здоровье, превышающее верхнюю границу даоданавой силы, отображается как равное верхней границе, и соответствует аналогичной даодановой силе.

"В принципе, количество здоровья не ограничивается никакими разумными рамками". Это так но у меня больше 1 и 31 нуля, поставить нельзя. Коноко просто умрёт. Может это у меня одного так, но наверняка нет. Я вводил chr_set_health 0 1 и при постановке тридцати двух нулей, игра заканчивалась смертью. Будьте бдительны!!


Только не говорите, что у меня глаза на заднице, чего нет того нет

Оффлайн

 

#20 12-01-2009 16:25:09

awp_master.pro^no clear* (муж.)
Полицейский TCTF
Откуда: питер
Регистрация: 21-12-2008
Сообщений: 98
Профиль

Re: Oni Scripts: FAQ-пособие

погоди,но ведь я думаю никому не нужно ставить 32 нуля,это глупо,легче ввести liveforever.А то что тебя не ограничивают,так это правда,ставь какие угодно числа,но команда ведь работает


шоу начинается!

Оффлайн

 

Board footer

© 2006-2018 Амэ & Mih@
ОНИмия – фан-сайт игры Oni
Движок форума - модифицированный PunBB

[генерация скрипта: 0.033 с.] [запросов к БД: 28]