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

Comparing deliantra/maps/perl/NPC_Dialogue.pm (file contents):
Revision 1.8 by root, Thu Jul 20 04:28:26 2006 UTC vs.
Revision 1.9 by root, Fri Jul 21 00:25:29 2006 UTC

84 84
85=item $msg - The actual message as passed to this method. 85=item $msg - The actual message as passed to this method.
86 86
87=item $match - An arrayref with previous results from C<@parse>. 87=item $match - An arrayref with previous results from C<@parse>.
88 88
89=item $state - A hashref that stores state variables associated
90with the NPC and the player, that is, it's values relate to the the
91specific player-NPC interaction and other players will see a different
92state. Useful to react to players in a stateful way. See C<@setstate> and
93C<@ifstate>.
94
95=item $flag - A hashref that stores flags associated with the player and
96can be seen by all NPCs (so better name your flags uniquely). This is
97useful for storing e.g. quest information. See C<@setflag> and C<@ifflag>.
98
89=back 99=back
90 100
91The environment is that standard "map scripting environment", which is 101The environment is that standard "map scripting environment", which is
92limited in the type of constructs allowed (no loops, for example). 102limited in the type of constructs allowed (no loops, for example).
93 103
94=item @eval perl 104=item @eval perl
95 105
96Like C<@cond>, but proceed regardless of the outcome. 106Like C<@cond>, but proceed regardless of the outcome.
97 107
108=item @msg perl
109
110Like C<@cond>, but the return value will be stringified and prepended to
111the message.
112
113=item @setstate state value
114
115Sets the named state C<state> to the given C<value>. State values are
116associated with a specific player-NPC pair, so each NPC has its own state
117with respect to a particular player, which makes them useful to store
118information about previous questions and possibly answers. State values
119get reset whenever the NPC gets reset.
120
121See C<@ifstate> for an example.
122
123=item @ifstate state value
124
125Requires that the named C<state> has the given C<value>, otherwise this
126topic is skipped. For more complex comparisons, see C<@cond> with
127C<$state>. Example:
128
129 @match quest
130 @setstate question quest
131 Do you really want to help find the magic amulet of Beeblebrox?
132 @match yes
133 @ifstate question quest
134 Then fetch it, stupid!
135
136=item @setflag flag value
137
138Sets the named flag C<flag> to the given C<value>. Flag values are
139associated with a specific player and can be seen by all NPCs. with
140respect to a particular player, which makes them suitable to store quest
141markers and other information (e.g. reputation/alignment). Flags are
142persistent over the lifetime of a player, so be careful :)
143
144See C<@ifflag> for an example.
145
146=item @ifflag flag value
147
148Requires that the named C<flag> has the given C<value>, otherwise this
149topic is skipped. For more complex comparisons, see C<@cond> with
150C<$flag>. Example:
151
152 @match I want to do the quest!
153 @setflag kings_quest 1
154 Then seek out Bumblebee in Navar, he will tell you...
155 @match I did the quest
156 @ifflag kings_quest 1
157 Really, which quets?
158
159And Bumblebee might have:
160
161 @match hi
162 @ifflag kings_quest
163 Hi, I was told you want to do the kings quest?
164
98=item @trigger connected-id 165=item @trigger connected-id
99 166
100Trigger all objects with the given connected-id. The trigger is stateful 167Trigger all objects with the given connected-id. The trigger is stateful
101and retains state per connected-id. 168and retains state per connected-id.
102 169
112sub tell { 179sub tell {
113 my ($self, $msg) = @_; 180 my ($self, $msg) = @_;
114 181
115 my $lcmsg = lc $msg; 182 my $lcmsg = lc $msg;
116 183
117 match: 184 topic:
118 for my $match (@{ $self->{match} }) { 185 for my $match (@{ $self->{match} }) {
119 for (split /\|/, $match->[0]) { 186 for (split /\|/, $match->[0]) {
120 if ($_ eq "*" || $lcmsg eq lc) { 187 if ($_ eq "*" || $lcmsg eq lc) {
121 my $reply = $match->[1]; 188 my $reply = $match->[1];
122 my @kw; 189 my @kw;
123 190
124 my @replies; 191 my @replies;
125 my @match; # @match/@parse command results 192 my @match; # @match/@parse command results
193
194 my $state = $self->{npc}{$self->{ob}->name}{dialog_state} ||= {};
195 my $flag = $self->{ob}{dialog_flag} ||= {};
196
197 my %vars = (
198 who => $self->{ob},
199 npc => $self->{npc},
200 state => $state,
201 flag => $flag,
202 msg => $msg,
203 match => \@match,
204 );
205
126 local $self->{ob}{record_replies} = \@replies; 206 local $self->{ob}{record_replies} = \@replies;
127 207
128 # now execute @-commands (which can result in a no-match) 208 # now execute @-commands (which can result in a no-match)
129 while ($reply =~ s/^\@(\w+)\s*([^\n]*)\n?//) { 209 while ($reply =~ s/^\@(\w+)\s*([^\n]*)\n?//) {
130 my ($cmd, $args) = ($1, $2); 210 my ($cmd, $args) = ($1, $2);
131 211
132 if ($cmd eq "parse" || $cmd eq "match") { # match is future rename 212 if ($cmd eq "parse" || $cmd eq "match") { # match is future rename
133 no re 'eval'; # default, but make sure 213 no re 'eval'; # default, but make sure
134 @match = $msg =~ /$args/i 214 @match = $msg =~ /$args/i
135 or next match; 215 or next topic;
136 216
137 } elsif ($cmd eq "cond") { 217 } elsif ($cmd eq "cond") {
138 cf::safe_eval $args, who => $self->{ob}, npc => $self->{npc}, msg => $msg, match => \@match 218 cf::safe_eval $args, %vars
139 or next match; 219 or next topic;
140 220
141 } elsif ($cmd eq "eval") { 221 } elsif ($cmd eq "eval") {
142 cf::safe_eval $args, who => $self->{ob}, npc => $self->{npc}, msg => $msg, match => \@match; 222 cf::safe_eval $args, %vars;
143 warn "\@eval evaluation error: $@\n" if $@; 223 warn "\@eval evaluation error: $@\n" if $@;
224
225 } elsif ($cmd eq "msg") {
226 push @replies, [$self->{npc}, (scalar cf::safe_eval $args, %vars)];
227
228 } elsif ($cmd eq "setflag") {
229 my ($name, $value) = split /\s+/, $args, 2;
230 $value ? $flag->{$name} = $value
231 : delete $flag->{$name};
232
233 } elsif ($cmd eq "setstate") {
234 my ($name, $value) = split /\s+/, $args, 2;
235 $value ? $state->{$name} = $value
236 : delete $state->{$name};
237
238 } elsif ($cmd eq "ifflag") {
239 my ($name, $value) = split /\s+/, $args, 2;
240 $flag->{$name} eq $value
241 or next topic;
242
243 } elsif ($cmd eq "ifstate") {
244 my ($name, $value) = split /\s+/, $args, 2;
245 $state->{$name} eq $value
246 or next topic;
144 247
145 } elsif ($cmd eq "trigger") { 248 } elsif ($cmd eq "trigger") {
146 my $rvalue = \$self->{npc}{dialog_trigger}{$args*1}; 249 my $rvalue = \$self->{npc}{dialog_trigger}{$args*1};
147 250
148 my $trigger = cf::object::new "magic_ear"; 251 my $trigger = cf::object::new "magic_ear";
162 265
163 $$rvalue = !$$rvalue; 266 $$rvalue = !$$rvalue;
164 267
165 } elsif ($cmd eq "addtopic") { 268 } elsif ($cmd eq "addtopic") {
166 push @kw, split /\|/, $args; 269 push @kw, split /\|/, $args;
270 $self->{add_topic}->(split /\s*\|\s*/, $args) if $self->{add_topic};
271
272 } elsif ($cmd eq "deltopic") {
273 # not yet implemented, do it out-of-band
274 $self->{del_topic}->(split /\s*\|\s*/, $args) if $self->{del_topic};
167 275
168 } else { 276 } else {
169 warn "unknown dialogue command <$cmd,$args> used (from " . $self->{npc}->get_message . ")"; 277 warn "unknown dialogue command <$cmd,$args> used (from " . $self->{npc}->get_message . ")";
170 } 278 }
171 } 279 }
280
281 delete $self->{npc}{$self->{ob}->name}{dialog_state} unless %$state;
282 delete $self->{ob}{dialog_flag} unless %$flag;
172 283
173 # combine lines into paragraphs 284 # combine lines into paragraphs
174 $reply =~ s/(?<=\S)\n(?=\w)/ /g; 285 $reply =~ s/(?<=\S)\n(?=\w)/ /g;
175 $reply =~ s/\n\n/\n/g; 286 $reply =~ s/\n\n/\n/g;
176 287

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines