--- deliantra/Deliantra-Client/DC/Protocol.pm 2006/06/07 07:00:30 1.27
+++ deliantra/Deliantra-Client/DC/Protocol.pm 2006/06/18 17:13:11 1.38
@@ -10,6 +10,8 @@
use base 'Crossfire::Protocol::Base';
+our %open_logs;
+
sub new {
my $class = shift;
@@ -61,6 +63,28 @@
$self
}
+sub logprint {
+ my ($self, @a) = @_;
+ my $filename = "$Crossfire::VARDIR/log.$self->{host}";
+
+ my $fh = $open_logs{$filename};
+ unless ($fh) {
+ # FIXME: handle this more gracefully?
+ open $fh, ">>", $filename
+ or die "Couldn't open logfile: log.$self->{host}: $!";
+
+ $open_logs{$filename} = $fh;
+ }
+
+ my ($sec, $min, $hour, $mday, $mon, $year) = localtime (time);
+
+ my $ts = sprintf "%04d-%02d-%02d %02d:%02d:%02d",
+ $year + 1900, $mon + 1, $mday, $hour, $min, $sec;
+
+ print $fh "$ts ", @a, "\n";
+ $fh->flush;
+}
+
sub stats_update {
my ($self, $stats) = @_;
@@ -81,6 +105,7 @@
push @{$self->{record}}, $command;
}
+ $self->logprint ("send: ", $command);
$self->send_command ($command);
::status $command;
}
@@ -109,6 +134,12 @@
$self->{map_widget}->update;
}
+sub magicmap {
+ my ($self, $w, $h, $x, $y, $data) = @_;
+
+ $self->{map_widget}->set_magicmap ($w, $h, $x, $y, $data);
+}
+
sub flush_map {
my ($self) = @_;
@@ -129,6 +160,7 @@
delete $self->{neigh_map};
$self->{map}->clear;
+ delete $self->{map_widget}{magicmap};
}
@@ -281,7 +313,7 @@
my $txn = $CFClient::DB_ENV->txn_begin;
my $status = $self->{facemap}->db_get (id => $id);
if ($status == 0 || $status == BerkeleyDB::DB_NOTFOUND) {
- $id = ($id || 16) + 1;
+ $id = ($id || 64) + 1;
if ($self->{facemap}->put (id => $id) == 0
&& $self->{facemap}->put ($hash => $id) == 0) {
$txn->txn_commit;
@@ -371,6 +403,8 @@
[0.74, 0.65, 0.41],
);
+ $self->logprint ("info: ", $text);
+
my $time = sprintf "%02d:%02d:%02d", (localtime time)[2,1,0];
# try to create single paragraphs of multiple lines sent by the server
@@ -502,8 +536,8 @@
$row++;
} else {
$::FLOORBOX->add (1, $row, new CFClient::UI::Button
- text => "More...",
- on_activate => sub { $::INV_WINDOW->toggle_visibility },
+ text => "More...",
+ on_activate => sub { $::INV_WINDOW->toggle_visibility; 0 },
);
last;
}
@@ -528,6 +562,7 @@
$::CONN->send ("apply $tag") # $::CONN->{open_container}")
if $tag != 0;
#if $CONN->{open_container} != 0;
+ 0
},
);
}
@@ -625,11 +660,194 @@
my ($self, $player) = @_;
$::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_support => "1", sub {
+ $self->{cfplus_ext} = $_[0];
+ $self->update_server_info;
+ });
+
+ $self->update_server_info;
- # do it here because it is ignored earlier, and there is no "login" event
$self->send_command ("output-sync $::CFG->{output_sync}");
$self->send_command ("output-count $::CFG->{output_count}");
- $self->send_command ("pickup $::CFG->{pickup}")
+ $self->send_command ("pickup $::CFG->{pickup}");
+}
+
+sub lookat {
+ my ($self, $x, $y) = @_;
+
+ 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);
+
+ 0
+ },
+ );
+
+ $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; 0 },
+ ;
+
+ $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}->grab_focus;
+
+ $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);
+ 0
+ },
+ );
+ }
+}
+
+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;