--- deliantra/Deliantra-Client/bin/cfplus 2006/07/02 18:52:05 1.84 +++ deliantra/Deliantra-Client/bin/cfplus 2006/07/19 16:41:51 1.97 @@ -42,6 +42,7 @@ use CFClient::MapWidget; $SIG{QUIT} = sub { Carp::cluck "QUIT" }; +$SIG{PIPE} = 'IGNORE'; $Event::DIED = sub { # TODO: display dialog box or so @@ -87,15 +88,24 @@ our $LOGIN_BUTTON; our $QUIT_DIALOG; our $HOST_ENTRY; +our $FULLSCREEN_ENABLE; +our $PICKUP_ENABLE; our $SERVER_INFO; our $SETUP_DIALOG; our $SETUP_NOTEBOOK; our $SETUP_SERVER; our $SETUP_KEYBOARD; -our $SETUP_SPELLS; -our $STATS_WINDOW; +our $PL_NOTEBOOK; +our $PL_WINDOW; + +our $INVENTORY_PAGE; +our $STATS_PAGE; +our $SKILL_PAGE; +our $SPELL_PAGE; + +our $HELP_WINDOW; our $MESSAGE_WINDOW; our $FLOORBOX; our $GAUGES; @@ -112,7 +122,6 @@ our $STATUSBOX; our $DEBUG_STATUS; -our $INV_WINDOW; our $INV; our $INVR; our $INV_RIGHT_HB; @@ -223,7 +232,7 @@ return; } - $STATS_WINDOW->show; + $STATS_PAGE->show; $MESSAGE_WINDOW->hide; unshift @dialog, new CFClient::UI::Label @@ -273,7 +282,7 @@ text => "Accept", on_activate => sub { $conn->send ("reply n"); - $STATS_WINDOW->hide; + $STATS_PAGE->hide; destroy_query_dialog $conn; 0 }, @@ -375,8 +384,8 @@ $LOGIN_BUTTON->set_text ("Login"); $SETUP_NOTEBOOK->set_current_page ($SETUP_SERVER); $SETUP_DIALOG->show; - $INV_WINDOW->hide; - $SETUP_SPELLS->clear_spells; + $PL_WINDOW->hide; + $SPELL_PAGE->clear_spells; return unless $CONN; @@ -411,7 +420,7 @@ my $row = 1; $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fullscreen"); - $table->add (1, $row++, new CFClient::UI::CheckBox + $table->add (1, $row++, $FULLSCREEN_ENABLE = new CFClient::UI::CheckBox state => $CFG->{fullscreen}, tooltip => "Bring the client into fullscreen mode.", on_changed => sub { my ($self, $value) = @_; $CFG->{fullscreen} = $value; 0 } @@ -471,18 +480,6 @@ on_changed => sub { $LOGVIEW->set_fontsize ($CFG->{log_fontsize} = $_[1]); 0 }, ); - $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Stats Fontsize"); - - $table->add (1, $row++, new CFClient::UI::Slider - range => [$CFG->{stat_fontsize}, 0.5, 2, 0, 0.1], - tooltip => "The font size used by the statistics window only. Changes are instant.", - on_changed => sub { - $CFG->{stat_fontsize} = $_[1]; - &set_stats_window_fontsize; - 0 - } - ); - $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Gauge fontsize"); $table->add (1, $row++, new CFClient::UI::Slider range => [$CFG->{gauge_fontsize}, 0.5, 2, 0, 0.1], @@ -561,12 +558,6 @@ $vbox } -sub set_stats_window_fontsize { - for (values %{$STATWIDS}) { - $_->set_fontsize ($::CFG->{stat_fontsize}); - } -} - sub set_gauge_window_fontsize { for (map { $GAUGES->{$_} } grep { $_ ne 'win' } keys %{$GAUGES}) { $_->set_fontsize ($::CFG->{gauge_fontsize}); @@ -655,14 +646,13 @@ } sub stats_window { - my $tgw = new CFClient::UI::FancyFrame - y => $HEIGHT * (2/8), - x => "max", - title => "Stats", - name => "stats_window", - has_close_button => 1; + my $r = + new CFClient::UI::ScrolledWindow ( + expand => 1, + scroll_y => 1 + ); + $r->add (my $vb = new CFClient::UI::VBox); - $tgw->add (new CFClient::UI::Window child => my $vb = new CFClient::UI::VBox); $vb->add ($STATWIDS->{title} = new CFClient::UI::Label valign => 0, align => -1, text => "Title:", expand => 1, can_hover => 1, can_events => 1, tooltip => "Your name and title. You can change your title by using the title command, if supported by the server."); @@ -708,30 +698,48 @@ font => $FONT_FIXED, can_hover => 1, can_events => 1, fg => $color2, valign => 0, align => -1, text => $label, tooltip => $tooltip); } - $hb->add (my $tbl2 = new CFClient::UI::Table expand => 1); + $vb->add (my $tbl2 = new CFClient::UI::Table expand => 1); my $row = 0; my $col = 0; my %resist_names = ( - slow => "Slow (slows you down when you are hit by the spell. Monsters will have an opportunity to come near you faster and hit you more often.)", - holyw => "Holy Word (resistance you against getting the fear when someone whose god doesn't like you spells the holy word on you.)", - conf => "Confusion (If you are hit by confusion you will move into random directions, and likely into monsters.)", - fire => "Fire (just your resistance to fire spells like burning hands, dragonbreath, meteor swarm fire, ...)", - depl => "Depletion (some monsters and other effects can cause stats depletion)", - magic => "Magic (resistance to magic spells like magic missile or similar)", - drain => "Draining (some monsters (e.g. vampires) and other effects can steal experience)", - acid => "Acid (resistance to acid, acid hurts pretty much and also corrodes your weapons)", - pois => "Poison (resistance to getting poisoned)", - para => "Paralysation (this resistance affects the chance you get paralysed)", - deat => "Death (resistance against death spells)", - phys => "Physical (this is the resistance against physical attacks, like when a monster hit you in melee combat. The value displayed here is also displayed in the 'Arm' field on the left.)", - blind => "Blind (blind resistance affects the chance of a successful blinding attack)", - fear => "Fear (this attack will drive you away from monsters who cast this and hit you successfully, being resistant to this helps a lot when fighting those monsters)", - tund => "Turn undead (affects your resistancy to various forms of 'turn undead' spells. Only relevant when you are, in fact, undead...", - elec => "Electricity (resistance against electricity, spells like large lightning, small lightning, ...)", - cold => "Cold (this is your resistance against cold spells like icestorm, snowstorm, ...)", - ghit => "Ghost hit (special attack used by ghosts and ghost-like beings)", + slow => ["Slow", + "Slow (slows you down when you are hit by the spell. Monsters will have an opportunity to come near you faster and hit you more often.)"], + holyw => ["Holy Word", + "Holy Word (resistance you against getting the fear when someone whose god doesn't like you spells the holy word on you.)"], + conf => ["Confusion", + "Confusion (If you are hit by confusion you will move into random directions, and likely into monsters.)"], + fire => ["Fire", + "Fire (just your resistance to fire spells like burning hands, dragonbreath, meteor swarm fire, ...)"], + depl => ["Depletion", + "Depletion (some monsters and other effects can cause stats depletion)"], + magic => ["Magic", + "Magic (resistance to magic spells like magic missile or similar)"], + drain => ["Draining", + "Draining (some monsters (e.g. vampires) and other effects can steal experience)"], + acid => ["Acid", + "Acid (resistance to acid, acid hurts pretty much and also corrodes your weapons)"], + pois => ["Poison", + "Poison (resistance to getting poisoned)"], + para => ["Paralysation", + "Paralysation (this resistance affects the chance you get paralysed)"], + deat => ["Death", + "Death (resistance against death spells)"], + phys => ["Physical", + "Physical (this is the resistance against physical attacks, like when a monster hit you in melee combat. The value displayed here is also displayed in the 'Arm' field on the left.)"], + blind => ["Blind", + "Blind (blind resistance affects the chance of a successful blinding attack)"], + fear => ["Fear", + "Fear (this attack will drive you away from monsters who cast this and hit you successfully, being resistant to this helps a lot when fighting those monsters)"], + tund => ["Turn undead", + "Turn undead (affects your resistancy to various forms of 'turn undead' spells. Only relevant when you are, in fact, undead..."], + elec => ["Electricity", + "Electricity (resistance against electricity, spells like large lightning, small lightning, ...)"], + cold => ["Cold", + "Cold (this is your resistance against cold spells like icestorm, snowstorm, ...)"], + ghit => ["Ghost hit", + "Ghost hit (special attack used by ghosts and ghost-like beings)"], ); for (qw/slow holyw conf fire depl magic drain acid pois para deat phys @@ -746,99 +754,43 @@ valign => 0, can_events => 1, can_hover => 1, - tooltip => $resist_names{$_}, + tooltip => $resist_names{$_}->[1], ); $tbl2->add ($col + 1, $row, new CFClient::UI::Image font => $FONT_FIXED, can_hover => 1, can_events => 1, path => "ui/resist/resist_$_.png", - tooltip => $resist_names{$_}, + tooltip => $resist_names{$_}->[1], + ); + $tbl2->add ($col + 2, $row, new CFClient::UI::Label + text => $resist_names{$_}->[0], + font => $FONT_FIXED, + can_hover => 1, + can_events => 1, + tooltip => $resist_names{$_}->[1], ); $row++; if ($row % 6 == 0) { - $col += 2; + $col += 3; $row = 0; } } - &set_stats_window_fontsize; - update_stats_window ({}); + #update_stats_window ({}); - $tgw + $r } -sub formsep($) { - scalar reverse join ",", unpack "(A3)*", reverse $_[0] * 1 +sub skill_window { + my $sw = new CFClient::UI::ScrolledWindow (expand => 1); + $sw->add ($STATWIDS->{skill_tbl} = new CFClient::UI::Table expand => 1, col_expand => [0, 0, 1, 0, 0, 1]); + $sw } -sub update_stats_window { - my ($stats) = @_; - - # I love text protocols... - - my $hp = $stats->{+CS_STAT_HP} * 1; - my $hp_m = $stats->{+CS_STAT_MAXHP} * 1; - my $sp = $stats->{+CS_STAT_SP} * 1; - my $sp_m = $stats->{+CS_STAT_MAXSP} * 1; - my $fo = $stats->{+CS_STAT_FOOD} * 1; - my $fo_m = 999; - my $gr = $stats->{+CS_STAT_GRACE} * 1; - my $gr_m = $stats->{+CS_STAT_MAXGRACE} * 1; - - $GAUGES->{hp} ->set_value ($hp, $hp_m); - $GAUGES->{mana} ->set_value ($sp, $sp_m); - $GAUGES->{food} ->set_value ($fo, $fo_m); - $GAUGES->{grace} ->set_value ($gr, $gr_m); - $GAUGES->{exp} ->set_text ("Exp: " . (formsep $stats->{+CS_STAT_EXP64}) - . " (lvl " . ($stats->{+CS_STAT_LEVEL} * 1) . ")"); - my $rng = $stats->{+CS_STAT_RANGE}; - $rng =~ s/^Range: //; # thank you so much dear server - $GAUGES->{range} ->set_text ("Rng: " . $rng); - my $title = $stats->{+CS_STAT_TITLE}; - $title =~ s/^Player: //; - $STATWIDS->{title} ->set_text ("Title: " . $title); - - $STATWIDS->{st_str} ->set_text (sprintf "%d" , $stats->{+CS_STAT_STR}); - $STATWIDS->{st_dex} ->set_text (sprintf "%d" , $stats->{+CS_STAT_DEX}); - $STATWIDS->{st_con} ->set_text (sprintf "%d" , $stats->{+CS_STAT_CON}); - $STATWIDS->{st_int} ->set_text (sprintf "%d" , $stats->{+CS_STAT_INT}); - $STATWIDS->{st_wis} ->set_text (sprintf "%d" , $stats->{+CS_STAT_WIS}); - $STATWIDS->{st_pow} ->set_text (sprintf "%d" , $stats->{+CS_STAT_POW}); - $STATWIDS->{st_cha} ->set_text (sprintf "%d" , $stats->{+CS_STAT_CHA}); - $STATWIDS->{st_wc} ->set_text (sprintf "%d" , $stats->{+CS_STAT_WC}); - $STATWIDS->{st_ac} ->set_text (sprintf "%d" , $stats->{+CS_STAT_AC}); - $STATWIDS->{st_dam} ->set_text (sprintf "%d" , $stats->{+CS_STAT_DAM}); - $STATWIDS->{st_arm} ->set_text (sprintf "%d" , $stats->{+CS_STAT_RES_PHYS}); - $STATWIDS->{st_spd} ->set_text (sprintf "%.1f", $stats->{+CS_STAT_SPEED}); - $STATWIDS->{st_wspd}->set_text (sprintf "%.1f", $stats->{+CS_STAT_WEAP_SP}); - - $STATWIDS->{m_weight}->set_text (sprintf "Max weight: %.1fkg", $stats->{+CS_STAT_WEIGHT_LIM} / 1000); - - my %tbl = ( - phys => CS_STAT_RES_PHYS, - magic => CS_STAT_RES_MAG, - fire => CS_STAT_RES_FIRE, - elec => CS_STAT_RES_ELEC, - cold => CS_STAT_RES_COLD, - conf => CS_STAT_RES_CONF, - acid => CS_STAT_RES_ACID, - drain => CS_STAT_RES_DRAIN, - ghit => CS_STAT_RES_GHOSTHIT, - pois => CS_STAT_RES_POISON, - slow => CS_STAT_RES_SLOW, - para => CS_STAT_RES_PARA, - tund => CS_STAT_TURN_UNDEAD, - fear => CS_STAT_RES_FEAR, - depl => CS_STAT_RES_DEPLETE, - deat => CS_STAT_RES_DEATH, - holyw => CS_STAT_RES_HOLYWORD, - blind => CS_STAT_RES_BLIND, - ); - - $STATWIDS->{"res_$_"}->set_text (sprintf "%d%", $stats->{$tbl{$_}}) - for keys %tbl; +sub formsep($) { + scalar reverse join ",", unpack "(A3)*", reverse $_[0] * 1 } my $METASERVER_ATIME; @@ -1094,7 +1046,6 @@ name => "message_window", title => "Messages", border_bg => [1, 1, 1, 1], - bg => [0, 0, 0, 0.75], x => "max", y => 0, force_w => $::WIDTH * 0.4, @@ -1190,7 +1141,7 @@ for ( ["General", 0, 0, - ["Enable autopickup" => PICKUP_NEWMODE], + ["Enable autopickup" => PICKUP_NEWMODE, \$PICKUP_ENABLE], ["Inhibit autopickup" => PICKUP_INHIBIT], ["Stop before pickup" => PICKUP_STOP], ["Debug autopickup" => PICKUP_DEBUG], @@ -1237,7 +1188,7 @@ my $mask = $_->[1]; $table->add ($x , $y, new CFClient::UI::Label text => $_->[0], align => 1, expand => 1); - $table->add ($x+1, $y, new CFClient::UI::CheckBox + $table->add ($x+1, $y, my $checkbox = new CFClient::UI::CheckBox state => $::CFG->{pickup} & $mask, on_changed => sub { my ($box, $value) = @_; @@ -1253,6 +1204,8 @@ 0 }); + + ${$_->[2]} = $checkbox if $_->[2]; } } @@ -1280,37 +1233,78 @@ $table } -sub inventory_window { - my $invwin = $INV_WINDOW = new CFClient::UI::FancyFrame - x => "center", - y => "center", - force_w => $WIDTH * 9/10, - force_h => $HEIGHT * 9/10, - title => "Inventory", - name => "inventory_window", - has_close_button => 1, - ; - - $invwin->add (my $hb = new CFClient::UI::HBox homogeneous => 1); +sub inventory_widget { + my $hb = new CFClient::UI::HBox homogeneous => 1; $hb->add (my $vb1 = new CFClient::UI::VBox); $vb1->add (new CFClient::UI::Label align => 0, text => "Player"); - $vb1->add ($INV = new CFClient::UI::Inventory expand => 1); + $vb1->add (my $sw1 = new CFClient::UI::ScrolledWindow expand => 1, scroll_y => 1); + $sw1->add ($INV = new CFClient::UI::Inventory); $hb->add (my $vb2 = new CFClient::UI::VBox); $vb2->add ($INV_RIGHT_HB = new CFClient::UI::HBox); - $vb2->add ($INVR = new CFClient::UI::Inventory expand => 1); + $vb2->add (my $sw2 = new CFClient::UI::ScrolledWindow expand => 1, scroll_y => 1); + $sw2->add ($INVR = new CFClient::UI::Inventory); # XXX: Call after $INVR = ... because set_opencont sets the items CFClient::Protocol::set_opencont ($::CONN, 0, "Floor"); - $invwin + $hb } -sub spell_setup { - new CFClient::UI::SpellList +sub toggle_player_page { + my ($widget) = @_; + + if ($PL_WINDOW->{visible} && $PL_NOTEBOOK->get_current_page == $widget) { + $PL_WINDOW->hide; + } else { + $PL_NOTEBOOK->set_current_page ($widget); + $PL_WINDOW->show; + } +} + +sub player_window { + my $plwin = $PL_WINDOW = new CFClient::UI::FancyFrame + x => "center", + y => "center", + force_w => $WIDTH * 9/10, + force_h => $HEIGHT * 9/10, + title => "Player", + name => "playerbook", + has_close_button => 1 + ; + + my $ntb = + $PL_NOTEBOOK = + new CFClient::UI::Notebook expand => 1, debug => 1; + + $ntb->add ( + "Statistics (F2)" => $STATS_PAGE = stats_window, + "Shows statistics, where all your Stats and Resistances are shown." + ); + $ntb->add ( + "Skills (F3)" => $SKILL_PAGE = skill_window, + "Shows all your Skills." + ); + + my $spellsw = new CFClient::UI::ScrolledWindow (expand => 1, scroll_y => 1); + $spellsw->add ($SPELL_PAGE = new CFClient::UI::SpellList); + $ntb->add ( + "Spellbook (F4)" => $spellsw, + "Displays all spells you have and lets you edit keyboard shortcuts for them." + ); + $ntb->add ( + "Inventory (F5)" => $INVENTORY_PAGE = inventory_widget, + "Toggles the inventory window, where you can manage your loot (or treasures :). " + . "You can also hit the Tab-key to show/hide the Inventory." + ); + + $ntb->set_current_page ($INVENTORY_PAGE); + + $plwin->add ($ntb); + $plwin } sub update_bindings { @@ -1425,6 +1419,83 @@ $vb } +# just weirdness, pls. ignore +sub load_html_page { + my ($viewer, $base) = @_; + + $viewer->clear; + + require LWP::Simple; + require HTML::Parser; + require URI; + + my $page = LWP::Simple::get ($base) + or return; + + my @s = { }; + my %passthrough = map ($_ => undef), qw(b i u s tt big small sub sup); + + my $parser = HTML::Parser->new ( + text_h => [sub { + my ($text) = @_; + $text =~ s/\s+/ /g; + $s[-1]{text} .= CFClient::UI::Label::escape $text; + }, "dtext"], + start_h => [sub { + my ($tag, $attr) = @_; + if ($passthrough{$tag}) { + $s[-1]{text} .= "<$tag>"; + } elsif ($tag eq "h1") { + push @s, { text => "" }; + } elsif ($tag eq "h2") { + push @s, { text => "" }; + } elsif ($tag eq "h3") { + push @s, { text => "" }; + } elsif ($tag eq "a") { + push @s, { text => "", url => $attr->{href} }; + } elsif ($tag eq "p") { + push @s, { }; + } elsif ($tag eq "img") { + eval { + push @{$s[-1]{obj}}, new CFClient::UI::Image + tex => (new_from_image CFClient::Texture LWP::Simple::get (URI->new ($attr->{src}, $base)->abs ($base))); + $s[-1]{text} .= "\x{fffc}"; + }; + } + }, "tagname, attr"], + end_h => [sub { + my ($tag) = @_; + if ($passthrough{$tag}) { + $s[-1]{text} .= ""; + } elsif ($tag =~ /^h\d$/) { + $s[-1]{text} .= ""; + push @s, { }; + } elsif ($tag eq "a") { + my $S = pop @s; + $s[-1]{text} .= "\x{fffc}"; + push @{$s[-1]{obj}}, new CFClient::UI::Label + fg => [0.8, 0.8, 1], + markup => "$S->{text}", + fontsize => 0.8, + can_events => 1, + can_focus => 1, + on_button_up => sub { + load_html_page ($viewer, URI->new ($S->{url}, $base)->abs ($base)); + }, + ; + } + }, "tagname"], + ); + + $parser->parse ($page); + $parser->eof; + + $viewer->add_paragraph ([1, 1, 1, 1], [$_->{text}, @{ $_->{obj} || [] }], $_->{indent}) + for @s; + + $viewer->set_offset (0); +} + sub help_window { my $win = new CFClient::UI::FancyFrame x => 'center', @@ -1433,7 +1504,8 @@ name => 'doc_browser', force_w => int $WIDTH * 7/8, force_h => int $HEIGHT * 7/8, - title => "Documentation"; + title => "Help Browser", + has_close_button => 1; $win->add (my $vbox = new CFClient::UI::VBox); @@ -1451,10 +1523,19 @@ [command_help => "Command Reference"], [dmcommand_help => "DM Commands"], [COPYING => "License Terms"], + [test => "test (do not select)"], #d#TODO ], on_changed => sub { my ($self, $pod) = @_; + if ($pod eq "test") {#d#TODO + eval { + load_html_page $viewer, "http://crossfire.real-time.com/guides/walkthrough/newbie-tower.html"; + }; + warn "$@" if $@; + return; + } + my $pom = CFClient::load_pod CFClient::find_rcfile "pod/$pod.pod", doc_viewer => 1, sub { CFClient::pod_to_pango_list $_[0] }; @@ -1607,8 +1688,6 @@ . "want to record press Insert and you will be asked to press a key-combo. " . "After pressing the combo the binding will be saved automatically and the " . "binding editor closes"); - $SETUP_NOTEBOOK->add (Spells => $SETUP_SPELLS = spell_setup, - "Displays all spells you have and lets you edit keyboard shortcuts for them."); $SETUP_NOTEBOOK->add (Debug => debug_setup, "Some debuggin' options. Do not ask."); @@ -1622,11 +1701,8 @@ make_gauge_window->show; # XXX: this has to be set before make_stats_window as make_stats_window calls update_stats_window which updated the gauges also X-D - $BUTTONBAR->add (new CFClient::UI::Flopper text => "Stats Window", other => $STATS_WINDOW = stats_window, - tooltip => "Toggles the statistics window, where all your Stats and Resistances are being displayed at all times."); - $BUTTONBAR->add (new CFClient::UI::Flopper text => "Inventory", other => inventory_window, - tooltip => "Toggles the inventory window, where you can manage your loot (or treasures :). " - . "You can also hit the Tab-key to show/hide the Inventory."); + $BUTTONBAR->add (new CFClient::UI::Flopper text => "Playerbook", other => player_window, + tooltip => "Toggles the player view, where you can manage Inventory, Spells, Skills and see your Stats."); $BUTTONBAR->add (new CFClient::UI::Button text => "Save Config", @@ -1639,7 +1715,7 @@ }, ); - $BUTTONBAR->add (new CFClient::UI::Flopper text => "Help!", other => help_window, + $BUTTONBAR->add (new CFClient::UI::Flopper text => "Help!", other => $HELP_WINDOW = help_window, tooltip => "View Documentation"); $BUTTONBAR->add (new CFClient::UI::Button @@ -1855,8 +1931,8 @@ CFClient::SDL_KEYDOWN => sub { if ($_[0]{mod} & CFClient::KMOD_ALT && $_[0]{sym} == 13) { # alt-enter + $FULLSCREEN_ENABLE->toggle; video_shutdown; - $CFG->{fullscreen} = !$CFG->{fullscreen}; video_init; } else { CFClient::UI::feed_sdl_key_down_event ($_[0]); @@ -1882,7 +1958,7 @@ { local $SIG{__DIE__} = sub { return unless defined $^S && !$^S; - Carp::confess $_[1];#d#TODO: remove when stable + Carp::confess $_[0];#d#TODO: remove when stable CFClient::fatal $_[0]; };