--- deliantra/Deliantra-Client/DC/Protocol.pm 2006/06/11 18:41:30 1.30
+++ deliantra/Deliantra-Client/DC/Protocol.pm 2006/06/12 14:06:27 1.33
@@ -627,27 +627,189 @@
$::STATWIDS->{weight}->set_text (sprintf "Weight: %.1fkg", $player->{weight} / 1000);
}
+sub update_server_info {
+ my ($self) = @_;
+
+ my @yesno = ("no", "yes");
+
+ $::SERVER_INFO->set_markup (
+ "server $self->{host}:$self->{port}\n"
+ . "protocol version $self->{version}\n"
+ . "minimap support $yesno[$self->{setup}{mapinfocmd} > 0]\n"
+ . "extended command support $yesno[$self->{setup}{extcmd} > 0]\n"
+ . "cfplus support $yesno[$self->{cfplus_ext} > 0]"
+ . ($self->{cfplus_ext} > 0 ? ", version $self->{cfplus_ext}" : "") ."\n"
+ . "map size $self->{mapw}×$self->{maph}\n"
+ );
+}
+
sub logged_in {
my ($self) = @_;
- $self->send_ext_req (cfplus => "version", "1", sub {
+ $self->send_ext_req (cfplus_support => "1", sub {
$self->{cfplus_ext} = $_[0];
+ $self->update_server_info;
});
+ $self->update_server_info;
+
$self->send_command ("output-sync $::CFG->{output_sync}");
$self->send_command ("output-count $::CFG->{output_count}");
$self->send_command ("pickup $::CFG->{pickup}");
+}
- my @yesno = ("no", "yes");
+sub lookat {
+ my ($self, $x, $y) = @_;
- $::SERVER_INFO->set_markup (
- "server $self->{host}:$self->{port}\n"
- . "protocol version $self->{version}\n"
- . "minimap support $yesno[$self->{setup}{mapinfocmd} > 0]\n"
- . "extended command support $yesno[$self->{setup}{extcmd} > 0]\n"
- . "cfplus support $yesno[$self->{cfplus_ext} > 0]\n"
- . "map size $self->{mapw}×$self->{maph}\n"
+ if ($self->{cfplus_ext}) {
+ $self->send_ext_req (lookat => "$x $y", sub {
+ my %res = split /\x00/, $_[0];
+
+ if (exists $res{npc_dialog}) {
+ # start npc chat dialog
+ $self->{npc_dialog} = new CFClient::NPCDialog::
+ dx => $x,
+ dy => $y,
+ title => "$res{npc_dialog} (NPC)",
+ conn => $self,
+ ;
+ }
+ });
+ }
+
+ $self->send ("lookat $x $y");
+}
+
+sub destroy {
+ my ($self) = @_;
+
+ $self->{npc_dialog}->destroy
+ if $self->{npc_dialog};
+
+ $self->SUPER::destroy;
+}
+
+package CFClient::NPCDialog;
+
+our @ISA = 'CFClient::UI::FancyFrame';
+
+sub new {
+ my $class = shift;
+
+ my $self = $class->SUPER::new (
+ x => 'center',
+ y => 'center',
+ name => "npc_dialog",
+ force_w => $::WIDTH * 0.7,
+ force_h => $::HEIGHT * 0.7,
+ title => "NPC Dialog",
+ kw => { hi => 0, yes => 0, no => 0 },
+ @_,
+ );
+
+ Scalar::Util::weaken (my $this = $self);
+
+ # better use a pane...
+ $self->add (my $hbox = new CFClient::UI::HBox);
+ $hbox->add ($self->{textview} = new CFClient::UI::TextScroller expand => 1);
+
+ $hbox->add (my $vbox = new CFClient::UI::VBox);
+
+ $vbox->add (new CFClient::UI::Label text => "Message Entry:");
+ $vbox->add ($self->{entry} = new CFClient::UI::Entry
+ tooltip => "Enter a message you want to tell the NPC and press return.\n\n"
+ . "Sometimes you have to tell an NPC something you cannot find out during "
+ . "a normal conversation (such as a password). In those cases you have to use "
+ . "this text entry. You can also enter responses manually instead of using the response "
+ . "buttons below.",
+ on_activate => sub {
+ my ($entry, $text) = @_;
+
+ return unless $text =~ /\S/;
+
+ $entry->set_text ("");
+ $this->send ($text);
+ },
);
+
+ $vbox->add ($self->{options} = new CFClient::UI::VBox);
+
+ $self->{close_button} = new CFClient::UI::Button
+ text => "Bye (close)",
+ tooltip => "Use this button to end talking to the NPC. This also closes the dialog window.",
+ on_activate => sub { $this->destroy },
+ ;
+
+ $self->update_options;
+
+ $self->{token} = $self->{conn}->ext_token;
+ $self->{conn}->connect_ext ($self->{token} => sub { $this->feed (@_) });
+ $self->{conn}->send ("ext npc_dialog_begin $self->{token} $self->{dx} $self->{dy}");
+
+ $self->{entry}->focus_in;
+
+ $self->{textview}->add_paragraph ([1, 1, 0, 1], "[starting conversation with $self->{title}]\n\n");
+
+ $self->show;
+ $self
+};
+
+sub update_options {
+ my ($self) = @_;
+
+ Scalar::Util::weaken $self;
+
+ $self->{options}->clear;
+ $self->{options}->add ($self->{close_button});
+
+ for my $kw (sort keys %{ $self->{kw} }) {
+ $self->{options}->add (new CFClient::UI::Button
+ text => $kw,
+ on_activate => sub {
+ $self->send ($kw);
+ },
+ );
+ }
+}
+
+sub feed {
+ my ($self, $data) = @_;
+
+ my ($type, $msg) = split / /, $data, 2;
+
+ if ($type eq "msg") {
+ my ($msg, @kw) = split /\x00/, $msg;
+ $self->{kw}{$_} = 1 for @kw;
+
+ $msg = CFClient::UI::Label::escape $msg;
+ my $match = join "|", map "\\b\Q$_\E\\b", sort { (length $b) <=> (length $a) } keys %{ $self->{kw} };
+ $msg =~ s/($match)/$1<\/span>/gi; # underline when http-ready, huh.
+
+ $self->{textview}->add_paragraph ([1, 1, 1, 1], "\n$msg");
+ $self->update_options;
+ } else {
+ $self->destroy;
+ }
+
+ 1
+}
+
+sub send {
+ my ($self, $msg) = @_;
+
+ $self->{conn}->send ("ext npc_dialog_tell $self->{token} $msg");
+ $self->{textview}->add_paragraph ([1, 1, 0, 1], "\n" . CFClient::UI::Label::escape $msg);
+}
+
+sub destroy {
+ my ($self) = @_;
+
+ #Carp::cluck "debug\n";#d# #todo# enable: destroyx gets called twice because scalar keys {} is 1
+
+ delete $self->{conn}{npc_dialog};
+ $self->{conn}->disconnect_ext ($self->{token});
+
+ $self->SUPER::destroy;
}
1;