--- deliantra/Deliantra-Client/DC.pm 2006/07/14 17:35:34 1.99 +++ deliantra/Deliantra-Client/DC.pm 2006/09/12 20:51:17 1.119 @@ -1,10 +1,10 @@ =head1 NAME -CFClient - undocumented utility garbage for our crossfire client +CFPlus - undocumented utility garbage for our crossfire client =head1 SYNOPSIS - use CFClient; + use CFPlus; =head1 DESCRIPTION @@ -12,13 +12,13 @@ =cut -package CFClient; +package CFPlus; BEGIN { - $VERSION = '0.1'; + $VERSION = '0.51'; use XSLoader; - XSLoader::load "CFClient", $VERSION; + XSLoader::load "CFPlus", $VERSION; } use utf8; @@ -30,66 +30,31 @@ use Scalar::Util (); use Storable (); # finally -package CFClient::PodToPango; +=item guard { BLOCK } -use base Pod::POM::View::Text; +Returns an object that executes the given block as soon as it is destroyed. -our $VERSION = 1; # bump if resultant formatting changes - -our $indent = 0; - -*view_seq_code = -*view_seq_bold = sub { "$_[1]" }; -*view_seq_italic = sub { "$_[1]" }; -*view_seq_space = -*view_seq_link = -*view_seq_index = sub { CFClient::UI::Label::escape ($_[1]) }; - -sub view_seq_text { - my $text = $_[1]; - $text =~ s/\s+/ /g; - CFClient::UI::Label::escape ($text) -} - -sub view_item { - ("\t" x ($indent / 4)) - . $_[1]->title->present ($_[0]) - . "\n\n" - . $_[1]->content->present ($_[0]) -} +=cut -sub view_verbatim { - (join "", - map +("\t" x ($indent / 2)) . "$_\n", - split /\n/, CFClient::UI::Label::escape ($_[1])) - . "\n" +sub guard(&) { + bless \(my $cb = $_[0]), "CFPlus::Guard" } -sub view_textblock { - ("\t" x ($indent / 2)) . "$_[1]\n\n" +sub CFPlus::Guard::DESTROY { + ${$_[0]}->() } -sub view_head1 { - "\n\n" . $_[1]->title->present ($_[0]) . "\n\n" - . $_[1]->content->present ($_[0]) -}; - -sub view_head2 { - "\n" . $_[1]->title->present ($_[0]) . "\n\n" - . $_[1]->content->present ($_[0]) -}; +sub asxml($) { + local $_ = $_[0]; -sub view_head3 { - "\n" . $_[1]->title->present ($_[0]) . "\n\n" - . $_[1]->content->present ($_[0]) -}; + s/&/&/g; + s/>/>/g; + s/indent; - $_[1]->content->present ($_[0]) + $_ } -package CFClient::Database; +package CFPlus::Database; our @ISA = BerkeleyDB::Btree::; @@ -106,54 +71,63 @@ sub put($$$) { my ($db, $key, $data) = @_; - $DB_SYNC{$db} = AnyEvent->timer (after => 5, cb => sub { $db->db_sync }); + my $hkey = $db + 0; + Scalar::Util::weaken $db; + $DB_SYNC{$hkey} ||= AnyEvent->timer (after => 5, cb => sub { + delete $DB_SYNC{$hkey}; + $db->db_sync if $db; + }); $db->db_put ($key => $data) } -package CFClient; +package CFPlus; sub find_rcfile($) { my $path; for (grep !ref, @INC) { - $path = "$_/CFClient/resources/$_[0]"; + $path = "$_/CFPlus/resources/$_[0]"; return $path if -r $path; } die "FATAL: can't find required file $_[0]\n"; } +BEGIN { + use Crossfire::Protocol::Base (); + *to_json = \&Crossfire::Protocol::Base::to_json; + *from_json = \&Crossfire::Protocol::Base::from_json; +} + sub read_cfg { my ($file) = @_; - open CFG, $file + open my $fh, $file or return; - my $CFG; - local $/; - $CFG = eval ; - - $::CFG = $CFG; + my $CFG = <$fh>; - close CFG; + if ($CFG =~ /^---/) { ## TODO compatibility cruft, remove + require YAML; + utf8::decode $CFG; + $::CFG = YAML::Load ($CFG); + } elsif ($CFG =~ /^\{/) { + $::CFG = from_json $CFG; + } else { + $::CFG = eval $CFG; ## todo comaptibility cruft + } } sub write_cfg { my ($file) = @_; - open CFG, ">$file" - or return; + $::CFG->{VERSION} = $::VERSION; - { - require Data::Dumper; - local $Data::Dumper::Purity = 1; - $::CFG->{VERSION} = $::VERSION; - print CFG Data::Dumper->Dump ([$::CFG], [qw/CFG/]); - } - - close CFG; + open my $fh, ">:utf8", $file + or return; + print $fh to_json $::CFG; } our $DB_ENV; @@ -182,7 +156,7 @@ $table =~ s/([^a-zA-Z0-9_\-])/sprintf "=%x=", ord $1/ge; - new CFClient::Database + new CFPlus::Database -Env => $DB_ENV, -Filename => $table, # -Filename => "database", @@ -192,58 +166,13 @@ or die "unable to create/open database table $_[0]: $BerkeleyDB::Error" } -my $pod_cache = db_table "pod_cache"; - -sub load_pod($$$$) { - my ($path, $filtertype, $filterversion, $filtercb) = @_; - - stat $path - or die "$path: $!"; - - my $phash = join ",", $filterversion, $CFClient::PodToPango::VERSION, (stat _)[7,9]; - - my ($chash, $pom) = eval { @{ Storable::thaw $pod_cache->get ("$path/$filtertype") } }; - - return $pom if $chash eq $phash; - - my $pod = do { - local $/; - open my $pod, "<:utf8", $_[0] - or die "$_[0]: $!"; - <$pod> - }; - - #utf8::downgrade $pod; - - $pom = $filtercb-> (Pod::POM->new->parse_text ($pod)); - - $pod_cache->put ("$path/$filtertype" => Storable::nfreeze [$phash, $pom]); - - $pom -} - -sub pod_to_pango($) { - my ($pom) = @_; +package CFPlus::Layout; - $pom->present ("CFClient::PodToPango") -} - -sub pod_to_pango_list($) { - my ($pom) = @_; - - [ - map s/^(\s*)// && [40 * length $1, length $_ ? $_ : " "], - split /\n/, $pom->present ("CFClient::PodToPango") - ] -} - -package CFClient::Layout; - -$CFClient::OpenGL::SHUTDOWN_HOOK{"CFClient::Layout"} = sub { +$CFPlus::OpenGL::SHUTDOWN_HOOK{"CFPlus::Layout"} = sub { reset_glyph_cache; }; -package CFClient::Item; +package CFPlus::Item; use strict; use Crossfire::Protocol::Constants; @@ -287,22 +216,28 @@ sub do_n_dialog { my ($cb) = @_; - my $w = new CFClient::UI::FancyFrame; - $w->add (my $vb = new CFClient::UI::VBox x => "center", y => "center"); - $vb->add (new CFClient::UI::Label text => "Enter item count:"); - $vb->add (my $entry = new CFClient::UI::Entry + my $w = new CFPlus::UI::Toplevel + on_delete => sub { $_[0]->destroy; 1 }, + has_close_button => 1, + ; + + $w->add (my $vb = new CFPlus::UI::VBox x => "center", y => "center"); + $vb->add (new CFPlus::UI::Label text => "Enter item count:"); + $vb->add (my $entry = new CFPlus::UI::Entry text => $last_enter_count, on_activate => sub { my ($entry) = @_; $last_enter_count = $entry->get_text; $cb->($last_enter_count); $w->hide; - $w = undef; - } + $w->destroy; + + 0 + }, + on_escape => sub { $w->destroy; 1 }, ); $entry->grab_focus; $w->show; - } sub update_widgets { @@ -320,10 +255,10 @@ $targ = $::CONN->{open_container}; } - if (($ev->{mod} & CFClient::KMOD_SHIFT) && $ev->{button} == 1) { + if (($ev->{mod} & CFPlus::KMOD_SHIFT) && $ev->{button} == 1) { $::CONN->send ("move $targ $self->{tag} 0") if $targ || !($self->{flags} & F_LOCKED); - } elsif (($ev->{mod} & CFClient::KMOD_SHIFT) && $ev->{button} == 2) { + } elsif (($ev->{mod} & CFPlus::KMOD_SHIFT) && $ev->{button} == 2) { $self->{flags} & F_LOCKED ? $::CONN->send ("lock " . pack "CN", 0, $self->{tag}) : $::CONN->send ("lock " . pack "CN", 1, $self->{tag}) @@ -332,6 +267,11 @@ } elsif ($ev->{button} == 2) { $::CONN->send ("apply $self->{tag}"); } elsif ($ev->{button} == 3) { + my $move_prefix = $::CONN->{open_container} ? 'put' : 'drop'; + if ($self->{container} == $::CONN->{open_container}) { + $move_prefix = "take"; + } + my @menu_items = ( ["examine", sub { $::CONN->send ("examine $self->{tag}") }], ["mark", sub { $::CONN->send ("mark ". pack "N", $self->{tag}) }], @@ -341,6 +281,25 @@ $::CONN->send ("command apply flint and steel"); } ], + ["inscribe", # first try of an easier use of flint&steel + sub { + &::open_string_query ("Text to inscribe", sub { + my ($entry, $txt) = @_; + $::CONN->send ("mark ". pack "N", $self->{tag}); + $::CONN->send ("command use_skill inscription $txt"); + }); + } + ], + ["rename", # first try of an easier use of flint&steel + sub { + &::open_string_query ("Rename item to:", sub { + my ($entry, $txt) = @_; + $::CONN->send ("mark ". pack "N", $self->{tag}); + $::CONN->send ("command rename to <$txt>"); + }, $self->{name}, + "If you input no name or erase the current custom name, the custom name will be unset"); + } + ], ["apply", sub { $::CONN->send ("apply $self->{tag}") }], ( $self->{flags} & F_LOCKED @@ -349,8 +308,8 @@ ) : ( ["lock", sub { $::CONN->send ("lock " . pack "CN", 1, $self->{tag}) }], - ["drop", sub { $::CONN->send ("move $::CONN->{open_container} $self->{tag} 0") }], - ["move n", + ["$move_prefix all", sub { $::CONN->send ("move $targ $self->{tag} 0") }], + ["$move_prefix <n>", sub { do_n_dialog (sub { $::CONN->send ("move $targ $self->{tag} $_[0]") }) } @@ -359,7 +318,7 @@ ), ); - CFClient::UI::Menu->new (items => \@menu_items)->popup ($ev); + CFPlus::UI::Menu->new (items => \@menu_items)->popup ($ev); } 1 @@ -373,13 +332,18 @@ . "Right click - further options" . "\n"; - $self->{face_widget} ||= new CFClient::UI::Face + my $bg = $self->{flags} & F_CURSED ? [1 , 0 , 0, 0.5] + : $self->{flags} & F_MAGIC ? [0.2, 0.2, 1, 0.5] + : undef; + + $self->{face_widget} ||= new CFPlus::UI::Face can_events => 1, can_hover => 1, anim => $self->{anim}, animspeed => $self->{animspeed}, # TODO# must be set at creation time on_button_down => $button_cb, ; + $self->{face_widget}{bg} = $bg; $self->{face_widget}{face} = $self->{face}; $self->{face_widget}{anim} = $self->{anim}; $self->{face_widget}{animspeed} = $self->{animspeed}; @@ -390,26 +354,27 @@ . "\n\n$tooltip_std" ); - $self->{desc_widget} ||= new CFClient::UI::Label + $self->{desc_widget} ||= new CFPlus::UI::Label can_events => 1, can_hover => 1, ellipsise => 2, align => -1, on_button_down => $button_cb, ; - my $desc = CFClient::Item::desc_string $self; + my $desc = CFPlus::Item::desc_string $self; + $self->{desc_widget}{bg} = $bg; $self->{desc_widget}->set_text ($desc); $self->{desc_widget}->set_tooltip ("$desc.\n$tooltip_std"); - $self->{weight_widget} ||= new CFClient::UI::Label + $self->{weight_widget} ||= new CFPlus::UI::Label can_events => 1, can_hover => 1, ellipsise => 0, align => 0, on_button_down => $button_cb, ; - $self->{weight_widget}->set_text (CFClient::Item::weight_string $self); - + $self->{weight_widget}{bg} = $bg; + $self->{weight_widget}->set_text (CFPlus::Item::weight_string $self); $self->{weight_widget}->set_tooltip ( "Weight.\n" . ($self->{weight} >= 0 ? "One item weighs $self->{weight}g. " : "You have no idea how much this weighs. ")