» TeamX (Архив Форума)«


Форум TeamX » Исследования » Делимся опытом (Наследие "Техподдержки")

Переход по темам
<< Пред. След. >>
Страницы этой темы [ 1 2 3 ] Все собщения

 
Raven
Пользователь

Откуда: Владик
Регистрация: Февр. 2004

Всего: 408 сообщений

>>мне вдруг тоже чертовски интересны стали последние разработки в области диалогов.

Ну, в диалогах, не в диалогах. Но наработки есть. Сегодня расскажу про одну (и постараюсь делать это более-менее регулярно). Начнём с мелочей.

ВНИМАНИЕ! Всё, о чём я (пока) буду говорить - это техническая сторона скриптинга.

Говорить будем про msg-файлы. Что это такое? Пронумерованный (необязательно последовательно) список строк. Имя должно совпадать с одним из имён существующих скриптов. Номер совпадает с номером одноимённого скрипта.

Для работы с msg-фйалом с помощью стандартных макросов необходимо определить дефайн NAME:
#define NAME номер_скрипта

После этого mstr(xxx) вернёт строку xxx.

Задача 1.

Недостаток: привязка скрипта к какому-то там номеру. Если вы поменяете положение скрипта в scripts.lst (а номер строки, где прописан скрипт и есть номер скрипта), то скрипт перестаёт работать - т.к. не находит свою msg-шку.

Решение: устранить привязку. Делаем это следующим образом. В msg на фиксированной строчке заводим определённую запись. Например, у нас есть персонаж по имени Сайег (имя из прототипа):
------------------------
{1000}{}{Сайег}
------------------------

Пишем код:
------------------------
#define LIMIT 2000 //на каком номере остановиться
variable msg_num; //глобальная вара, в которую пойдёт номер найденой msg-шки
<...>
variable i:=1300; //ищем только в своих msg-шках, игровые не трогаем
while message_str(i,1000)!=obj_name(self_obj) and i<LIMIT do i+=1;
if i==LIMIT then display_msg("ERROR: msg not found.");
else msg_num:=i;
<...>
------------------------

Всё это легко запихивается в макрос - и вуаля!

Задача 2:

Мы хотим сделать набор флоатеров для персонажа, так чтобы он выбирал и говорил случайную строку из некоторого диапазона номеров в msg-файле. Но! Мы хотим, чтобы диапазон изменялся динамически - т.е. если в msg-шке у нас 15 реплик, то он выбирал 1 из 15; 20 - 1 из 20.

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

Решение:
Заводим такой вот msg:
------------------------
<...> //номера произвольны, главное - последовательны
{231}{}{BEGIN REPLICS}
{232}{}{Привет}
{233}{}{Хай}
{234}{}{Как дела?}
<...>
{240}{}{END REPLICS}
<...>
------------------------

Код:
------------------------
#define LIMIT 5000 //сколько строк обрабатывать

//msg_num - номер нашей msg-шки, найденный заранее

<...>
variable i:=1;
variable first; //номер строки с первой репликой
variable last; //с последней

while message_str(msg_num,i)!="BEGIN REPLICS" and i<LIMIT do i+=1;
if i==LIMIT then display_msg("ERROR: replics list not found");
else start:=i+1;

//Начинаем искать от строки first
//Ищем либо закрывающий "тэг", либо первую пустую строку
while message_str(msg_num,i)!="END REPLICS" or message_str(msg_num,i)!="Error" do i+=1;
last:=i-1; //проверки на ошибку не делаем, т.к. список не может быть бесконечным, пустая строка всегда найдётся
//Закрывающий тэг нужен "для себя", как комментарий

floater(random(first,last));
<...>
------------------------

Тормозов никаких нет, всё работает довольно шустро. Но ОБЯЗАТЕЛЬНО вводите ограничители! Бесконечный цикл подвешивает игру.

Ладно, на сегодня хватит. Следущий постинг будет взаимодействие объектов, наверное.

Отзывы?

И, да - не стесняётесь постить свои мысли/наработки.

Отправлено: 11:41 - 24 Ноября, 2004
Mynah
Модератор

Откуда: Пермь
Регистрация: Окт. 2004

Всего: 469 сообщений

Цитата:

Тормозов никаких нет, всё работает довольно шустро.


А если таких скриптов 15-20? Тоже всё ок?

С устранением привязки - рулез :)

-----
Scio me nihil scire

Отправлено: 12:52 - 24 Ноября, 2004
Raven
Пользователь

Откуда: Владик
Регистрация: Февр. 2004

Всего: 408 сообщений

На Йцукеновском Cel 1700 всё нормально (по его словам) на схожем скрипте. На моём Athlon XP 3000+ - тоже :-) На моём бывшем 166... Не должно, по идее.

Это всё выполняется один раз, в map_enter. А msg-шку можно и в LVARу запомнить, если что.

Отправлено: 13:01 - 24 Ноября, 2004
Mynah
Модератор

Откуда: Пермь
Регистрация: Окт. 2004

