ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/bin/deliantra
(Generate patch)

Comparing deliantra/Deliantra-Client/bin/deliantra (file contents):
Revision 1.78 by root, Tue Sep 30 03:05:07 2008 UTC vs.
Revision 1.110 by root, Mon Apr 12 02:03:33 2010 UTC

17 $zip->extractMember ("SPLASH.bmp", "$ENV{PAR_TEMP}/SPLASH.bmp"); 17 $zip->extractMember ("SPLASH.bmp", "$ENV{PAR_TEMP}/SPLASH.bmp");
18 } 18 }
19 19
20 require Win32::GUI::SplashScreen; 20 require Win32::GUI::SplashScreen;
21 21
22 # initialise the resolver now, as vista forces us back to the desktop
23 # when doing this.
24 use AnyEvent::DNS ();
25 AnyEvent::DNS::resolver;
26
22 Win32::GUI::SplashScreen::Show ( 27 Win32::GUI::SplashScreen::Show (
23 -file => "$ENV{PAR_TEMP}/SPLASH.bmp", 28 -file => "$ENV{PAR_TEMP}/SPLASH.bmp",
24 ); 29 );
25 30
26 $startup_done = sub { 31 $startup_done = sub {
27 Win32::GUI::SplashScreen::Done (1); 32 Win32::GUI::SplashScreen::Done (1);
28 }; 33 };
29 } 34 }
30} 35}
31 36
32use strict; 37use common::sense;
33use utf8;
34 38
35use Carp 'verbose'; 39use Carp 'verbose';
36 40
37# do things only needed for single-binary version (par) 41# do things only needed for single-binary version (par)
38BEGIN { 42BEGIN {
51 55
52 if ($^O eq "MSWin32") { 56 if ($^O eq "MSWin32") {
53 # pango is relocatable on win32 57 # pango is relocatable on win32
54 } else { 58 } else {
55 # OS X 59 # OS X
56 $ENV{FONTCONFIG_FILE} = "$root/fonts.conf"; # no effect??!?!
57 $ENV{FONTCONFIG_DIR} = $root; # no effect??!?!
58 $ENV{PANGO_RC_FILE} = "$root/pango.rc"; 60 $ENV{PANGO_RC_FILE} = "$root/pango.rc";
59 $ENV{DYLD_LIBRARY_PATH} = $root; 61 $ENV{DYLD_LIBRARY_PATH} = $root;
60 chdir $root; # for pango modules, maybe other things 62 chdir $root; # for pango modules, maybe other things
61 } 63 }
62 64
63 unshift @INC, $root; 65 unshift @INC, $root;
64 } 66 }
65} 67}
66 68
67# prepend private library directory 69# prepend private library directory and prepare env
68BEGIN { 70BEGIN {
69 for (grep !ref, @INC) { 71 for (grep !ref, @INC) {
70 my $path = "$_/Deliantra/Client/private"; 72 my $path = "$_/Deliantra/Client/private";
71 if (-d $path) { 73 if (-d $path) {
72 unshift @INC, $path; 74 unshift @INC, $path;
86 88
87use Deliantra; 89use Deliantra;
88use Deliantra::Protocol::Constants; 90use Deliantra::Protocol::Constants;
89 91
90use AnyEvent::Util (); 92use AnyEvent::Util ();
91use AnyEvent::DNS;
92use AnyEvent::Socket (); 93use AnyEvent::Socket ();
94use AnyEvent::DNS ();
93 95
94use Compress::LZF; 96use Compress::LZF;
95use JSON::XS; 97use JSON::XS;
96 98
97use DC; 99use DC;
125 127
126$SIG{QUIT} = sub { Carp::cluck "QUIT" }; 128$SIG{QUIT} = sub { Carp::cluck "QUIT" };
127$SIG{PIPE} = 'IGNORE'; 129$SIG{PIPE} = 'IGNORE';
128 130
129$EV::DIED = sub { 131$EV::DIED = sub {
130 crash "CRASH/EV::DIED: $@" => 1; 132 crash "CRASH/EV::DIED: $@" => 0;
131 DC::fatal Carp::longmess $@; 133 DC::fatal Carp::longmess $@;
132}; 134};
133 135
134my $MAX_FPS = 60; 136my $MAX_FPS = 60;
137
138our $DEFAULT_SERVER = "gameserver.deliantra.net";
135 139
136our $META_SERVER = "http://metaserver.schmorp.de/current.json"; 140our $META_SERVER = "http://metaserver.schmorp.de/current.json";
137 141
138our $LAST_REFRESH; 142our $LAST_REFRESH;
139our $NOW; 143our $NOW;
140 144
141our $CFG; 145our $CFG;
142our $PROFILE; # current profile 146our $PROFILE; # current profile
143our $FAST; # fast, low-quality mode, possibly useful for software-rendering 147our $FAST; # fast, low-quality mode, possibly useful for software-rendering
148our $DELIANTRA_DEBUG = $ENV{DELIANTRA_DEBUG} * 1;
144 149
145our $WANT_REFRESH; 150our $WANT_REFRESH;
146 151
147our $MODE_SLIDER; 152our $MODE_SLIDER;
148our $CAVEAT_LABEL; 153our $CAVEAT_LABEL;
161 166
162our $MAP; 167our $MAP;
163our $MAPMAP; 168our $MAPMAP;
164our $MAPWIDGET; 169our $MAPWIDGET;
165our $COMPLETER; 170our $COMPLETER;
166our $BUTTONBAR; 171our $MENUFRAME; # the rectangle at the top
172our $MENUBAR; # the hbox at the top
173our $MENUPOPUP;
174our $BUTTONBAR; # the menu buttons
167our $METASERVER; 175our $METASERVER;
168our $LOGIN_BUTTON; 176our $LOGIN_BUTTON;
169our $QUIT_DIALOG; 177our $QUIT_DIALOG;
170our $HOST_ENTRY; 178our $HOST_ENTRY;
171our $FULLSCREEN_ENABLE; 179our $FULLSCREEN_ENABLE;
197our $FLOORBOX; 205our $FLOORBOX;
198our $GAUGES; 206our $GAUGES;
199our $STATWIDS; 207our $STATWIDS;
200 208
201our $SDL_ACTIVE; 209our $SDL_ACTIVE;
202our %SDL_CB; 210our @SDL_CB;
203 211
204our $ALT_ENTER_MESSAGE; 212our $ALT_ENTER_MESSAGE;
205our $STATUSBOX; 213our $STATUSBOX;
206our $MODBOX; 214our $MODBOX;
207our $DEBUG_STATUS; 215our $DEBUG_STATUS;
215# write a crash message blockingly to the socket, if possible 223# write a crash message blockingly to the socket, if possible
216# this is a bit too complicated for my tastes, but it was easy. 224# this is a bit too complicated for my tastes, but it was easy.
217*crash = sub($;$) { 225*crash = sub($;$) {
218 my ($msg, $backtrace) = @_; 226 my ($msg, $backtrace) = @_;
219 227
228 warn $msg;
229
220 return unless $CONN; 230 return unless $CONN;
221 231
222 my $fh = $CONN->{fh} 232 my $fh = $CONN->{fh}
223 or return; 233 or return;
224 234
234 244
235 # backtrace as second step, in case it crashes, too 245 # backtrace as second step, in case it crashes, too
236 crash Carp::longmess "$msg\nbacktrace, for client version $DC::VERSION, generated" 246 crash Carp::longmess "$msg\nbacktrace, for client version $DC::VERSION, generated"
237 if $backtrace; 247 if $backtrace;
238}; 248};
249
250sub clienterror($;$) {
251 my ($msg, $backtrace) = @_;
252
253 warn $msg;
254
255 return unless $CONN;
256
257 $CONN->send_exti_msg (clientlog => $msg);
258 $CONN->send_exti_msg (clientlog => Carp::longmess "$msg\nbacktrace, for client version $DC::VERSION, generated") if $backtrace;
259}
239 260
240############################################################################# 261#############################################################################
241 262
242sub status { 263sub status {
243 $STATUSBOX->add (DC::asxml $_[0], pri => -10, group => "status", timeout => 10, fg => [1, 1, 0, 1]); 264 $STATUSBOX->add (DC::asxml $_[0], pri => -10, group => "status", timeout => 10, fg => [1, 1, 0, 1]);
325 or return; 346 or return;
326 347
327 $meta->{data} 348 $meta->{data}
328 or return; 349 or return;
329 350
330 # if its a jingle, play it as ambient music 351 # if it's a jingle, play it as ambient music
331 if ($meta->{data}{jingle}) { 352 if ($meta->{data}{jingle}) {
332 if (delete $AUDIO_PLAY{$face}) { # take the jingle out of the sound queue 353 if (delete $AUDIO_PLAY{$face}) { # take the jingle out of the sound queue
333 push @MUSIC_JINGLE, $meta; # push it oto the music/jingle queue 354 push @MUSIC_JINGLE, $meta; # push it unto the music/jingle queue
334 &audio_music_push ($face); 355 &audio_music_push ($face);
335 } 356 }
336 } else { 357 } else {
337 # fetch from database 358 # fetch from database
338 DC::DB::get res_data => $meta->{name}, sub { 359 DC::DB::get res_data => $meta->{name}, sub {
339 my $rwops = new DC::RW $_[0]; 360 my $rwops = new DC::RW $_[0];
340 my $chunk = new DC::MixChunk $rwops 361 my $chunk = new DC::MixChunk $rwops
341 or Carp::confess "sound face " . (JSON::XS::encode_json $meta) . " unloadable: " . DC::Mix_GetError; 362 or Carp::confess "sound face " . (JSON::XS::encode_json $meta) . " (" . (unpack "H64", $_[0]) . ") unloadable: " . DC::Mix_GetError;
342 $chunk->volume (($meta->{data}{volume} || 1) * 128); 363 $chunk->volume (($meta->{data}{volume} || 1) * 128);
343 $AUDIO_CHUNK{$face} = $chunk; 364 $AUDIO_CHUNK{$face} = $chunk;
344 365
345 audio_sound_push ($face); 366 audio_sound_push ($face);
346 }; 367 };
393 414
394 audio_music_update_volume; 415 audio_music_update_volume;
395 416
396 $MUSIC_PLAYING_DATA = \$_[0]; 417 $MUSIC_PLAYING_DATA = \$_[0];
397 418
419 $meta->{path} or length $_[0]
420 or return clienterror "empty music face from res_data ($meta->{face})";#d#
421
398 my $rwops = $meta->{path} 422 my $rwops = $meta->{path}
399 ? new_from_file DC::RW $meta->{path} 423 ? (new_from_file DC::RW $meta->{path} or return clienterror "unable to load music face $meta->{path}: $!")#d#clienterror
400 : new DC::RW $$MUSIC_PLAYING_DATA; 424 : new DC::RW $$MUSIC_PLAYING_DATA;
401 425
402 $MUSIC_PLAYER = new DC::MixMusic $rwops 426 $MUSIC_PLAYER = new DC::MixMusic $rwops
403 or Carp::confess "music face $meta->{face} unloadable: " . DC::Mix_GetError; 427 or return clienterror "music face $meta->{face} unloadable: " . DC::Mix_GetError => 1;
404 428
405 my $NOW = time; 429 my $NOW = time;
406 430
407 if ($MUSIC_PLAYING_META->{stop_time} > $NOW - $MUSIC_RESUME) { 431 if ($MUSIC_PLAYING_META->{stop_time} > $NOW - $MUSIC_RESUME) {
408 my $pos = $MUSIC_PLAYING_META->{stop_pos}; 432 my $pos = $MUSIC_PLAYING_META->{stop_pos};
517 sub audio_tab_update; 541 sub audio_tab_update;
518 audio_tab_update; 542 audio_tab_update;
519} 543}
520 544
521sub audio_shutdown { 545sub audio_shutdown {
546 if ($SDL_MIXER) {
547 DC::MixMusic::halt;
548 DC::Mix_AllocateChannels 0;
549 }
550
522 undef $MUSIC_PLAYER; 551 undef $MUSIC_PLAYER;
523 undef $MUSIC_PLAYING_META; 552 undef $MUSIC_PLAYING_META;
524 undef $MUSIC_PLAYING_DATA; 553 undef $MUSIC_PLAYING_DATA;
525 554
526 $MUSIC_WANT = []; 555 $MUSIC_WANT = [];
766} 795}
767 796
768sub dc_connect { 797sub dc_connect {
769 my ($host, $port) = @_; 798 my ($host, $port) = @_;
770 799
771 my $mapsize = List::Util::min 32, List::Util::max 11, int $WIDTH * $CFG->{mapsize} * 0.01 / 32; 800 my $mapw = List::Util::min 48, List::Util::max 11, int 1.5 + $WIDTH * $CFG->{mapsize} * 0.01 / 32;
801 my $maph = List::Util::min 48, List::Util::max 11, int 1.5 + $HEIGHT * $CFG->{mapsize} * 0.01 / 32;
772 802
773 $CONN = 803 $CONN =
774 new DC::Protocol 804 new DC::Protocol
775 host => $host, 805 host => $host,
776 port => $port, 806 port => $port,
777 user => $PROFILE->{user}, 807 user => $PROFILE->{user},
778 pass => $PROFILE->{password}, 808 pass => $PROFILE->{password},
779 mapw => $mapsize, 809 mapw => $mapw,
780 maph => $mapsize, 810 maph => $maph,
781 811
812 c_version => {
813 client => "deliantra",
782 client => "$DC::VERSION $] $^O", 814 clientver => $DC::VERSION,
815 gl_vendor => DC::OpenGL::gl_vendor,
816 gl_version => DC::OpenGL::gl_version,
817 },
783 818
784 map_widget => $MAPWIDGET, 819 map_widget => $MAPWIDGET,
785 statusbox => $STATUSBOX, 820 statusbox => $STATUSBOX,
786 map => $MAP, 821 map => $MAP,
787 mapmap => $MAPMAP, 822 mapmap => $MAPMAP,
793 828
794 on_connect => sub { 829 on_connect => sub {
795 if ($_[0]) { 830 if ($_[0]) {
796 DC::lowdelay fileno $CONN->{fh}; 831 DC::lowdelay fileno $CONN->{fh};
797 832
798 status "login successful"; 833 status "successfully connected to the server";
799 } else { 834 } else {
800 undef $CONN; 835 undef $CONN;
801 status "unable to connect: $!"; 836 status "unable to connect: $!";
802 stop_game(); 837 stop_game();
803 } 838 }
805 ; 840 ;
806} 841}
807 842
808sub start_game { 843sub start_game {
809 status "logging in..."; 844 status "logging in...";
845
846 my $server = $PROFILE->{host} || $DEFAULT_SERVER;
847 my ($host, $port) = AnyEvent::Socket::parse_hostport $server, "deliantra=13327"
848 or return status "$server: unable to parse server address, try an empty field.";
810 849
811 $LOGIN_BUTTON->set_text ("Logout"); 850 $LOGIN_BUTTON->set_text ("Logout");
812 $SETUP_DIALOG->hide; 851 $SETUP_DIALOG->hide;
813
814 my ($host, $port) = AnyEvent::Socket::parse_hostport $PROFILE->{host}, "deliantra=13327";
815 852
816 $MAP = new DC::Map; 853 $MAP = new DC::Map;
817 854
818 # hack to make SURE we find the IP address all right 855 # hack to make SURE we find the IP address all right
819 # can be removed once AnyEvent::DNS is proven stable. 856 # can be removed once AnyEvent::DNS is proven stable.
820 if ($host eq "gameserver.deliantra.net") { 857 if ($host eq "gameserver.deliantra.net") {
821 AnyEvent::DNS::a "dnstest.deliantra.net", sub { 858 AnyEvent::DNS::a "dnstest.deliantra.net", sub {
822 if ($_[0] ne "80.101.114.108") { # Perl 859 if ($_[0] ne "80.101.114.108") { # Perl
860 status "dns failure, trying differently";
861 $host = eval { Socket::inet_ntoa Socket::inet_aton "gameserver.deliantra.net" };
862 unless (defined $host) {
823 status "dns failure, using hardcoded address"; 863 status "dns failure, using hardcoded address";
824 $host = "129.13.162.95"; 864 $host = "129.13.162.95";
865 }
825 } 866 }
826 867
827 dc_connect $host, $port; 868 dc_connect $host, $port;
828 }; 869 };
829 } else { 870 } else {
896 937
897 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Video Mode"); 938 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Video Mode");
898 $table->add_at (1, $row++, my $hbox = new DC::UI::HBox); 939 $table->add_at (1, $row++, my $hbox = new DC::UI::HBox);
899 940
900 $hbox->add ($MODE_SLIDER = new DC::UI::Slider 941 $hbox->add ($MODE_SLIDER = new DC::UI::Slider
942 c_rescale => 1,
901 force_w => $WIDTH * 0.1, expand => 1, 943 force_w => $WIDTH * 0.1, expand => 1,
902 range => [ ($CFG->{sdl_mode}) x 3 ], 944 range => [ ($CFG->{sdl_mode}) x 3 ],
903 tooltip => $vidmode_tooltip); 945 tooltip => $vidmode_tooltip);
904 $hbox->add (my $mode_label = new DC::UI::Label 946 $hbox->add (my $mode_label = new DC::UI::Label
905 height => 0.8, template => "9999x9999@9+9", 947 height => 0.8, template => "9999x9999@9+9",
933 ); 975 );
934 976
935 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Forbid Alpha"); 977 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Forbid Alpha");
936 $table->add_at (1, $row++, new DC::UI::CheckBox 978 $table->add_at (1, $row++, new DC::UI::CheckBox
937 state => $CFG->{disable_alpha}, 979 state => $CFG->{disable_alpha},
938 tooltip => "Forbid off the use of the alpha channel. This makes Deliantra look a lot worse " 980 tooltip => "Forbid the use of the alpha channel. This makes Deliantra look a lot worse "
939 . "by disabling a number of textures and transparency effects. Normally, these " 981 . "by disabling a number of textures and transparency effects. Normally, these "
940 . "effects do not cost a lot of resources, but some graphics cards might fall " 982 . "effects do not cost a lot of resources, but some graphics cards might fall "
941 . "back to extremely slow rendering if this is enabled. If disabling this option " 983 . "back to extremely slow rendering if this is enabled. If disabling this option "
942 . "noticably improves the framerate of the client please report this! " 984 . "noticably improves the framerate of the client please report this! "
943 . "<b>If you experience extremely low framerates and your card should do better, try this option.</b>", 985 . "<b>If you experience extremely low framerates and your card should do better, try this option.</b>",
997 . "If you have a very slow system, non-accelerated drivers or plain dislike smooth scrolling, " 1039 . "If you have a very slow system, non-accelerated drivers or plain dislike smooth scrolling, "
998 . "then disable this option. Changes take effect immdiately.", 1040 . "then disable this option. Changes take effect immdiately.",
999 on_changed => sub { my ($self, $value) = @_; $CFG->{smooth_movement} = $value; 0 } 1041 on_changed => sub { my ($self, $value) = @_; $CFG->{smooth_movement} = $value; 0 }
1000 ); 1042 );
1001 1043
1044 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Smooth Transitions");
1045 $table->add_at (1, $row++, new DC::UI::CheckBox
1046 state => $CFG->{smooth_transitions},
1047 tooltip => "<b>Smooth Transitions</b> tries to blend the fog of war and lighting smoothly between updates. "
1048 . "If you have a very slow system, non-accelerated drivers or plain dislike smooth scrolling, "
1049 . "then disable this option. Requires Smooth Movement and OpenGL Multitexturing. Changes take effect immdiately.",
1050 on_changed => sub { my ($self, $value) = @_; $CFG->{smooth_transitions} = $value; 0 }
1051 );
1052
1053
1002 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Map Scale"); 1054 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Map Scale");
1003 $table->add_at (1, $row++, new DC::UI::Slider 1055 $table->add_at (1, $row++, new DC::UI::Slider
1004 range => [(log $CFG->{map_scale}) / (log 2), -3, 1, 0, 1], 1056 range => [(log $CFG->{map_scale}) / (log 2), -3, 1, 0, 1],
1005 tooltip => "Enlarge or shrink the displayed map. Changes are instant.", 1057 tooltip => "Enlarge or shrink the displayed map. Changes are instant.",
1006 on_changed => sub { my ($self, $value) = @_; $CFG->{map_scale} = 2 ** $value; 0 } 1058 on_changed => sub { my ($self, $value) = @_; $CFG->{map_scale} = 2 ** $value; 0 }
1018 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Fog of War"); 1070 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Fog of War");
1019 $table->add_at (1, $row++, new DC::UI::CheckBox 1071 $table->add_at (1, $row++, new DC::UI::CheckBox
1020 state => $CFG->{fow_enable}, 1072 state => $CFG->{fow_enable},
1021 tooltip => "<b>Fog-of-War</b> marks areas that cannot be seen by the player. Changes are instant.", 1073 tooltip => "<b>Fog-of-War</b> marks areas that cannot be seen by the player. Changes are instant.",
1022 on_changed => sub { my ($self, $value) = @_; $CFG->{fow_enable} = $value; 0 } 1074 on_changed => sub { my ($self, $value) = @_; $CFG->{fow_enable} = $value; 0 }
1075 );
1076
1077 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "FoW Pattern");
1078 $table->add_at (1, $row++, new DC::UI::ImageButton
1079 tex => $DC::MapWidget::TEX_HIDDEN[$CFG->{fow_texture}],
1080 bg => [0.3, 0.3, 0.2],
1081 force_w => 64,
1082 force_h => 64,
1083 tooltip => "<b>Fog of War Pattern.</b> The pattern that is overlaid over areas hidden from view. Click to cycle through various alternatives. Changes are instant.",
1084 on_activate => sub {
1085 my ($self) = @_;
1086 $CFG->{fow_texture} = ($CFG->{fow_texture} + 1) % @DC::MapWidget::TEX_HIDDEN;
1087 $self->set_texture ($DC::MapWidget::TEX_HIDDEN[$CFG->{fow_texture}]);
1088 $MAPWIDGET->update;
1089 }
1023 ); 1090 );
1024 1091
1025 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "FoW Intensity"); 1092 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "FoW Intensity");
1026 $table->add_at (1, $row++, new DC::UI::Slider 1093 $table->add_at (1, $row++, new DC::UI::Slider
1027 range => [$CFG->{fow_intensity}, 0, 1, 0, 1 / 256], 1094 range => [$CFG->{fow_intensity}, 0, 1, 0, 1 / 256],
1079 1146
1080 my $text = !$freq 1147 my $text = !$freq
1081 ? "audio is off" 1148 ? "audio is off"
1082 : "audio is enabled\n" 1149 : "audio is enabled\n"
1083 . "frequency (Hz): $freq\n" 1150 . "frequency (Hz): $freq\n"
1084 . "channels: $chans"; 1151 . "channels: $chans\n"
1152 . "chunk decoders available: " . (join ", ", DC::MixChunk::decoders) . "\n"
1153 . "music decoders available: " . (join ", ", DC::MixMusic::decoders);
1085 1154
1086 $AUDIO_INFO->set_text ($text); 1155 $AUDIO_INFO->set_text ($text);
1087} 1156}
1088 1157
1089sub audio_setup { 1158sub audio_setup {
1118 ); 1187 );
1119 1188
1120 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Background Music"); 1189 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Background Music");
1121 $table->add_at (1, $row, new DC::UI::CheckBox 1190 $table->add_at (1, $row, new DC::UI::CheckBox
1122 expand => 1, state => $CFG->{bgm_enable}, 1191 expand => 1, state => $CFG->{bgm_enable},
1123 tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played.", 1192 tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played. Needs server reconnect to take effect.",
1124 on_changed => sub { 1193 on_changed => sub {
1125 $CFG->{bgm_enable} = $_[1]; 1194 $CFG->{bgm_enable} = $_[1];
1126 $CONN->update_fx_want if $CONN; 1195 $CONN->update_fx_want if $CONN;
1127 audio_music_push; 1196 audio_music_push;
1128 1 1197 1
1229} 1298}
1230 1299
1231sub make_gauge_window { 1300sub make_gauge_window {
1232 my $gh = int $HEIGHT * $CFG->{gauge_size}; 1301 my $gh = int $HEIGHT * $CFG->{gauge_size};
1233 1302
1234 my $win = new DC::UI::Frame ( 1303 $GAUGES->{win} = my $win = new DC::UI::Frame (
1235 force_x => 0, 1304 force_x => 0,
1236 force_y => "max", 1305 force_y => "max",
1237 force_w => $WIDTH, 1306 force_w => $WIDTH,
1238 force_h => $gh, 1307 force_h => $gh,
1239 ); 1308 );
1255 (new DC::UI::Empty expand => 1), 1324 (new DC::UI::Empty expand => 1),
1256 (my $hb = new DC::UI::HBox), 1325 (my $hb = new DC::UI::HBox),
1257 ], 1326 ],
1258 ); 1327 );
1259 1328
1260 $hb->add (my $hg = new DC::UI::Gauge type => 'hp', tooltip => "#stat_health"); 1329 $hb->add ($GAUGES->{hp} = new DC::UI::Gauge type => 'hp', tooltip => "#stat_health");
1261 $hb->add (my $mg = new DC::UI::Gauge type => 'mana', tooltip => "#stat_mana"); 1330 $hb->add ($GAUGES->{mana} = new DC::UI::Gauge type => 'mana', tooltip => "#stat_mana");
1262 $hb->add (my $gg = new DC::UI::Gauge type => 'grace', tooltip => "#stat_grace"); 1331 $hb->add ($GAUGES->{grace} = new DC::UI::Gauge type => 'grace', tooltip => "#stat_grace");
1263 $hb->add (my $fg = new DC::UI::Gauge type => 'food', tooltip => "#stat_food"); 1332 $hb->add ($GAUGES->{food} = new DC::UI::Gauge type => 'food', tooltip => "#stat_food");
1264
1265 $vbox->add (my $exp = new DC::UI::Label align => 1, can_hover => 1, can_events => 1, tooltip => "#stat_exp");
1266 $vbox->add (my $prg = new DC::UI::ExperienceProgress);
1267 $vbox->add (my $sklprg = new DC::UI::ExperienceProgress);
1268 $vbox->add (my $rng = new DC::UI::Label align => 1, can_hover => 1, can_events => 1, tooltip => "#stat_ranged");
1269
1270 $GAUGES = {
1271 exp => $exp, prg => $prg, sklprg => $sklprg,
1272 win => $win, range => $rng,
1273 hp => $hg, mana => $mg, grace => $gg, food => $fg,
1274 };
1275 1333
1276 &set_gauge_window_fontsize; 1334 &set_gauge_window_fontsize;
1277 1335
1278 $win 1336 $win
1337}
1338
1339our $BW_WATCHER;
1340
1341sub debug_toggle($) {
1342 $DELIANTRA_DEBUG ^= $_[0];
1343
1344 if ($DELIANTRA_DEBUG & 16) {
1345 $BW_WATCHER = EV::periodic 0, 1, 0, sub {
1346 return unless $CONN;
1347 debug sprintf "%.2gKB/s", $CONN->{octets_in} / 1e3;
1348 $CONN->{octets_in} = 0;
1349 };
1350 } else {
1351 undef $BW_WATCHER;
1352 }
1353
1279} 1354}
1280 1355
1281sub debug_setup { 1356sub debug_setup {
1282 my $table = new DC::UI::Table; 1357 my $table = new DC::UI::Table;
1283 1358
1284 $table->add_at (0, 0, new DC::UI::Label text => "Widget Borders"); 1359 $table->add_at (0, 0, new DC::UI::Label text => "Widget Borders");
1285 $table->add_at (1, 0, new DC::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 1; 0 }); 1360 $table->add_at (1, 0, new DC::UI::CheckBox on_changed => sub { debug_toggle 1; 0 });
1286 $table->add_at (0, 1, new DC::UI::Label text => "Tooltip Widget Info"); 1361 $table->add_at (0, 1, new DC::UI::Label text => "Tooltip Widget Info");
1287 $table->add_at (1, 1, new DC::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 2; 0 }); 1362 $table->add_at (1, 1, new DC::UI::CheckBox on_changed => sub { debug_toggle 2; 0 });
1288 $table->add_at (0, 2, new DC::UI::Label text => "Show FPS"); 1363 $table->add_at (0, 2, new DC::UI::Label text => "Show FPS");
1289 $table->add_at (1, 2, new DC::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 4; 0 }); 1364 $table->add_at (1, 2, new DC::UI::CheckBox on_changed => sub { debug_toggle 4; 0 });
1290 $table->add_at (0, 3, new DC::UI::Label text => "Suppress Tooltips"); 1365 $table->add_at (0, 3, new DC::UI::Label text => "Suppress Tooltips");
1291 $table->add_at (1, 3, new DC::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 8; 0 }); 1366 $table->add_at (1, 3, new DC::UI::CheckBox on_changed => sub { debug_toggle 8; 0 });
1367 $table->add_at (0, 4, new DC::UI::Label text => "Show Bandwidth");
1368 $table->add_at (1, 4, new DC::UI::CheckBox on_changed => sub { debug_toggle 16; 0 });
1369
1292 $table->add_at (0, 4, new DC::UI::Button text => "die on click(tm)", on_activate => sub { &DC::debug() } ); 1370 $table->add_at (0, 6, new DC::UI::Button text => "die on click(tm)", on_activate => sub { &DC::debug() } );
1293
1294 $table->add_at (0, 5, new DC::UI::TextEdit text => "line1\0152\0153\nµikachu\nづx゙つ゛");#d# 1371 $table->add_at (0, 7, new DC::UI::TextEdit text => "line1\0152\0153\nµikachu\nづx゙つ゛");#d#
1295 1372
1296 $table->add_at (7,7, my $t = new DC::UI::Table expand => 0); 1373 $table->add_at (7,7, my $t = new DC::UI::Table expand => 0);
1297 $t->add_at (0,0, new DC::UI::Label text => "a a", c_rowspan => 1, c_colspan => 2); 1374 $t->add_at (0,0, new DC::UI::Label text => "a a", c_rowspan => 1, c_colspan => 2);
1298 $t->add_at (2,0, new DC::UI::Label text => "b\nb", c_rowspan => 2, c_colspan => 1, ellipsise => 0 ); 1375 $t->add_at (2,0, new DC::UI::Label text => "b\nb", c_rowspan => 2, c_colspan => 1, ellipsise => 0 );
1299 $t->add_at (1,2, new DC::UI::Label text => "c c", c_rowspan => 1, c_colspan => 2); 1376 $t->add_at (1,2, new DC::UI::Label text => "c c", c_rowspan => 1, c_colspan => 2);
1620 child => (my $table = new DC::UI::Table expand => 1, col_expand => [0, 1]), 1697 child => (my $table = new DC::UI::Table expand => 1, col_expand => [0, 1]),
1621 ); 1698 );
1622 1699
1623 $table->add_at (0, 4, new DC::UI::Label align => 1, text => "Username"); 1700 $table->add_at (0, 4, new DC::UI::Label align => 1, text => "Username");
1624 $table->add_at (1, 4, new DC::UI::Entry 1701 $table->add_at (1, 4, new DC::UI::Entry
1625 text => $CFG->{profile}{default}{user}, 1702 text => $PROFILE->{user},
1626 tooltip => "The name of your character on the server.", 1703 tooltip => "The name of your character on the server. The name is case-sensitive!",
1627 on_changed => sub { my ($self, $value) = @_; $CFG->{profile}{default}{user} = $value; 1 } 1704 on_changed => sub { my ($self, $value) = @_; $PROFILE->{user} = $value; 1 }
1628 ); 1705 );
1629 1706
1630 $table->add_at (0, 5, new DC::UI::Label align => 1, text => "Password"); 1707 $table->add_at (0, 5, new DC::UI::Label align => 1, text => "Password");
1631 $table->add_at (1, 5, new DC::UI::Entry 1708 $table->add_at (1, 5, new DC::UI::Entry
1632 text => $CFG->{profile}{default}{password}, 1709 text => $PROFILE->{password},
1633 hidden => 1, 1710 hidden => 1,
1634 tooltip => "The password for your character.", 1711 tooltip => "The password for your character.",
1635 on_changed => sub { my ($self, $value) = @_; $CFG->{profile}{default}{password} = $value; 1 } 1712 on_changed => sub { my ($self, $value) = @_; $PROFILE->{password} = $value; 1 }
1636 ); 1713 );
1637 1714
1638 $table->add_at (1, 11, $LOGIN_BUTTON = new DC::UI::Button 1715 $table->add_at (1, 11, $LOGIN_BUTTON = new DC::UI::Button
1639 expand => 1, 1716 expand => 1,
1640 text => "Login / Register", 1717 text => "Login / Register",
1676 $table->add_at (1, $row, my $vbox = new DC::UI::VBox); 1753 $table->add_at (1, $row, my $vbox = new DC::UI::VBox);
1677 1754
1678 $vbox->add ( 1755 $vbox->add (
1679 $HOST_ENTRY = new DC::UI::Entry 1756 $HOST_ENTRY = new DC::UI::Entry
1680 expand => 1, 1757 expand => 1,
1681 text => $CFG->{profile}{default}{host}, 1758 text => $PROFILE->{host},
1682 tooltip => "The hostname or ip address of the Deliantra server to connect to (e.g. <b>gameserver.deliantra.net</b>)", 1759 tooltip => "The hostname or ip address of the Deliantra server to connect to (e.g. <b>gameserver.deliantra.net</b>)",
1683 on_changed => sub { 1760 on_changed => sub {
1684 my ($self, $value) = @_; 1761 my ($self, $value) = @_;
1685 $CFG->{profile}{default}{host} = $value; 1762 $PROFILE->{host} = $value;
1686 1 1763 1
1687 } 1764 }
1688 ); 1765 );
1689 1766
1690 if (0) { #d# disabled 1767 if (0) { #d# disabled
1733 1810
1734 my $row = 0; 1811 my $row = 0;
1735 1812
1736 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Tip of the day"); 1813 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Tip of the day");
1737 $table->add_at (1, $row++, new DC::UI::CheckBox 1814 $table->add_at (1, $row++, new DC::UI::CheckBox
1815 c_colspan => 2,
1738 state => $CFG->{show_tips}, 1816 state => $CFG->{show_tips},
1739 tooltip => "Show the <b>Tip of the day</b> window at startup?", 1817 tooltip => "Show the <b>Tip of the day</b> window at startup?",
1740 on_changed => sub { 1818 on_changed => sub {
1741 my ($self, $value) = @_; 1819 my ($self, $value) = @_;
1742 $CFG->{show_tips} = $value; 1820 $CFG->{show_tips} = $value;
1744 } 1822 }
1745 ); 1823 );
1746 1824
1747 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Message Window Size"); 1825 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Message Window Size");
1748 $table->add_at (1, $row++, my $saycmd = new DC::UI::Entry 1826 $table->add_at (1, $row++, my $saycmd = new DC::UI::Entry
1827 c_colspan => 2,
1749 text => $CFG->{logview_max_par}, 1828 text => $CFG->{logview_max_par},
1750 tooltip => "This is maximum number of messages remembered in the <b>Message</b> window. If the server " 1829 tooltip => "This is maximum number of messages remembered in the <b>Message</b> window. If the server "
1751 . "sends more messages than this number, older messages get removed to save memory and " 1830 . "sends more messages than this number, older messages get removed to save memory and "
1752 . "computing time. A value of <b>0</b> disables this feature, but that is not recommended.", 1831 . "computing time. A value of <b>0</b> disables this feature, but that is not recommended.",
1753 on_changed => sub { 1832 on_changed => sub {
1755 $MESSAGE_DIST->set_max_par ($CFG->{logview_max_par} = $value*1); 1834 $MESSAGE_DIST->set_max_par ($CFG->{logview_max_par} = $value*1);
1756 0 1835 0
1757 }, 1836 },
1758 ); 1837 );
1759 1838
1839 $table->add_at (0, $row, new DC::UI::Label align => 1, text => "Config Autosave");
1840 $table->add_at (1, $row, new DC::UI::CheckBox
1841 state => $CFG->{config_autosave},
1842 tooltip => "Normally, configuration settings and the user interface layout "
1843 . "are saved on client exit. You can disable this behaviour by "
1844 . "unchecking this checkbox.",
1845 on_changed => sub {
1846 my ($self, $value) = @_;
1847 $CFG->{config_autosave} = $value;
1848 0
1849 }
1850 );
1851 $table->add_at (2, $row++, new DC::UI::Button
1852 text => "Save Now",
1853 tooltip => "Use this to manually save configuration and UI layout when "
1854 . "autosave is disabled.",
1855 on_activate => sub {
1856 DC::write_cfg;
1857 0
1858 }
1859 );
1860
1760 $table 1861 $table
1761} 1862}
1762 1863
1763sub autopickup_setup { 1864sub autopickup_setup {
1764 my $r = new DC::UI::ScrolledWindow ( 1865 my $r = new DC::UI::ScrolledWindow (
1770 col_expand => [0, 1, 0, 1], 1871 col_expand => [0, 1, 0, 1],
1771 ); 1872 );
1772 1873
1773 for ( 1874 for (
1774 ["General", 0, 0, 1875 ["General", 0, 0,
1775 ["Enable autopickup" => PICKUP_NEWMODE, \$PICKUP_ENABLE],
1776 ["Inhibit autopickup" => PICKUP_INHIBIT], 1876# ["Inhibit autopickup" => PICKUP_INHIBIT],
1777 ["Stop before pickup" => PICKUP_STOP], 1877 ["Stop before pickup" => PICKUP_STOP],
1778 ["Debug autopickup" => PICKUP_DEBUG], 1878 ["Debug autopickup" => PICKUP_DEBUG],
1779 ], 1879 ],
1780 ["Weapons", 0, 6, 1880 ["Weapons", 0, 6,
1781 ["All weapons" => PICKUP_ALLWEAPON], 1881 ["All weapons" => PICKUP_ALLWEAPON],
1829 $::CFG->{pickup} |= $mask; 1929 $::CFG->{pickup} |= $mask;
1830 } else { 1930 } else {
1831 $::CFG->{pickup} &= ~$mask; 1931 $::CFG->{pickup} &= ~$mask;
1832 } 1932 }
1833 1933
1834 $::CONN->send_command ("pickup $::CFG->{pickup}") 1934 $::CONN->send_pickup ($::CFG->{pickup})
1835 if defined $::CONN; 1935 if defined $::CONN;
1836 1936
1837 0 1937 0
1838 }); 1938 });
1839 1939
1856 }); 1956 });
1857 1957
1858 $table->add_at (3, 18, new DC::UI::Button 1958 $table->add_at (3, 18, new DC::UI::Button
1859 text => "set", 1959 text => "set",
1860 on_activate => sub { 1960 on_activate => sub {
1861 $::CONN->send_command ("pickup $::CFG->{pickup}") 1961 $::CONN->send_pickup ($::CFG->{pickup})
1862 if defined $::CONN; 1962 if defined $::CONN;
1863 0 1963 0
1864 }); 1964 });
1865 1965
1866 $r 1966 $r
1867} 1967}
1868 1968
1869my %SORT_ORDER = ( 1969my %SORT_ORDER = (
1870 type => sub { 1970 type => sub {
1971 use sort 'stable';
1871 sort { $a->{type} <=> $b->{type} or $a->{name} cmp $b->{name} } @_ 1972 sort { $a->{type} <=> $b->{type} or $a->{name} cmp $b->{name} } @_
1872 }, 1973 },
1873 mtime => sub { 1974 mtime => sub {
1975 use sort 'stable';
1874 my $NOW = time; 1976 my $NOW = time;
1875 sort { 1977 sort {
1876 my $atime = $a->{mtime} - $NOW; $atime = $atime < 5 * 60 ? int $atime / 60 : 6; 1978 my $atime = $a->{mtime} - $NOW; $atime = $atime < 5 * 60 ? int $atime / 60 : 6;
1877 my $btime = $b->{mtime} - $NOW; $btime = $btime < 5 * 60 ? int $btime / 60 : 6; 1979 my $btime = $b->{mtime} - $NOW; $btime = $btime < 5 * 60 ? int $btime / 60 : 6;
1878 1980
1879 ($a->{flags} & F_LOCKED) <=> ($b->{flags} & F_LOCKED) 1981 ($a->{flags} & F_LOCKED) <=> ($b->{flags} & F_LOCKED)
1880 or $btime <=> $atime 1982 or $btime <=> $atime
1881 or $a->{type} <=> $b->{type} 1983 or $a->{type} <=> $b->{type}
1882 } @_ 1984 } @_
1883 }, 1985 },
1884 weight => sub { sort { 1986 weight => sub {
1987 use sort 'stable';
1988 sort {
1885 $a->{weight} * ($a->{nrof} || 1) <=> $b->{weight} * ($b->{nrof} || 1) 1989 $a->{weight} * ($a->{nrof} || 1) <=> $b->{weight} * ($b->{nrof} || 1)
1886 or $a->{type} <=> $b->{type} 1990 or $a->{type} <=> $b->{type}
1887 } @_ }, 1991 } @_
1992 },
1888); 1993);
1889 1994
1890sub inventory_widget { 1995sub inventory_widget {
1891 my $hb = new DC::UI::HBox homogeneous => 1; 1996 my $hb = new DC::UI::HBox homogeneous => 1;
1892 1997
1979 $PL_NOTEBOOK->set_current_page ($widget); 2084 $PL_NOTEBOOK->set_current_page ($widget);
1980 $PL_WINDOW->show; 2085 $PL_WINDOW->show;
1981 } 2086 }
1982} 2087}
1983 2088
1984sub player_window { 2089sub make_playerbook {
1985 my $plwin = $PL_WINDOW = new DC::UI::Toplevel 2090 my $plwin = $PL_WINDOW = new DC::UI::Toplevel
1986 x => "center", 2091 x => "center",
1987 y => "center", 2092 y => "center",
1988 force_w => $WIDTH * 9/10, 2093 force_w => $WIDTH * 9/10,
1989 force_h => $HEIGHT * 9/10, 2094 force_h => $HEIGHT * 9/10,
2023 "License, Author and Source info for media sent by the server."); 2128 "License, Author and Source info for media sent by the server.");
2024 2129
2025 $ntb->set_current_page ($INVENTORY_PAGE); 2130 $ntb->set_current_page ($INVENTORY_PAGE);
2026 2131
2027 $plwin->add ($ntb); 2132 $plwin->add ($ntb);
2028 $plwin
2029} 2133}
2030 2134
2031sub keyboard_setup { 2135sub keyboard_setup {
2032 DC::Macro::keyboard_setup 2136 DC::Macro::keyboard_setup
2033} 2137}
2034 2138
2035sub help_window { 2139sub make_help_window {
2036 my $win = new DC::UI::Toplevel 2140 my $win = new DC::UI::Toplevel
2037 x => 'center', 2141 x => 'center',
2038 y => 'center', 2142 y => 'center',
2039 z => 4, 2143 z => 4,
2040 name => 'doc_browser', 2144 name => 'doc_browser',
2129 2233
2130 $load_node->((DC::Pod::find @path)[0]); 2234 $load_node->((DC::Pod::find @path)[0]);
2131 $win->show; 2235 $win->show;
2132 }; 2236 };
2133 2237
2134 $win 2238 $HELP_WINDOW = $win;
2135}
2136
2137sub open_string_query {
2138 my ($title, $cb, $txt, $tooltip) = @_;
2139 my $dialog = new DC::UI::Toplevel
2140 x => "center",
2141 y => "center",
2142 z => 50,
2143 force_w => $WIDTH * 4/5,
2144 title => $title;
2145
2146 $dialog->add (
2147 my $e = new DC::UI::Entry
2148 on_activate => sub { $cb->(@_); $dialog->hide; 0 },
2149 on_key_down => sub { $_[1]->{sym} == 27 and $dialog->hide; 0 },
2150 tooltip => $tooltip
2151 );
2152
2153 $e->grab_focus;
2154 $e->set_text ($txt) if $txt;
2155 $dialog->show;
2156} 2239}
2157 2240
2158sub open_quit_dialog { 2241sub open_quit_dialog {
2159 unless ($QUIT_DIALOG) { 2242 unless ($QUIT_DIALOG) {
2160 $QUIT_DIALOG = new DC::UI::Toplevel 2243 $QUIT_DIALOG = new DC::UI::Toplevel
2193 2276
2194 $QUIT_DIALOG->show; 2277 $QUIT_DIALOG->show;
2195 $QUIT_DIALOG->grab_focus; 2278 $QUIT_DIALOG->grab_focus;
2196} 2279}
2197 2280
2281sub make_menubar {
2282 $MENUFRAME = new DC::UI::Toplevel
2283 border => 0,
2284 force_x => 0,
2285 force_y => 0,
2286 force_w => $::WIDTH,
2287 child => ($MENUBAR = new DC::UI::HBox),
2288 ;
2289
2290 $MENUBAR->add ($BUTTONBAR = new DC::UI::Buttonbar);
2291
2292 # XXX: this has to be done before make_stats_window as make_stats_window calls update_stats_window which updated the gauges also X-D
2293 make_gauge_window->show;
2294
2295# $BUTTONBAR->add (new DC::UI::Flopper text => "Message Window", other => $MESSAGE_WINDOW,
2296# tooltip => "Toggles the server message log, where the client collects <i>all</i> messages from the server.");
2297
2298 make_playerbook;
2299
2300 $MENUPOPUP = DC::UI::Menu->new (items => [
2301 ["Setup…\tF9" , sub { $SETUP_DIALOG->toggle_visibility }],
2302 ["Playerbook…\tTab" , sub { $PL_WINDOW ->toggle_visibility }],
2303 ["…Statistics\tF2" , sub { toggle_player_page ($::STATS_PAGE) }],
2304 ["…Skills\tF3" , sub { toggle_player_page ($::SKILL_PAGE) }],
2305 ["…Spells\tF4" , sub { toggle_player_page ($::SPELL_PAGE) }],
2306 ["…Inventory\tF5" , sub { toggle_player_page ($::INVENTORY_PAGE) }],
2307 ["Help Browser…\tF1" , sub { $HELP_WINDOW ->toggle_visibility }],
2308 ["Quit…" , sub {
2309 if ($CONN) {
2310 open_quit_dialog;
2311 } else {
2312 EV::unloop EV::UNLOOP_ALL;
2313 }
2314 }],
2315 ]);
2316
2317 $BUTTONBAR->add (new DC::UI::Button text => "Menu…",
2318 tooltip => "Shows the main menu",
2319 on_button_down => sub {
2320 my ($self, $ev) = @_;
2321 local $ev->{x} = 0;
2322 local $ev->{y} = 0;
2323 $MENUPOPUP->popup ($ev);
2324 },
2325 );
2326
2327 $MENUBAR->add ($GAUGES->{exp} = new DC::UI::ExperienceProgress
2328 padding_x => 6,
2329 padding_y => 3,
2330 tooltip => "This progress bar shows your overall experience and your progress towards the next character level.",
2331 template => " Exp: 888,888,888,888 (lvl 188) ",
2332 );
2333
2334 $MENUBAR->add ($PICKUP_ENABLE = new DC::UI::CheckBox # checkbox bad, button better?
2335 tooltip => "Automatic Pickup Enable - when this checkbox is enabled, then your character "
2336 . "will automatically pick up items as defined by your item pickup settings "
2337 . "in the playerbook. Often (e.g. in apartments) you want to temporarily "
2338 . "disable autopickup by disabling this checkbox.",
2339 state => $CFG->{pickup} & PICKUP_INHIBIT ? 0 : 1,
2340 on_changed => sub {
2341 my ($self, $value) = @_;
2342 $CFG->{pickup} &= ~PICKUP_INHIBIT;
2343 $CFG->{pickup} |= PICKUP_INHIBIT unless $_[1];
2344 $CONN->send_pickup ($CFG->{pickup})
2345 if $CONN;
2346 },
2347 );
2348
2349 $MENUBAR->add ($GAUGES->{skillexp} = new DC::UI::ExperienceProgress
2350 c_rescale => 1,
2351 padding_x => 6,
2352 padding_y => 3,
2353 force_w => $::WIDTH * 0.2,
2354 tooltip => "This progress bar shows the currently used skill and your progress towards the next skill level of that skill.",
2355 template => "two handed weapons 99%",
2356 );
2357
2358 $MENUBAR->add ($GAUGES->{range} = new DC::UI::Label
2359 expand => 1,
2360 align => 1, can_hover => 1, can_events => 1,
2361 text => "Range and Combat Slots",
2362 tooltip => "#stat_ranged",
2363 );
2364
2365 $MENUFRAME->show;
2366}
2367
2368sub open_string_query {
2369 my ($title, $cb, $txt, $tooltip) = @_;
2370 my $dialog = new DC::UI::Toplevel
2371 x => "center",
2372 y => "center",
2373 z => 50,
2374 force_w => $WIDTH * 4/5,
2375 title => $title;
2376
2377 $dialog->add (
2378 my $e = new DC::UI::Entry
2379 on_activate => sub { $cb->(@_); $dialog->hide; 0 },
2380 on_key_down => sub { $_[1]->{sym} == 27 and $dialog->hide; 0 },
2381 tooltip => $tooltip
2382 );
2383
2384 $e->grab_focus;
2385 $e->set_text ($txt) if $txt;
2386 $dialog->show;
2387}
2388
2198sub show_tip_of_the_day { 2389sub show_tip_of_the_day {
2199 # find all tips 2390 # find all tips
2200 my @tod = DC::Pod::find tip_of_the_day => "*"; 2391 my @tod = DC::Pod::find tip_of_the_day => "*";
2201 2392
2202 DC::DB::get state => "tip_of_the_day", sub { 2393 DC::DB::get state => "tip_of_the_day", sub {
2320 2511
2321 $DEBUG_STATUS = new DC::UI::Label 2512 $DEBUG_STATUS = new DC::UI::Label
2322 padding => 0, 2513 padding => 0,
2323 z => 100, 2514 z => 100,
2324 force_x => "max", 2515 force_x => "max",
2325 force_y => 0; 2516 force_y => 20;
2326 $DEBUG_STATUS->show; 2517 $DEBUG_STATUS->show;
2327 2518
2328 $STATUSBOX = new DC::UI::Statusbox; 2519 $STATUSBOX = new DC::UI::Statusbox;
2329 2520
2330 $MODBOX = new DC::UI::Label 2521 $MODBOX = new DC::UI::Label
2341 2532
2342 (new DC::UI::Frame 2533 (new DC::UI::Frame
2343 bg => [0, 0, 0, 0.4], 2534 bg => [0, 0, 0, 0.4],
2344 force_x => 0, 2535 force_x => 0,
2345 force_y => "max", 2536 force_y => "max",
2346 child => (my $LR = new DC::UI::VBox), 2537 child => (my $LL = new DC::UI::VBox),
2347 )->show; 2538 )->show;
2348 2539
2349 $LR->add ($STATUSBOX); 2540 $LL->add ($STATUSBOX);
2350 $LR->add ($MODBOX); 2541 $LL->add ($MODBOX);
2351 $LR->add (new DC::UI::Label 2542 $LL->add (new DC::UI::Label
2352 align => 0, 2543 align => 0,
2353 markup => "Use <b>Alt-Enter</b> to toggle fullscreen mode", 2544 markup => "Use <b>Alt-Enter</b> to toggle fullscreen mode",
2354 fontsize => 0.5, 2545 fontsize => 0.5,
2355 fg => [1, 1, 0, 0.7], 2546 fg => [1, 1, 0, 0.7],
2356 ); 2547 );
2357 2548
2358 DC::UI::Toplevel->new ( 2549 DC::UI::Toplevel->new (
2359 title => "Minimap", 2550 title => "Minimap",
2360 name => "mapmap", 2551 name => "mapmap",
2361 x => 0, 2552 x => 0,
2362 y => $FONTSIZE + 8, 2553 y => $::FONTSIZE + 8,#d# hack to move messages window below the menubar
2363 border_bg => [1, 1, 1, 192/255], 2554 border_bg => [1, 1, 1, 192/255],
2364 bg => [1, 1, 1, 0], 2555 bg => [1, 1, 1, 0],
2365 child => ($MAPMAP = new DC::MapWidget::MapMap 2556 child => ($MAPMAP = new DC::MapWidget::MapMap
2366 tooltip => "<b>Minimap</b>. This will display an overview of the surrounding areas.", 2557 tooltip => "<b>Minimap</b>. This will display an overview of the surrounding areas.",
2367 ), 2558 ),
2396 $METASERVER = metaserver_dialog; 2587 $METASERVER = metaserver_dialog;
2397 # the name is changed to not conflict with the older name as users could have hidden it 2588 # the name is changed to not conflict with the older name as users could have hidden it
2398 $MESSAGE_WINDOW = new DC::UI::Dockbar 2589 $MESSAGE_WINDOW = new DC::UI::Dockbar
2399 name => "message_window2", 2590 name => "message_window2",
2400 title => 'Messages', 2591 title => 'Messages',
2592 y => $::FONTSIZE + 8,#d# hack to move messages window below the menubar
2401 force_w => $::WIDTH * 0.6, 2593 force_w => $::WIDTH * 0.6,
2402 force_h => $::HEIGHT * 0.25, 2594 force_h => $::HEIGHT * 0.25,
2403 ; 2595 ;
2404 2596
2405 $MESSAGE_DIST = new DC::MessageDistributor dockbar => $MESSAGE_WINDOW; 2597 $MESSAGE_DIST = new DC::MessageDistributor dockbar => $MESSAGE_WINDOW;
2425 . "After pressing the combo the binding will be saved automatically and the " 2617 . "After pressing the combo the binding will be saved automatically and the "
2426 . "binding editor closes"); 2618 . "binding editor closes");
2427 $SETUP_NOTEBOOK->add_tab (Debug => debug_setup, 2619 $SETUP_NOTEBOOK->add_tab (Debug => debug_setup,
2428 "Some debuggin' options. Do not ask."); 2620 "Some debuggin' options. Do not ask.");
2429 2621
2430 $BUTTONBAR = new DC::UI::Buttonbar x => 0, y => 0, z => 200; # put on top 2622 make_help_window;
2623 make_menubar;
2431 2624
2432 $BUTTONBAR->add (new DC::UI::Flopper text => "Setup", other => $SETUP_DIALOG,
2433 tooltip => "Toggles a dialog where you can configure all aspects of this client.");
2434
2435# $BUTTONBAR->add (new DC::UI::Flopper text => "Message Window", other => $MESSAGE_WINDOW,
2436# tooltip => "Toggles the server message log, where the client collects <i>all</i> messages from the server.");
2437
2438 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
2439
2440 $BUTTONBAR->add (new DC::UI::Flopper text => "Playerbook", other => player_window,
2441 tooltip => "Toggles the player view, where you can manage Inventory, Spells, Skills and see your Stats.");
2442
2443 $BUTTONBAR->add (new DC::UI::Button
2444 text => "Save Config",
2445 tooltip => "Saves the options chosen in the client setting, server settings and the window layout to be restored on later runs.",
2446 on_activate => sub {
2447 $::CFG->{layout} = DC::UI::get_layout;
2448 DC::write_cfg;
2449 status "Configuration Saved";
2450 0
2451 },
2452 );
2453
2454 $BUTTONBAR->add (new DC::UI::Flopper text => "Help!", other => $HELP_WINDOW = help_window,
2455 tooltip => "View Documentation");
2456
2457 $BUTTONBAR->add (new DC::UI::Button
2458 text => "Quit",
2459 tooltip => "Terminates the program",
2460 on_activate => sub {
2461 if ($CONN) {
2462 open_quit_dialog;
2463 } else {
2464 EV::unloop EV::UNLOOP_ALL;
2465 }
2466 0
2467 },
2468 );
2469
2470 $BUTTONBAR->show;
2471 $SETUP_DIALOG->show; 2625 $SETUP_DIALOG->show;
2472 $MESSAGE_WINDOW->show; 2626 $MESSAGE_WINDOW->show;
2473 } 2627 }
2474 2628
2475 $MODE_SLIDER->set_range ([$CFG->{sdl_mode}, 0, scalar @SDL_MODES, 1, 1]); 2629 $MODE_SLIDER->set_range ([$CFG->{sdl_mode}, 0, scalar @SDL_MODES, 1, 1]);
2476 $MODE_SLIDER->emit (changed => $CFG->{sdl_mode}); 2630 $MODE_SLIDER->emit (changed => $CFG->{sdl_mode});
2477 2631
2478 $CAVEAT_LABEL->set_text ("None :)"); 2632 $CAVEAT_LABEL->set_text ("None :)");
2633 $CAVEAT_LABEL->set_text ("Apple/NVIDIA Texture bug (slow)")
2634 if $DC::OpenGL::APPLE_NVIDIA_BUG;
2479 $CAVEAT_LABEL->set_text ("Software Rendering (very slow)") 2635 $CAVEAT_LABEL->set_text ("Software Rendering (very slow)")
2480 unless DC::SDL_GL_GetAttribute DC::SDL_GL_ACCELERATED_VISUAL; 2636 unless DC::SDL_GL_GetAttribute DC::SDL_GL_ACCELERATED_VISUAL;
2481 2637
2482 $STATUSBOX->add ("Set video mode $WIDTH×$HEIGHT", timeout => 10, fg => [1, 1, 1, 0.5]); 2638 $STATUSBOX->add ("Set video mode $WIDTH×$HEIGHT", timeout => 10, fg => [1, 1, 1, 0.5]);
2483} 2639}
2493my $animate_timer; 2649my $animate_timer;
2494 2650
2495my $fps = 9; 2651my $fps = 9;
2496 2652
2497sub force_refresh { 2653sub force_refresh {
2498 if ($ENV{CFPLUS_DEBUG} & 4) { 2654 if ($DELIANTRA_DEBUG & 4) {
2499 $fps = $fps * 0.98 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.02; 2655 $fps = $fps * 0.98 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.02;
2500 debug sprintf "%3.2f", $fps; 2656 debug sprintf "%3.2f", $fps;
2501 } 2657 }
2502 2658
2503 undef $WANT_REFRESH; 2659 undef $WANT_REFRESH;
2511my $want_refresh = EV::prepare_ns \&force_refresh; 2667my $want_refresh = EV::prepare_ns \&force_refresh;
2512 2668
2513my $input = EV::periodic 0, 1 / $MAX_FPS, undef, sub { 2669my $input = EV::periodic 0, 1 / $MAX_FPS, undef, sub {
2514 $NOW = EV::now; 2670 $NOW = EV::now;
2515 2671
2516 ($SDL_CB{$_->{type}} || sub { warn "unhandled event $_->{type}" })->($_) 2672 ($SDL_CB[$_->{type}] || sub { warn "unhandled event $_->{type}" })->($_)
2517 for DC::poll_events; 2673 for DC::poll_events;
2518 2674
2519 if (%animate_object) { 2675 if (%animate_object) {
2520 $_->animate ($LAST_REFRESH - $NOW) for values %animate_object; 2676 $_->animate ($LAST_REFRESH - $NOW) for values %animate_object;
2521 $WANT_REFRESH = 1; 2677 $WANT_REFRESH = 1;
2533sub animation_stop { 2689sub animation_stop {
2534 my ($widget) = @_; 2690 my ($widget) = @_;
2535 delete $animate_object{$widget}; 2691 delete $animate_object{$widget};
2536} 2692}
2537 2693
2538%SDL_CB = (
2539 DC::SDL_QUIT => sub { 2694$SDL_CB[DC::SDL_QUIT] = sub {
2540 crash "SDL_QUIT"; 2695 crash "SDL_QUIT";
2541 EV::unloop EV::UNLOOP_ALL; 2696 EV::unloop EV::UNLOOP_ALL;
2542 }, 2697};
2543 DC::SDL_VIDEORESIZE => sub { 2698$SDL_CB[DC::SDL_VIDEORESIZE] = sub { };
2544 },
2545 DC::SDL_VIDEOEXPOSE => sub { 2699$SDL_CB[DC::SDL_VIDEOEXPOSE] = sub {
2546 DC::UI::full_refresh; 2700 DC::UI::full_refresh;
2547 }, 2701};
2548 DC::SDL_ACTIVEEVENT => sub { 2702$SDL_CB[DC::SDL_ACTIVEEVENT] = sub {
2549# not useful, as APPACTIVE includes only iconified state, not unmapped 2703# not useful, as APPACTIVE includes only iconified state, not unmapped
2550# printf "active %x %x %x\n", $_[0]{gain}, $_[0]{state}, DC::SDL_GetAppState;#d# 2704# printf "active %x %x %x\n", $_[0]{gain}, $_[0]{state}, DC::SDL_GetAppState;#d#
2551# printf "a %x\n", DC::SDL_GetAppState & DC::SDL_APPACTIVE;#d# 2705# printf "a %x\n", DC::SDL_GetAppState & DC::SDL_APPACTIVE;#d#
2552# printf "A\n" if $_[0]{state} & DC::SDL_APPACTIVE; 2706# printf "A\n" if $_[0]{state} & DC::SDL_APPACTIVE;
2553# printf "K\n" if $_[0]{state} & DC::SDL_APPINPUTFOCUS; 2707# printf "K\n" if $_[0]{state} & DC::SDL_APPINPUTFOCUS;
2554# printf "M\n" if $_[0]{state} & DC::SDL_APPMOUSEFOCUS; 2708# printf "M\n" if $_[0]{state} & DC::SDL_APPMOUSEFOCUS;
2555 }, 2709};
2556 DC::SDL_KEYDOWN => sub { 2710$SDL_CB[DC::SDL_KEYDOWN] = sub {
2557 if ($_[0]{mod} & DC::KMOD_ALT && $_[0]{sym} == 13) { 2711 if ($_[0]{mod} & DC::KMOD_ALT && $_[0]{sym} == 13) {
2558 # alt-enter 2712 # alt-enter
2559 video_shutdown; 2713 video_shutdown;
2560 $FULLSCREEN_ENABLE->toggle; 2714 $FULLSCREEN_ENABLE->toggle;
2561 video_init; 2715 video_init;
2562 } else { 2716 } else {
2563 &DC::UI::feed_sdl_key_down_event; 2717 &DC::UI::feed_sdl_key_down_event;
2564 } 2718 }
2565 update_modbox; 2719 update_modbox;
2566 }, 2720};
2567 DC::SDL_KEYUP => sub { 2721$SDL_CB[DC::SDL_KEYUP] = sub {
2568 &DC::UI::feed_sdl_key_up_event; 2722 &DC::UI::feed_sdl_key_up_event;
2569 update_modbox; 2723 update_modbox;
2570 }, 2724};
2571 DC::SDL_MOUSEMOTION => \&DC::UI::feed_sdl_motion_event, 2725$SDL_CB[DC::SDL_MOUSEMOTION] = \&DC::UI::feed_sdl_motion_event,
2572 DC::SDL_MOUSEBUTTONDOWN => \&DC::UI::feed_sdl_button_down_event, 2726$SDL_CB[DC::SDL_MOUSEBUTTONDOWN] = \&DC::UI::feed_sdl_button_down_event,
2573 DC::SDL_MOUSEBUTTONUP => \&DC::UI::feed_sdl_button_up_event, 2727$SDL_CB[DC::SDL_MOUSEBUTTONUP] = \&DC::UI::feed_sdl_button_up_event,
2574 DC::SDL_USEREVENT => sub { 2728$SDL_CB[DC::SDL_USEREVENT] = sub {
2575 if ($_[0]{code} == 1) { 2729 if ($_[0]{code} == 1) {
2576 audio_channel_finished $_[0]{data1}; 2730 audio_channel_finished $_[0]{data1};
2577 } elsif ($_[0]{code} == 0) { 2731 } elsif ($_[0]{code} == 0) {
2578 audio_music_finished; 2732 audio_music_finished;
2579 }
2580 }, 2733 }
2581); 2734};
2582 2735
2583############################################################################# 2736#############################################################################
2584 2737
2585$SIG{INT} = $SIG{TERM} = sub { 2738$SIG{INT} = $SIG{TERM} = sub {
2586 EV::unloop; 2739 EV::unloop;
2587 #d# TODO calling exit here hangs the process in some futex 2740 #d# TODO calling exit here hangs the process in some futex
2588}; 2741};
2589 2742
2590# due to mac os x + sdl combined briandamage, we need this contortion 2743# due to mac os x + sdl combined braindamage, we need this contortion
2591sub main { 2744sub main {
2592 { 2745 {
2593 DC::Pod::load_docwiki DC::find_rcfile "docwiki.pst"; 2746 DC::Pod::load_docwiki DC::find_rcfile "docwiki.pst";
2594 2747
2595 if (-e "$Deliantra::VARDIR/client.cf") { 2748 if (-e "$Deliantra::VARDIR/client.cf") {
2612 DC::DB::open_db; 2765 DC::DB::open_db;
2613 2766
2614 DC::UI::set_layout ($::CFG->{layout}); 2767 DC::UI::set_layout ($::CFG->{layout});
2615 2768
2616 my %DEF_CFG = ( 2769 my %DEF_CFG = (
2770 config_autosave => 1,
2617 sdl_mode => undef, 2771 sdl_mode => undef,
2618 fullscreen => 1, 2772 fullscreen => 1,
2619 fast => 0, 2773 fast => 0,
2620 force_opengl11 => undef, 2774 force_opengl11 => undef,
2621 disable_alpha => 0, 2775 disable_alpha => 0,
2622 smooth_movement => 1, 2776 smooth_movement => 1,
2777 smooth_transitions => 1,
2623 texture_compression => 1, 2778 texture_compression => 1,
2624 map_scale => 1, 2779 map_scale => 1,
2625 fow_enable => 1, 2780 fow_enable => 1,
2626 fow_intensity => 0, 2781 fow_intensity => 0,
2782 fow_texture => 0,
2627 map_smoothing => 1, 2783 map_smoothing => 1,
2628 gui_fontsize => 1, 2784 gui_fontsize => 1,
2629 log_fontsize => 0.7, 2785 log_fontsize => 0.7,
2630 gauge_fontsize => 1, 2786 gauge_fontsize => 1,
2631 gauge_size => 0.35, 2787 gauge_size => 0.35,
2639 effects_enable => 1, 2795 effects_enable => 1,
2640 effects_volume => 1, 2796 effects_volume => 1,
2641 bgm_enable => 1, 2797 bgm_enable => 1,
2642 bgm_volume => 0.5, 2798 bgm_volume => 0.5,
2643 output_rate => "", 2799 output_rate => "",
2644 pickup => 0, 2800 pickup => PICKUP_SPELLBOOK | PICKUP_SKILLSCROLL | PICKUP_VALUABLES,
2645 inv_sort => "mtime", 2801 inv_sort => "mtime",
2646 default => "profile", # default profile 2802 default => "profile", # default profile
2647 show_tips => 1, 2803 show_tips => 1,
2648 logview_max_par => 1000, 2804 logview_max_par => 1000,
2649 shift_fire_stop => 0, 2805 shift_fire_stop => 0,
2650 uitheme => "wood", 2806 uitheme => "wood",
2651 ); 2807 map_shift_x => -24, # arbitrary
2808 map_shift_y => +24, # arbitrary
2652 2809 );
2810
2653 while (my ($k, $v) = each %DEF_CFG) { 2811 while (my ($k, $v) = each %DEF_CFG) {
2654 $CFG->{$k} = $v unless exists $CFG->{$k}; 2812 $CFG->{$k} = $v unless exists $CFG->{$k};
2655 } 2813 }
2656 2814
2657 $CFG->{profile}{default}{host} ||= "gameserver.deliantra.net"; 2815 my @args = @ARGV;
2816
2817 my $profile = 'default';
2818
2819 for (my $i = 0; $i < @args; $i++) {
2820 if ($args[$i] =~ /^--?profile$/) {
2821 $profile = $args[$i + 1];
2822 splice @args, $i, 2, ();
2823 $i = 0;
2824 } elsif ($args[$i] =~ /^--?h/) {
2825 print STDERR "Usage: $0 [--profile name] [host [user [password]]]\n";
2826 exit 0;
2827 }
2828 }
2829
2830 $CFG->{profile}{$profile} ||= {};
2658 $PROFILE = $CFG->{profile}{default}; 2831 $PROFILE = $CFG->{profile}{$profile};
2832 $PROFILE->{host} ||= "gameserver.deliantra.net";
2833
2834 $PROFILE->{host} = $args[0] if @args > 0;
2835 $PROFILE->{user} = $args[1] if @args > 1;
2836 $PROFILE->{password} = $args[2] if @args > 2;
2659 2837
2660 # convert old bindings (only default profile matters) 2838 # convert old bindings (only default profile matters)
2661 if (my $bindings = delete $PROFILE->{bindings}) { 2839 if (my $bindings = delete $PROFILE->{bindings}) {
2662 while (my ($mod, $syms) = each %$bindings) { 2840 while (my ($mod, $syms) = each %$bindings) {
2663 while (my ($sym, $cmds) = each %$syms) { 2841 while (my ($sym, $cmds) = each %$syms) {
2669 } 2847 }
2670 } 2848 }
2671 2849
2672 sdl_init; 2850 sdl_init;
2673 2851
2852 $ENV{FONTCONFIG_FILE} = DC::find_rcfile "fonts/fonts.conf";
2853 $ENV{FONTCONFIG_DIR} = DC::find_rcfile "fonts";
2854
2674 { 2855 {
2675 my @fonts = map DC::find_rcfile "fonts/$_", qw( 2856 my @fonts = map DC::find_rcfile "fonts/$_", qw(
2676 DejaVuSans.ttf 2857 DejaVuSans.ttf
2677 DejaVuSansMono.ttf 2858 DejaVuSansMono.ttf
2678 DejaVuSans-Bold.ttf 2859 DejaVuSans-Bold.ttf
2679 DejaVuSansMono-Bold.ttf 2860 DejaVuSansMono-Bold.ttf
2680 DejaVuSans-Oblique.ttf 2861 DejaVuSans-Oblique.ttf
2681 DejaVuSansMono-Oblique.ttf 2862 DejaVuSansMono-Oblique.ttf
2682 DejaVuSans-BoldOblique.ttf 2863 DejaVuSans-BoldOblique.ttf
2683 DejaVuSansMono-BoldOblique.ttf 2864 DejaVuSansMono-BoldOblique.ttf
2865 mona.ttf
2684 ); 2866 );
2685 2867
2686 DC::add_font $_ for @fonts; 2868 DC::add_font $_ for @fonts;
2687 2869
2688 $FONT_PROP = new_from_file DC::Font $fonts[0]; 2870 $FONT_PROP = new_from_file DC::Font $fonts[0];
2689 $FONT_FIXED = new_from_file DC::Font $fonts[1]; 2871 $FONT_FIXED = new_from_file DC::Font $fonts[1];
2690 2872
2691 $FONT_PROP->make_default; 2873 $FONT_PROP->make_default;
2692 2874
2715 our $STARTUP_CANCEL = EV::idle sub { 2897 our $STARTUP_CANCEL = EV::idle sub {
2716 undef $::STARTUP_CANCEL; 2898 undef $::STARTUP_CANCEL;
2717 $startup_done->(); 2899 $startup_done->();
2718 }; 2900 };
2719 2901
2902 debug_toggle 0;
2903
2720 delete $SIG{__DIE__}; 2904 delete $SIG{__DIE__};
2721 EV::loop; 2905 EV::loop;
2722 2906
2907 DC::write_cfg if $CFG->{config_autosave};
2908
2723#video_shutdown; 2909 #video_shutdown;
2724#audio_shutdown; 2910 #audio_shutdown;
2911
2725 DC::OpenGL::quit; 2912 DC::OpenGL::quit;
2726 DC::SDL_Quit; 2913 DC::SDL_Quit;
2727 DC::DB::Server::stop; 2914 DC::DB::Server::stop;
2728} 2915}
2729 2916
2733 2920
2734deliantra - A Deliantra MORPG game client 2921deliantra - A Deliantra MORPG game client
2735 2922
2736=head1 SYNOPSIS 2923=head1 SYNOPSIS
2737 2924
2738Just run it - no commandline arguments are supported. 2925 deliantra [--profile name] [host [user [password]]]
2926 deliantra --help
2739 2927
2740=head1 USAGE 2928=head1 USAGE
2741 2929
2742deliantra utilises OpenGL for all UI elements and the game. It is supposed to 2930The deliantra client utilises OpenGL for all UI elements and the game. It
2743be used in fullscreen mode and interactively. 2931is supposed to be used in fullscreen mode and interactively.
2744 2932
2745=head1 DEBUGGING 2933=head1 DEBUGGING
2746 2934
2747
2748CFPLUS_DEBUG - environment variable 2935DELIANTRA_DEBUG - environment variable
2749 2936
2750 1 draw borders around widgets 2937 1 draw borders around widgets
2751 2 add low-level widget info to tooltips 2938 2 add low-level widget info to tooltips
2752 4 show fps 2939 4 show fps
2753 8 suppress tooltips 2940 8 suppress tooltips
2941 16 show bandwidth downstream
2754 2942
2755=head1 AUTHOR 2943=head1 AUTHOR
2756 2944
2757Marc Lehmann <deliantra@schmorp.de>, Robin Redeker <elmex@ta-sa.org> 2945Marc Lehmann <deliantra@schmorp.de>, Robin Redeker <elmex@ta-sa.org>
2758 2946

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines