#! perl # additional support for cfplus client cf::register_extcmd cfplus_support => sub { my ($pl, $data) = @_; my ($token, $client_version) = split / /, $data, 2; $pl->send ("ext $token 1"); }; sub parse_message($) { map [split /\n/, $_, 2], grep length, split /^\@match /m, $_[0] } my %dialog; # currently active dialogs sub dialog_tell { my ($dialog, $msg) = @_; my $pl = cf::player::find $dialog->{name}; for my $match (@{ $dialog->{match} }) { for (split /\|/, $match->[0]) { if ($_ eq "*" || 0 <= index $msg, $_) { my $reply = $match->[1]; # combine lines into paragraphs $reply =~ s/(?<=\S)\n(?=\w)/ /g; $reply =~ s/\n\n/\n/g; my @kw; # now mark up all matching keywords for my $match (@{ $dialog->{match} }) { for (sort { (length $b) <=> (length $a) } split /\|/, $match->[0]) { if ($reply =~ /\b\Q$_\E\b/i) { push @kw, $_; last; } } } $pl->send ("ext $dialog->{token} msg " . join "\x00", $reply, @kw); return; } } } $pl->send ("ext $dialog->{token} msg ..."); } # return "interesting" information about the given tile # currently only returns the npc_dialog title when a dialog is possible cf::register_extcmd lookat => sub { my ($pl, $data) = @_; my ($token, $dx, $dy) = split / /, $data; my %res; my $near = (abs $dx) <= 2 && (abs $dy) <= 2; if ($pl->cell_visible ($dx, $dy)) { for my $ob ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) { $res{npc_dialog} = $ob->name if $near && $ob->message =~ /^\@match /; } } $pl->send ("ext $token " . join "\x00", %res); }; cf::register_extcmd npc_dialog_begin => sub { my ($pl, $data) = @_; my ($token, $dx, $dy) = split / /, $data; return unless (abs $dx) <= 2 && (abs $dy) <= 2; return unless $pl->cell_visible ($dx, $dy); for my $npc ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) { if (my @match = parse_message $npc->get_message) { $dialog{$token} = { name => $pl->ob->name, token => $token, npc => $npc, match => \@match, }; dialog_tell $dialog{$token}, "hi"; return; } } $pl->send ("ext $token error"); }; cf::register_extcmd npc_dialog_tell => sub { my ($pl, $data) = @_; my ($token, $msg) = split / /, $data, 2; dialog_tell $dialog{$token}, $msg if $dialog{$token}; }; cf::register_extcmd npc_dialog_end => sub { my ($pl, $token) = @_; delete $dialog{$token}; }; sub on_clock { return 0 unless %dialog; while (my ($token, $dialog) = each %dialog) { if (my $pl = cf::player::find $dialog->{name}) { my (undef, $dx, $dy) = $pl->ob->rangevector ($dialog->{npc}); next if (abs $dx) <= 2 && (abs $dy) <= 2; $pl->send ("ext $token out_of_range"); } delete $dialog{$token}; } 0 }