… | |
… | |
19 | highest version of the protocol it supports in the C<version> key itself. |
19 | highest version of the protocol it supports in the C<version> key itself. |
20 | |
20 | |
21 | =cut |
21 | =cut |
22 | |
22 | |
23 | cf::register_extcmd cfplus_support => sub { |
23 | cf::register_extcmd cfplus_support => sub { |
24 | my ($pl, $msg) = @_; |
24 | my ($pl, %msg) = @_; |
25 | |
25 | |
26 | # $msg->{version} |
26 | $pl->ns->{cfplus_ext} = $msg{version}; |
27 | |
27 | |
28 | ( |
28 | (version => $msg{version} >= 2 ? 2 : 0) |
29 | version => 2, |
|
|
30 | ) |
|
|
31 | }; |
29 | }; |
32 | |
30 | |
33 | sub dialog_tell { |
31 | sub dialog_tell { |
34 | my ($id, $dialog, $msg) = @_; |
32 | my ($id, $dialog, $msg) = @_; |
35 | |
33 | |
36 | my $pl = $dialog->{pl}; |
34 | my $pl = $dialog->{pl}; |
37 | my ($reply, @kw) = $dialog->tell ($msg); |
35 | my ($reply, @kw) = $dialog->tell ($msg); |
38 | |
36 | |
39 | $reply = "..." unless defined $reply; |
37 | $reply = "..." unless defined $reply; |
|
|
38 | |
|
|
39 | $pl->ext_msg ($id, update => msg => $pl->expand_cfpod ($reply), add_topics => \@kw) |
40 | return if $reply eq ""; # NPC doesn't want to say, or wants to say something later |
40 | if $reply ne ""; # NPC might not want to say, or wants to say something later |
41 | |
|
|
42 | $pl->ext_reply ($id => msgtype => "reply", msg => $reply, add_topics => \@kw); |
|
|
43 | } |
41 | } |
44 | |
42 | |
45 | =item ... = extcmd lookat { dx => $dx, dy => $dy } |
43 | =item ... = extcmd lookat { dx => $dx, dy => $dy } |
46 | |
44 | |
47 | "Looks at" the mapspace displaced (dx|dy) relative to the player |
45 | "Looks at" the mapspace displaced (dx|dy) relative to the player |
… | |
… | |
53 | There is an npc or other object that can "talk" to the player. |
51 | There is an npc or other object that can "talk" to the player. |
54 | |
52 | |
55 | =cut |
53 | =cut |
56 | |
54 | |
57 | cf::register_extcmd lookat => sub { |
55 | cf::register_extcmd lookat => sub { |
58 | my ($pl, $msg) = @_; |
56 | my ($pl, $dx, $dy) = @_; |
59 | my ($dx, $dy) = @$msg{qw(dx dy)}; |
|
|
60 | |
57 | |
61 | return unless $pl->ob && $pl->ob->map; |
58 | return unless $pl->ob && $pl->ob->map; |
62 | |
59 | |
63 | my $near = (abs $dx) <= 2 && (abs $dy) <= 2; |
60 | my $near = (abs $dx) <= 2 && (abs $dy) <= 2; |
64 | |
61 | |
65 | my %res; |
62 | my %res; |
66 | |
63 | |
67 | if ($pl->cell_visible ($dx, $dy)) { |
64 | if ($pl->cell_visible ($dx, $dy)) { |
68 | for my $ob ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) { |
65 | for my $ob ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) { |
69 | $res{npc_dialog} = $ob->name |
66 | $res{npc_dialog} = [$ob->name, $dx, $dy] |
70 | if $near && NPC_Dialogue::has_dialogue $ob && !$pl->{npc_dialog}; |
67 | if $near && NPC_Dialogue::has_dialogue $ob && !$pl->{npc_dialog}; |
71 | } |
68 | } |
72 | } |
69 | } |
73 | |
70 | |
74 | %res |
71 | %res |
… | |
… | |
85 | npc_dialog_tell>. |
82 | npc_dialog_tell>. |
86 | |
83 | |
87 | =cut |
84 | =cut |
88 | |
85 | |
89 | cf::register_extcmd npc_dialog_begin => sub { |
86 | cf::register_extcmd npc_dialog_begin => sub { |
90 | my ($pl, $msg) = @_; |
87 | my ($pl, $id, $token) = @_; |
91 | my ($id, $dx, $dy) = @$msg{qw(msgid dx dy)}; |
88 | |
|
|
89 | #TODO: |
|
|
90 | # this is not a request, so returnign does no good: make it a request and die on error |
92 | |
91 | |
93 | return unless $pl->ob && $pl->ob->map; |
92 | return unless $pl->ob && $pl->ob->map; |
|
|
93 | |
|
|
94 | my ($name, $dx, $dy) = @$token; |
|
|
95 | |
94 | return unless (abs $dx) <= 2 && (abs $dy) <= 2; |
96 | return (error => "too far away") unless (abs $dx) <= 2 && (abs $dy) <= 2; |
95 | return unless $pl->cell_visible ($dx, $dy); |
97 | return (error => "nothing to talk there") unless $pl->cell_visible ($dx, $dy); |
96 | return if $pl->{npc_dialog}; # only one dialog at a time |
98 | return (error => "only one dialog can be open at a time") if $pl->{npc_dialog}; # only one dialog at a time |
97 | |
99 | |
98 | for my $npc ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) { |
100 | for my $npc ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) { |
99 | if (NPC_Dialogue::has_dialogue $npc) { |
101 | if (NPC_Dialogue::has_dialogue $npc) { |
100 | $pl->attach ("npc_dialog_active"); |
102 | $pl->attach ("npc_dialog_active"); |
101 | $pl->{npc_dialog} = new NPC_Dialogue pl => $pl, npc => $npc, id => $id; |
103 | $pl->{npc_dialog} = new NPC_Dialogue pl => $pl, npc => $npc, id => $id; |
102 | dialog_tell $id, $pl->{npc_dialog}, "hi"; |
104 | dialog_tell $id, $pl->{npc_dialog}, "hi"; |
103 | return; |
105 | return; |
104 | } |
106 | } |
105 | } |
107 | } |
106 | |
108 | |
107 | (msgtype => "error", msg => "nothing to talk to found") |
109 | (error => "nothing to talk to to found") |
108 | }; |
110 | }; |
109 | |
111 | |
110 | =item ... = extcmd npc_dialog_tell { msgid => $id, msg => $text } |
112 | =item ... = extcmd npc_dialog_tell { msgid => $id, msg => $text } |
111 | |
113 | |
112 | Tells the NPC the given $text message and returns a reply structure which |
114 | Tells the NPC the given $text message and returns a reply structure which |
113 | can have the following keys: |
115 | can have the following keys: |
114 | |
116 | |
115 | msgtype => "reply" |
|
|
116 | msg => $reply_text, |
117 | msg => $reply_text, |
117 | add_topics => [additional topic strings] |
118 | add_topics => [additional topic strings] |
118 | del_topics => [invalidated topic strings] |
119 | del_topics => [invalidated topic strings] |
119 | |
120 | |
120 | =cut |
121 | =cut |
121 | |
122 | |
122 | cf::register_extcmd npc_dialog_tell => sub { |
123 | cf::register_extcmd npc_dialog_tell => sub { |
123 | my ($pl, $msg) = @_; |
124 | my ($pl, $id, $msg) = @_; |
124 | |
125 | |
125 | if (my $dialog = $pl->{npc_dialog}) { |
126 | if (my $dialog = $pl->{npc_dialog}) { |
126 | dialog_tell $msg->{msgid}, $dialog, $msg->{msg}; |
127 | dialog_tell $id, $dialog, $msg; |
127 | } |
128 | } |
128 | |
|
|
129 | () |
|
|
130 | }; |
129 | }; |
131 | |
130 | |
132 | =item extcmd npc_dialog_end { msgid => $id } |
131 | =item extcmd npc_dialog_end { msgid => $id } |
133 | |
132 | |
134 | Finishes the dialog, invalidating the handle. |
133 | Finishes the dialog, invalidating the handle. |
135 | |
134 | |
136 | =cut |
135 | =cut |
137 | |
136 | |
138 | cf::register_extcmd npc_dialog_end => sub { |
137 | cf::register_extcmd npc_dialog_end => sub { |
139 | my ($pl, $msg) = @_; |
138 | my ($pl, $id) = @_; |
140 | |
139 | |
141 | if (my $dialog = delete $pl->{npc_dialog}) { |
140 | if (my $dialog = delete $pl->{npc_dialog}) { |
142 | $pl->detach ("ncpa_dialog_active"); |
141 | $pl->detach ("ncp_dialog_active"); |
143 | } |
142 | } |
144 | |
|
|
145 | () |
|
|
146 | }; |
143 | }; |
147 | |
144 | |
148 | =item ... = extcmd editor_support |
145 | =item ... = extcmd editor_support |
149 | |
146 | |
150 | Returns the value required by clients that have an editor to download and |
147 | Returns the value required by clients that have an editor to download and |
… | |
… | |
172 | cf_password: crossfire server password, optionally used for authentication purposes |
169 | cf_password: crossfire server password, optionally used for authentication purposes |
173 | |
170 | |
174 | =cut |
171 | =cut |
175 | |
172 | |
176 | cf::register_extcmd editor_support => sub { |
173 | cf::register_extcmd editor_support => sub { |
177 | my ($pl, $msg) = @_; |
174 | my ($pl, %msg) = @_; |
178 | |
175 | |
179 | map +($_ => $cf::CFG{"editor_$_"}), qw(servertype gameserver testserver cvs_root lib_root builder_ui) |
176 | map +($_ => $cf::CFG{"editor_$_"}), qw(servertype gameserver testserver cvs_root lib_root builder_ui) |
180 | }; |
177 | }; |
181 | |
178 | |
182 | sub unload { |
179 | sub unload { |
183 | for my $pl (cf::player::list) { |
180 | for my $pl (cf::player::list) { |
184 | if (my $dialog = delete $pl->{npc_dialog}) { |
181 | if (my $dialog = delete $pl->{npc_dialog}) { |
185 | $pl->detach ("npc_dialog_active"); |
182 | $pl->detach ("npc_dialog_active"); |
186 | $pl->ext_reply ($dialog->{id} => msgtype => "error", msg => "npc dialogue module was reloaded"); |
183 | $pl->ext_msg ($dialog->{id} => error => "npc dialogue module was reloaded"); |
187 | } |
184 | } |
188 | } |
185 | } |
189 | } |
186 | } |
190 | |
187 | |
191 | cf::player::attachment npc_dialog_active => |
188 | cf::player::attachment npc_dialog_active => |
… | |
… | |
196 | $pl->detach ("npc_dialog_active"); |
193 | $pl->detach ("npc_dialog_active"); |
197 | }, |
194 | }, |
198 | on_move => sub { |
195 | on_move => sub { |
199 | my ($pl, $dir) = @_; |
196 | my ($pl, $dir) = @_; |
200 | |
197 | |
|
|
198 | # must delay a bit :/ |
|
|
199 | my $delay; $delay = EV::timer 0, 0, sub { |
|
|
200 | undef $delay; |
|
|
201 | |
201 | if (my $dialog = $pl->{npc_dialog}) { |
202 | if (my $dialog = $pl->{npc_dialog}) { |
202 | warn "on_move<@_>\n";#d# |
|
|
203 | warn $pl->ob; |
|
|
204 | warn $dialog; |
|
|
205 | warn $dialog->{npc}; |
|
|
206 | warn $dialog->{npc}->is_valid; |
|
|
207 | |
|
|
208 | my (undef, $dx, $dy) = $pl->ob->rangevector ($dialog->{npc}); |
203 | my (undef, $dx, $dy) = $pl->ob->rangevector ($dialog->{npc}); |
209 | |
204 | |
210 | return if (abs $dx) <= 2 && (abs $dy) <= 2; |
205 | return if (abs $dx) <= 2 && (abs $dy) <= 2; |
211 | |
206 | |
212 | $pl->ext_reply ($dialog->{id} => msgtype => "error", msg => "out of range"); |
207 | $pl->ext_msg ($dialog->{id} => error => "out of range"); |
213 | } |
208 | } |
214 | |
209 | |
215 | delete $pl->{npc_dialog}; |
210 | delete $pl->{npc_dialog}; |
216 | $pl->detach ("npc_dialog_active"); |
211 | $pl->detach ("npc_dialog_active"); |
|
|
212 | }; |
217 | }, |
213 | }, |
218 | ; |
214 | ; |
219 | |
215 | |
220 | cf::player->attach ( |
216 | cf::player->attach ( |
221 | on_login => sub { |
217 | on_login => sub { |