… | |
… | |
8 | my ($token, $client_version) = split / /, $data, 2; |
8 | my ($token, $client_version) = split / /, $data, 2; |
9 | |
9 | |
10 | $pl->send ("ext $token 1"); |
10 | $pl->send ("ext $token 1"); |
11 | }; |
11 | }; |
12 | |
12 | |
|
|
13 | { |
|
|
14 | package NPC_Dialogue; |
|
|
15 | |
|
|
16 | sub has_dialogue { |
|
|
17 | my ($ob) = @_; |
|
|
18 | |
|
|
19 | $ob->get_message =~ /^\@match /; |
|
|
20 | } |
|
|
21 | |
13 | sub parse_message($) { |
22 | sub parse_message($) { |
14 | map [split /\n/, $_, 2], |
23 | map [split /\n/, $_, 2], |
15 | grep length, |
24 | grep length, |
16 | split /^\@match /m, |
25 | split /^\@match /m, |
17 | $_[0] |
26 | $_[0] |
|
|
27 | } |
|
|
28 | |
|
|
29 | sub new { |
|
|
30 | my ($class, %arg) = @_; |
|
|
31 | |
|
|
32 | my $self = bless { |
|
|
33 | %arg, |
|
|
34 | }, $class; |
|
|
35 | |
|
|
36 | $self->{match} ||= [parse_message $self->{npc}->get_message]; |
|
|
37 | |
|
|
38 | $self; |
|
|
39 | } |
|
|
40 | |
|
|
41 | sub greet { |
|
|
42 | my ($self) = @_; |
|
|
43 | |
|
|
44 | $self->tell ("hi") |
|
|
45 | } |
|
|
46 | |
|
|
47 | sub tell { |
|
|
48 | my ($self, $msg) = @_; |
|
|
49 | |
|
|
50 | for my $match (@{ $self->{match} }) { |
|
|
51 | for (split /\|/, $match->[0]) { |
|
|
52 | if ($_ eq "*" || 0 <= index $msg, $_) { |
|
|
53 | my $reply = $match->[1]; |
|
|
54 | |
|
|
55 | # combine lines into paragraphs |
|
|
56 | $reply =~ s/(?<=\S)\n(?=\w)/ /g; |
|
|
57 | $reply =~ s/\n\n/\n/g; |
|
|
58 | |
|
|
59 | my @kw; |
|
|
60 | # now mark up all matching keywords |
|
|
61 | for my $match (@{ $self->{match} }) { |
|
|
62 | for (sort { (length $b) <=> (length $a) } split /\|/, $match->[0]) { |
|
|
63 | if ($reply =~ /\b\Q$_\E\b/i) { |
|
|
64 | push @kw, $_; |
|
|
65 | last; |
|
|
66 | } |
|
|
67 | } |
|
|
68 | } |
|
|
69 | |
|
|
70 | return wantarray ? ($reply, @kw) : $reply; |
|
|
71 | } |
|
|
72 | } |
|
|
73 | } |
|
|
74 | } |
|
|
75 | |
|
|
76 | () |
18 | } |
77 | } |
19 | |
78 | |
20 | my %dialog; # currently active dialogs |
79 | my %dialog; # currently active dialogs |
21 | |
80 | |
22 | sub dialog_tell { |
81 | sub dialog_tell { |
23 | my ($dialog, $msg) = @_; |
82 | my ($token, $dialog, $msg) = @_; |
24 | |
83 | |
25 | my $pl = cf::player::find $dialog->{name}; |
84 | my $pl = $dialog->{ob}->contr; |
26 | |
85 | my ($reply, @kw) = $dialog->tell ($msg); |
27 | for my $match (@{ $dialog->{match} }) { |
86 | $reply = "..." unless $reply; |
28 | for (split /\|/, $match->[0]) { |
|
|
29 | if ($_ eq "*" || 0 <= index $msg, $_) { |
|
|
30 | my $reply = $match->[1]; |
|
|
31 | |
|
|
32 | # combine lines into paragraphs |
|
|
33 | $reply =~ s/(?<=\S)\n(?=\w)/ /g; |
|
|
34 | $reply =~ s/\n\n/\n/g; |
|
|
35 | |
|
|
36 | my @kw; |
|
|
37 | # now mark up all matching keywords |
|
|
38 | for my $match (@{ $dialog->{match} }) { |
|
|
39 | for (sort { (length $b) <=> (length $a) } split /\|/, $match->[0]) { |
|
|
40 | if ($reply =~ /\b\Q$_\E\b/i) { |
|
|
41 | push @kw, $_; |
|
|
42 | last; |
|
|
43 | } |
|
|
44 | } |
|
|
45 | } |
|
|
46 | |
|
|
47 | $pl->send ("ext $dialog->{token} msg " . join "\x00", $reply, @kw); |
87 | $pl->send ("ext $token msg " . join "\x00", $reply, @kw); |
48 | return; |
|
|
49 | } |
|
|
50 | } |
|
|
51 | } |
|
|
52 | |
|
|
53 | $pl->send ("ext $dialog->{token} msg ..."); |
|
|
54 | } |
88 | } |
55 | |
89 | |
56 | # return "interesting" information about the given tile |
90 | # return "interesting" information about the given tile |
57 | # currently only returns the npc_dialog title when a dialog is possible |
91 | # currently only returns the npc_dialog title when a dialog is possible |
58 | cf::register_extcmd lookat => sub { |
92 | cf::register_extcmd lookat => sub { |
59 | my ($pl, $data) = @_; |
93 | my ($pl, $data) = @_; |
60 | |
94 | |
61 | my ($token, $dx, $dy) = split / /, $data; |
95 | my ($token, $dx, $dy) = split / /, $data; |
|
|
96 | my $near = (abs $dx) <= 2 && (abs $dy) <= 2; |
62 | |
97 | |
63 | my %res; |
98 | my %res; |
64 | |
|
|
65 | my $near = (abs $dx) <= 2 && (abs $dy) <= 2; |
|
|
66 | |
99 | |
67 | if ($pl->cell_visible ($dx, $dy)) { |
100 | if ($pl->cell_visible ($dx, $dy)) { |
68 | for my $ob ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) { |
101 | for my $ob ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) { |
69 | $res{npc_dialog} = $ob->name |
102 | $res{npc_dialog} = $ob->name |
70 | if $near && $ob->message =~ /^\@match /; |
103 | if $near && NPC_Dialogue::has_dialogue $ob; |
71 | } |
104 | } |
72 | } |
105 | } |
73 | |
106 | |
74 | $pl->send ("ext $token " . join "\x00", %res); |
107 | $pl->send ("ext $token " . join "\x00", %res); |
75 | }; |
108 | }; |
… | |
… | |
81 | |
114 | |
82 | return unless (abs $dx) <= 2 && (abs $dy) <= 2; |
115 | return unless (abs $dx) <= 2 && (abs $dy) <= 2; |
83 | return unless $pl->cell_visible ($dx, $dy); |
116 | return unless $pl->cell_visible ($dx, $dy); |
84 | |
117 | |
85 | for my $npc ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) { |
118 | for my $npc ($pl->ob->map->at ($pl->ob->x + $dx, $pl->ob->y + $dy)) { |
86 | if (my @match = parse_message $npc->get_message) { |
119 | if (NPC_Dialogue::has_dialogue $npc) { |
87 | $dialog{$token} = { |
120 | $dialog{$token} = new NPC_Dialogue ob => $pl->ob, npc => $npc; |
88 | name => $pl->ob->name, |
|
|
89 | token => $token, |
|
|
90 | npc => $npc, |
|
|
91 | match => \@match, |
|
|
92 | }; |
|
|
93 | |
|
|
94 | dialog_tell $dialog{$token}, "hi"; |
121 | dialog_tell $token, $dialog{$token}, "hi"; |
95 | return; |
122 | return; |
96 | } |
123 | } |
97 | } |
124 | } |
98 | |
125 | |
99 | $pl->send ("ext $token error"); |
126 | $pl->send ("ext $token error"); |
… | |
… | |
102 | cf::register_extcmd npc_dialog_tell => sub { |
129 | cf::register_extcmd npc_dialog_tell => sub { |
103 | my ($pl, $data) = @_; |
130 | my ($pl, $data) = @_; |
104 | |
131 | |
105 | my ($token, $msg) = split / /, $data, 2; |
132 | my ($token, $msg) = split / /, $data, 2; |
106 | |
133 | |
107 | dialog_tell $dialog{$token}, $msg |
134 | dialog_tell $token, $dialog{$token}, $msg |
108 | if $dialog{$token}; |
135 | if $dialog{$token}; |
109 | }; |
136 | }; |
110 | |
137 | |
111 | cf::register_extcmd npc_dialog_end => sub { |
138 | cf::register_extcmd npc_dialog_end => sub { |
112 | my ($pl, $token) = @_; |
139 | my ($pl, $token) = @_; |
113 | |
140 | |
114 | delete $dialog{$token}; |
141 | delete $dialog{$token}; |
115 | }; |
142 | }; |
116 | |
143 | |
|
|
144 | sub on_logout { |
|
|
145 | my ($pl, $host) = @_; |
|
|
146 | |
|
|
147 | delete $dialog{$_} for grep $pl->ob == $dialog{$_}{ob}, keys %dialog; |
|
|
148 | |
|
|
149 | 0 |
|
|
150 | } |
|
|
151 | |
117 | sub on_clock { |
152 | sub on_clock { |
118 | return 0 unless %dialog; |
153 | return 0 unless %dialog; |
119 | |
154 | |
120 | while (my ($token, $dialog) = each %dialog) { |
155 | while (my ($token, $dialog) = each %dialog) { |
121 | if (my $pl = cf::player::find $dialog->{name}) { |
|
|
122 | my (undef, $dx, $dy) = $pl->ob->rangevector ($dialog->{npc}); |
156 | my (undef, $dx, $dy) = $dialog->{ob}->rangevector ($dialog->{npc}); |
123 | next if (abs $dx) <= 2 && (abs $dy) <= 2; |
157 | next if (abs $dx) <= 2 && (abs $dy) <= 2; |
124 | |
158 | |
125 | $pl->send ("ext $token out_of_range"); |
159 | $dialog->{ob}->contr->send ("ext $token out_of_range"); |
126 | } |
|
|
127 | delete $dialog{$token}; |
160 | delete $dialog{$token}; |
128 | } |
161 | } |
129 | |
162 | |
130 | 0 |
163 | 0 |
131 | } |
164 | } |