|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
Сразу предупреждаю: описанный здаесь метод - каменный век скриптинга :-) Уже есть методы куда как более изящные (о них - позже). Сама тема взаимодействия объектов - тема меня живо интересующая. Я вижу в ней огромный потенциал. Поэтому и писать об этом буду, надеюсь, много и часто. Что такое межобъектное взаимодействие? Простейший случай - флоатер-диалог между двумя НПС. Случай посложнее - НПС, закрывающий на ночь дверь своего дома. Всё это - будет здесь озвучено :-) Stay on line :-) [Из TeamX-Tech] Товарищи скриптеры, а что вы знаете о способах организации взаимодействия между объектами и о пределах, в которых это взаимодействие возможно? Все мы знаем про экспорт и импорт переменных. Экспортируя переменную и сохраняя в неё указатель какого-либо объекта, мы можем пользоваться этим указателем из других скриптов. Что нам это даёт? Мы можем получить координаты и любую информацию о прототипе этого объекта. Общеизвестное здесь, видимо, заканчивается. Дальше идет известное не всем - мы можем управлять поведением объекта через его timed_event_p_proc, если знаем указатель на него: Клиент :-): ------------------------ #define Start_Talking 0 #define Attack_Dude 1 <...> import variable server; <...> if i_love_dude then add_timer_event(server,Start_Talking); else if i_hate_dude then add_timer_event(server,Attack_Dude); <...> ------------------------ Сервер: ------------------------ #define Start_Talking 0 #define Attack_Dude 1 export variable server; procedure map_enter_p_proc begin server:=self_obj; end <...> procedure timed_event_p_proc begin if fixed_param==Start_Talking then call talk_p_proc; else if fixed_param==Attack_Dude then attack(dude_obj); <...> end ------------------------ Потенциал того, что add_timer_event может быть использован на любой объект, до сих пор не был оценен по достоинству, и эта возможность редко используется в скриптинге, хотя с её помощью можно реализовать сложнейшие вещи. Итак, по указателю мы можем получить информацию ОБ объекте и даже влиять на его поведение (хотя и не можем полностью определить поведение, так как не способны явно задавать параметры вызываемых из te процедур). Казалось бы, всё. Но на самом деле это только начало :-) Мы можем получать/устанавливать значения ЛВАР-ов объекта, зная указатель на него. Думаем. Мы можем вызвать любую процедуру в скрипте объекта, зная указатель на него. В том числе и local_var. Но процедуре local_var нужен параметр. Кроме того, мы должны передать ещё один параметр, говорящий о том, что мы хотим вызвать именно local_var, а не talk_p_proc, к примеру. Наконец, запрошенное значение должно быть передано из скрипта носителя вары к запрашивающему, т.е. мы должны передать указатель на объект, от которого исходит запрос. Нам нужно передать три параметра. add_timer_event отводит под передачу параметров одну 32-ух битную переменную. Вопрос: как можно передать три параметра в одной переменной? Ответ: вспоминаем как в Фоле представляются координаты (coord:=x*200*y). Итак, параметр для передачи можно "собрать" следующим образом: ------------------------ self_obj*100+lvar_num*10+flag; ------------------------ lvar_num - номер запрашиваемой вары, flag используется в timed_event носителя вары: ------------------------ #define FLAG_read (0) #define FLAG_write (1) <...> procedure timed_event_p_proc begin <...> if flag=FLAG_read then begin <...> ------------------------ Ещё одна потенциальная проблема - 2 в 31 степени - это, на самом деле, до смешного мало, если учитывать что указатели имеют длину в 8-9 цифр. Может наступить переполнение вары и всё пойдёт на смарку. Решение: указатель - большое число, но вот *разность* двух указателей - число на несколько порядков меньшее. Т.е. мы можем сделать так: ------------------------ import variable container; <...> variable shift;variable key; shift:=container-self_obj; key:=(shift*10+lvar_num)*10+flag; add_timer_event(container,0,key); ------------------------ , где container хранит указатель на объект-носитель читаемой ЛВАРы. Здесь скрыта потенциальная ошибка - shift может как отрицательным, так и положительным. Правильный вариант: ------------------------ import variable container; <...> variable shift;variable key; shift:=container-self_obj; if shift>0 then key:=(shift*10+lvar_num)*10+flag; else key:=(shift*10+lvar_num)*10+flag; add_timer_event(container,0,key); ------------------------ В скрипте объекта-носителя пишем: ------------------------ flag:=fixed_param%10; if flag==FLAG_read then begin shift:=fixed_param/100; ptr_target:=self_obj-shift; lvar_num:=(fixed_param%100)/10; add_timer_event(ptr_target,0,local_var(lvar_num)); end else <...> ------------------------ Соответственно, в t_e отправителя запроса пишем: ------------------------ variable lvar_answer; <...> procedure timed_event_p_proc begin lvar_answer:=fixed_param; <...> ------------------------ Всё. Писать вары ещё проще, так как не надо передавать указатель на отправителя и использовать shift. Исходники с примерами нужны?
|
Отправлено: 12:16 - 25 Янв., 2005
|
|
Tehnokrat
Модератор
Откуда: Новосибирск Регистрация: Окт. 2003
Всего: 489 сообщений
|
>>Сразу предупреждаю: описанный здаесь метод - каменный век скриптинга :-) Уже есть методы куда как более изящные (о них - позже). А нельзя ли сразу перейти к методам атомного века?
----- Прошлое можно узнать, но нельзя изменить. Будущее можно изменить, но нельзя узнать.
|
Отправлено: 23:55 - 31 Янв., 2005
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
>>А нельзя ли сразу перейти к методам атомного века? Всё никак не соберусь :-) Может, завтра. Точнее, уже сегодня. Намёк: экспортируемые процедуры. Единственный нормальный способ разобраться с ситуацией, когда у нас есть много объектов с одинаковым скриптом и нам их надо заставить друг с другом взаимодействовать. Например, пишем мы (не с потолка пример :-) скрипт generic-крестьянина. "Личная" инфа (имя, профессия, хомтайл) берётся из таблицы в msg-файле. И хотим сделать так, чтобы эти крестьяне друг с другом общались при встрече. Что делать? Как быть? Первое, что приходит в головы - экспортировать указатель. Но копий скрипта-то много. И код: ------------------------------- export variable ptr_villager; procedure map_enter_p_proc begin ptr_villager:=self_obj; end ------------------------------- работать не будет по понятным причинам - вара одна, копий много. Можно, конечно, решить проблему в лоб: ------------------------------- export variable ptr_villager1; export variable ptr_villager2; <...> export variable ptr_villagerN; procedure map_enter_p_proc begin if not ptr_villager1 then ptr_villager1:=self_obj; else if not ptr_villager2 then ptr_villager2:=self_obj; <...> end ------------------------------- А если на карте будет N+1 НПС? Да и неизящно, согласитесь :-) Выход: заводим объект-сервер. При заходе на карту каждый НПС-крестьянин обращается к серверу. Тот его регистрирует, запоминает указатель, выдает строчку с началом блока (в msg), описывающего данный экземпляр. Если НПС захочет поговорить - отправляет запрос. Сервер перебирает таблицу указателей, проверяет дистанцию, видимость, возвращает указатель на оппонента. А может и не возвращать, а сам всё организовать. Ладно, затянул затравку-вступление :-)
|
Отправлено: 0:22 - 1 Фев., 2005
|
|
|
|