ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/cfplus.ext
Revision: 1.10
Committed: Wed Nov 14 08:09:46 2007 UTC (16 years, 6 months ago) by root
Branch: MAIN
Changes since 1.9: +2 -2 lines
Log Message:
switch from Event to EV

File Contents

# User Rev Content
1 root 1.1 #! perl
2    
3     # additional support for cfplus client
4    
5     use NPC_Dialogue;
6    
7     =head1 CF+ protocol extensions
8    
9     This module implements protocol extensions for use by the CF+ client, but
10     can be used by other clients as well. It uses the C<extcmd> mechanism
11     exclusively.
12    
13     =over 4
14    
15     =item ... = extcmd cfplus_support { version => $client_version }
16    
17     Registers the client the the server. the client should send the highest
18     version of the protocol it supports itself, and the server returns the
19     highest version of the protocol it supports in the C<version> key itself.
20    
21     =cut
22    
23     cf::register_extcmd cfplus_support => sub {
24 root 1.9 my ($pl, %msg) = @_;
25 root 1.1
26 root 1.9 $pl->ns->{cfplus_ext} = $msg{version};
27 root 1.1
28 root 1.9 (version => $msg{version} >= 2 ? 2 : 0)
29 root 1.1 };
30    
31     sub dialog_tell {
32     my ($id, $dialog, $msg) = @_;
33    
34 root 1.5 my $pl = $dialog->{pl};
35 root 1.1 my ($reply, @kw) = $dialog->tell ($msg);
36 elmex 1.7
37     $reply = "..." unless defined $reply;
38 root 1.1
39 root 1.9 $pl->ext_msg ($id, update => msg => $pl->expand_cfpod ($reply), add_topics => \@kw)
40     if $reply ne ""; # NPC might not want to say, or wants to say something later
41 root 1.1 }
42    
43     =item ... = extcmd lookat { dx => $dx, dy => $dy }
44    
45     "Looks at" the mapspace displaced (dx|dy) relative to the player
46     and returns "interesting" information about it.
47    
48     Keys it can return include:
49    
50     npc_dialog => $name
51     There is an npc or other object that can "talk" to the player.
52    
53     =cut
54    
55     cf::register_extcmd lookat => sub {
56 root 1.9 my ($pl, $dx, $dy) = @_;
57 root 1.1
58 root 1.2 return unless $pl->ob && $pl->ob->map;
59    
60 root 1.1 my $near = (abs $dx) <= 2 && (abs $dy) <= 2;
61    
62     my %res;
63    
64     if ($pl->cell_visible ($dx, $dy)) {
65     for my $ob ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) {
66 root 1.9 $res{npc_dialog} = [$ob->name, $dx, $dy]
67 root 1.5 if $near && NPC_Dialogue::has_dialogue $ob && !$pl->{npc_dialog};
68 root 1.1 }
69     }
70    
71     %res
72     };
73    
74     =item ... = extcmd npc_dialog_begin { msgid => $id, dx => $dx, dy => $dy }
75    
76     Tries to start a dialogue with the mapspace specified by $dx and $dy (see
77     C<extcmd lookat>). The $msgid will be used as a handle for all future
78     messages related to this dialog interaction.
79    
80     It either replies with an error reply or starts a dialog by telling
81 root 1.5 the npc "hi" and returning a reply structure as with C<extcmd
82 root 1.1 npc_dialog_tell>.
83    
84     =cut
85    
86     cf::register_extcmd npc_dialog_begin => sub {
87 root 1.9 my ($pl, $id, $token) = @_;
88    
89     #TODO:
90     # this is not a request, so returnign does no good: make it a request and die on error
91 root 1.1
92 root 1.2 return unless $pl->ob && $pl->ob->map;
93 root 1.9
94     my ($name, $dx, $dy) = @$token;
95    
96     return (error => "too far away") unless (abs $dx) <= 2 && (abs $dy) <= 2;
97     return (error => "nothing to talk there") unless $pl->cell_visible ($dx, $dy);
98     return (error => "only one dialog can be open at a time") if $pl->{npc_dialog}; # only one dialog at a time
99 root 1.1
100     for my $npc ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) {
101     if (NPC_Dialogue::has_dialogue $npc) {
102 root 1.5 $pl->attach ("npc_dialog_active");
103 root 1.6 $pl->{npc_dialog} = new NPC_Dialogue pl => $pl, npc => $npc, id => $id;
104 root 1.5 dialog_tell $id, $pl->{npc_dialog}, "hi";
105 root 1.1 return;
106     }
107     }
108    
109 root 1.9 (error => "nothing to talk to to found")
110 root 1.1 };
111    
112     =item ... = extcmd npc_dialog_tell { msgid => $id, msg => $text }
113    
114     Tells the NPC the given $text message and returns a reply structure which
115     can have the following keys:
116    
117     msg => $reply_text,
118     add_topics => [additional topic strings]
119     del_topics => [invalidated topic strings]
120    
121     =cut
122    
123     cf::register_extcmd npc_dialog_tell => sub {
124 root 1.9 my ($pl, $id, $msg) = @_;
125 root 1.1
126 root 1.5 if (my $dialog = $pl->{npc_dialog}) {
127 root 1.9 dialog_tell $id, $dialog, $msg;
128 root 1.5 }
129 root 1.1 };
130    
131     =item extcmd npc_dialog_end { msgid => $id }
132    
133     Finishes the dialog, invalidating the handle.
134    
135     =cut
136    
137     cf::register_extcmd npc_dialog_end => sub {
138 root 1.9 my ($pl, $id) = @_;
139 root 1.1
140 root 1.5 if (my $dialog = delete $pl->{npc_dialog}) {
141 root 1.9 $pl->detach ("ncp_dialog_active");
142 root 1.5 }
143 root 1.1 };
144    
145     =item ... = extcmd editor_support
146    
147     Returns the value required by clients that have an editor to download and
148     upload maps from/to the server.
149    
150     servertype => (game|test) type of this server
151     gameserver => the hostname:port of the normal game server
152     testserver => the hostname:port of the test server the maps can be tested on
153     cvs_root => the (http) url where the cvs root for downloading is located
154     lib_root => the (http) url where crossfire.0 and archetypes can be found
155     upload => the (http) url where clients can upload maps
156    
157     If those values are not supplied or empty strings, the server does not
158     support downloading, uploading, testing, respectively.
159    
160     The upload script expects the following values in a multipart form upload:
161    
162     client: a descriptive string describing the editor and version used to upload
163     path: absolute server-side map path beginning with /
164     map: the map file itself
165     mapdir: the cvs root url originally used to download the map
166     revision: cvs-revision originally used to download the map
167     comment: a comment supplied by the user that documents the changes
168     cf_login: crossfire server login
169     cf_password: crossfire server password, optionally used for authentication purposes
170    
171     =cut
172    
173     cf::register_extcmd editor_support => sub {
174 root 1.9 my ($pl, %msg) = @_;
175 root 1.1
176     map +($_ => $cf::CFG{"editor_$_"}), qw(servertype gameserver testserver cvs_root lib_root builder_ui)
177     };
178    
179     sub unload {
180 root 1.5 for my $pl (cf::player::list) {
181     if (my $dialog = delete $pl->{npc_dialog}) {
182     $pl->detach ("npc_dialog_active");
183 root 1.9 $pl->ext_msg ($dialog->{id} => error => "npc dialogue module was reloaded");
184 root 1.5 }
185 root 1.1 }
186 root 1.5 }
187 root 1.1
188 root 1.5 cf::player::attachment npc_dialog_active =>
189     on_logout => sub {
190     my ($pl) = @_;
191    
192     delete $pl->{npc_dialog};
193     $pl->detach ("npc_dialog_active");
194     },
195     on_move => sub {
196     my ($pl, $dir) = @_;
197    
198 root 1.9 # must delay a bit :/
199 root 1.10 my $delay; $delay = EV::timer 0, 0, sub {
200     undef $delay;
201 root 1.9
202     if (my $dialog = $pl->{npc_dialog}) {
203     my (undef, $dx, $dy) = $pl->ob->rangevector ($dialog->{npc});
204    
205     return if (abs $dx) <= 2 && (abs $dy) <= 2;
206 root 1.5
207 root 1.9 $pl->ext_msg ($dialog->{id} => error => "out of range");
208     }
209 root 1.5
210 root 1.9 delete $pl->{npc_dialog};
211     $pl->detach ("npc_dialog_active");
212     });
213 root 1.5 },
214     ;
215    
216     cf::player->attach (
217     on_login => sub {
218     my ($pl) = @_;
219    
220     delete $pl->{npc_dialog};
221     },
222     );
223 root 1.1
224     =back
225    
226     =cut
227