ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/cfplus.ext
Revision: 1.13
Committed: Fri Sep 19 01:39:45 2008 UTC (15 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-2_72, rel-2_71
Changes since 1.12: +3 -3 lines
Log Message:
*** empty log message ***

File Contents

# Content
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 my ($pl, %msg) = @_;
25
26 $pl->ns->{cfplus_ext} = $msg{version};
27
28 (version => $msg{version} >= 2 ? 2 : 0)
29 };
30
31 sub dialog_tell {
32 my ($id, $dialog, $msg) = @_;
33
34 my $pl = $dialog->{pl};
35 my ($reply, @kw) = $dialog->tell ($msg);
36
37 $reply = "..." unless defined $reply;
38
39 $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 }
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 my ($pl, $dx, $dy) = @_;
57
58 return unless $pl->ob && $pl->ob->map;
59
60 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 $res{npc_dialog} = [$ob->name, $dx, $dy]
67 if $near && $ob->has_dialogue && !$pl->{npc_dialog};
68 }
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 the npc "hi" and returning a reply structure as with C<extcmd
82 npc_dialog_tell>.
83
84 =cut
85
86 cf::register_extcmd npc_dialog_begin => sub {
87 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
92 return unless $pl->ob && $pl->ob->map;
93
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
100 for my $npc ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) {
101 if ($npc->has_dialogue) {
102 $pl->attach ("npc_dialog_active");
103 $pl->{npc_dialog} = new NPC_Dialogue pl => $pl, npc => $npc, id => $id;
104 dialog_tell $id, $pl->{npc_dialog}, "hi";
105 return;
106 }
107 }
108
109 (error => "nothing to talk to to found")
110 };
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 my ($pl, $id, $msg) = @_;
125
126 if (my $dialog = $pl->{npc_dialog}) {
127 dialog_tell $id, $dialog, $msg;
128 }
129 };
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 my ($pl, $id) = @_;
139
140 if (my $dialog = delete $pl->{npc_dialog}) {
141 $pl->detach ("ncp_dialog_active");
142 }
143 };
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 archetypes data 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 login: deliantra server login
169 password: deliantra server password, optionally used for authentication purposes
170
171 =cut
172
173 cf::register_extcmd editor_support => sub {
174 my ($pl, %msg) = @_;
175
176 map +($_ => $cf::CFG{"editor_$_"}), qw(servertype gameserver testserver cvs_root lib_root builder_ui)
177 };
178
179 sub unload {
180 for my $pl (cf::player::list) {
181 if (my $dialog = delete $pl->{npc_dialog}) {
182 $pl->detach ("npc_dialog_active");
183 $pl->ext_msg ($dialog->{id} => error => "npc dialogue module was reloaded");
184 }
185 }
186 }
187
188 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 # must delay a bit :/
199 my $delay; $delay = EV::timer 0, 0, sub {
200 undef $delay;
201
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
207 $pl->ext_msg ($dialog->{id} => error => "out of range");
208 }
209
210 delete $pl->{npc_dialog};
211 $pl->detach ("npc_dialog_active");
212 };
213 },
214 ;
215
216 cf::player->attach (
217 on_login => sub {
218 my ($pl) = @_;
219
220 delete $pl->{npc_dialog};
221 },
222 );
223
224 =back
225
226 =cut
227