--- deliantra/Deliantra-Client/bin/cfplus 2006/06/05 01:59:59 1.54 +++ deliantra/Deliantra-Client/bin/cfplus 2006/06/28 09:42:40 1.81 @@ -27,7 +27,6 @@ if %PAR::LibCache; use Time::HiRes 'time'; -use Pod::POM; use Event; use Crossfire; @@ -39,8 +38,11 @@ use CFClient::OpenGL (); use CFClient::Protocol; use CFClient::UI; +use CFClient::BindingEditor; use CFClient::MapWidget; +$SIG{QUIT} = sub { Carp::cluck "QUIT" }; + $Event::DIED = sub { # TODO: display dialog box or so Carp::confess $_[1];#d#TODO: remove when stable @@ -85,6 +87,7 @@ our $LOGIN_BUTTON; our $QUIT_DIALOG; our $HOST_ENTRY; +our $SERVER_INFO; our $SETUP_DIALOG; our $SETUP_NOTEBOOK; @@ -92,6 +95,8 @@ our $SETUP_KEYBOARD; our $SETUP_SPELLS; +our $STATS_WINDOW; +our $MESSAGE_WINDOW; our $FLOORBOX; our $GAUGES; our $STATWIDS; @@ -113,6 +118,7 @@ our $INV_RIGHT_HB; our $BIND_EDITOR; +our $BIND_UPD_CB; our $PICKUP_CFG; @@ -124,6 +130,196 @@ $DEBUG_STATUS->set_text ($_[0]); } +sub destroy_query_dialog { + (delete $_[0]{query_dialog})->destroy + if $_[0]{query_dialog}; +} + +# server query dialog +sub server_query { + my ($conn, $flags, $prompt) = @_; + + $conn->{query_dialog} = my $dialog = new CFClient::UI::FancyFrame + x => "center", + y => "center", + title => "Server Query", + child => my $vbox = new CFClient::UI::VBox, + ; + + my @dialog = my $label = new CFClient::UI::Label + max_w => $::WIDTH * 0.4, + ellipsise => 0, + text => $prompt; + + if ($flags & CS_QUERY_YESNO) { + push @dialog, my $hbox = new CFClient::UI::HBox; + + $hbox->add (new CFClient::UI::Button + text => "No", + on_activate => sub { + $conn->send ("reply n"); + $dialog->destroy; + 0 + } + ); + $hbox->add (new CFClient::UI::Button + text => "Yes", + on_activate => sub { + $conn->send ("reply y"); + destroy_query_dialog $conn; + 0 + }, + ); + + $dialog->grab_focus; + + } elsif ($flags & CS_QUERY_SINGLECHAR) { + $dialog->{tooltip} = "Press a key (click on the entry to make sure it has keyboard focus)"; + + if ($prompt =~ /Now choose a character|Press any key for the next race/i) { + $MESSAGE_WINDOW->show; + + unshift @dialog, new CFClient::UI::Label + max_w => $::WIDTH * 0.4, + ellipsise => 0, + markup => "\nOr use your keyboard:\n"; + + unshift @dialog, my $table = new CFClient::UI::Table; + + $table->add (0, 0, new CFClient::UI::Button + text => "Next Race", + on_activate => sub { + $conn->send ("reply n"); + destroy_query_dialog $conn; + 0 + }, + ); + $table->add (2, 0, new CFClient::UI::Button + text => "Accept", + on_activate => sub { + $conn->send ("reply d"); + destroy_query_dialog $conn; + 0 + }, + ); + + unshift @dialog, new CFClient::UI::Label + max_w => $::WIDTH * 0.4, + ellipsise => 0, + markup => + "Character Creation: Race\n\n" + . "Look at the Messages window to see a description of this race " + . "(or hover with your mouse over the bottommost entry in the status area in the lower left area of the screen) " + . "and the center of the screen to see how this race looks like " + . "(this is below this dialog window, you may need to click on the display area to make it visible).\n\n" + . "You can look at another race, or accept this race (you will come back to this race eventually, " + . "so you can take your time making this important choice." + ; + + } elsif ($prompt =~ /roll new stats/) { + if (my $stat = delete $conn->{stat_change_with}) { + $conn->send ("reply $stat"); + destroy_query_dialog $conn; + return; + } + + $STATS_WINDOW->show; + $MESSAGE_WINDOW->hide; + + unshift @dialog, new CFClient::UI::Label + max_w => $::WIDTH * 0.4, + ellipsise => 0, + markup => "\nOr use your keyboard:\n"; + + unshift @dialog, my $table = new CFClient::UI::Table; + + # left: re-roll + $table->add (0, 0, new CFClient::UI::Button + text => "Roll Again", + on_activate => sub { + $conn->send ("reply y"); + destroy_query_dialog $conn; + 0 + }, + ); + + # center: swap stats + my ($sw1, $sw2) = map +(new CFClient::UI::Combobox + value => $_, + options => [ + [1 => "Str", "Strength ($conn->{stat}{+CS_STAT_STR})"], + [2 => "Dex", "Dexterity ($conn->{stat}{+CS_STAT_DEX})"], + [3 => "Con", "Constitution ($conn->{stat}{+CS_STAT_CON})"], + [4 => "Int", "Intelligence ($conn->{stat}{+CS_STAT_INT})"], + [5 => "Wis", "Wisdom ($conn->{stat}{+CS_STAT_WIS})"], + [6 => "Pow", "Power ($conn->{stat}{+CS_STAT_POW})"], + [7 => "Cha", "Charisma ($conn->{stat}{+CS_STAT_CHA})"], + ], + ), 1 .. 2; + + $table->add (2, 0, new CFClient::UI::Button + text => "Swap Stats", + on_activate => sub { + $conn->{stat_change_with} = $sw2->{value}; + $conn->send ("reply $sw1->{value}"); + destroy_query_dialog $conn; + 0 + }, + ); + $table->add (2, 1, new CFClient::UI::HBox children => [$sw1, $sw2]); + + # right: accept + $table->add (4, 0, new CFClient::UI::Button + text => "Accept", + on_activate => sub { + $conn->send ("reply n"); + $STATS_WINDOW->hide; + destroy_query_dialog $conn; + 0 + }, + ); + + unshift @dialog, new CFClient::UI::Label + max_w => $::WIDTH * 0.4, + ellipsise => 0, + markup => + "Character Creation: Stats\n\n" + . "Look at the Stats window to see your basic stats " + . "(first column: 1 strength, 2 dexterity, 3 constitution, 4 intelligence, 5 wisdom, 6 power and 7 charisma).\n\n" + . "You can create another set of stats, swap two stat values with each other or accept the stats as they are now and continue. " + . "Race selection will influence those values later on." + ; + } + + push @dialog, my $entry = new CFClient::UI::Entry + on_changed => sub { + $conn->send ("reply $_[1]"); + destroy_query_dialog $conn; + 0 + }, + ; + + $entry->grab_focus; + + } else { + $dialog->{tooltip} = "Enter the reply and press return (click on the entry to make sure it has keyboard focus)"; + + push @dialog, my $entry = new CFClient::UI::Entry + $flags & CS_QUERY_HIDEINPUT ? (hidden => "*") : (), + on_activate => sub { + $conn->send ("reply $_[1]"); + destroy_query_dialog $conn; + 0 + }, + ; + + $entry->grab_focus; + } + + $vbox->add (@dialog); + $dialog->show; +} + sub start_game { status "logging in..."; @@ -132,7 +328,7 @@ my $mapsize = List::Util::min 32, List::Util::max 11, int $WIDTH * $CFG->{mapsize} * 0.01 / 32; - my ($host, $port) = split /:/, $CFG->{host}; + my ($host, $port) = split /:/, $CFG->{profile}{default}{host}; $MAP = new CFClient::Map $mapsize, $mapsize; @@ -140,8 +336,8 @@ new CFClient::Protocol host => $host, port => $port || 13327, - user => $CFG->{user}, - pass => $CFG->{password}, + user => $CFG->{profile}{default}{user}, + pass => $CFG->{profile}{default}{password}, mapw => $mapsize, maph => $mapsize, @@ -150,6 +346,7 @@ statusbox => $STATUSBOX, map => $MAP, mapmap => $MAPMAP, + query => \&server_query, sound_play => sub { my ($x, $y, $soundnum, $type) = @_; @@ -179,13 +376,17 @@ $SETUP_NOTEBOOK->set_current_page ($SETUP_SERVER); $SETUP_DIALOG->show; $INV_WINDOW->hide; + $SETUP_SPELLS->clear_spells; return unless $CONN; status "connection closed"; + destroy_query_dialog $CONN; $CONN->destroy; $CONN = 0; # false, does not autovivify + + undef $MAP; } sub graphics_setup { @@ -213,50 +414,35 @@ $table->add (1, $row++, new CFClient::UI::CheckBox state => $CFG->{fullscreen}, tooltip => "Bring the client into fullscreen mode.", - on_changed => sub { - my ($self, $value) = @_; - $CFG->{fullscreen} = $value; - } + on_changed => sub { my ($self, $value) = @_; $CFG->{fullscreen} = $value; 0 } ); $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fast & Ugly"); $table->add (1, $row++, new CFClient::UI::CheckBox state => $CFG->{fast}, tooltip => "Lower the visual quality considerably to speed up rendering.", - on_changed => sub { - my ($self, $value) = @_; - $CFG->{fast} = $value; - } + on_changed => sub { my ($self, $value) = @_; $CFG->{fast} = $value; 0 } ); $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Map Scale"); $table->add (1, $row++, new CFClient::UI::Slider range => [(log $CFG->{map_scale}) / (log 2), -3, 1, 0, 1], tooltip => "Enlarge or shrink the displayed map. Changes are instant.", - on_changed => sub { - my ($self, $value) = @_; - $CFG->{map_scale} = 2 ** $value; - } + on_changed => sub { my ($self, $value) = @_; $CFG->{map_scale} = 2 ** $value; 0 } ); $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fog of War"); $table->add (1, $row++, new CFClient::UI::CheckBox state => $CFG->{fow_enable}, tooltip => "Fog-of-War marks areas that cannot be seen by the player. Changes are instant.", - on_changed => sub { - my ($self, $value) = @_; - $CFG->{fow_enable} = $value; - } + on_changed => sub { my ($self, $value) = @_; $CFG->{fow_enable} = $value; 0 } ); $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "FoW Intensity"); $table->add (1, $row++, new CFClient::UI::Slider range => [$CFG->{fow_intensity}, 0, 1, 0, 1 / 256], tooltip => "Fog of War Lightness. The higher the intensity, the lighter the Fog-of-War color. Changes are instant.", - on_changed => sub { - my ($self, $value) = @_; - $CFG->{fow_intensity} = $value; - } + on_changed => sub { my ($self, $value) = @_; $CFG->{fow_intensity} = $value; 0 } ); $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "FoW Smooth"); @@ -267,6 +453,7 @@ my ($self, $value) = @_; $CFG->{fow_smooth} = $value; status "Fog of War smoothing requires OpenGL 1.2 or higher" if $CFClient::OpenGL::GL_VERSION < 1.2; + 0 } ); @@ -274,14 +461,14 @@ $table->add (1, $row++, new CFClient::UI::Slider range => [$CFG->{gui_fontsize}, 0.5, 2, 0, 0.1], tooltip => "The base font size used by most GUI elements that do not have their own setting.", - on_changed => sub { $CFG->{gui_fontsize} = $_[1] }, + on_changed => sub { $CFG->{gui_fontsize} = $_[1]; 0 }, ); $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Message Fontsize"); $table->add (1, $row++, new CFClient::UI::Slider range => [$CFG->{log_fontsize}, 0.5, 2, 0, 0.1], tooltip => "The font size used by the message/server log window only. Changes are instant.", - on_changed => sub { $LOGVIEW->set_fontsize ($CFG->{log_fontsize} = $_[1]) }, + 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"); @@ -292,6 +479,7 @@ on_changed => sub { $CFG->{stat_fontsize} = $_[1]; &set_stats_window_fontsize; + 0 } ); @@ -302,6 +490,7 @@ on_changed => sub { $CFG->{gauge_fontsize} = $_[1]; &set_gauge_window_fontsize; + 0 } ); @@ -312,6 +501,7 @@ on_changed => sub { $CFG->{gauge_size} = $_[1]; $GAUGES->{win}->set_size ($WIDTH, int $HEIGHT * $CFG->{gauge_size}); + 0 } ); @@ -321,6 +511,7 @@ on_activate => sub { video_shutdown (); video_init (); + 0 } ); @@ -338,9 +529,7 @@ $table->add (1, $row++, new CFClient::UI::CheckBox state => $CFG->{audio_enable}, tooltip => "Master Audio Enable. If enabled, sound effects and music will be played. If disabled, no audio will be used and the soundcard will not be opened.", - on_changed => sub { - $CFG->{audio_enable} = $_[1]; - } + on_changed => sub { $CFG->{audio_enable} = $_[1]; 0 } ); # $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Effects Volume"); # $table->add (1, 8, new CFClient::UI::Slider range => [$CFG->{effects_volume}, 0, 128, 1], on_changed => sub { @@ -351,17 +540,12 @@ $hbox->add (new CFClient::UI::CheckBox expand => 1, state => $CFG->{bgm_enable}, tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played.", - on_changed => sub { - $CFG->{bgm_enable} = $_[1]; - } + on_changed => sub { $CFG->{bgm_enable} = $_[1]; 0 } ); $hbox->add (new CFClient::UI::Slider expand => 1, range => [$CFG->{bgm_volume}, 0, 1, 0, 1/128], tooltip => "The volume of the background music. Changes are instant.", - on_changed => sub { - $CFG->{bgm_volume} = $_[1]; - CFClient::MixMusic::volume $_[1] * 128; - } + on_changed => sub { $CFG->{bgm_volume} = $_[1]; CFClient::MixMusic::volume $_[1] * 128; 0 } ); $table->add (1, $row++, new CFClient::UI::Button @@ -370,6 +554,7 @@ on_activate => sub { audio_shutdown (); audio_init (); + 0 } ); @@ -441,13 +626,41 @@ $win } +sub debug_setup { + my $table = new CFClient::UI::Table; -sub make_stats_window { + $table->add (0, 0, new CFClient::UI::Label text => "Widget Borders"); + $table->add (1, 0, new CFClient::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 1; 0 }); + $table->add (0, 1, new CFClient::UI::Label text => "Tooltip Widget Info"); + $table->add (1, 1, new CFClient::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 2; 0 }); + $table->add (0, 2, new CFClient::UI::Label text => "Show FPS"); + $table->add (1, 2, new CFClient::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 4; 0 }); + $table->add (0, 3, new CFClient::UI::Label text => "Suppress Tooltips"); + $table->add (1, 3, new CFClient::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 8; 0 }); + + my @default_smooth = (0.05, 0.13, 0.05, 0.13, 0.30, 0.13, 0.05, 0.13, 0.05); + + for my $x (0..2) { + for my $y (0 .. 2) { + $table->add ($x + 3, $y, + new CFClient::UI::Entry + text => $default_smooth[$x * 3 + $y], + on_changed => sub { $MAP->{smooth_matrix}[$x * 3 + $y] = $_[1] if $MAP; 0 }, + ); + } + } + + + $table +} + +sub stats_window { my $tgw = new CFClient::UI::FancyFrame y => $HEIGHT * (2/8), x => "max", title => "Stats", - name => "stats_window"; + name => "stats_window", + has_close_button => 1; $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, @@ -539,7 +752,7 @@ font => $FONT_FIXED, can_hover => 1, can_events => 1, - image => "ui/resist/resist_$_.png", + path => "ui/resist/resist_$_.png", tooltip => $resist_names{$_}, ); @@ -603,26 +816,25 @@ $STATWIDS->{m_weight}->set_text (sprintf "Max weight: %.1fkg", $stats->{+CS_STAT_WEIGHT_LIM} / 1000); - # TODO: replace by CS_STAT_RES_xxx constants my %tbl = ( - phys => 100, - magic => 101, - fire => 102, - elec => 103, - cold => 104, - conf => 105, - acid => 106, - drain => 107, - ghit => 108, - pois => 109, - slow => 110, - para => 111, - tund => 112, - fear => 113, - depl => 113, - deat => 115, - holyw => 116, - blind => 117, + 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{$_}}) @@ -632,6 +844,11 @@ my $METASERVER_ATIME; sub update_metaserver { + my ($metaserver_dialog) = @_; + + $METASERVER = $metaserver_dialog + if defined $metaserver_dialog; + return if $METASERVER_ATIME > time; $METASERVER_ATIME = time + 60; @@ -662,9 +879,19 @@ $table->clear; - my @col = qw(Use #Users Host Uptime Version Description); - $table->add ($_, 0, new CFClient::UI::Label align => 0, fg => [1, 1, 0], text => $col[$_]) - for 0 .. $#col; + my @tip = ( + "The current number of users logged in on the server.", + "The hostname of the server.", + "The time this server has been running without being restarted.", + "The server software version - a '+' indicates a Crossfire+ server.", + "Short information about this server provided by its admins.", + ); + my @col = qw(#Users Host Uptime Version Description); + $table->add ($_, 0, new CFClient::UI::Label + can_hover => 1, can_events => 1, + align => 0, fg => [1, 1, 0], + text => $col[$_], tooltip => $tip[$_]) + for 0 .. $#col; my @align = qw(1 0 1 1 -1); @@ -691,16 +918,27 @@ $y++; - $table->add (0, $y, new CFClient::UI::VBox children => [ - (new CFClient::UI::Button text => "Use", on_activate => sub { - $HOST_ENTRY->set_text ($CFG->{host} = $host); - $METASERVER->toggle_visibility; - }), + $table->add (scalar @$m, $y, new CFClient::UI::VBox children => [ + (new CFClient::UI::Button + text => "Use", + tooltip => "Put this server into the Host:Port field", + on_activate => sub { + $HOST_ENTRY->set_text ($CFG->{profile}{default}{host} = $host); + $METASERVER->hide; + 0 + }, + ), (new CFClient::UI::Empty expand => 1), ]); - $table->add ($_ + 1, $y, new CFClient::UI::Label - ellipsise => 0, align => $align[$_], text => $m->[$_], fontsize => 0.8) + $table->add ($_, $y, new CFClient::UI::Label + ellipsise => 0, + align => $align[$_], + text => $m->[$_], + tooltip => $tip[$_], + can_hover => 1, + can_events => 1, + fontsize => 0.8) for 0 .. $#$m; } } @@ -708,19 +946,26 @@ } sub metaserver_dialog { + my $vbox = new CFClient::UI::VBox; + my $table = new CFClient::UI::Table; + $vbox->add (new CFClient::UI::ScrolledWindow expand => 1, child => $table); + my $dialog = new CFClient::UI::FancyFrame - title => "Server List", - name => 'metaserver_dialog', - x => 'center', - y => 'center', - child => (my $vbox = new CFClient::UI::VBox), + title => "Server List", + name => 'metaserver_dialog', + x => 'center', + y => 'center', + z => 3, + force_h => $::HEIGHT * 0.4, + child => $vbox, + has_close_button => 1, + table => $table, on_visibility_change => sub { - update_metaserver if $_[1]; + update_metaserver ($_[0]) if $_[1]; + 0 }, ; - $vbox->add ($dialog->{table} = new CFClient::UI::Table); - $dialog } @@ -736,44 +981,38 @@ $vbox->add ( $HOST_ENTRY = new CFClient::UI::Entry expand => 1, - text => $CFG->{host}, + text => $CFG->{profile}{default}{host}, tooltip => "The hostname or ip address of the Crossfire(+) server to connect to", on_changed => sub { my ($self, $value) = @_; - $CFG->{host} = $value; + $CFG->{profile}{default}{host} = $value; + 0 } ); - $METASERVER = metaserver_dialog; - $vbox->add (new CFClient::UI::Button expand => 1, text => "Server List", other => $METASERVER, tooltip => "Show a list of available crossfire servers", - on_activate => sub { $METASERVER->toggle_visibility }, + on_activate => sub { $METASERVER->toggle_visibility; 0 }, + on_visibility_change => sub { $METASERVER->hide unless $_[1]; 0 }, ); } $table->add (0, 4, new CFClient::UI::Label valign => 0, align => 1, text => "Username"); $table->add (1, 4, new CFClient::UI::Entry - text => $CFG->{user}, + text => $CFG->{profile}{default}{user}, tooltip => "The name of your character on the server", - on_changed => sub { - my ($self, $value) = @_; - $CFG->{user} = $value; - } + on_changed => sub { my ($self, $value) = @_; $CFG->{profile}{default}{user} = $value } ); $table->add (0, 5, new CFClient::UI::Label valign => 0, align => 1, text => "Password"); $table->add (1, 5, new CFClient::UI::Entry - text => $CFG->{password}, + text => $CFG->{profile}{default}{password}, hidden => 1, tooltip => "The password for your character", - on_changed => sub { - my ($self, $value) = @_; - $CFG->{password} = $value; - } + on_changed => sub { my ($self, $value) = @_; $CFG->{profile}{default}{password} = $value } ); $table->add (0, 7, new CFClient::UI::Label valign => 0, align => 1, text => "Map Size"); @@ -784,11 +1023,7 @@ . "If you set this to a high value you will be able to see further, " . "but you also increase bandwidth requirements and latency. " . "This option is only used once at log-in.", - on_changed => sub { - my ($self, $value) = @_; - - $CFG->{mapsize} = $self->{range}[0] = $value = int $value; - }, + on_changed => sub { my ($self, $value) = @_; $CFG->{mapsize} = $self->{range}[0] = $value = int $value; 0 }, ); $table->add (0, 8, new CFClient::UI::Label valign => 0, align => 1, text => "Face Prefetch"); @@ -801,21 +1036,21 @@ . "It also uses up server bandwidth on every connect, " . "so only set it if you really need to prefetch images. " . "This option can be set and unset any time.", - on_changed => sub { $CFG->{face_prefetch} = $_[1] }, + on_changed => sub { $CFG->{face_prefetch} = $_[1]; 0 }, ); $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Count"); $table->add (1, 9, new CFClient::UI::Entry text => $CFG->{output_count}, tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.", - on_changed => sub { $CFG->{output_count} = $_[1] }, + on_changed => sub { $CFG->{output_count} = $_[1]; 0 }, ); $table->add (0, 10, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Sync"); $table->add (1, 10, new CFClient::UI::Entry text => $CFG->{output_sync}, tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.", - on_changed => sub { $CFG->{output_sync} = $_[1] }, + on_changed => sub { $CFG->{output_sync} = $_[1]; 0 }, ); $table->add (1, 11, $LOGIN_BUTTON = new CFClient::UI::Button @@ -825,6 +1060,7 @@ on_activate => sub { $CONN ? stop_game : start_game; + 0 }, ); @@ -837,9 +1073,19 @@ on_changed => sub { my ($self, $value) = @_; $CFG->{say_command} = $value; + 0 } ); + $vbox->add (new CFClient::UI::Label + text => "Server Info", + fontsize => 1.2, + padding_y => 8, + fg => [1, 1, 0, 1], + ); + + $vbox->add ($SERVER_INFO = new CFClient::UI::Label ellipsise => 0); + $vbox } @@ -851,9 +1097,10 @@ bg => [0, 0, 0, 0.75], x => "max", y => 0, - force_w => $::WIDTH / 3, - force_h => $::HEIGHT / 5, - child => (my $vbox = new CFClient::UI::VBox); + force_w => $::WIDTH * 0.4, + force_h => $::HEIGHT * 0.5, + child => (my $vbox = new CFClient::UI::VBox), + has_close_button => 1; $vbox->add ($LOGVIEW); @@ -871,6 +1118,8 @@ $input->{refocus_map} = 1; } delete $input->{auto_activated}; + + 0 }, on_activate => sub { my ($input, $text) = @_; @@ -886,9 +1135,13 @@ delete $input->{refocus_map}; $MAPWIDGET->focus_in } + + 0 }, on_escape => sub { - $MAPWIDGET->focus_in + $MAPWIDGET->grab_focus; + + 0 }, ); @@ -905,6 +1158,7 @@ $QUIT_DIALOG = new CFClient::UI::FancyFrame x => "center", y => "center", + z => 50, title => "Really Quit?", ; @@ -919,7 +1173,7 @@ $hb->add (new CFClient::UI::Button text => "Ok", expand => 1, - on_activate => sub { $QUIT_DIALOG->hide }, + on_activate => sub { $QUIT_DIALOG->hide; 0 }, ); $hb->add (new CFClient::UI::Button text => "Quit anyway", @@ -936,42 +1190,43 @@ for ( ["General", 0, 0, - ["Enable autopickup" => CFClient::Pickup::PU_NEWMODE], - ["Inhibit autopickup" => CFClient::Pickup::PU_INHIBIT], - ["Stop before pickup" => CFClient::Pickup::PU_STOP], - ["Debug autopickup" => CFClient::Pickup::PU_DEBUG], + ["Enable autopickup" => PICKUP_NEWMODE], + ["Inhibit autopickup" => PICKUP_INHIBIT], + ["Stop before pickup" => PICKUP_STOP], + ["Debug autopickup" => PICKUP_DEBUG], ], ["Weapons", 0, 6, - ["All weapons" => CFClient::Pickup::PU_ALLWEAPON], - ["Missile weapons" => CFClient::Pickup::PU_MISSILEWEAPON], - ["Bows" => CFClient::Pickup::PU_BOW], - ["Arrows" => CFClient::Pickup::PU_ARROW], + ["All weapons" => PICKUP_ALLWEAPON], + ["Missile weapons" => PICKUP_MISSILEWEAPON], + ["Bows" => PICKUP_BOW], + ["Arrows" => PICKUP_ARROW], ], ["Armour", 0, 12, - ["Helmets" => CFClient::Pickup::PU_HELMET], - ["Shields" => CFClient::Pickup::PU_SHIELD], - ["Body Armour" => CFClient::Pickup::PU_ARMOUR], - ["Boots" => CFClient::Pickup::PU_BOOTS], - ["Gloves" => CFClient::Pickup::PU_GLOVES], - ["Cloaks" => CFClient::Pickup::PU_CLOAK], + ["Helmets" => PICKUP_HELMET], + ["Shields" => PICKUP_SHIELD], + ["Body Armour" => PICKUP_ARMOUR], + ["Boots" => PICKUP_BOOTS], + ["Gloves" => PICKUP_GLOVES], + ["Cloaks" => PICKUP_CLOAK], ], ["Readables", 2, 2, - ["Spellbooks" => CFClient::Pickup::PU_SPELLBOOK], - ["Skillscrolls" => CFClient::Pickup::PU_SKILLSCROLL], - ["Normal Books/Scrolls" => CFClient::Pickup::PU_READABLES], + ["Spellbooks" => PICKUP_SPELLBOOK], + ["Skillscrolls" => PICKUP_SKILLSCROLL], + ["Normal Books/Scrolls" => PICKUP_READABLES], ], ["Misc", 2, 7, - ["Food" => CFClient::Pickup::PU_FOOD], - ["Drinks" => CFClient::Pickup::PU_DRINK], - ["Valuables (Money, Gems)" => CFClient::Pickup::PU_VALUABLES], - ["Keys" => CFClient::Pickup::PU_KEY], - ["Magical Items" => CFClient::Pickup::PU_MAGICAL], - ["Potions" => CFClient::Pickup::PU_POTION], - ["Magic Devices" => CFClient::Pickup::PU_MAGIC_DEVICE], - ["Ignore cursed" => CFClient::Pickup::PU_NOT_CURSED], - ["Jewelery" => CFClient::Pickup::PU_JEWELS], + ["Food" => PICKUP_FOOD], + ["Drinks" => PICKUP_DRINK], + ["Valuables (Money, Gems)" => PICKUP_VALUABLES], + ["Keys" => PICKUP_KEY], + ["Magical Items" => PICKUP_MAGICAL], + ["Potions" => PICKUP_POTION], + ["Magic Devices" => PICKUP_MAGIC_DEVICE], + ["Ignore cursed" => PICKUP_NOT_CURSED], + ["Jewelery" => PICKUP_JEWELS], ], + ["Weight/Value ratio", 2, 17] ) { my ($title, $x, $y, @bits) = @$_; @@ -986,27 +1241,52 @@ state => $CFG->{pickup} & $mask, on_changed => sub { my ($box, $value) = @_; + if ($value) { $::CFG->{pickup} |= $mask; } else { - $::CFG->{pickup} = $::CFG->{pickup} & ~$mask; + $::CFG->{pickup} &= ~$mask; } - $::CONN->send (sprintf "command pickup %u", $::CFG->{pickup}) + + $::CONN->send_command ("pickup $::CFG->{pickup}") if defined $::CONN; + + 0 }); } } + $table->add (2, 18, new CFClient::UI::ValSlider + range => [0, 0, 16, 1, 1], + to_value => sub { ">= " . 5 * $_[0] }, + on_changed => sub { + my ($slider, $value) = @_; + + $::CFG->{pickup} &= ~0x7; + $::CFG->{pickup} |= int $value + if $value; + 1; + }); + $table->add (3, 18, new CFClient::UI::Button + text => "set", + on_activate => sub { + $::CONN->send_command ("pickup $::CFG->{pickup}") + if defined $::CONN; + 0 + }); + $table } -sub make_inventory_window { +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); @@ -1031,16 +1311,20 @@ new CFClient::UI::SpellList } +sub update_bindings { + $BIND_UPD_CB->() if $BIND_UPD_CB; +} + sub keyboard_setup { my $binding_list = new CFClient::UI::VBox; my $refresh; - $refresh = sub { + $refresh = $BIND_UPD_CB = sub { $binding_list->clear (); - for my $mod (keys %{$::CFG->{bindings}}) { - for my $sym (keys %{$::CFG->{bindings}->{$mod}}) { - my $cmds = $::CFG->{bindings}->{$mod}->{$sym}; + for my $mod (keys %{$::CFG->{profile}{default}{bindings}}) { + for my $sym (keys %{$::CFG->{profile}{default}{bindings}{$mod}}) { + my $cmds = $::CFG->{profile}{default}{bindings}{$mod}{$sym}; next unless ref $cmds eq 'ARRAY' and @$cmds > 0; my $lbl = join "; ", @$cmds; @@ -1051,7 +1335,8 @@ tooltip => "Deletes the binding", on_activate => sub { $binding_list->remove ($hb); - delete $::CFG->{bindings}->{$mod}->{$sym}; + delete $::CFG->{profile}{default}{bindings}{$mod}{$sym}; + 0 }); $hb->add (new CFClient::UI::Button @@ -1059,11 +1344,11 @@ tooltip => "Edits the binding", on_activate => sub { $::BIND_EDITOR->set_binding ( - $mod, $sym, $::CFG->{bindings}->{$mod}->{$sym}, + $mod, $sym, $::CFG->{profile}{default}{bindings}{$mod}{$sym}, sub { my ($nmod, $nsym, $ncmds) = @_; - delete $::CFG->{bindings}->{$mod}->{$sym}; - $::CFG->{bindings}->{$nmod}->{$nsym} = $ncmds; + $::BIND_EDITOR->cfg_unbind ($mod, $sym); + $::BIND_EDITOR->cfg_bind ($nmod, $nsym, $ncmds); $refresh->(); $SETUP_NOTEBOOK->set_current_page ($SETUP_KEYBOARD); $SETUP_DIALOG->show; @@ -1074,6 +1359,7 @@ }); $::BIND_EDITOR->show; $SETUP_DIALOG->hide; + 0 }); $hb->add (new CFClient::UI::Label text => "(Key: $nam)"); @@ -1083,6 +1369,18 @@ }; my $vb = new CFClient::UI::VBox; + $vb->add (my $hb = new CFClient::UI::HBox); + $hb->add (new CFClient::UI::Label text => "only shift-up stops fire"); + $hb->add (new CFClient::UI::CheckBox + expand => 1, + state => $CFG->{shift_fire_stop}, + tooltip => "If this checkbox is enabled you will stop fire only if you stop pressing shift", + on_changed => sub { + my ($cbox, $value) = @_; + $CFG->{shift_fire_stop} = $value; + 0 + }); + $vb->add ($binding_list); $vb->add (my $hb = new CFClient::UI::HBox); @@ -1094,7 +1392,7 @@ $::BIND_EDITOR->set_binding (undef, undef, [], sub { my ($mod, $sym, $cmds) = @_; - $::CFG->{bindings}->{$mod}->{$sym} = $cmds; + $::BIND_EDITOR->cfg_bind ($mod, $sym, $cmds); $refresh->(); $SETUP_NOTEBOOK->set_current_page ($SETUP_KEYBOARD); $SETUP_DIALOG->show; @@ -1106,6 +1404,7 @@ ); $SETUP_DIALOG->hide; $::BIND_EDITOR->show; + 0 }, ); @@ -1115,6 +1414,7 @@ expand => 1, on_activate => sub { $SETUP_DIALOG->hide; + 0 } ); @@ -1123,10 +1423,11 @@ $vb } -sub make_help_window { +sub help_window { my $win = new CFClient::UI::FancyFrame x => 'center', y => 'center', + z => 2, name => 'doc_browser', force_w => int $WIDTH * 7/8, force_h => int $HEIGHT * 7/8, @@ -1135,33 +1436,48 @@ $win->add (my $vbox = new CFClient::UI::VBox); $vbox->add (my $buttons = new CFClient::UI::HBox); - $vbox->add (my $viewer = new CFClient::UI::TextView expand => 1, fontsize => 0.8); + $vbox->add (my $viewer = new CFClient::UI::TextScroller + expand => 1, fontsize => 0.8, padding_x => 4); - for ( - [intro => "Introduction"], - [manual => "Manual"], - [command_help => "Commands"], - [skill_help => "Skills"], - ) { - my ($pod, $label) = @$_; + $buttons->add (new CFClient::UI::Label text => "Choose a document to display: "); + $buttons->add (my $combo = new CFClient::UI::Combobox + value => undef, + options => [ + [intro => "Introduction"], + [manual => "Main Manual"], + [skill_help => "Skill Reference"], + [command_help => "Command Reference"], + [dmcommand_help => "DM Commands"], + [COPYING => "License Terms"], + ], + on_changed => sub { + my ($self, $pod) = @_; - $buttons->add (new CFClient::UI::Button - text => $label, - on_activate => sub { - my $parser = new Pod::POM; - my $pom = $parser->parse_file (CFClient::find_rcfile "pod/$pod.pod"); + my $pom = CFClient::load_pod CFClient::find_rcfile "pod/$pod.pod", + doc_viewer => 1, sub { CFClient::pod_to_pango_list $_[0] }; - $viewer->clear; - - $viewer->add_paragraph ([1, 1, 1, 1], $_->[1], $_->[0]) - for @{ CFClient::pod_to_pango_list $pom }; + $viewer->clear; - $viewer->set_offset (0); - }, - ); - } +# $viewer->add_paragraph ([1, 1, 1, 1], ["Test\n\n \x{fffc} \x{fffc}\n", +# (new CFClient::UI::Image path => "x.png", can_hover => 1, can_events => 1), +# (new CFClient::UI::Label text => "üüüü", can_hover => 1, can_events => 1, tooltip => "??"), +# ]);#d# + + $viewer->add_paragraph ([1, 1, 1, 1], $_->[1], $_->[0]) + for @$pom; - $viewer->add_paragraph ([1, 1, 0, 1], "Use one of the buttons above to display a document."); + $viewer->set_offset (0); + + 0 + }, + on_visibility_change => sub { + my ($self, $visible) = @_; + return unless $visible; + return if $self->{value}; + $self->set_value ("intro"); + 0 + }, + ); $win } @@ -1208,7 +1524,7 @@ force_y => 0; $DEBUG_STATUS->show; - $BIND_EDITOR = new CFClient::UI::BindEditor (x => "max", y => 0); + $BIND_EDITOR = new CFClient::BindingEditor (x => "max", y => 0); $STATUSBOX = new CFClient::UI::Statusbox; $STATUSBOX->add ("Use Alt-Enter to toggle fullscreen mode", timeout => 864000, pri => -100, color => [1, 1, 1, 0.8]); @@ -1238,7 +1554,7 @@ if ($CONSOLE) { $CONSOLE->{input}->{auto_activated} = 1; - $CONSOLE->{input}->focus_in; + $CONSOLE->{input}->grab_focus; if ($preset && $CONSOLE->{input}->get_text eq '') { $CONSOLE->{input}->set_text ($preset); @@ -1246,12 +1562,13 @@ } }); $MAPWIDGET->show; - $MAPWIDGET->focus_in; + $MAPWIDGET->grab_focus; - $LOGVIEW = new CFClient::UI::TextView + $LOGVIEW = new CFClient::UI::TextScroller expand => 1, font => $FONT_FIXED, fontsize => $::CFG->{log_fontsize}, + indent => -4, can_hover => 1, can_events => 1, tooltip => "Server Log. This text viewer contains all the messages sent by the server.", @@ -1265,42 +1582,47 @@ z => 2, force_w => $::WIDTH * 0.6, force_h => $::HEIGHT * 0.6, + has_close_button => 1, ; + $METASERVER = metaserver_dialog; + $SETUP_DIALOG->add ($SETUP_NOTEBOOK = new CFClient::UI::Notebook expand => 1, debug => 1, - filter => new CFClient::UI::ScrolledWindow xxx => 1, expand => 1, scroll_y => 1); + filter => new CFClient::UI::ScrolledWindow expand => 1, scroll_y => 1); $SETUP_NOTEBOOK->add (Server => $SETUP_SERVER = server_setup, "Configure the server to play on, your username, password and other server-related options."); $SETUP_NOTEBOOK->add (Pickup => autopickup_setup, - "Configure autopicking stetings, i.e. which items you will pick up automatically when walking over them."); + "Configure autopickup settings, i.e. which items you will pick up automatically when walking (or running) over them."); $SETUP_NOTEBOOK->add (Graphics => graphics_setup, "Configure the video mode, performance, fonts and other graphical aspects of the game."); $SETUP_NOTEBOOK->add (Audio => audio_setup, "Configure the use of audio, sound effects and background music."); $SETUP_NOTEBOOK->add (Keyboard => $SETUP_KEYBOARD = keyboard_setup, - "Lets you define, edit and delete bindings." - . "There is a shortcut for making bindings: Left Control + Insert opens the binding editor " + "Lets you define, edit and delete key bindings." + . "There is a shortcut for making bindings: Control-Insert opens the binding editor " . "with nothing set and the recording started. After doing the actions you " . "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."); - $BUTTONBAR = new CFClient::UI::HBox x => 0, y => 0; + $BUTTONBAR = new CFClient::UI::Buttonbar x => 0, y => 0, z => 200; # put on top $BUTTONBAR->add (new CFClient::UI::Flopper text => "Setup", other => $SETUP_DIALOG, tooltip => "Toggles a dialog where you can configure all aspects of this client."); - $BUTTONBAR->add (new CFClient::UI::Flopper text => "Message Window", other => message_window, + $BUTTONBAR->add (new CFClient::UI::Flopper text => "Message Window", other => $MESSAGE_WINDOW = message_window, tooltip => "Toggles the server message log, where the client collects all messages from the server."); 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 => make_stats_window, + $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 => make_inventory_window, + $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."); @@ -1311,10 +1633,11 @@ $::CFG->{layout} = CFClient::UI::get_layout; CFClient::write_cfg "$Crossfire::VARDIR/cfplusrc"; status "Configuration Saved"; + 0 }, ); - $BUTTONBAR->add (new CFClient::UI::Flopper text => "Help!", other => make_help_window, + $BUTTONBAR->add (new CFClient::UI::Flopper text => "Help!", other => help_window, tooltip => "View Documentation"); $BUTTONBAR->add (new CFClient::UI::Button @@ -1326,6 +1649,7 @@ } else { exit; } + 0 }, ); @@ -1337,6 +1661,8 @@ } sub video_shutdown { + CFClient::OpenGL::shutdown; + undef $SDL_ACTIVE; } @@ -1562,35 +1888,38 @@ CFClient::UI::set_layout ($::CFG->{layout}); my %DEF_CFG = ( - sdl_mode => 0, - width => 640, - height => 480, - fullscreen => 0, - fast => 0, - map_scale => 1, - fow_enable => 1, - fow_intensity => 0.45, - fow_smooth => 0, - gui_fontsize => 1, - log_fontsize => 1, - gauge_fontsize=> 1, - gauge_size => 0.35, - stat_fontsize => 1, - mapsize => 100, - host => "crossfire.schmorp.de", - say_command => 'say', - audio_enable => 1, - bgm_enable => 1, - bgm_volume => 0.25, - face_prefetch => 0, - output_sync => 1, - output_count => 1, + sdl_mode => 0, + width => 640, + height => 480, + fullscreen => 0, + fast => 0, + map_scale => 1, + fow_enable => 1, + fow_intensity => 0.45, + fow_smooth => 0, + gui_fontsize => 1, + log_fontsize => 0.7, + gauge_fontsize => 1, + gauge_size => 0.35, + stat_fontsize => 0.7, + mapsize => 100, + say_command => 'say', + audio_enable => 1, + bgm_enable => 1, + bgm_volume => 0.25, + face_prefetch => 0, + output_sync => 1, + output_count => 1, + pickup => 0, + default => "profile", # default profile ); - + while (my ($k, $v) = each %DEF_CFG) { $CFG->{$k} = $v unless exists $CFG->{$k}; } + $CFG->{profile}{default}{host} ||= "crossfire.schmorp.de"; + sdl_init; @SDL_MODES = reverse @@ -1641,6 +1970,8 @@ } Event::loop; +#CFClient::SDL_Quit; +#CFClient::_exit 0; END { CFClient::SDL_Quit }