ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/ext/NPC_Dialogue.pm
(Generate patch)

Comparing deliantra/server/ext/NPC_Dialogue.pm (file contents):
Revision 1.10 by root, Mon Jul 14 23:57:45 2008 UTC vs.
Revision 1.20 by root, Fri Mar 19 21:40:39 2010 UTC

96 96
97=item $flag - A hashref that stores flags associated with the player and 97=item $flag - A hashref that stores flags associated with the player and
98can be seen by all NPCs (so better name your flags uniquely). This is 98can be seen by all NPCs (so better name your flags uniquely). This is
99useful for storing e.g. quest information. See C<@setflag> and C<@ifflag>. 99useful for storing e.g. quest information. See C<@setflag> and C<@ifflag>.
100 100
101=item $find - see @find, below.
102
101=back 103=back
102 104
103The environment is that standard "map scripting environment", which is 105The environment is that standard "map scripting environment", which is
104limited in the type of constructs allowed (no loops, for example). 106limited in the type of constructs allowed (no loops, for example).
105 107
138Like C<@cond>, but proceed regardless of the outcome. 140Like C<@cond>, but proceed regardless of the outcome.
139 141
140=item @msg perl 142=item @msg perl
141 143
142Like C<@cond>, but the return value will be stringified and prepended to 144Like C<@cond>, but the return value will be stringified and prepended to
143the message. 145the reply message.
146
147=item @check match expression
148
149Executes a match expression (see
150http://pod.tst.eu/http://cvs.schmorp.de/deliantra/server/lib/cf/match.pm)
151to see if it matches.
152
153C<self> is the npc object, C<object>, C<source> and C<originator> are the
154player communicating with the NPC.
155
156If the check fails, the match is skipped.
157
158=item @find match expression
159
160Like C<@check> in that it executes a match expression, but instead of
161failing, it gathers all objects into an array and provides a reference to
162the array in the C<$find> variable.
163
164When you want to skip the match when no objects have been found, combine
165C<@find> with C<@cond>:
166
167 @match see my spellbook
168 @find type=SPELLBOOK in inv
169 @cond @$find
170 It looks dirty.
171 @match see my spellbook
172 I can't see any, where do you have it?
144 173
145=item @setstate state value 174=item @setstate state value
146 175
147Sets the named state C<state> to the given C<value>. State values are 176Sets the named state C<state> to the given C<value>. State values are
148associated with a specific player-NPC pair, so each NPC has its own state 177associated with a specific player-NPC pair, so each NPC has its own state
153See C<@ifstate> for an example. 182See C<@ifstate> for an example.
154 183
155=item @ifstate state value 184=item @ifstate state value
156 185
157Requires that the named C<state> has the given C<value>, otherwise this 186Requires that the named C<state> has the given C<value>, otherwise this
158topic is skipped. For more complex comparisons, see C<@cond> with 187topic is skipped. For more complex comparisons, see C<@cond> with
159C<$state>. Example: 188C<$state>. Example:
160 189
161 @match quest 190 @match quest
162 @setstate question quest 191 @setstate question quest
163 Do you really want to help find the magic amulet of Beeblebrox? 192 Do you really want to help find the magic amulet of Beeblebrox?
171associated with a specific player and can be seen by all NPCs. with 200associated with a specific player and can be seen by all NPCs. with
172respect to a particular player, which makes them suitable to store quest 201respect to a particular player, which makes them suitable to store quest
173markers and other information (e.g. reputation/alignment). Flags are 202markers and other information (e.g. reputation/alignment). Flags are
174persistent over the lifetime of a player, so be careful :) 203persistent over the lifetime of a player, so be careful :)
175 204
205Perversely enough, using C<@setfflag> without a C<value> clears the flag
206as if it was never set, so always provide a flag value (e.g. C<1>) when
207you want to set the flag.
208
176See C<@ifflag> for an example. 209See C<@ifflag> for an example.
177 210
178=item @ifflag flag value 211=item @ifflag flag value
179 212
180Requires that the named C<flag> has the given C<value>, otherwise this 213Requires that the named C<flag> has the given C<value>, otherwise this
181topic is skipped. For more complex comparisons, see C<@cond> with 214topic is skipped. For more complex comparisons, see C<@cond> with
182C<$flag>. Example: 215C<$flag>.
216
217If no C<value> is given, then the ifflag succeeds when the flag is true.
218
219Example:
183 220
184 @match I want to do the quest! 221 @match I want to do the quest!
185 @setflag kings_quest 1 222 @setflag kings_quest 1
186 Then seek out Bumblebee in Navar, he will tell you... 223 Then seek out Bumblebee in Navar, he will tell you...
187 @match I did the quest 224 @match I did the quest
201When the state argument is omitted the trigger is stateful and retains an 238When the state argument is omitted the trigger is stateful and retains an
202internal state per connected-id. There is a limitation to the use of this: The 239internal state per connected-id. There is a limitation to the use of this: The
203state won't be changed when the connection is triggered by other triggers. So 240state won't be changed when the connection is triggered by other triggers. So
204be careful when triggering the connection from other objects. 241be careful when triggering the connection from other objects.
205 242
206When a state argument is given it should be either 0 or 1. 1 will 'push' the connection 243When a state argument is given it should be a positive integer. Any value
207and 0 will 'release' the connection. This is useful for example when you want to 244C<!= 0> will 'push' the connection (in general, you should specify C<1>
208let a npc control a door. 245for this) and C<0> will 'release' the connection. This is useful for
246example when you want to let an NPC control a door.
209 247
210Trigger all objects with the given connected-id by 'releasing' the connection. 248Trigger all objects with the given connected-id by 'releasing' the connection.
211 249
212=item @playersound face-name 250=item @playersound face-name
213 251
244 my @replies; 282 my @replies;
245 my @match; # @match/@parse command results 283 my @match; # @match/@parse command results
246 284
247 my $state = $self->{npc}{$self->{ob}->name}{dialog_state} ||= {}; 285 my $state = $self->{npc}{$self->{ob}->name}{dialog_state} ||= {};
248 my $flag = $self->{ob}{dialog_flag} ||= {}; 286 my $flag = $self->{ob}{dialog_flag} ||= {};
287
288 my @find;
249 289
250 my %vars = ( 290 my %vars = (
251 who => $self->{ob}, 291 who => $self->{ob},
252 npc => $self->{npc}, 292 npc => $self->{npc},
253 state => $state, 293 state => $state,
254 flag => $flag, 294 flag => $flag,
255 msg => $msg, 295 msg => $msg,
256 match => \@match, 296 match => \@match,
297 find => \@find,
257 ); 298 );
258 299
259 local $self->{ob}{record_replies} = \@replies; 300 local $self->{ob}{record_replies} = \@replies;
260 301
261 # now execute @-commands (which can result in a no-match) 302 # now execute @-commands (which can result in a no-match)
282 323
283 } elsif ($cmd eq "eval") { 324 } elsif ($cmd eq "eval") {
284 cf::safe_eval $args, %vars; 325 cf::safe_eval $args, %vars;
285 warn "\@eval evaluation error: $@\n" if $@; 326 warn "\@eval evaluation error: $@\n" if $@;
286 327
328 } elsif ($cmd eq "check") {
329 eval {
330 cf::match::match $args, $self->{ob}, $self->{npc}, $self->{ob}
331 or next topic;
332 };
333 warn "\@check evaluation error: $@\n" if $@;
334
335 } elsif ($cmd eq "find") {
336 @find = eval {
337 cf::match::match $args, $self->{ob}, $self->{npc}, $self->{ob}
338 };
339 warn "\@find evaluation error: $@\n" if $@;
340
287 } elsif ($cmd eq "msg") { 341 } elsif ($cmd eq "msg") {
288 push @replies, [$self->{npc}, (scalar cf::safe_eval $args, %vars)]; 342 push @replies, [$self->{npc}, (scalar cf::safe_eval $args, %vars)];
289 343
290 } elsif ($cmd eq "setflag") { 344 } elsif ($cmd eq "setflag") {
291 my ($name, $value) = split /\s+/, $args, 2; 345 my ($name, $value) = split /\s+/, $args, 2;
292 $value ? $flag->{$name} = $value 346 defined $value ? $flag->{$name} = $value
293 : delete $flag->{$name}; 347 : delete $flag->{$name};
294 348
295 } elsif ($cmd eq "setstate") { 349 } elsif ($cmd eq "setstate") {
296 my ($name, $value) = split /\s+/, $args, 2; 350 my ($name, $value) = split /\s+/, $args, 2;
297 $value ? $state->{$name} = $value 351 defined $value ? $state->{$name} = $value
298 : delete $state->{$name}; 352 : delete $state->{$name};
299 353
300 } elsif ($cmd eq "ifflag") { 354 } elsif ($cmd eq "ifflag") {
301 my ($name, $value) = split /\s+/, $args, 2; 355 my ($name, $value) = split /\s+/, $args, 2;
302 $flag->{$name} eq $value 356 defined $value ? $flag->{$name} eq $value
357 : $flag->{$name}
303 or next topic; 358 or next topic;
304 359
305 } elsif ($cmd eq "ifstate") { 360 } elsif ($cmd eq "ifstate") {
306 my ($name, $value) = split /\s+/, $args, 2; 361 my ($name, $value) = split /\s+/, $args, 2;
307 $state->{$name} eq $value 362 defined $value ? $state->{$name} eq $value
363 : $state->{$name}
308 or next topic; 364 or next topic;
309 365
310 } elsif ($cmd eq "trigger") { 366 } elsif ($cmd eq "trigger") {
311 my ($con, $state) = split /\s+/, $args, 2; 367 my ($con, $state) = split /\s+/, $args, 2;
312 $con = $con * 1;
313 368
314 if (defined $state) { 369 if (defined $state) {
315 $self->{npc}->map->trigger ($args, $state); 370 $self->{npc}->map->trigger ($con, $state, $self->{npc}, $self->{ob});
316 } else { 371 } else {
317 my $rvalue = \$self->{npc}{dialog_trigger}{$con}; 372 my $rvalue = \$self->{npc}{dialog_trigger}{$con+0};
318 $self->{npc}->map->trigger ($con, $$rvalue = !$$rvalue); 373 $self->{npc}->map->trigger ($con, $$rvalue = !$$rvalue, $self->{npc}, $self->{ob});
319 } 374 }
320 375
321 } elsif ($cmd eq "addtopic") { 376 } elsif ($cmd eq "addtopic") {
322 push @kw, split /\|/, $args; 377 push @kw, split /\|/, $args;
323 $self->{add_topic}->(split /\s*\|\s*/, $args) if $self->{add_topic}; 378 $self->{add_topic}->(split /\s*\|\s*/, $args) if $self->{add_topic};
331 } 386 }
332 } 387 }
333 388
334 delete $self->{npc}{$self->{ob}->name}{dialog_state} unless %$state; 389 delete $self->{npc}{$self->{ob}->name}{dialog_state} unless %$state;
335 delete $self->{ob}{dialog_flag} unless %$flag; 390 delete $self->{ob}{dialog_flag} unless %$flag;
336
337 # combine lines into paragraphs
338 $reply =~ s/(?<=\S)\n(?=\w)/ /g;
339 $reply =~ s/\n\n/\n/g;
340 391
341 # ignores flags and npc from replies 392 # ignores flags and npc from replies
342 $reply = join "\n", (map $_->[1], @replies), $reply; 393 $reply = join "\n", (map $_->[1], @replies), $reply;
343 394
344 # now mark up all matching keywords 395 # now mark up all matching keywords
349 last; 400 last;
350 } 401 }
351 } 402 }
352 } 403 }
353 404
405 $self->{npc}->use_trigger ($self->{ob})
406 if $self->{npc}->type == cf::MAGIC_EAR;
407
354 return wantarray ? ($reply, @kw) : $reply; 408 return wantarray ? ($reply, @kw) : $reply;
355 } 409 }
356 } 410 }
357 } 411 }
358 412

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines