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


Форум TeamX » Исследования » Взаимодействие между объектами (Вариант 1: timed_event/add_timer_event)

Переход по темам
<< Пред. След. >>
Единственная страница этой темы

 
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
 

Переход по темам
<< Пред. След. >>
Единственная страница этой темы


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