|
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
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
Обещанный рассказ про atoi. С опозданием в неделю :-( Atoi - это процедура преобразующая string-число в int-число. Проблема: Для тех, кто не смотрел исходники компилятора скриптов Фола (точнее, klngon Academy, однодвижковой игры) - коммент из parse.c: ---------------------------------- /* * Parser for SSL (Startrek Scripting Language). * * All variables are "typeless"; their type is defined by how * they are used. All types are promoted to the "highest" type * in an expression, where the order is from lowest to highest: * int, float, string. * * So, * if you do 2 + "foo", you get back "2foo". * if you do 2 + 2.4, you get 4.4 * if you do 2 + 4, you get 6 (hopefully :) * if you do 2 + 2.4 + "foo", you get "4.4foo", since * expressions are parsed left to right. * if you do 2 + (2.4 + "foo") you get "22.4foo", due * to the parentheses. * etc. */ ---------------------------------- Т.е.: ---------------------------------- variable a:="1234"; a+=1; display_msg("a="+a); ---------------------------------- выведет "a=12341". Это ставит крест на хранении в msg-файлах числовых значений. А делать так было бы удобно, т.к. тогда можно хранить в msg PID-ы предметов, номера/значения квестовых GVAR, номера "домашних" тайлов - т.е. изменяющиеся в процессе модинга величины - что упростило бы разработку, избавив модера от необходимости отслеживать и перекомпилировать всё, что использует ГВАРу/PID. Кроме того, можно было бы хранить там количество экспы, денег, PID-ы предетов выдаваемых в качестве квестовых наград; временные таблицы для создания НПС, двигающихся по карте "по расписанию"; значения скилов/параметров, необходимых для выдачи/решения квеста - т.е. упростить итоговую балансировку мода. Принцип работы: Итак, у нас есть строки. Что мы можем с ними делать? Только склейку? Неправильный ответ. Мы можем их сравнивать: "abc"=="abc" //true "abc">"abc" //false "b">"a" //true "b">"abczz" //true "abc">"abd" //false "b">"A" //false Принцип понятен? Строки сравниваются посимвольно, как только найдено различие - сравниваются ASCII-коды символов. Символ с бОльшим номером делает больше всю строку. Что нам это даёт? Рассмотрим строку "123". Что мы можем сказать? "123">"1". И "123"<"2" Уловили? Мы только что выявили первый символ. Запомнили его. Смотрим дальше. "123">"11", "123">"12", "123"<"13". Нашли второй. Прибавили к первому. "123">"121","123">"122","123"=="123". Нашли строку. Параллельно с конструированием строки мы можем собирать число - поразрядно. Пишем код: ---------------------------------- procedure atoi(var str) begin var tmp_str:=""; //инициализация обязательна, иначе tmp_str="0" var value; //числовое значение //""+0=="0" if (str>tmp_str+0 and str<tmp_str+1) or str==tmp_str+0 then begin tmp_str+=0; //дополняем строку. "123"+0=="1230" value:=value*10+0; //"дописываем" ноль справа end //тоже для остальных цифр <...> ---------------------------------- Всё это должно быть загнано в цикл: ---------------------------------- procedure atoi(var str) begin var tmp_str:=""; var value; var i; //для ограничения на длину преобразуемой строки while str!=tmp_str and i<16 do begin if (str>tmp_str+0 and str<tmp_str+1) or str==tmp_str+0 then begin tmp_str+=0; value:=value*10+0; end <...> i+=1; end if i!=16 then return value; //строка >16 символов либо содержит нецифровые символы else return -1; end ---------------------------------- Теперь чуть-чуть укоротим, введя двойной цикл: ---------------------------------- procedure atoi(var str) begin var tmp_str:=""; var value; var i; var j; //для ограничения на длину преобразуемой строки while (str!=tmp_str) and j<16 do begin //относительно сложное выражение. Надеюсь, разберётесь :-) while not ((str>tmp_str+i and str<tmp_str+(i+1)) or str==tmp_str+i) and i<9 do i+=1; //при i=9 предыдущее выражение не работает (str>...+9 and str<...+10) //случай с девяткой обрабатываем отдельно if i==9 and not (ostr>str+9 or ostr==str+9) then i:=10; //дописываем tmp_str и value if i<10 then begin tmp_str+=i; value:=value*10+i; end //в строке попался нечисловой символ else return -1; i:=0;j+=1; end return val; end ---------------------------------- После удаления комментариев получится меньше 10 строк :-) Ну вот и всё. Теперь если msg: ---------------------------------- {214}{}{2000} ---------------------------------- ,то код ---------------------------------- give_exp(atoi(mstr(214)); ---------------------------------- даст Чузу 2000 экспы. Учитывая мои предыдущие наработки (идея присвоения мсг-шкам уникальных строк-меток), можно подумать о создании этакого ini-файла, где могут быть прописаны: 1. экспа за каждый квест 2. изменения кармы за квесты 3. значения квестовых GVAR (взял/сделал/сдал и т.д.) 4. награды за квесты В общем, эдакие const GVAR-ы. Всё в одном месте, перекомпиляции не требуется. Балансировка упрощается. P.S. Mynah, ты говорил про hear/see? Запость, не стесняйся. ================================================= Диалог между NPC. Никогда не задумывались как можно организовать floater-дилог между двумя НПС? Рассказываю. Решение: Итак, у нас два объекта. К ним привязан скрипт (один и тот же). Различаются они по указателям.Каждый знает указатель другого (импорт/экспорт - предыдущие наработки). Что такое с точки зрения скриптера floater-диалог? Это последовательность вызовов floater-ов, разнесённая по времени (floater над первым НПС, пауза в секунду, floater над другим НПС ...). Т.е. очевидно, что реализуется он с помощью add_timer_event. Начинаем писать скрипт: msg: ------------------------------ {1}{}{Phrase1} {2}{}{Phrase2} {3}{}{Phrase3} {4}{}{Phrase4} ------------------------------ Код: ------------------------------ export var begin ptr_chat_1; ptr_chat_2; end procedure start begin end procedure map_enter_p_proc begin if not ptr_chat_1 then ptr_chat_1:=self_obj; else ptr_chat_2:=self_obj; end procedure talk_p_proc begin var i:=1; //i==началу блока реплик - пред. наработки while (mstr(i)!="Error") do begin //добавляем события по таймеру ч/з 0,1,2,3 секунды add_timer_event(self_obj,i-1,i); i+=1; end end procedure timed_event_p_proc begin var who; //кто говорит //если номер реплики чётный - говорит первый чар, иначе - второй if fixed_param%2 then who:=ptr_chat_1; else who:=ptr_chat_2; float_msg(who,mstr(fixed_param),0); end ------------------------------ Всё. Лучше, конечно, добавить код для поиска начала блока фраз - для унификации. С этим скриптом появляется один "баг" - сколько раз ткнули в НПС - столько диалогов и удет. Одновременно. Как можно исправить? Завести вару, ставить её один в начале диалога, сбрасывать в конце. Маленькая трабла - в конце значит после последнего вызова timed_event, а не после добавления событий (которое происходит сразу и очень быстро). Т.е. мы должны добавить 4 таймерных события для вывода фраз + ещё одно для сброса переменной. Как их различать? Ведь номер фразы (спасибо Алану) может быть любым - и отрицательным, и положительным, и нулевым - т.е. принять некоторые фиксированные значения параметра за "установить/сбросить флаг" мы, вообще говоря, не можем. Выход: "сборные" параметры. Как пакеты в локальных сетях. Т.е. мы "забираем" один разряд передаваемого значения под "флаг", определяющий тип значения. Например, флаг "0" озачает, что параметр - номер строки в msg для floater. Если пришло 3130 - значит надоы вывести строку 313, пришло 120 - выводим строку 12, 900 - строку 90. А флаг "1" будет означать сброс/установку вару "диалог уже идёт". ------------------------------ export var is_chatting; <...> //первый разряд числа #define flag (fixed_param%10) //число без первого разряда #define param (fixed_param/10) procedure timed_event_p_proc begin if flag==0 then begin if param%2 then float_msg(ptr_chat_1,mstr(param),0) else float_msg(ptr_chat_2,mstr(param),0); end else if flag==1 then is_chatting:=param; end procedure talk_p_proc begin var i:=1; //если уже болтаем - ничего не делать if is_chatting then return 0; //устанавливаем флаг add_timer_event(self_obj,0,11); //передаём номера строк с добавленным нулём справа while (mstr(i)!="Error") do begin add_timer_event(self_obj,i-1,i*10+0); i+=1; end //добавляем событие снятия флага по окончанию разговора add_timer_event(self_obj,i,01); end ------------------------------ Всё. Вообще, у timed_event/add_timer_event чрезвычайно мощный потенциал. Подумайте: ведь, зная указатель на объект, с помощью add_timer_event мы можем "приказать" ему что угодно - устанавливать/читать LVAR-ы, вызывать процедуры, проигрывать анимацию, начинать диалог, двигаться. Это - основа межобъектного взаимодействия. И, ИМХО, новая парадигма в Ф-скриптинге :-) Есть ещё кое-что - экспрот/импорт процедур. Но об этом - в следующих сериях. Не переключайте канал :-) (Отредактировал(а) Raven - 12:47 - 7 Дек., 2004)
|
Отправлено: 4:50 - 7 Дек., 2004
|
|
Alan Killenger
Пользователь
Откуда: Россия, Ижевск Регистрация: Июль 2004
Всего: 404 сообщения
|
Быть может удобнее не добавлять с одного маха все таймерные события, а делать их вызов последовательным?
Цитата:
.. variable self_sing:=false; .. procedure talk_p_proc begin if not(self_sing) then begin self_sing:=true; add_timer_event(self_obj,30,/*позиция песни*/); end end .. procedure timed_event_p_proc begin if self_sing then self_sing:=sing_song(fixed_param,/*задержка*/); end .. procedure sing_song(variable P_pos,variable P_delay) begin if /*нет конца песни*/ then begin float_msg(self_obj,mstr(P_pos),0); add_timer_event(self_obj,P_delay,P_pos+1); return true; end else return false; end ..
Таким образом переменная self_sing автоматически примет значение false, когда песня(или *float диалог) будет закончена. Этот прием дает большие возможности в плане развития событий: например, если чуз убежал от криттера на 30 хексов разумно прекратить диалог; или если чуз повернулся к NPC спиной диалог пойдет иначе.
----- hit me, nail me, make me god
|
Отправлено: 12:29 - 8 Дек., 2004
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
Да, так будет гораздо гибче. Я показываю самые простые решения, as-is, саму идею. Реализация в каждом конкретном случае за вами. Но вот такие предложения/дополнения, разумеется, приветствуются. А вторая часть с is_chatting флагом была добавлена ради озвучивания идеи об "упаковке" нескольких значений в вару. Знание этого пригодится при прочтении наработки о взаимодействии двух скриптов ч/з timed_event.
|
Отправлено: 15:07 - 8 Дек., 2004
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
Say-режим. Что это вообще такое. В Фоле есть набор команд, начинающихся с say, которые не описаны в API и не использованы в игре. Например: saystart saysend sayoption sayreply и т.д. После не слишком длительной целенаправленной возни, мне удалось с ними разобраться. Итак, что это такое. Это - режим организации диалога. да-да, такого же, что вызывается с помощью start_gdialog, но куда как более гибкого. А именно: 1. мы можем задавать координаты, размеры и бэкграунд reply- и option-окон (потенциально возможно разные диалоги - с компами, с людьми, с предметами - оформлять по разному) 2. мы можем задавать шрифт, цвет шрифта, подсветку при наведении, выравнивание, отступы 3. для организации простых диалоговых веток (без if-проверок, установок флагов и т.п.) не требуется создавать отдельные ноды 4. самое главное. Этот режим можно инициализировать в любой момент - во время боя, из инвентаря etc. После его использования инвентарь *обновляется*. Т.е. можно сделать, например, свою карту, которая при использовании из инвентаря вызовет say-режим, а по его окончании - исчезнет из инвентаря. Проблема, считаемая нерешимой. Время при переходе в say-режим останавливается (как с инвентарём/диалогом). Минус - исчезает курсор :-( Обратно его можно вызвать переместив мышку на display-экранчик. Он сменится на скроллинг-курсор и появится обратно. Как скриптится. Есть два типа процедур - подготовительные и управляющие. К подоготовительным относятся, например: sayreplywindow(x,y,width,height,"path/to/pcx_file.pcx"); Задаёт координаты, размер и картинку окна. Путь - относительно Data. Т.е., создаём data/pcx, кладём туда pcx-картинку и пишем путь в скрипте. setfont(num); num - номер шрифта (1-5 с пропусками, см. корень master.dat) sayborder(x,y); Отступы для выводимого в окно текста - по вертикали и горизонтали - с обеих сторон. Ладно, пока хватит, потом раскажу об остальных. Теперь про управляющие. Вначале надо перейти в режим командой saystart. После этого вплоть до saysend sayreply(str node_name, str text); Второй параметр - выводимый текст (окно создаётся автоматом в соответствии с параметрами, заданными sayreplywindow). Первый - это имя этого "нода". Потом его можно будет вызывать наравне с процедурами из sayoption. sayoption(str text,str/proc node); Выводит вариант ответа в option-окно (параметры задаются в sayoptionwindow, аналогично reply). Внимание! Если ответ на фразу один, то option окно не создаётся и ответ не выводится. Для продолжения диалога при этом надо кликнуть на reply-окно. Причём, результат будет браться из того самого написанного, но не выводящегося на экран sayoption. Первый - текст. Второй - имя нода из sayreply (в кавычках) *или* имя вызываемой процедуры (без кавычек). Простой пример: ----------------------------- procedure start begin end procedure critter_p_proc begin end procedure talk_p_proc begin sayreplywindow(20,10,200,100,"111.pcx"); sayoptionwindow(230,10,200,100,"111.pcx"); setfont(5); sayborder(10,10); saystart; sayreply("NodeHi","Hello"); sayoption("Hi. How it goes?","NodeHow"); sayoption("Bye","NodeClose"); sayreply("NodeHow","Fine, thanks"); sayoption("Well, gotta get moving.","NodeClose"); sayoption("Bye","NodeClose"); sayreply("NodeClose","Bye"); sayoption("Bye","Empty"); sayend; end ----------------------------- Как видите, никаких предобъявлений, обилия процедур и т.п. Процедуры понадобятся, если захотите организовать выдачу вещей, установку вар и т.п. if-ы работают. Компилируем, привязываем, смотрим. Можете пока pcx-ину прикрутить, поиграться с расположением окон, проверить работу с отдельными процедурами и т.п. Остальное - завтра :-) (Отредактировал(а) Raven - 23:29 - 14 Янв., 2005)
|
Отправлено: 15:41 - 14 Янв., 2005
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
Извините, обещанного продолжения не будет.
|
Отправлено: 12:07 - 15 Янв., 2005
|
|
Tehnokrat
Модератор
Откуда: Новосибирск Регистрация: Окт. 2003
Всего: 489 сообщений
|
Это ещё в честь чего? Я между-прочим ждал. Может всё-таки напишешь кратенько, в формате доки WG?
----- Прошлое можно узнать, но нельзя изменить. Будущее можно изменить, но нельзя узнать.
|
Отправлено: 23:48 - 15 Янв., 2005
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
>>Это ещё в честь чего? Есть повод. >>Я между-прочим ждал. Может всё-таки напишешь Как накатаю - пошлю на мыло.
|
Отправлено: 0:36 - 16 Янв., 2005
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
Оказалось, что ограничение на число ГВАР - миф. Всё, что мы допишем в vault13.gam, может быть использовано в игре. Что думаете по этому поводу?
|
Отправлено: 16:16 - 20 Янв., 2005
|
|
YikxX
Пользователь
Откуда: NCR :) Регистрация: Февр. 2004
Всего: 304 сообщения
|
Хм, я например всегда думал, что после резервных можно еще своих гвар кучу понаписать. И уж точно больше, чем мне будет нужно.
----- Обломись! Я подложил туда носок...
|
Отправлено: 17:00 - 20 Янв., 2005
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
Ну так правильно думал :-) А я, помню, считал ограничение на число ГВАР потенциальной проблемой - и со мной могие соглашались :-) Вот так вот и рождаются мифы, блин :-)
|
Отправлено: 17:27 - 20 Янв., 2005
|
|
Tehnokrat
Модератор
Откуда: Новосибирск Регистрация: Окт. 2003
Всего: 489 сообщений
|
Никогда не слышал про какие-либо ограничения на число GVAR.
----- Прошлое можно узнать, но нельзя изменить. Будущее можно изменить, но нельзя узнать.
|
Отправлено: 0:06 - 21 Янв., 2005
|
|
binyan
Пользователь
Откуда: Israel Регистрация: Март 2005
Всего: 292 сообщения
|
Я может конечно и археолог, но не могу , когда люди подолгу мучаются. Я вот например полчаса потратил на то, чтобы сообразить в чем дело. Смотрим первый пост:
Цитата:
//Начинаем искать от строки first //Ищем либо закрывающий "тэг", либо первую пустую строку while message_str(msg_num,i)!="END REPLICS" or message_str(msg_num,i)!="Error" do i+=1; last:=i-1; //проверки на ошибку не делаем, т.к. список не может быть бесконечным, пустая строка всегда найдётся //Закрывающий тэг нужен "для себя", как комментарий
Там где )!="END REPLICS" or message_str должно быть AND вместо or, потому как пустая строка у нас не "Всегда найдётся". Проверено.
----- ...выражая озадаченность, граничащую с озабоченностью..
|
Отправлено: 21:43 - 17 Авг., 2006
|
|
Oleg1969
Пользователь
Откуда: Саратов Регистрация: Май 2006
Всего: 168 сообщений
|
ЭЭЭЭ... А что, оскудела земля Русская? Тихо то как тута... Мож чем хозяева поделятся...
----- За сим прощаюсь, Олег.
|
Отправлено: 21:00 - 24 Сент., 2006
|
|
Dweller
Пользователь
Откуда: Е-бург Регистрация: Июль 2007
Всего: 29 сообщений
|
Как ни пробывал я избавиться от привязки скрипта к номеру, добился только вылета Фола. Путем экспериментов понял, что вылетает из-за строчки message_str(i,1000)!=obj_name(self_obj). Помогите, кто разобрался!
----- Не нужна мне эта подпись
|
Отправлено: 2:12 - 30 Июля, 2007
|
|
Wasteland Ghost
Маленькое Злое Привидение
Откуда: Россия, Самара Регистрация: Дек. 2002
Всего: 2251 сообщение
|
Включи дебаг-режим. Патч с объяснениями есть в разделе загрузок. Сообщения из лог-файла запость сюда. Тогда и посмотрим. У меня были такие проблемы со скриптом фиксита. Фол отказывается нормально грузить "чужой" для данного скрипта мсг большого размера с большими номерами строк. При малых размерах мсг всё нормально. При больших размерах мсг у меня грузился нормально при повторном обращении, но через некоторое время Фол слетал.
|
Отправлено: 12:13 - 2 Авг., 2007
|
|
Ray
Модератор
Откуда: Донецк,Украина Регистрация: Янв. 2004
Всего: 746 сообщений
|
Цитата: Фол отказывается нормально грузить "чужой" для данного скрипта мсг большого размера с большими номерами строк. При малых размерах мсг всё нормально. При больших размерах мсг у меня грузился нормально при повторном обращении, но через некоторое время Фол слетал
А можешь попробовать с этим изменением? 0x96F8A оригинальное значение: 000F85A500 изменить: FF7400EB02
----- Не бывает невозможных задач – бывает мало времени.
|
Отправлено: 21:32 - 2 Авг., 2007
|
|
Wasteland Ghost
Маленькое Злое Привидение
Откуда: Россия, Самара Регистрация: Дек. 2002
Всего: 2251 сообщение
|
Попробовала. Ничего не изменилось:
Код:
Error loading message file text\english\dialog\test0.msg at offset 3d03. Error loading script dialog message file! ERROR: message_str: can't find message file: List: 2! Error: No message file EXISTS!: index 2, line 500
Уменьшаю файл вдвое -- работает отлично. Эх, плакал Фиксит с расширенной сортировкой и апгрейдами...
|
Отправлено: 11:10 - 9 Авг., 2007
|
|
Ray
Модератор
Откуда: Донецк,Украина Регистрация: Янв. 2004
Всего: 746 сообщений
|
Отправь, пожалуйста, на мыло этот скрипт. Буду мудрить...
----- Не бывает невозможных задач – бывает мало времени.
|
Отправлено: 11:51 - 9 Авг., 2007
|
|
|
|