Всего: 469 сообщений

Если кому-то интересно - могу выложить свои наработки. В частности obj_hear_obj и obj_see_obj.

Мои функции вроде бы работают не так глючно как бисовские :)

-----
Scio me nihil scire

Отправлено: 4:20 - 26 Ноября, 2004
Raven
Пользователь

Откуда: Владик
Регистрация: Февр. 2004

Всего: 408 сообщений

>>Если кому-то интересно...

Для того эта тема и создана. Выкладывайте все, без всякого "если кому-то надо". Надо.

P.S. Егор планирует отдельный форум для таких вещей.

Отправлено: 4:37 - 26 Ноября, 2004
Alan Killenger
Пользователь

Откуда: Россия, Ижевск
Регистрация: Июль 2004

Всего: 404 сообщения

Даже не знаю, прав ли я.. или опять глючу :).

----------
procedure set_script_number begin
 variable V_index;
 V_index:=C_identify_start;
 while not(V_index>C_identify_end) do begin
   if message_str(V_index,C_identify)==obj_name(self_obj) then begin
     set_local_var(LV_script,V_index);
     V_index:=C_identify_end+1;
   end else begin
     V_index:=V_index+1;
   end
 end
 if local_var(LV_script)==0 then begin
   display_msg("Error: *.msg file not found for "+obj_name(self_obj)+".");
 end else begin
   display_msg("Соответствующий номер найден: "+local_var(LV_script)+".");
 end
end
----------

Искомого *.msg файла заранее не существует.

Эксперимент #1:
----------
 #define C_identify 0
 #define C_identify_start 1000
 #define C_identify_end 1300
----------
Результат: после одной-двух секунд раздумий, появляется надпись: "Error: *.msg file not found for Алан."

Эксперимент #2:
----------
 #define C_identify 0
 #define C_identify_start 1000
 #define C_identify_end 1400
----------
Результат: после одной-двух секунд раздумий, Fallout (как и маппер) вылетает с надписью: ".. память не может быть read."

Догадываетесь, чего не позволяет нам делать коварная win2k? Объясните, кто догадался :).

(Отредактировал(а) Raven - 17:01 - 25 Янв., 2005)

Отправлено: 2:39 - 27 Ноября, 2004
Raven
Пользователь

Откуда: Владик
Регистрация: Февр. 2004

Всего: 408 сообщений

Посмотри вот это:
if message_str(V_index,C_identify)

И вот это:
#define C_identify 0

Понял, нет? Ты пытаешся читать нулевые строчки в мсг-шках. А строчки там нумеруются от единицы. Понимаешь? Естественно, Фол может вылететь - ведь непонятно в какую область памяти ты лезешь с такими запросами.

Вторая потенциальная трабла (вызывающая тормоза :-) - диапазон (1000-1300). Строчки 1-1304 заняты под оригинальные скрипты Фола, поэтом искать в них *свою* мскг-шку бессмысленно. В идеале диапазон должен быть: строчка с первым добавленным тобою скриптом (1305) - последняя строчка в scripts.lst + небольшой запас.

>>Догадываетесь, чего не позволяет нам делать коварная win2k? Объясните, кто догадался.

Так это - загадка, типа, была - если так, то хорошо :-)

P.S. Всю процедуру перебора проще записать так:
-------------------------------------------
#define LIM 1500
#define search(line,what) while not message_str(i,line)!=what and i<LIM do i+=1; \
                         if i==LIM then display_mg(what + " not found")
<...>
variable i:=1300;
search(1,obj_name(self_obj));
set_local_var(0,i);
<...>
-------------------------------------------


(Добавление от 5:03 - 27 Ноября, 2004.)


Наработка номер 2.

Проблема:

Есть generic-скрипт, определяющий поведение многих объектов сразу (НПС-крестьян в моём случае).

Нужно выдавать каждой копии скрипта уникальное имя из списка, чтобы все эти крестьяне были не так безлики. Трабла в том, что так как они являются копиями одного и того же скрипта, то и совпадает у них практически всё - и SID, и имя/описание из scrname.msg, и реакция на talk/description, и данные прототипа...

Как быть?

Отступление:

Полагаю, все знают про импорт/экспорт переменных. Так вот, стандартный метод - это миф. Это недопонимание принципов работы БИСовскими скриптерамИ, перенесённое сюда.

Итак, как работает импорт/экспорт. Любая переменная, объявленная как export попадает в некоторый общий namespace - из какого бы скрипта она не экспортировалась. После этого любой другой скрипт может её импортировать. Скрипт карты трогать не нужно.

Решение:

Всё-таки наши объекты кое-чем различаются - указателями. Вот и воспользуемся этим.

--------------------------
//Объявляем набор вар для указателей
export variable begin
ptr_1;
ptr_2;
ptr_3;
end

procedure start begin
end

procedure map_enter_p_proc begin
if not ptr_1 then ptr_1:=self_obj;
else if not ptr_2 then ptr_2:=self_obj;
else if not ptr_3 then ptr_3:=self_obj;
end

procedure talk_p_proc begin
if self_obj==ptr_1 then display_msg("NPC 1");
else if self_obj==ptr_2 then display_msg("NPC 2");
else if self_obj==ptr_3 then display_msg("NPC 3");
end
--------------------------

Фокус в том, что все "внешние" вары хранятся в общем нэймспэйсе и сохраняются/берутся оттуда. Поэтому если мы ставим ptr_1, то для всех остальных объектов, импортировавших (или экспортировавших!) эту вару, она будет уже занята.

Это - самый простой (и в плане возможностей, и в плане реализации) вариант. Можно брать имена из msg, сделать его для неограниченного числа НПС с повторениями имён и т.д.

Естественно, я описываю идею вообще, не какой-то частный случай. Можно, например, запоминать указатель на последнего чара, говорившего с чузом. А следующий будет справшивать "Я видел, ты там с ... болтал, ну что, как дела у него?".

Отправлено: 4:04 - 27 Ноября, 2004
Alan Killenger
Пользователь

Откуда: Россия, Ижевск
Регистрация: Июль 2004

Всего: 404 сообщения

Что-то не спешат скриптологи делиться опытом, видать коммерческая ценность . Три эксперимента, которые достаточно явно показывают все, что я знаю о номерах реплик в *.msg файлах:

Цитата:

display_msg(message_str(1304,0));
display_msg(message_str(1304,999));
display_msg(message_str(1304,-998));
display_msg(message_str(1304,998));
display_msg(message_str(1304,-999));



Эксперимент #1.
Цитата:

{0}{}{реплика 0}
{999}{}{реплика 999}
{-998}{}{реплика -998}
{998}{}{реплика 998}
{-999}{}{реплика -999}


Цитата:

•реплика 0
•реплика 999
•реплика -998
•реплика 998
•реплика -999



Эксперимент #2.
Цитата:

{0}{}{реплика 0}
{999}{}{реплика 999}
{-998}{}{реплика -998}
#{1.5}{}{реплика 1.5}
{998}{}{реплика 998}
{-999}{}{реплика -999}


Цитата:

•Error
•реплика 999
•реплика -998
•Error
•Error


Два раза проверял - именно так.

Эксперимент #3.
Цитата:

{0}{}{реплика 0}
{999}{}{реплика 999}
{-998}{}{реплика -998}
#{998}{}{неиспользуемая реплика 998}
{998}{}{реплика 998}
{-999}{}{реплика -999}


Цитата:

•реплика 0
•реплика 999
•реплика -998
•реплика 998
•реплика -999



P.S. Пошлите кто-нибудь please на мыло любой исходник с использованием таких вещей как spawn или расскажите об этом в "Скриптах".

3.12.04

Выложил работающий скриптик, в котором реализована наработка Raven'а относительно не фиксированных номеров реплик.

4.12.04

Ссылка исправлена.

(Отредактировал(а) Alan Killenger - 21:09 - 4 Дек., 2004)

-----
hit me, nail me, make me god

Отправлено: 20:10 - 29 Ноября, 2004
Raven
Пользователь

Откуда: Владик
Регистрация: Февр. 2004

Всего: 408 сообщений

spawn, exec и fork

По порядку. Синткаксис:
spawn("путь_к_скрипту/файл_скрипта.int");
Запускает скрипт на исполнение (взывает в нём процедуру start). Пока выполняется child-скрипт, родительский простаивает. По прекращению выполнения происходит возврат в исходный скрипт. Т.е. это call для скриптов, а не процедур.

exec фнфлогичен spawn, но возвращение происходит только по команде exit. Если она опущена - Фол вылетает.

fork - тот же spawn, но вызываемый скрипт работает параллельно основному.

Теперь почему это всё нафиг не надо: скрипты, вызванные таким образом, не привязываются к какому-либо объекту (self_obj==0). Естественно, обработчики в них вызваны никогда не будут. И пропадает весь смысл использования скрипта. Кроме того, в вызваном скрипте выполняется только процедура start (хотя можно делать call), по её выполнению скрипт прекраает работу.

Пример:
------------------
<...>
spawn("scripts/fork.int");
display_msg("back to main");
<...>
------------------

forks.ssl:
------------------
procedure start begin
 display_msg("spawned script");
end
------------------

Вывод:
spawned script
back to main

(Отредактировал(а) Raven - 10:32 - 30 Ноября, 2004)

Отправлено: 3:31 - 30 Ноября, 2004
Ray
Модератор

Откуда: Донецк,Украина
Регистрация: Янв. 2004

Всего: 746 сообщений

[deleted]

Ой не в тему... Читай ФАК. Там всё описано.
WG

Отправлено: 15:19 - 5 Дек., 2004
 

Переход по темам
<< Пред. След. >>
Страницы этой темы [ 1 2 3 ] Все собщения


Powered by Ikonboard 2.1.9 RUS
Modified by RU.Board Team
© 2000 Ikonboard.com