=head1 NAME NPC_Dialogue =head1 DESCRIPTION NPC dialogue support module. =cut package NPC_Dialogue; use strict; sub has_dialogue($) { my ($ob) = @_; $ob->get_message =~ /^\@match /; } sub parse_message($) { map [split /\n/, $_, 2], grep length, split /^\@match /m, $_[0] } sub new { my ($class, %arg) = @_; my $self = bless { %arg, }, $class; $self->{match} ||= [parse_message $self->{npc}->get_message]; $self; } sub greet { my ($self) = @_; $self->tell ("hi") } sub tell { my ($self, $msg) = @_; my $lcmsg = lc $msg; match: for my $match (@{ $self->{match} }) { for (split /\|/, $match->[0]) { if ($_ eq "*" || $lcmsg eq lc) { my $reply = $match->[1]; # combine lines into paragraphs $reply =~ s/(?<=\S)\n(?=\w)/ /g; $reply =~ s/\n\n/\n/g; my @replies; my @match; # @match/@parse command results local $self->{ob}{record_replies} = \@replies; # now execute @-commands (which can result in a no-match) while ($reply =~ s/^\@(\w+)\s*([^\n]*)\n?//) { my ($cmd, $args) = ($1, $2); if ($cmd eq "parse" || $cmd eq "match") { # match is future rename no re 'eval'; # default, but make sure @match = $msg =~ /$args/i or next match; } elsif ($cmd eq "cond") { cf::safe_eval $args, who => $self->{ob}, npc => $self->{npc}, msg => $msg or next match; } elsif ($cmd eq "eval") { cf::safe_eval $args, who => $self->{ob}, npc => $self->{npc}, msg => $msg; warn "\@eval evaluation error: $@\n" if $@; } else { warn "unknown dialogue command <$cmd,$args> used (from " . $self->{npc}->get_message . ")"; } } # ignores flags and npc from replies $reply = join "\n", (map $_->[1], @replies), $reply; my @kw; # now mark up all matching keywords for my $match (@{ $self->{match} }) { for (sort { (length $b) <=> (length $a) } split /\|/, $match->[0]) { if ($reply =~ /\b\Q$_\E\b/i) { push @kw, $_; last; } } } return wantarray ? ($reply, @kw) : $reply; } } } () } 1