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

Comparing deliantra/Deliantra-Client/bin/cfplus (file contents):
Revision 1.16 by elmex, Sat May 27 20:00:40 2006 UTC vs.
Revision 1.165 by root, Thu Jul 12 18:57:45 2007 UTC

1#!/opt/bin/perl 1#!/opt/bin/perl
2
3my $startup_done = sub { };
4our $PANGO = "1.5.0";
5
6# do splash-screen thingy on win32
7BEGIN {
8 if (%PAR::LibCache && $^O eq "MSWin32") {
9 while (my ($filename, $zip) = each %PAR::LibCache) {
10 $zip->extractMember ("SPLASH.bmp", "$ENV{PAR_TEMP}/SPLASH.bmp");
11 }
12
13 require Win32::GUI::SplashScreen;
14
15 Win32::GUI::SplashScreen::Show (
16 -file => "$ENV{PAR_TEMP}/SPLASH.bmp",
17 );
18
19 $startup_done = sub {
20 Win32::GUI::SplashScreen::Done (1);
21 };
22 }
23}
2 24
3use strict; 25use strict;
4use utf8; 26use utf8;
27
28use Carp 'verbose';
5 29
6# do things only needed for single-binary version (par) 30# do things only needed for single-binary version (par)
7BEGIN { 31BEGIN {
8 if (%PAR::LibCache) { 32 if (%PAR::LibCache) {
9 @INC = grep ref, @INC; # weed out all paths except pars loader refs 33 @INC = grep ref, @INC; # weed out all paths except pars loader refs
10 34
35 my $tmp = $ENV{PAR_TEMP};
36
11 while (my ($filename, $zip) = each %PAR::LibCache) { 37 while (my ($filename, $zip) = each %PAR::LibCache) {
12 for ($zip->memberNames) { 38 for ($zip->memberNames) {
13 next unless /^\/root\/(.*)/; 39 next unless /^root\/(.*)/;
14 $zip->extractMember ($_, "$ENV{PAR_TEMP}/$1") 40 $zip->extractMember ($_, "$tmp/$1")
15 unless -e "$ENV{PAR_TEMP}/$1"; 41 unless -e "$tmp/$1";
16 } 42 }
17 } 43 }
18 44
19 # TODO: pango-rc file, anybody? 45 if ($^O eq "MSWin32") {
46 # relocatable
47 } else {
48 # unix, need to patch pango rc file
49 open my $fh, "<:perlio", "$tmp/usr/lib/pango/$PANGO/module-files.d/libpango1.0-0.modules"
50 or die "$tmp/usr/lib/$PANGO/module-files.d/libpango1.0-0.modules: $!";
51 local $/;
52 my $rc = <$fh>;
53 $rc =~ s/^\//$tmp\//gm; # replace abs paths by relative ones
20 54
21 unshift @INC, $ENV{PAR_TEMP}; 55 mkdir "$tmp/pango-modules";
56 open my $fh, ">:perlio", "$tmp/pango-modules/pango.modules"
57 or die "$tmp/pango-modules/pango.modules: $!";
58 print $fh $rc;
59
60 $ENV{PANGO_RC_FILE} = "$tmp/pango.rc";
61 open my $fh, ">:perlio", $ENV{PANGO_RC_FILE}
62 or die "$ENV{PANGO_RC_FILE}: $!";
63 print $fh "[Pango]\nModuleFiles = $tmp/pango-modules\n";
64 }
65
66 unshift @INC, $tmp;
22 } 67 }
23} 68}
24 69
25# need to do it again because that pile of garbage called PAR nukes it before main 70# need to do it again because that pile of garbage called PAR nukes it before main
26unshift @INC, $ENV{PAR_TEMP} 71unshift @INC, $ENV{PAR_TEMP}
27 if %PAR::LibCache; 72 if %PAR::LibCache;
28 73
29use Time::HiRes 'time'; 74use Time::HiRes 'time';
30use Pod::POM;
31use Event; 75use Event;
32 76
33use Crossfire; 77use Crossfire;
34use Crossfire::Protocol::Constants; 78use Crossfire::Protocol::Constants;
35 79
36use Compress::LZF; 80use Compress::LZF;
37 81
38use CFClient; 82use CFPlus;
39use CFClient::OpenGL (); 83use CFPlus::OpenGL ();
40use CFClient::Protocol; 84use CFPlus::Protocol;
85use CFPlus::DB;
41use CFClient::UI; 86use CFPlus::UI;
87use CFPlus::UI::Inventory;
88use CFPlus::UI::SpellList;
89use CFPlus::Pod;
42use CFClient::MapWidget; 90use CFPlus::MapWidget;
91use CFPlus::Macro;
43 92
93$SIG{QUIT} = sub { Carp::cluck "QUIT" };
94$SIG{PIPE} = 'IGNORE';
95
96$Event::Eval = 1;
44$Event::DIED = sub { 97$Event::DIED = sub {
45 # TODO: display dialog box or so 98 CFPlus::fatal Carp::longmess $_[1]
46 CFClient::error $_[1];
47}; 99};
48
49#$SIG{__WARN__} = sub { Carp::cluck $_[0] };#d#
50
51our $VERSION = '0.1';
52 100
53my $MAX_FPS = 60; 101my $MAX_FPS = 60;
54my $MIN_FPS = 5; # unused as of yet 102my $MIN_FPS = 5; # unused as of yet
55 103
56our $META_SERVER = "crossfire.real-time.com:13326"; 104our $META_SERVER = "http://metaserver.schmorp.de/current.json";
57 105
58our $LAST_REFRESH; 106our $LAST_REFRESH;
59our $NOW; 107our $NOW;
60 108
61our $CFG; 109our $CFG;
62our $CONN; 110our $CONN;
111our $PROFILE; # current profile
63our $FAST; # fast, low-quality mode, possibly useful for software-rendering 112our $FAST; # fast, low-quality mode, possibly useful for software-rendering
64 113
65our $WANT_REFRESH; 114our $WANT_REFRESH;
66our $CAN_REFRESH; 115our $CAN_REFRESH;
67 116
81our $LOGVIEW; 130our $LOGVIEW;
82our $CONSOLE; 131our $CONSOLE;
83our $METASERVER; 132our $METASERVER;
84our $LOGIN_BUTTON; 133our $LOGIN_BUTTON;
85our $QUIT_DIALOG; 134our $QUIT_DIALOG;
135our $HOST_ENTRY;
136our $FULLSCREEN_ENABLE;
137our $PICKUP_ENABLE;
138our $SERVER_INFO;
86 139
140our $SETUP_DIALOG;
141our $SETUP_NOTEBOOK;
142our $SETUP_SERVER;
143our $SETUP_KEYBOARD;
144
145our $PL_NOTEBOOK;
146our $PL_WINDOW;
147
148our $INVENTORY_PAGE;
149our $STATS_PAGE;
150our $SKILL_PAGE;
151our $SPELL_PAGE;
152our $SPELL_LIST;
153
154our $HELP_WINDOW;
155our $MESSAGE_WINDOW;
87our $FLOORBOX; 156our $FLOORBOX;
88our $GAUGES; 157our $GAUGES;
89our $STATWIDS; 158our $STATWIDS;
90 159
91our $SDL_ACTIVE; 160our $SDL_ACTIVE;
92our %SDL_CB; 161our %SDL_CB;
93 162
94our $SDL_MIXER; 163our $SDL_MIXER;
164our $MUSIC_DEFAULT = "in_a_heartbeat.ogg";
165our @MUSIC_WANT;
166our $MUSIC_PLAYING;
167our $MUSIC_PLAYER;
95our @SOUNDS; # event => file mapping 168our @SOUNDS; # event => file mapping
96our %AUDIO_CHUNKS; # audio files 169our %AUDIO_CHUNKS; # audio files
97 170
98our $ALT_ENTER_MESSAGE; 171our $ALT_ENTER_MESSAGE;
99our $STATUSBOX; 172our $STATUSBOX;
100our $DEBUG_STATUS; 173our $DEBUG_STATUS;
101 174
102our $INV; 175our $INV;
103our $INVR; 176our $INVR;
104our $INVR_LBL; 177our $INV_RIGHT_HB;
178
179our $PICKUP_CFG;
180
181our $IN_BUILD_MODE;
182our $BUILD_BUTTON;
105 183
106sub status { 184sub status {
107 $STATUSBOX->add (CFClient::UI::Label::escape $_[0], pri => -10, group => "status", timeout => 10, fg => [1, 1, 0, 1]); 185 $STATUSBOX->add (CFPlus::asxml $_[0], pri => -10, group => "status", timeout => 10, fg => [1, 1, 0, 1]);
108} 186}
109 187
110sub debug { 188sub debug {
111 $DEBUG_STATUS->set_text ($_[0]); 189 $DEBUG_STATUS->set_text ($_[0]);
112 my ($w, $h) = $DEBUG_STATUS->size_request; 190}
113 $DEBUG_STATUS->move ($WIDTH - $w, 0); 191
192sub message {
193 my ($para) = @_;
194
195 my $time = sprintf "%02d:%02d:%02d", (localtime time)[2,1,0];
196
197 $para->{markup} = "<span foreground='#ffffff'>$time</span> $para->{markup}";
198
199 $LOGVIEW->add_paragraph ($para);
200 $LOGVIEW->scroll_to_bottom;
201}
202
203sub destroy_query_dialog {
204 (delete $_[0]{query_dialog})->destroy
205 if $_[0]{query_dialog};
206}
207
208# FIXME: a very ugly hack to wait for stat update look below! #d#
209our $QUERY_TIMER; #d#
210
211# server query dialog
212sub server_query {
213 my ($conn, $flags, $prompt) = @_;
214
215 # FIXME: a very ugly hack to wait for stat update #d#
216 if ($prompt =~ /roll new stats/ and not $conn->{stat_change_with}) {
217 unless ($QUERY_TIMER) {
218 $QUERY_TIMER =
219 Event->timer (
220 after => 1,
221 cb => sub {
222 server_query ($conn, $flags, $prompt, 1);
223 $QUERY_TIMER = undef
224 }
225 );
226 return;
227 }
228 }
229
230 $conn->{query_dialog} = my $dialog = new CFPlus::UI::Toplevel
231 x => "center",
232 y => "center",
233 title => "Server Query",
234 child => my $vbox = new CFPlus::UI::VBox,
235 ;
236
237 my @dialog = my $label = new CFPlus::UI::Label
238 max_w => $::WIDTH * 0.8,
239 ellipsise => 0,
240 text => $prompt;
241
242 if ($flags & CS_QUERY_YESNO) {
243 push @dialog, my $hbox = new CFPlus::UI::HBox;
244
245 $hbox->add (new CFPlus::UI::Button
246 text => "No",
247 on_activate => sub {
248 $conn->send ("reply n");
249 $dialog->destroy;
250 0
251 }
252 );
253 $hbox->add (new CFPlus::UI::Button
254 text => "Yes",
255 on_activate => sub {
256 $conn->send ("reply y");
257 destroy_query_dialog $conn;
258 0
259 },
260 );
261
262 $dialog->grab_focus;
263
264 } elsif ($flags & CS_QUERY_SINGLECHAR) {
265 if ($prompt =~ /Now choose a character|Press any key for the next race/i) {
266 $dialog->{tooltip} = "#charcreation_focus";
267
268 unshift @dialog, new CFPlus::UI::Label
269 max_w => $::WIDTH * 0.8,
270 ellipsise => 0,
271 markup => "\nOr use your keyboard and the text entry below:\n";
272
273 unshift @dialog, my $table = new CFPlus::UI::Table;
274
275 $table->add (0, 0, new CFPlus::UI::Button
276 text => "Next Race",
277 on_activate => sub {
278 $conn->send ("reply n");
279 destroy_query_dialog $conn;
280 0
281 },
282 );
283 $table->add (2, 0, new CFPlus::UI::Button
284 text => "Accept",
285 on_activate => sub {
286 $conn->send ("reply d");
287 destroy_query_dialog $conn;
288 0
289 },
290 );
291
292 if ($conn->{chargen_race_description}) {
293 unshift @dialog, new CFPlus::UI::Label
294 max_w => $::WIDTH * 0.8,
295 ellipsise => 0,
296 markup => "<span foreground='#ccccff'>$conn->{chargen_race_description}</span>",
297 ;
298 }
299
300 unshift @dialog, new CFPlus::UI::Face
301 face => $conn->{player}{face},
302 bg => [.2, .2, .2, 1],
303 min_w => 64,
304 min_h => 64,
305 ;
306
307 if ($conn->{chargen_race_title}) {
308 unshift @dialog, new CFPlus::UI::Label
309 allign => 1,
310 ellipsise => 0,
311 markup => "<span foreground='#ccccff' size='large'>Race: $conn->{chargen_race_title}</span>",
312 ;
313 }
314
315 unshift @dialog, new CFPlus::UI::Label
316 max_w => $::WIDTH * 0.4,
317 ellipsise => 0,
318 markup => (CFPlus::Pod::section_label ui => "chargen_race"),
319 ;
320
321 } elsif ($prompt =~ /roll new stats/) {
322 if (my $stat = delete $conn->{stat_change_with}) {
323 $conn->send ("reply $stat");
324 destroy_query_dialog $conn;
325 return;
326 }
327
328 $STATS_PAGE->show;
329 $MESSAGE_WINDOW->hide;
330
331 unshift @dialog, new CFPlus::UI::Label
332 max_w => $::WIDTH * 0.4,
333 ellipsise => 0,
334 markup => "\nOr use your keyboard and the text entry below:\n";
335
336 unshift @dialog, my $table = new CFPlus::UI::Table;
337
338 # left: re-roll
339 $table->add (0, 0, new CFPlus::UI::Button
340 text => "Roll Again",
341 on_activate => sub {
342 $conn->send ("reply y");
343 destroy_query_dialog $conn;
344 0
345 },
346 );
347
348 # center: swap stats
349 my ($sw1, $sw2) = map +(new CFPlus::UI::Selector
350 expand => 1,
351 value => $_,
352 options => [
353 [1 => "Str", "Strength ($conn->{stat}{+CS_STAT_STR})"],
354 [2 => "Dex", "Dexterity ($conn->{stat}{+CS_STAT_DEX})"],
355 [3 => "Con", "Constitution ($conn->{stat}{+CS_STAT_CON})"],
356 [4 => "Int", "Intelligence ($conn->{stat}{+CS_STAT_INT})"],
357 [5 => "Wis", "Wisdom ($conn->{stat}{+CS_STAT_WIS})"],
358 [6 => "Pow", "Power ($conn->{stat}{+CS_STAT_POW})"],
359 [7 => "Cha", "Charisma ($conn->{stat}{+CS_STAT_CHA})"],
360 ],
361 ), 1 .. 2;
362
363 $table->add (2, 0, new CFPlus::UI::Button
364 text => "Swap Stats",
365 on_activate => sub {
366 $conn->{stat_change_with} = $sw2->{value};
367 $conn->send ("reply $sw1->{value}");
368 destroy_query_dialog $conn;
369 0
370 },
371 );
372 $table->add (2, 1, new CFPlus::UI::HBox children => [$sw1, $sw2]);
373
374 # right: accept
375 $table->add (4, 0, new CFPlus::UI::Button
376 text => "Accept",
377 on_activate => sub {
378 $conn->send ("reply n");
379 $STATS_PAGE->hide;
380 destroy_query_dialog $conn;
381 0
382 },
383 );
384
385 unshift @dialog, my $hbox = new CFPlus::UI::HBox;
386 for (
387 [Str => CS_STAT_STR],
388 [Dex => CS_STAT_DEX],
389 [Con => CS_STAT_CON],
390 [Int => CS_STAT_INT],
391 [Wis => CS_STAT_WIS],
392 [Pow => CS_STAT_POW],
393 [Cha => CS_STAT_CHA],
394 ) {
395 my ($name, $id) = @$_;
396 $hbox->add (new CFPlus::UI::Label
397 markup => "$conn->{stat}{$id} <span foreground='yellow'>$name</span>",
398 align => 0,
399 expand => 1,
400 can_events => 1,
401 can_hover => 1,
402 tooltip => "#stat_$name",
403 );
404 }
405
406 unshift @dialog, new CFPlus::UI::Label
407 max_w => $::WIDTH * 0.4,
408 ellipsise => 0,
409 markup => (CFPlus::Pod::section_label ui => "chargen_stats"),
410 ;
411 }
412
413 push @dialog, my $entry = new CFPlus::UI::Entry
414 on_changed => sub {
415 $conn->send ("reply $_[1]");
416 destroy_query_dialog $conn;
417 0
418 },
419 ;
420
421 $entry->grab_focus;
422
423 } else {
424 $dialog->{tooltip} = "Enter the reply and press return (click on the entry to make sure it has keyboard focus)";
425
426 push @dialog, my $entry = new CFPlus::UI::Entry
427 $flags & CS_QUERY_HIDEINPUT ? (hidden => "*") : (),
428 on_activate => sub {
429 $conn->send ("reply $_[1]");
430 destroy_query_dialog $conn;
431 0
432 },
433 ;
434
435 $entry->grab_focus;
436 }
437
438 $vbox->add (@dialog);
439 $dialog->show;
114} 440}
115 441
116sub start_game { 442sub start_game {
117 status "logging in..."; 443 status "logging in...";
118 444
445 $LOGIN_BUTTON->set_text ("Logout");
446 $SETUP_DIALOG->hide;
447
119 my $mapsize = List::Util::min 32, List::Util::max 11, int $WIDTH * $CFG->{mapsize} * 0.01 / 32; 448 my $mapsize = List::Util::min 32, List::Util::max 11, int $WIDTH * $CFG->{mapsize} * 0.01 / 32;
120 449
121 my ($host, $port) = split /:/, $CFG->{host}; 450 my ($host, $port) = split /:/, $PROFILE->{host};
122 451
123 $MAP = new CFClient::Map $mapsize, $mapsize; 452 $MAP = new CFPlus::Map;
124 453
125 $CONN = eval { 454 $CONN = eval {
126 new CFClient::Protocol 455 new CFPlus::Protocol
127 host => $host, 456 host => $host,
128 port => $port || 13327, 457 port => $port || 13327,
129 user => $CFG->{user}, 458 user => $PROFILE->{user},
130 pass => $CFG->{password}, 459 pass => $PROFILE->{password},
131 mapw => $mapsize, 460 mapw => $mapsize,
132 maph => $mapsize, 461 maph => $mapsize,
462
463 client => "cfplus $CFPlus::VERSION $] $^O",
133 464
134 map_widget => $MAPWIDGET, 465 map_widget => $MAPWIDGET,
135 logview => $LOGVIEW, 466 logview => $LOGVIEW,
136 statusbox => $STATUSBOX, 467 statusbox => $STATUSBOX,
137 map => $MAP, 468 map => $MAP,
138 mapmap => $MAPMAP, 469 mapmap => $MAPMAP,
470 query => \&server_query,
471
472 setup_req => {
473 smoothing => $CFG->{map_smoothing}*1,
474 },
139 475
140 sound_play => sub { 476 sound_play => sub {
141 my ($x, $y, $soundnum, $type) = @_; 477 my ($x, $y, $soundnum, $type) = @_;
142 478
143 $SDL_MIXER 479 $SDL_MIXER
149 $chunk->play; 485 $chunk->play;
150 }, 486 },
151 }; 487 };
152 488
153 if ($CONN) { 489 if ($CONN) {
154 CFClient::lowdelay fileno $CONN->{fh}; 490 CFPlus::lowdelay fileno $CONN->{fh};
155 491
156 $LOGIN_BUTTON->set_text ("Logout");
157 status "login successful"; 492 status "login successful";
158
159 $BUTTONBAR->{children}[1]->emit ("activate")
160 if $BUTTONBAR->{children}[1]->{state};
161
162 } else { 493 } else {
163 status "unable to connect"; 494 status "unable to connect";
164 stop_game(); 495 stop_game();
165 } 496 }
166} 497}
167 498
168sub stop_game { 499sub stop_game {
500 $LOGIN_BUTTON->set_text ("Login");
501 $SETUP_NOTEBOOK->set_current_page ($SETUP_SERVER);
502 $SETUP_DIALOG->show;
503 $PL_WINDOW->hide;
504 $SPELL_LIST->clear_spells;
505 $CFPlus::UI::ROOT->emit (stop_game => ! ! $CONN);
506
169 return unless $CONN; 507 return unless $CONN;
170 508
171 status "connection closed"; 509 status "connection closed";
172 $LOGIN_BUTTON->set_text ("Login"); 510
511 destroy_query_dialog $CONN;
173 $CONN->destroy; 512 $CONN->destroy;
174 $CONN = 0; # false, does not autovivify 513 $CONN = 0; # false, does not autovivify
175 514
176 $BUTTONBAR->{children}[1]->emit ("activate") 515 undef $MAP;
177 unless $BUTTONBAR->{children}[1]->{state};
178} 516}
179 517
180sub client_setup { 518sub graphics_setup {
181 my $dialog = new CFClient::UI::FancyFrame 519 my $vbox = new CFPlus::UI::VBox;
182 name => "client_setup", 520
183 title => "Client Setup",
184 child => (my $vbox = new CFClient::UI::VBox);
185 $vbox->add (my $table = new CFClient::UI::Table expand => 1, col_expand => [0, 1]); 521 $vbox->add (my $table = new CFPlus::UI::Table expand => 1, col_expand => [0, 1]);
186 522
523 my $row = 0;
524
525 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "OpenGL Info");
526 $table->add (1, $row++, new CFPlus::UI::Label valign => 0, fontsize => 0.8, text => CFPlus::OpenGL::gl_vendor . ", " . CFPlus::OpenGL::gl_version,
527 can_events => 1,
528 tooltip => "<tt><span size='8192'>" . (CFPlus::OpenGL::gl_extensions) . "</span></tt>");
529
187 $table->add (0, 0, new CFClient::UI::Label valign => 0, align => 1, text => "Video Mode"); 530 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Video Mode");
188 $table->add (1, 0, my $hbox = new CFClient::UI::HBox); 531 $table->add (1, $row++, my $hbox = new CFPlus::UI::HBox);
189 532
190 $hbox->add (my $mode_slider = new CFClient::UI::Slider expand => 1, req_w => 100, range => [$CFG->{sdl_mode}, 0, $#SDL_MODES, 0, 1]); 533 $hbox->add (my $mode_slider = new CFPlus::UI::Slider force_w => $WIDTH * 0.1, expand => 1, range => [$CFG->{sdl_mode}, 0, $#SDL_MODES, 0, 1]);
191 $hbox->add (my $mode_label = new CFClient::UI::Label align => 0, valign => 0, height => 0.8, template => "9999x9999"); 534 $hbox->add (my $mode_label = new CFPlus::UI::Label align => 0, valign => 0, height => 0.8, template => "9999x9999");
192 535
193 $mode_slider->connect (changed => sub { 536 $mode_slider->connect (changed => sub {
194 my ($self, $value) = @_; 537 my ($self, $value) = @_;
195 538
196 $CFG->{sdl_mode} = $self->{range}[0] = $value = int $value; 539 $CFG->{sdl_mode} = $self->{range}[0] = $value = int $value;
197 $mode_label->set_text (sprintf "%dx%d", @{$SDL_MODES[$value]}); 540 $mode_label->set_text (sprintf "%dx%d", @{$SDL_MODES[$value]});
198 }); 541 });
199 $mode_slider->emit (changed => $mode_slider->{range}[0]); 542 $mode_slider->emit (changed => $mode_slider->{range}[0]);
200 543
201 my $row = 1;
202
203 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fullscreen"); 544 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Fullscreen");
204 $table->add (1, $row++, new CFClient::UI::CheckBox 545 $table->add (1, $row++, $FULLSCREEN_ENABLE = new CFPlus::UI::CheckBox
205 state => $CFG->{fullscreen}, 546 state => $CFG->{fullscreen},
206 tooltip => "Bring the client into fullscreen mode.", 547 tooltip => "Bring the client into fullscreen mode.",
207 connect_changed => sub { 548 on_changed => sub { my ($self, $value) = @_; $CFG->{fullscreen} = $value; 0 }
208 my ($self, $value) = @_;
209 $CFG->{fullscreen} = $value;
210 }
211 ); 549 );
212 550
213 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fast & Ugly"); 551 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Fast & Ugly");
214 $table->add (1, $row++, new CFClient::UI::CheckBox 552 $table->add (1, $row++, new CFPlus::UI::CheckBox
215 state => $CFG->{fast}, 553 state => $CFG->{fast},
216 tooltip => "Lower the visual quality considerably to speed up rendering.", 554 tooltip => "Lower the visual quality considerably to speed up rendering.",
555 on_changed => sub { my ($self, $value) = @_; $CFG->{fast} = $value; 0 }
556 );
557
558 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "GUI Fontsize");
559 $table->add (1, $row++, new CFPlus::UI::Slider
560 range => [$CFG->{gui_fontsize}, 0.5, 2, 0, 0.1],
561 tooltip => "The base font size used by most GUI elements that do not have their own setting.",
562 on_changed => sub { $CFG->{gui_fontsize} = $_[1]; 0 },
563 );
564
565 $table->add (1, $row++, new CFPlus::UI::Button
566 expand => 1, align => 0, text => "Apply",
567 tooltip => "Apply the video settings above.",
217 connect_changed => sub { 568 on_activate => sub {
218 my ($self, $value) = @_; 569 video_shutdown ();
219 $CFG->{fast} = $value; 570 video_init ();
571 0
220 } 572 }
221 ); 573 );
222 574
223 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Map Scale"); 575 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Map Scale");
224 $table->add (1, $row++, new CFClient::UI::Slider 576 $table->add (1, $row++, new CFPlus::UI::Slider
225 range => [(log $CFG->{map_scale}) / (log 2), -3, 1, 0, 1], 577 range => [(log $CFG->{map_scale}) / (log 2), -3, 1, 0, 1],
226 tooltip => "Enlarge or shrink the displayed map. Changes are instant.", 578 tooltip => "Enlarge or shrink the displayed map. Changes are instant.",
227 connect_changed => sub { 579 on_changed => sub { my ($self, $value) = @_; $CFG->{map_scale} = 2 ** $value; 0 }
228 my ($self, $value) = @_;
229 $CFG->{map_scale} = 2 ** $value;
230 }
231 ); 580 );
232 581
582 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Smoothing");
583 $table->add (1, $row++, new CFPlus::UI::CheckBox
584 state => $CFG->{map_smoothing},
585 tooltip => "<b>Map Smoothing</b> tries to make tile borders less square. "
586 . "This increases load on the graphics subsystem and works only with 2.x servers. "
587 . "Changes take effect at next connection only.",
588 on_changed => sub { my ($self, $value) = @_; $CFG->{map_smoothing} = $value; 0 }
589 );
590
233 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fog of War"); 591 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Fog of War");
234 $table->add (1, $row++, new CFClient::UI::CheckBox 592 $table->add (1, $row++, new CFPlus::UI::CheckBox
235 state => $CFG->{fow_enable}, 593 state => $CFG->{fow_enable},
236 tooltip => "<b>Fog-of-War</b> marks areas that cannot be seen by the player. Changes are instant.", 594 tooltip => "<b>Fog-of-War</b> marks areas that cannot be seen by the player. Changes are instant.",
237 connect_changed => sub { 595 on_changed => sub { my ($self, $value) = @_; $CFG->{fow_enable} = $value; 0 }
238 my ($self, $value) = @_;
239 $CFG->{fow_enable} = $value;
240 }
241 ); 596 );
242 597
243 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "FoW Intensity"); 598 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "FoW Intensity");
244 $table->add (1, $row++, new CFClient::UI::Slider 599 $table->add (1, $row++, new CFPlus::UI::Slider
245 range => [$CFG->{fow_intensity}, 0, 1, 0, 1 / 256], 600 range => [$CFG->{fow_intensity}, 0, 1, 0, 1 / 256],
246 tooltip => "<b>Fog of War Lightness.</b> The higher the intensity, the lighter the Fog-of-War color. Changes are instant.", 601 tooltip => "<b>Fog of War Lightness.</b> The higher the intensity, the lighter the Fog-of-War color. Changes are instant.",
247 connect_changed => sub { 602 on_changed => sub { my ($self, $value) = @_; $CFG->{fow_intensity} = $value; 0 }
248 my ($self, $value) = @_;
249 $CFG->{fow_intensity} = $value;
250 }
251 ); 603 );
252 604
253 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "FoW Smooth"); 605 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "FoW Smooth");
254 $table->add (1, $row++, new CFClient::UI::CheckBox 606 $table->add (1, $row++, new CFPlus::UI::CheckBox
255 state => $CFG->{fow_smooth}, 607 state => $CFG->{fow_smooth},
256 tooltip => "Smooth the Fog-of-War a bit to make it more realistic. Changes are instant.", 608 tooltip => "Smooth the Fog-of-War a bit to make it more realistic. Changes are instant.",
257 connect_changed => sub { 609 on_changed => sub {
258 my ($self, $value) = @_; 610 my ($self, $value) = @_;
259 $CFG->{fow_smooth} = $value; 611 $CFG->{fow_smooth} = $value;
260 status "Fog of War smoothing requires OpenGL 1.2 or higher" if $CFClient::OpenGL::GL_VERSION < 1.2; 612 status "Fog of War smoothing requires OpenGL 1.2 or higher" if $CFPlus::OpenGL::GL_VERSION < 1.2;
613 0
261 } 614 }
262 ); 615 );
263 616
264 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "GUI Fontsize");
265 $table->add (1, $row++, new CFClient::UI::Slider
266 range => [$CFG->{gui_fontsize}, 0.5, 2, 0, 0.1],
267 tooltip => "The base font size used by most GUI elements that do not have their own setting.",
268 connect_changed => sub { $CFG->{gui_fontsize} = $_[1] },
269 );
270
271 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Message Fontsize"); 617 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Message Fontsize");
272 $table->add (1, $row++, new CFClient::UI::Slider 618 $table->add (1, $row++, new CFPlus::UI::Slider
273 range => [$CFG->{log_fontsize}, 0.5, 2, 0, 0.1], 619 range => [$CFG->{log_fontsize}, 0.5, 2, 0, 0.1],
274 tooltip => "The font size used by the <b>message/server log</b> window only. Changes are instant.", 620 tooltip => "The font size used by the <b>message/server log</b> window only. Changes are instant.",
275 connect_changed => sub { $LOGVIEW->set_fontsize ($CFG->{log_fontsize} = $_[1]) }, 621 on_changed => sub { $LOGVIEW->set_fontsize ($CFG->{log_fontsize} = $_[1]); 0 },
276 ); 622 );
277 623
278 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Stats Fontsize");
279
280 $table->add (1, $row++, new CFClient::UI::Slider
281 range => [$CFG->{stat_fontsize}, 0.5, 2, 0, 0.1],
282 tooltip => "The font size used by the <b>statistics window</b> only. Changes are instant.",
283 connect_changed => sub {
284 $CFG->{stat_fontsize} = $_[1];
285 &set_stats_window_fontsize;
286 }
287 );
288
289 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Gauge fontsize"); 624 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Gauge fontsize");
290 $table->add (1, $row++, new CFClient::UI::Slider 625 $table->add (1, $row++, new CFPlus::UI::Slider
291 range => [$CFG->{gauge_fontsize}, 0.5, 2, 0, 0.1], 626 range => [$CFG->{gauge_fontsize}, 0.5, 2, 0, 0.1],
292 tooltip => "Adjusts the fontsize of the gauges at the bottom right. Changes are instant.", 627 tooltip => "Adjusts the fontsize of the gauges at the bottom right. Changes are instant.",
293 connect_changed => sub { 628 on_changed => sub {
294 $CFG->{gauge_fontsize} = $_[1]; 629 $CFG->{gauge_fontsize} = $_[1];
295 &set_gauge_window_fontsize; 630 &set_gauge_window_fontsize;
631 0
296 } 632 }
297 ); 633 );
298 634
299 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Gauge size"); 635 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Gauge size");
300 $table->add (1, $row++, new CFClient::UI::Slider 636 $table->add (1, $row++, new CFPlus::UI::Slider
301 range => [$CFG->{gauge_size}, 0.2, 0.8], 637 range => [$CFG->{gauge_size}, 0.2, 0.8],
302 tooltip => "Adjust the size of the stats gauges at the bottom right. Changes are instant.", 638 tooltip => "Adjust the size of the stats gauges at the bottom right. Changes are instant.",
303 connect_changed => sub { 639 on_changed => sub {
304 $CFG->{gauge_size} = $_[1]; 640 $CFG->{gauge_size} = $_[1];
305 $GAUGES->{win}->set_size ($WIDTH, int $HEIGHT * $CFG->{gauge_size}); 641 $GAUGES->{win}->set_size ($WIDTH, int $HEIGHT * $CFG->{gauge_size});
642 0
306 } 643 }
307 ); 644 );
308 645
309 $table->add (1, $row++, new CFClient::UI::Button 646 $vbox
310 expand => 1, align => 0, text => "Apply", 647}
311 tooltip => "Apply the video settings",
312 connect_activate => sub {
313 video_shutdown ();
314 video_init ();
315 }
316 );
317 648
649sub audio_setup {
650 my $vbox = new CFPlus::UI::VBox;
651
652 $vbox->add (my $table = new CFPlus::UI::Table expand => 1, col_expand => [0, 1]);
653
654 my $row = 0;
655
318 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Audio Enable"); 656 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Audio Enable");
319 $table->add (1, $row++, new CFClient::UI::CheckBox 657 $table->add (1, $row++, new CFPlus::UI::CheckBox
320 state => $CFG->{audio_enable}, 658 state => $CFG->{audio_enable},
321 tooltip => "<b>Master Audio Enable.</b> If enabled, sound effects and music will be played. If disabled, no audio will be used and the soundcard will not be opened.", 659 tooltip => "<b>Master Audio Enable.</b> If enabled, sound effects and music will be played. If disabled, no audio will be used and the soundcard will not be opened.",
322 connect_changed => sub { 660 on_changed => sub { $CFG->{audio_enable} = $_[1]; 0 }
323 $CFG->{audio_enable} = $_[1];
324 }
325 ); 661 );
326# $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Effects Volume"); 662# $table->add (0, 9, new CFPlus::UI::Label valign => 0, align => 1, text => "Effects Volume");
327# $table->add (1, 8, new CFClient::UI::Slider range => [$CFG->{effects_volume}, 0, 128, 1], connect_changed => sub { 663# $table->add (1, 8, new CFPlus::UI::Slider range => [$CFG->{effects_volume}, 0, 128, 1], on_changed => sub {
328# $CFG->{effects_volume} = $_[1]; 664# $CFG->{effects_volume} = $_[1];
329# }); 665# });
330 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Background Music"); 666 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Background Music");
331 $table->add (1, $row++, my $hbox = new CFClient::UI::HBox); 667 $table->add (1, $row++, my $hbox = new CFPlus::UI::HBox);
332 $hbox->add (new CFClient::UI::CheckBox 668 $hbox->add (new CFPlus::UI::CheckBox
333 expand => 1, state => $CFG->{bgm_enable}, 669 expand => 1, state => $CFG->{bgm_enable},
334 tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played.", 670 tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played.",
335 connect_changed => sub { 671 on_changed => sub { $CFG->{bgm_enable} = $_[1]; 0 }
336 $CFG->{bgm_enable} = $_[1];
337 }
338 ); 672 );
339 $hbox->add (new CFClient::UI::Slider 673 $hbox->add (new CFPlus::UI::Slider
340 expand => 1, range => [$CFG->{bgm_volume}, 0, 1, 0, 1/128], 674 expand => 1, range => [$CFG->{bgm_volume}, 0, 1, 0, 1/128],
341 tooltip => "The volume of the background music. Changes are instant.", 675 tooltip => "The volume of the background music. Changes are instant.",
342 connect_changed => sub { 676 on_changed => sub { $CFG->{bgm_volume} = $_[1]; CFPlus::MixMusic::volume $_[1] * 128; 0 }
343 $CFG->{bgm_volume} = $_[1];
344 CFClient::MixMusic::volume $_[1] * 128;
345 }
346 ); 677 );
347 678
348 $table->add (1, $row++, new CFClient::UI::Button 679 $table->add (1, $row++, new CFPlus::UI::Button
349 expand => 1, align => 0, text => "Apply", 680 expand => 1, align => 0, text => "Apply",
350 tooltip => "Apply the audio settings", 681 tooltip => "Apply the audio settings",
351 connect_activate => sub { 682 on_activate => sub {
352 audio_shutdown (); 683 audio_shutdown ();
353 audio_init (); 684 audio_init ();
685 0
354 } 686 }
355 ); 687 );
356 688
357 $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Chat Command"); 689 $vbox
358 $table->add (1, $row++, my $saycmd = new CFClient::UI::Entry
359 text => $CFG->{say_command},
360 tooltip => "This is the command that will be used if you write a line in the message window entry or press <b>\"</b> in the map window. "
361 . "Usually you want to enter something like 'say' or 'shout' or 'gsay' here. "
362 . "But you could also set it to <b>tell <i>playername</i></b> to only chat with that user.",
363 connect_changed => sub {
364 my ($self, $value) = @_;
365 $CFG->{say_command} = $value;
366 }
367 );
368
369 $dialog
370}
371
372sub set_stats_window_fontsize {
373 for (values %{$STATWIDS}) {
374 $_->set_fontsize ($::CFG->{stat_fontsize});
375 }
376} 690}
377 691
378sub set_gauge_window_fontsize { 692sub set_gauge_window_fontsize {
379 for (map { $GAUGES->{$_} } grep { $_ ne 'win' } keys %{$GAUGES}) { 693 for (map { $GAUGES->{$_} } grep { $_ ne 'win' } keys %{$GAUGES}) {
380 $_->set_fontsize ($::CFG->{gauge_fontsize}); 694 $_->set_fontsize ($::CFG->{gauge_fontsize});
382} 696}
383 697
384sub make_gauge_window { 698sub make_gauge_window {
385 my $gh = int $HEIGHT * $CFG->{gauge_size}; 699 my $gh = int $HEIGHT * $CFG->{gauge_size};
386 700
387 my $win = new CFClient::UI::Frame ( 701 my $win = new CFPlus::UI::Frame (
388 req_y => -1, 702 force_x => 0,
703 force_y => "max",
389 user_w => $WIDTH, 704 force_w => $WIDTH,
390 user_h => $gh, 705 force_h => $gh,
391 ); 706 );
392 707
393 $win->add (my $hbox = new CFClient::UI::HBox 708 $win->add (my $hbox = new CFPlus::UI::HBox
394 children => [ 709 children => [
395 (new CFClient::UI::HBox expand => 1), 710 (new CFPlus::UI::HBox expand => 1),
396 (new CFClient::UI::VBox children => [ 711 (new CFPlus::UI::VBox children => [
397 (new CFClient::UI::Empty expand => 1), 712 (new CFPlus::UI::Empty expand => 1),
398 (new CFClient::UI::Frame bg => [0, 0, 0, 0.4], child => ($FLOORBOX = new CFClient::UI::Table)), 713 (new CFPlus::UI::Frame bg => [0, 0, 0, 0.4], child => ($FLOORBOX = new CFPlus::UI::Table)),
399 ]), 714 ]),
400 (my $vbox = new CFClient::UI::VBox), 715 (my $vbox = new CFPlus::UI::VBox),
401 ], 716 ],
402 ); 717 );
403 718
404 $vbox->add (new CFClient::UI::HBox 719 $vbox->add (new CFPlus::UI::HBox
405 expand => 1, 720 expand => 1,
406 children => [ 721 children => [
407 (new CFClient::UI::Empty expand => 1), 722 (new CFPlus::UI::Empty expand => 1),
408 (my $hb = new CFClient::UI::HBox), 723 (my $hb = new CFPlus::UI::HBox),
409 ], 724 ],
410 ); 725 );
411 726
412 $hb->add (my $hg = new CFClient::UI::Gauge type => 'hp', 727 $hb->add (my $hg = new CFPlus::UI::Gauge type => 'hp', tooltip => "#stat_health");
413 tooltip => "<b>Health points</b>. Measures of how much damage you can take before dying. Hit points are determined from your level and are influenced by the value of your Con. Hp value may range between 1 to beyond 500 and higher values indicate a greater ability to withstand punishment.");
414 $hb->add (my $mg = new CFClient::UI::Gauge type => 'mana', 728 $hb->add (my $mg = new CFPlus::UI::Gauge type => 'mana', tooltip => "#stat_mana");
415 tooltip => "<b>Spell points</b>. Measures of how much \"fuel\" you have for casting spells and incantations. Mana is calculated from your level and your Pow. Mana values can range between 1 to beyond 500 (glowing crystals can increase the current spell points beyond your normal maximum). Higher values indicate greater amounts of mana.");
416 $hb->add (my $gg = new CFClient::UI::Gauge type => 'grace', 729 $hb->add (my $gg = new CFPlus::UI::Gauge type => 'grace', tooltip => "#stat_grace");
417 tooltip => "<b>Grace points</b> - how favored you are by your god. In game terms, how much divine magic you can cast. Your level, Wis and Pow effect what the value of grace is. Prayong on an altar of your god can increase this value beyond your normal maximum. Grace can take on large positive and negative values. Positive values indicate favor by the gods.");
418 $hb->add (my $fg = new CFClient::UI::Gauge type => 'food', 730 $hb->add (my $fg = new CFPlus::UI::Gauge type => 'food', tooltip => "#stat_food");
419 tooltip => "<b>Food</b>. Ranges between 0 (starving) and 999 (satiated). At a value of 0 the character begins to die. Some magic can speed up or slow down the character digestion. Healing wounds will speed up digestion too.");
420 731
421 $vbox->add (my $exp = new CFClient::UI::Label valign => 0, align => 1, can_hover => 1, can_events => 1, 732 $vbox->add (my $exp = new CFPlus::UI::Label valign => 0, align => 1, can_hover => 1, can_events => 1, tooltip => "#stat_exp");
422 tooltip => "<b>Experience points and overall level</b> - experience is increased as a reward for appropriate action (such as killing monsters) and may decrease as a result of a magical attack or dying. Level is directly derived from the experience value. As the level of the character increases, the character becomes able to succeed at more difficult tasks. A character's level starts at a value of 0 and may range up beyond 100.");
423 $vbox->add (my $rng = new CFClient::UI::Label valign => 0, align => 1, can_hover => 1, can_events => 1, 733 $vbox->add (my $rng = new CFPlus::UI::Label valign => 0, align => 1, can_hover => 1, can_events => 1, tooltip => "#stat_ranged");
424 tooltip => "<b>Ranged attack</b> - how you attack when you press shift-cursor (spell, skill, weapon etc.)");
425 734
426 $GAUGES = { 735 $GAUGES = {
427 exp => $exp, win => $win, range => $rng, 736 exp => $exp, win => $win, range => $rng,
428 food => $fg, mana => $mg, hp => $hg, grace => $gg 737 food => $fg, mana => $mg, hp => $hg, grace => $gg
429 }; 738 };
431 &set_gauge_window_fontsize; 740 &set_gauge_window_fontsize;
432 741
433 $win 742 $win
434} 743}
435 744
745sub debug_setup {
746 my $table = new CFPlus::UI::Table;
747
748 $table->add (0, 0, new CFPlus::UI::Label text => "Widget Borders");
749 $table->add (1, 0, new CFPlus::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 1; 0 });
750 $table->add (0, 1, new CFPlus::UI::Label text => "Tooltip Widget Info");
751 $table->add (1, 1, new CFPlus::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 2; 0 });
752 $table->add (0, 2, new CFPlus::UI::Label text => "Show FPS");
753 $table->add (1, 2, new CFPlus::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 4; 0 });
754 $table->add (0, 3, new CFPlus::UI::Label text => "Suppress Tooltips");
755 $table->add (1, 3, new CFPlus::UI::CheckBox on_changed => sub { $ENV{CFPLUS_DEBUG} ^= 8; 0 });
756 $table->add (0, 4, new CFPlus::UI::Button text => "die on click(tm)", on_activate => sub { &CFPlus::debug() } );
757
758 my @default_smooth = (0.05, 0.13, 0.05, 0.13, 0.30, 0.13, 0.05, 0.13, 0.05);
759
760 for my $x (0..2) {
761 for my $y (0 .. 2) {
762 $table->add ($x + 3, $y,
763 new CFPlus::UI::Entry
764 text => $default_smooth[$x * 3 + $y],
765 on_changed => sub { $MAP->{smooth_matrix}[$x * 3 + $y] = $_[1] if $MAP; 0 },
766 );
767 }
768 }
769
770 $table->add (0, 5, new CFPlus::UI::TextEdit text => "line1\0152\0153");#d#
771
772 $table
773}
774
436sub make_stats_window { 775sub stats_window {
437 my $tgw = new CFClient::UI::FancyFrame title => "Stats", name => "stats_window"; 776 my $r = new CFPlus::UI::ScrolledWindow (
777 expand => 1,
778 scroll_y => 1
779 );
780 $r->add (my $vb = new CFPlus::UI::VBox);
438 781
439 $tgw->add (new CFClient::UI::Window child => my $vb = new CFClient::UI::VBox); 782 $vb->add (new CFPlus::UI::FancyFrame
783 label => "Player",
784 child => (my $pi = new CFPlus::UI::VBox),
785 );
786
440 $vb->add ($STATWIDS->{title} = new CFClient::UI::Label valign => 0, align => -1, text => "Title:", expand => 1, 787 $pi->add ($STATWIDS->{title} = new CFPlus::UI::Label valign => 0, align => -1, text => "Title:", expand => 1,
441 can_hover => 1, can_events => 1, 788 can_hover => 1, can_events => 1,
442 tooltip => "Your name and title. You can change your title by using the <b>title</b> command, if supported by the server."); 789 tooltip => "Your name and title. You can change your title by using the <b>title</b> command, if supported by the server.");
443 $vb->add ($STATWIDS->{map} = new CFClient::UI::Label valign => 0, align => -1, text => "Map:", expand => 1, 790 $pi->add ($STATWIDS->{map} = new CFPlus::UI::Label valign => 0, align => -1, text => "Map:", expand => 1,
444 can_hover => 1, can_events => 1, 791 can_hover => 1, can_events => 1,
445 tooltip => "The map you are currently on (if supported by the server)."); 792 tooltip => "The map you are currently on (if supported by the server).");
446 793
447 $vb->add (my $hb0 = new CFClient::UI::HBox); 794 $pi->add (my $hb0 = new CFPlus::UI::HBox);
448 $hb0->add ($STATWIDS->{weight} = new CFClient::UI::Label valign => 0, align => -1, text => "Weight:", expand => 1, 795 $hb0->add ($STATWIDS->{weight} = new CFPlus::UI::Label valign => 0, align => -1, text => "Weight:", expand => 1,
449 can_hover => 1, can_events => 1, 796 can_hover => 1, can_events => 1,
450 tooltip => "The weight of the player including all inventory items."); 797 tooltip => "The weight of the player including all inventory items.");
451 $hb0->add ($STATWIDS->{m_weight} = new CFClient::UI::Label valign => 0, align => -1, text => "Max weight:", expand => 1, 798 $hb0->add ($STATWIDS->{m_weight} = new CFPlus::UI::Label valign => 0, align => -1, text => "Max weight:", expand => 1,
452 can_hover => 1, can_events => 1, 799 can_hover => 1, can_events => 1,
453 tooltip => "The weight limit: you cannot carry more than this."); 800 tooltip => "The weight limit: you cannot carry more than this.");
454 801
455 802 $vb->add (new CFPlus::UI::FancyFrame
803 label => "Primary/Secondary Statistics",
456 $vb->add (my $hb = new CFClient::UI::HBox expand => 1); 804 child => (my $hb = new CFPlus::UI::HBox expand => 1),
805 );
457 $hb->add (my $tbl = new CFClient::UI::Table expand => 1); 806 $hb->add (my $tbl = new CFPlus::UI::Table expand => 1);
458 807
459 my $color2 = [1, 1, 0]; 808 my $color2 = [1, 1, 0];
460 809
461 for ( 810 for (
462 [0, 0, st_str => "Str", 30, "<b>Physical Strength</b>, determines damage dealt with weapons, how much you can carry, and how often you can attack"], 811 [0, 0, st_str => "Str", 30],
463 [0, 1, st_dex => "Dex", 30, "<b>Dexterity</b>, your physical agility. Determines chance of being hit and affects armor class and speed"], 812 [0, 1, st_dex => "Dex", 30],
464 [0, 2, st_con => "Con", 30, "<b>Constitution</b>, physical health and toughness. Determines how many healthpoints you can have"], 813 [0, 2, st_con => "Con", 30],
465 [0, 3, st_int => "Int", 30, "<b>Intelligence</b>, your ability to learn and use skills and incantations (both prayers and magic) and determines how much spell points you can have"], 814 [0, 3, st_int => "Int", 30],
466 [0, 4, st_wis => "Wis", 30, "<b>Wisdom</b>, the ability to learn and use divine magic (prayers). Determines how many grace points you can have"], 815 [0, 4, st_wis => "Wis", 30],
467 [0, 5, st_pow => "Pow", 30, "<b>Power</b>, your magical potential. Influences the strength of spell effects, and also how much your spell and grace points increase when leveling up"], 816 [0, 5, st_pow => "Pow", 30],
468 [0, 6, st_cha => "Cha", 30, "<b>Charisma</b>, how well you are received by NPCs. Affects buying and selling prices in shops."], 817 [0, 6, st_cha => "Cha", 30],
469 818
470 [2, 0, st_wc => "Wc", -120, "<b>Weapon Class</b>, effectiveness of melee/missile attacks. Lower is more potent. Current weapon, level and Str are some things which effect the value of Wc. The value of Wc may range between 25 and -72."], 819 [2, 0, st_wc => "Wc", -120],
471 [2, 1, st_ac => "Ac", -120, "<b>Armour Class</b>, how protected you are from being hit by any attack. Lower values are better. Ac is based on your race and is modified by the Dex and current armour worn. For characters that cannot wear armour, Ac improves as their level increases."], 820 [2, 1, st_ac => "Ac", -120],
472 [2, 2, st_dam => "Dam", 120, "<b>Damage</b>, how much damage your melee/missile attack inflicts. Higher values indicate a greater amount of damage will be inflicted with each attack."], 821 [2, 2, st_dam => "Dam", 120],
473 [2, 3, st_arm => "Arm", 120, "<b>Armour</b>, how much damage (from physical attacks) will be subtracted from successful hits made upon you. This value ranges between 0 to 99%. Current armour worn primarily determines Arm value."], 822 [2, 3, st_arm => "Arm", 120],
474 [2, 4, st_spd => "Spd", 10.54, "<b>Speed</b>, how fast you can move. The value of speed may range between nearly 0 (\"very slow\") to higher than 5 (\"lightning fast\"). Base speed is determined from the Dex and modified downward proportionally by the amount of weight carried which exceeds the Max Carry limit. The armour worn also sets the upper limit on speed."], 823 [2, 4, st_spd => "Spd", 10.54],
475 [2, 5, st_wspd => "WSp", 10.54, "<b>Weapon Speed</b>, how many attacks you may make per unit of time (0.120s). Higher values indicate faster attack speed. Current weapon and Dex effect the value of weapon speed."], 824 [2, 5, st_wspd => "WSp", 10.54],
476 ) { 825 ) {
477 my ($col, $row, $id, $label, $template, $tooltip) = @$_; 826 my ($col, $row, $id, $label, $template) = @$_;
478 827
479 $tbl->add ($col , $row, $STATWIDS->{$id} = new CFClient::UI::Label 828 $tbl->add ($col , $row, $STATWIDS->{$id} = new CFPlus::UI::Label
480 font => $FONT_FIXED, can_hover => 1, can_events => 1, valign => 0, align => +1, template => $template, tooltip => $tooltip); 829 font => $FONT_FIXED, can_hover => 1, can_events => 1, valign => 0,
830 align => +1, template => $template, tooltip => "#stat_$label");
481 $tbl->add ($col + 1, $row, $STATWIDS->{"$id\_lbl"} = new CFClient::UI::Label 831 $tbl->add ($col + 1, $row, $STATWIDS->{"$id\_lbl"} = new CFPlus::UI::Label
482 font => $FONT_FIXED, can_hover => 1, can_events => 1, fg => $color2, valign => 0, align => -1, text => $label, tooltip => $tooltip); 832 font => $FONT_FIXED, can_hover => 1, can_events => 1, fg => $color2, valign => 0,
833 align => -1, text => $label, tooltip => "#stat_$label");
483 } 834 }
484 835
836 $vb->add (new CFPlus::UI::FancyFrame
837 label => "Resistancies",
485 $hb->add (my $tbl2 = new CFClient::UI::Table expand => 1); 838 child => (my $tbl2 = new CFPlus::UI::Table expand => 1),
839 );
486 840
487 my $row = 0; 841 my $row = 0;
488 my $col = 0; 842 my $col = 0;
489 843
490 my %resist_names = ( 844 my %resist_names = (
845 slow => ["Slow",
491 slow => "<b>Slow</b> (slows you down when you are hit by the spell. Monsters will have an opportunity to come near you faster and hit you more often.)", 846 "<b>Slow</b> (slows you down when you are hit by the spell. Monsters will have an opportunity to come near you faster and hit you more often.)"],
847 holyw => ["Holy Word",
492 holyw => "<b>Holy Word</b> (resistance you against getting the fear when someone whose god doesn't like you spells the holy word on you.)", 848 "<b>Holy Word</b> (resistance you against getting the fear when someone whose god doesn't like you spells the holy word on you.)"],
849 conf => ["Confusion",
493 conf => "<b>Confusion</b> (If you are hit by confusion you will move into random directions, and likely into monsters.)", 850 "<b>Confusion</b> (If you are hit by confusion you will move into random directions, and likely into monsters.)"],
851 fire => ["Fire",
494 fire => "<b>Fire</b> (just your resistance to fire spells like burning hands, dragonbreath, meteor swarm fire, ...)", 852 "<b>Fire</b> (just your resistance to fire spells like burning hands, dragonbreath, meteor swarm fire, ...)"],
853 depl => ["Depletion",
495 depl => "<b>Depletion</b> (some monsters and other effects can cause stats depletion)", 854 "<b>Depletion</b> (some monsters and other effects can cause stats depletion)"],
855 magic => ["Magic",
496 magic => "<b>Magic</b> (resistance to magic spells like magic missile or similar)", 856 "<b>Magic</b> (resistance to magic spells like magic missile or similar)"],
857 drain => ["Draining",
497 drain => "<b>Draining</b> (some monsters (e.g. vampires) and other effects can steal experience)", 858 "<b>Draining</b> (some monsters (e.g. vampires) and other effects can steal experience)"],
859 acid => ["Acid",
498 acid => "<b>Acid</b> (resistance to acid, acid hurts pretty much and also corrodes your weapons)", 860 "<b>Acid</b> (resistance to acid, acid hurts pretty much and also corrodes your weapons)"],
861 pois => ["Poison",
499 pois => "<b>Poison</b> (resistance to getting poisoned)", 862 "<b>Poison</b> (resistance to getting poisoned)"],
863 para => ["Paralysation",
500 para => "<b>Paralysation</b> (this resistance affects the chance you get paralysed)", 864 "<b>Paralysation</b> (this resistance affects the chance you get paralysed)"],
865 deat => ["Death",
501 deat => "<b>Death</b> (resistance against death spells)", 866 "<b>Death</b> (resistance against death spells)"],
502 phys => "<b>Physical</b> (this is the resistance against physical attacks, like when a monster hit you in melee combat)", 867 phys => ["Physical",
868 "<b>Physical</b> (this is the resistance against physical attacks, like when a monster hit you in melee combat. The value displayed here is also displayed in the 'Arm' field on the left.)"],
869 blind => ["Blind",
503 blind => "<b>Blind</b> (blind resistance affects the chance of a successful blinding attack)", 870 "<b>Blind</b> (blind resistance affects the chance of a successful blinding attack)"],
871 fear => ["Fear",
504 fear => "<b>Fear</b> (this attack will drive you away from monsters who cast this and hit you successfully, being resistant to this helps a lot when fighting those monsters)", 872 "<b>Fear</b> (this attack will drive you away from monsters who cast this and hit you successfully, being resistant to this helps a lot when fighting those monsters)"],
873 tund => ["Turn undead",
505 tund => "<b>Turn undead</b> (affects your resistancy to various forms of 'turn undead' spells. Only relevant when you are, in fact, undead...", 874 "<b>Turn undead</b> (affects your resistancy to various forms of 'turn undead' spells. Only relevant when you are, in fact, undead..."],
875 elec => ["Electricity",
506 elec => "<b>Electricity</b> (resistance against electricity, spells like large lightning, small lightning, ...)", 876 "<b>Electricity</b> (resistance against electricity, spells like large lightning, small lightning, ...)"],
877 cold => ["Cold",
507 cold => "<b>Cold</b> (this is your resistance against cold spells like icestorm, snowstorm, ...)", 878 "<b>Cold</b> (this is your resistance against cold spells like icestorm, snowstorm, ...)"],
879 ghit => ["Ghost hit",
508 ghit => "<b>Ghost hit</b> (special attack used by ghosts and ghost-like beings)", 880 "<b>Ghost hit</b> (special attack used by ghosts and ghost-like beings)"],
509 ); 881 );
510 for (qw/slow holyw conf fire depl magic 882 for (qw/slow holyw conf fire depl magic
511 drain acid pois para deat phys 883 drain acid pois para deat phys
512 blind fear tund elec cold ghit/) 884 blind fear tund elec cold ghit/)
513 { 885 {
514 $tbl2->add ($col, $row, 886 $tbl2->add ($col, $row,
515 $STATWIDS->{"res_$_"} = 887 $STATWIDS->{"res_$_"} =
516 new CFClient::UI::Label 888 new CFPlus::UI::Label
517 font => $FONT_FIXED, 889 font => $FONT_FIXED,
518 template => "-100%", 890 template => "-100%",
519 align => +1, 891 align => +1,
520 valign => 0, 892 valign => 0,
521 can_events => 1, 893 can_events => 1,
522 can_hover => 1, 894 can_hover => 1,
523 tooltip => $resist_names{$_}, 895 tooltip => $resist_names{$_}->[1],
524 ); 896 );
525 $tbl2->add ($col + 1, $row, new CFClient::UI::Image 897 $tbl2->add ($col + 1, $row, new CFPlus::UI::Image
526 font => $FONT_FIXED, 898 font => $FONT_FIXED,
527 can_hover => 1, 899 can_hover => 1,
528 can_events => 1, 900 can_events => 1,
529 image => "ui/resist/resist_$_.png", 901 path => "ui/resist/resist_$_.png",
530 tooltip => $resist_names{$_}, 902 tooltip => $resist_names{$_}->[1],
903 );
904 $tbl2->add ($col + 2, $row, new CFPlus::UI::Label
905 text => $resist_names{$_}->[0],
906 font => $FONT_FIXED,
907 can_hover => 1,
908 can_events => 1,
909 tooltip => $resist_names{$_}->[1],
531 ); 910 );
532 911
533 $row++; 912 $row++;
534 if ($row % 6 == 0) { 913 if ($row % 6 == 0) {
535 $col += 2; 914 $col += 3;
536 $row = 0; 915 $row = 0;
537 } 916 }
538 } 917 }
539 918
540 &set_stats_window_fontsize;
541 update_stats_window ({}); 919 #update_stats_window ({});
542 920
921 $r
922}
923
924sub skill_window {
925 my $sw = new CFPlus::UI::ScrolledWindow (expand => 1);
926 $sw->add ($STATWIDS->{skill_tbl} = new CFPlus::UI::Table expand => 1, col_expand => [0, 0, 1, 0, 0, 1]);
543 $tgw 927 $sw
544} 928}
545 929
546sub formsep { 930sub formsep($) {
547 reverse join ",", grep length, split /(...)/, reverse $_[0] * 1 931 scalar reverse join ",", unpack "(A3)*", reverse $_[0] * 1
548}
549
550sub update_stats_window {
551 my ($stats) = @_;
552
553 # I love text protocols...
554
555 my $hp = $stats->{+CS_STAT_HP} * 1;
556 my $hp_m = $stats->{+CS_STAT_MAXHP} * 1;
557 my $sp = $stats->{+CS_STAT_SP} * 1;
558 my $sp_m = $stats->{+CS_STAT_MAXSP} * 1;
559 my $fo = $stats->{+CS_STAT_FOOD} * 1;
560 my $fo_m = 999;
561 my $gr = $stats->{+CS_STAT_GRACE} * 1;
562 my $gr_m = $stats->{+CS_STAT_MAXGRACE} * 1;
563
564 $GAUGES->{hp} ->set_value ($hp, $hp_m);
565 $GAUGES->{mana} ->set_value ($sp, $sp_m);
566 $GAUGES->{food} ->set_value ($fo, $fo_m);
567 $GAUGES->{grace} ->set_value ($gr, $gr_m);
568 $GAUGES->{exp} ->set_text ("Exp: " . (formsep $stats->{+CS_STAT_EXP64})
569 . " (lvl " . ($stats->{+CS_STAT_LEVEL} * 1) . ")");
570 my $rng = $stats->{+CS_STAT_RANGE};
571 $rng =~ s/^Range: //; # thank you so much dear server
572 $GAUGES->{range} ->set_text ("Rng: " . $rng);
573 my $title = $stats->{+CS_STAT_TITLE};
574 $title =~ s/^Player: //;
575 $STATWIDS->{title} ->set_text ("Title: " . $title);
576
577 $STATWIDS->{st_str} ->set_text (sprintf "%d" , $stats->{+CS_STAT_STR});
578 $STATWIDS->{st_dex} ->set_text (sprintf "%d" , $stats->{+CS_STAT_DEX});
579 $STATWIDS->{st_con} ->set_text (sprintf "%d" , $stats->{+CS_STAT_CON});
580 $STATWIDS->{st_int} ->set_text (sprintf "%d" , $stats->{+CS_STAT_INT});
581 $STATWIDS->{st_wis} ->set_text (sprintf "%d" , $stats->{+CS_STAT_WIS});
582 $STATWIDS->{st_pow} ->set_text (sprintf "%d" , $stats->{+CS_STAT_POW});
583 $STATWIDS->{st_cha} ->set_text (sprintf "%d" , $stats->{+CS_STAT_CHA});
584 $STATWIDS->{st_wc} ->set_text (sprintf "%d" , $stats->{+CS_STAT_WC});
585 $STATWIDS->{st_ac} ->set_text (sprintf "%d" , $stats->{+CS_STAT_AC});
586 $STATWIDS->{st_dam} ->set_text (sprintf "%d" , $stats->{+CS_STAT_DAM});
587 $STATWIDS->{st_arm} ->set_text (sprintf "%d" , $stats->{+CS_STAT_ARMOUR});
588 $STATWIDS->{st_spd} ->set_text (sprintf "%.1f", $stats->{+CS_STAT_SPEED});
589 $STATWIDS->{st_wspd}->set_text (sprintf "%.1f", $stats->{+CS_STAT_WEAP_SP});
590
591 $STATWIDS->{m_weight}->set_text (sprintf "Max weight: %.1fkg", $stats->{+CS_STAT_WEIGHT_LIM} / 1000);
592
593 # TODO: replace by CS_STAT_RES_xxx constants
594 my %tbl = (
595 phys => 100,
596 magic => 101,
597 fire => 102,
598 elec => 103,
599 cold => 104,
600 conf => 105,
601 acid => 106,
602 drain => 107,
603 ghit => 108,
604 pois => 109,
605 slow => 110,
606 para => 111,
607 tund => 112,
608 fear => 113,
609 depl => 113,
610 deat => 115,
611 holyw => 116,
612 blind => 117,
613 );
614
615 $STATWIDS->{"res_$_"}->set_text (sprintf "%d%", $stats->{$tbl{$_}})
616 for keys %tbl;
617}
618
619sub metaserver_dialog {
620 my $dialog = new CFClient::UI::FancyFrame
621 title => "Server List",
622 child => (my $vbox = new CFClient::UI::VBox);
623
624 $vbox->add ($dialog->{table} = new CFClient::UI::Table);
625
626 $dialog
627} 932}
628 933
629my $METASERVER_ATIME; 934my $METASERVER_ATIME;
630 935
631sub update_metaserver { 936sub update_metaserver {
632 my ($HOST) = @_; 937 my ($metaserver_dialog) = @_;
938
939 $METASERVER = $metaserver_dialog
940 if defined $metaserver_dialog;
633 941
634 return if $METASERVER_ATIME > time; 942 return if $METASERVER_ATIME > time;
635 $METASERVER_ATIME = time + 60; 943 $METASERVER_ATIME = time + 60;
636 944
637 my $table = $METASERVER->{table}; 945 my $table = $METASERVER->{table};
638 $table->clear; 946 $table->clear;
639 $table->add (0, 0, my $label = new CFClient::UI::Label max_w => $WIDTH * 0.8, text => "fetching server list..."); 947 $table->add (0, 0, my $label = new CFPlus::UI::Label max_w => $WIDTH * 0.8, text => "fetching server list...");
640 948
641 my $buf; 949 my $ok = 0;
642 950
643 my $fh = new IO::Socket::INET PeerHost => $META_SERVER, Blocking => 0; 951 CFPlus::background {
952 my $ua = CFPlus::lwp_useragent;
644 953
645 unless ($fh) { 954 CFPlus::background_msg CFPlus::from_json +(CFPlus::lwp_check $ua->get ($META_SERVER))->decoded_content;
646 $label->set_text ("unable to contact metaserver: $!"); 955 } sub {
647 return; 956 my ($msg) = @_;
648 } 957 if ($msg) {
649
650 Event->io (fd => $fh, poll => 'r', cb => sub {
651 my $res = sysread $fh, $buf, 8192, length $buf;
652
653 if (!defined $res) {
654 $_[0]->w->cancel;
655 $label->set_text ("error while retrieving server list: $!");
656 } elsif ($res == 0) {
657 $_[0]->w->cancel;
658 status "server list retrieved";
659
660 utf8::decode $buf if utf8::valid $buf;
661
662 $table->clear; 958 $table->clear;
663 959
960 my @tip = (
961 "The current number of users logged in on the server.",
962 "The hostname of the server.",
963 "The time this server has been running without being restarted.",
964 "The server software version - a '+' indicates a Crossfire+ server.",
965 "Short information about this server provided by its admins.",
966 );
664 my @col = qw(Use #Users Host Uptime Version Description); 967 my @col = qw(#Users Host Uptime Version Description);
665 $table->add ($_, 0, new CFClient::UI::Label align => 0, fg => [1, 1, 0], text => $col[$_]) 968 $table->add ($_, 0, new CFPlus::UI::Label
969 can_hover => 1, can_events => 1,
970 align => 0, fg => [1, 1, 0],
971 text => $col[$_], tooltip => $tip[$_])
666 for 0 .. $#col; 972 for 0 .. $#col;
667 973
668 my @align = qw(1 0 1 1 -1); 974 my @align = qw(1 0 1 1 -1);
669 975
670 my $y = 0; 976 my $y = 0;
671 for my $m (sort { $b->[3] <=> $a->[3] } map [split /\|/], split /\015?\012/, $buf) { 977 for my $m (@{ $msg->{servers} }) {
672 my ($ip, $last, $host, $users, $version, $desc, $ibytes, $obytes, $uptime) = @$m; 978 my ($ip, $last, $host, $users, $version, $desc, $ibytes, $obytes, $uptime, $highlight) =
979 @$m{qw(ip age hostname users version description ibytes obytes uptime highlight)};
673 980
674 for ($desc) { 981 for ($desc) {
675 s/<br>/\n/gi; 982 s/<br>/\n/gi;
676 s/<li>/\n· /gi; 983 s/<li>/\n· /gi;
677 s/<.*?>//sgi; 984 s/<.*?>//sgi;
678 s/&/&amp;/g; 985 s/&amp;/&/g;
679 s/</&lt;/g; 986 s/&lt;/</g;
680 s/>/&gt;/g; 987 s/&gt;/>/g;
681 } 988 }
682 989
683 $uptime = sprintf "%dd %02d:%02d:%02d", 990 $uptime = sprintf "%dd %02d:%02d:%02d",
684 (int $m->[8] / 86400), 991 (int $uptime / 86400),
685 (int $m->[8] / 3600) % 24, 992 (int $uptime / 3600) % 24,
686 (int $m->[8] / 60) % 60, 993 (int $uptime / 60) % 60,
687 $m->[8] % 60; 994 $uptime % 60;
688 995
689 $m = [$users, $host, $uptime, $version, $desc]; 996 $m = [$users, $host, $uptime, $version, $desc];
690 997
691 $y++; 998 $y++;
692 999
693 $table->add (0, $y, new CFClient::UI::VBox children => [ 1000 $table->add (scalar @$m, $y, new CFPlus::UI::VBox children => [
694 (new CFClient::UI::Button text => "Use", connect_activate => sub { 1001 (new CFPlus::UI::Button
1002 text => "Use",
1003 tooltip => "Put this server into the <b>Host:Port</b> field",
1004 on_activate => sub {
695 $HOST->set_text ($CFG->{host} = $host); 1005 $HOST_ENTRY->set_text ($CFG->{profile}{default}{host} = $host);
1006 $METASERVER->hide;
1007 0
1008 },
696 }), 1009 ),
697 (new CFClient::UI::Empty expand => 1), 1010 (new CFPlus::UI::Empty expand => 1),
698 ]); 1011 ]);
699 1012
700 $table->add ($_ + 1, $y, new CFClient::UI::Label 1013 $table->add ($_, $y, new CFPlus::UI::Label
701 ellipsise => 0, align => $align[$_], text => $m->[$_], fontsize => 0.8) 1014 max_w => $::WIDTH * 0.4,
1015 ellipsise => 0,
1016 align => $align[$_],
1017 text => $m->[$_],
1018 tooltip => $tip[$_],
1019 fg => ($highlight ? [1, 1, 1] : [.7, .7, .7]),
1020 can_hover => 1,
1021 can_events => 1,
1022 fontsize => 0.8)
702 for 0 .. $#$m; 1023 for 0 .. $#$m;
703 } 1024 }
1025 } else {
1026 $ok or $label->set_text ("error while contacting metaserver");
1027 }
1028 };
1029
1030}
1031
1032sub metaserver_dialog {
1033 my $vbox = new CFPlus::UI::VBox;
1034 my $table = new CFPlus::UI::Table;
1035 $vbox->add (new CFPlus::UI::ScrolledWindow expand => 1, child => $table);
1036
1037 my $dialog = new CFPlus::UI::Toplevel
1038 title => "Server List",
1039 name => 'metaserver_dialog',
1040 x => 'center',
1041 y => 'center',
1042 z => 3,
1043 force_w => $::WIDTH * 0.9,
1044 force_h => $::HEIGHT * 0.7,
1045 child => $vbox,
1046 has_close_button => 1,
1047 table => $table,
1048 on_visibility_change => sub {
1049 update_metaserver ($_[0]) if $_[1];
1050 0
704 } 1051 },
705 }); 1052 ;
1053
1054 $dialog
706} 1055}
707 1056
708sub server_setup { 1057sub server_setup {
709 my $dialog = new CFClient::UI::FancyFrame 1058 my $vbox = new CFPlus::UI::VBox;
710 name => "server_setup", 1059
711 title => "Server Setup", 1060 $vbox->add (new CFPlus::UI::FancyFrame
712 child => (my $vbox = new CFClient::UI::VBox); 1061 label => "Connection Settings",
713
714 $vbox->add (my $table = new CFClient::UI::Table expand => 1, col_expand => [0, 1]); 1062 child => (my $table = new CFPlus::UI::Table expand => 1, col_expand => [0, 1]),
1063 );
715 $table->add (0, 2, new CFClient::UI::Label valign => 0, align => 1, text => "Host:Port"); 1064 $table->add (0, 2, new CFPlus::UI::Label valign => 0, align => 1, text => "Host:Port");
716 1065
717 { 1066 {
718 $table->add (1, 2, my $vbox = new CFClient::UI::VBox); 1067 $table->add (1, 2, my $vbox = new CFPlus::UI::VBox);
719 1068
720 $vbox->add ( 1069 $vbox->add (
721 my $HOST = new CFClient::UI::Entry 1070 $HOST_ENTRY = new CFPlus::UI::Entry
722 expand => 1, 1071 expand => 1,
723 text => $CFG->{host}, 1072 text => $CFG->{profile}{default}{host},
724 tooltip => "The hostname or ip address of the Crossfire(+) server to connect to", 1073 tooltip => "The hostname or ip address of the Crossfire(+) server to connect to",
725 connect_changed => sub { 1074 on_changed => sub {
726 my ($self, $value) = @_; 1075 my ($self, $value) = @_;
727 $CFG->{host} = $value; 1076 $CFG->{profile}{default}{host} = $value;
1077 0
728 } 1078 }
729 ); 1079 );
730 1080
731 $METASERVER = metaserver_dialog;
732
733 $vbox->add (new CFClient::UI::Flopper 1081 $vbox->add (new CFPlus::UI::Button
734 expand => 1, 1082 expand => 1,
735 text => "Server List", 1083 text => "Server List",
736 other => $METASERVER, 1084 other => $METASERVER,
737 tooltip => "Show a list of available crossfire servers", 1085 tooltip => "Show a list of available crossfire servers",
738 connect_open => sub { 1086 on_activate => sub { $METASERVER->toggle_visibility; 0 },
739 update_metaserver $HOST; 1087 on_visibility_change => sub { $METASERVER->hide unless $_[1]; 0 },
740 }
741 ); 1088 );
742 } 1089 }
743 1090
744 $table->add (0, 4, new CFClient::UI::Label valign => 0, align => 1, text => "Username"); 1091 $table->add (0, 4, new CFPlus::UI::Label valign => 0, align => 1, text => "Username");
745 $table->add (1, 4, new CFClient::UI::Entry 1092 $table->add (1, 4, new CFPlus::UI::Entry
746 text => $CFG->{user}, 1093 text => $CFG->{profile}{default}{user},
747 tooltip => "The name of your character on the server", 1094 tooltip => "The name of your character on the server",
748 connect_changed => sub { 1095 on_changed => sub { my ($self, $value) = @_; $CFG->{profile}{default}{user} = $value }
749 my ($self, $value) = @_;
750 $CFG->{user} = $value;
751 }
752 ); 1096 );
753 1097
754 $table->add (0, 5, new CFClient::UI::Label valign => 0, align => 1, text => "Password"); 1098 $table->add (0, 5, new CFPlus::UI::Label valign => 0, align => 1, text => "Password");
755 $table->add (1, 5, new CFClient::UI::Entry 1099 $table->add (1, 5, new CFPlus::UI::Entry
756 text => $CFG->{password}, 1100 text => $CFG->{profile}{default}{password},
757 hidden => 1, 1101 hidden => 1,
758 tooltip => "The password for your character", 1102 tooltip => "The password for your character",
759 connect_changed => sub { 1103 on_changed => sub { my ($self, $value) = @_; $CFG->{profile}{default}{password} = $value }
760 my ($self, $value) = @_;
761 $CFG->{password} = $value;
762 }
763 ); 1104 );
764 1105
765 $table->add (0, 7, new CFClient::UI::Label valign => 0, align => 1, text => "Map Size"); 1106 $table->add (0, 7, new CFPlus::UI::Label valign => 0, align => 1, text => "Map Size");
766 $table->add (1, 7, new CFClient::UI::Slider 1107 $table->add (1, 7, new CFPlus::UI::Slider
767 req_w => 100, 1108 force_w => 100,
768 range => [$CFG->{mapsize}, 10, 100, 0, 1], 1109 range => [$CFG->{mapsize}, 10, 100, 0, 1],
769 tooltip => "This is the size of the portion of the map update the server sends you. " 1110 tooltip => "This is the size of the portion of the map update the server sends you. "
770 . "If you set this to a high value you will be able to see further, " 1111 . "If you set this to a high value you will be able to see further, "
771 . "but you also increase bandwidth requirements and latency. " 1112 . "but you also increase bandwidth requirements and latency. "
772 . "This option is only used once at log-in.", 1113 . "This option is only used once at log-in.",
773 connect_changed => sub { 1114 on_changed => sub { my ($self, $value) = @_; $CFG->{mapsize} = $self->{range}[0] = $value = int $value; 0 },
774 my ($self, $value) = @_;
775
776 $CFG->{mapsize} = $self->{range}[0] = $value = int $value;
777 },
778 ); 1115 );
779 1116
780 $table->add (0, 8, new CFClient::UI::Label valign => 0, align => 1, text => "Face Prefetch"); 1117 $table->add (0, 8, new CFPlus::UI::Label valign => 0, align => 1, text => "Face Prefetch");
781 $table->add (1, 8, new CFClient::UI::CheckBox 1118 $table->add (1, 8, new CFPlus::UI::CheckBox
782 state => $CFG->{face_prefetch}, 1119 state => $CFG->{face_prefetch},
783 tooltip => "<b>Background Image Prefetch</b>\n\n" 1120 tooltip => "<b>Background Image Prefetch</b>\n\n"
784 . "If enabled, the client automatically pre-fetches images from the server. " 1121 . "If enabled, the client automatically pre-fetches images from the server. "
785 . "This might increase or create lag, but increases the chances " 1122 . "This might increase or create lag, but increases the chances "
786 . "of faces being ready for display when you encounter them. " 1123 . "of faces being ready for display when you encounter them. "
787 . "It also uses up server bandwidth on every connect, " 1124 . "It also uses up server bandwidth on every connect, "
788 . "so only set it if you really need to prefetch images. " 1125 . "so only set it if you really need to prefetch images. "
789 . "This option can be set and unset any time.", 1126 . "This option can be set and unset any time.",
790 connect_changed => sub { $CFG->{face_prefetch} = $_[1] }, 1127 on_changed => sub { $CFG->{face_prefetch} = $_[1]; 0 },
791 ); 1128 );
792 1129
1130 $table->add (0, 9, new CFPlus::UI::Label valign => 0, align => 1, text => "Output-Rate");
1131 $table->add (1, 9, new CFPlus::UI::Entry
1132 text => $CFG->{output_rate},
1133 tooltip => "The approximate bandwidth in bytes per second that the server should not exceed "
1134 . "when sending images, to ensure interactiveness. When 0 or unset, the server "
1135 . "default will be used, which is usually around 100kb/s.",
1136 on_changed => sub { $CFG->{output_rate} = $_[1]; 0 },
1137 );
1138
793 $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Count"); 1139 $table->add (0, 10, new CFPlus::UI::Label valign => 0, align => 1, text => "Output-Count");
794 $table->add (1, 9, new CFClient::UI::Entry 1140 $table->add (1, 10, new CFPlus::UI::Entry
795 text => $CFG->{output_count}, 1141 text => $CFG->{output_count},
796 tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.", 1142 tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.",
797 connect_changed => sub { $CFG->{output_count} = $_[1] }, 1143 on_changed => sub { $CFG->{output_count} = $_[1]; 0 },
798 ); 1144 );
799 1145
800 $table->add (0, 10, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Sync"); 1146 $table->add (0, 11, new CFPlus::UI::Label valign => 0, align => 1, text => "Output-Sync");
801 $table->add (1, 10, new CFClient::UI::Entry 1147 $table->add (1, 11, new CFPlus::UI::Entry
802 text => $CFG->{output_sync}, 1148 text => $CFG->{output_sync},
803 tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.", 1149 tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.",
804 connect_changed => sub { $CFG->{output_sync} = $_[1] }, 1150 on_changed => sub { $CFG->{output_sync} = $_[1]; 0 },
805 ); 1151 );
806 1152
807 $table->add (1, 11, $LOGIN_BUTTON = new CFClient::UI::Button 1153 $table->add (1, 12, $LOGIN_BUTTON = new CFPlus::UI::Button
808 expand => 1, 1154 expand => 1,
809 align => 0, 1155 align => 0,
810 text => "Login", 1156 text => "Login",
811 connect_activate => sub { 1157 on_activate => sub {
812 $CONN ? stop_game 1158 $CONN ? stop_game
813 : start_game; 1159 : start_game;
1160 0
814 }, 1161 },
815 ); 1162 );
816 1163
817 $dialog 1164 $vbox->add (new CFPlus::UI::FancyFrame
1165 label => "Server Info",
1166 child => ($SERVER_INFO = new CFPlus::UI::Label ellipsise => 0),
1167 );
1168
1169 $vbox
1170}
1171
1172sub client_setup {
1173 my $table = new CFPlus::UI::Table expand => 1, col_expand => [0, 1];
1174
1175 my $row = 0;
1176
1177 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Chat Command");
1178 $table->add (1, $row++, my $saycmd = new CFPlus::UI::Entry
1179 text => $CFG->{say_command},
1180 tooltip => "This is the command that will be used if you write a line in the message window entry or press <b>\"</b> in the map window. "
1181 . "Usually you want to enter something like 'say' or 'shout' or 'gsay' here. "
1182 . "But you could also set it to <b>tell <i>playername</i></b> to only chat with that user.",
1183 on_changed => sub {
1184 my ($self, $value) = @_;
1185 $CFG->{say_command} = $value;
1186 0
1187 }
1188 );
1189
1190 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Tip of the day");
1191 $table->add (1, $row++, new CFPlus::UI::CheckBox
1192 state => $CFG->{show_tips},
1193 tooltip => "Show the <b>Tip of the day</b> window at startup?",
1194 on_changed => sub {
1195 my ($self, $value) = @_;
1196 $CFG->{show_tips} = $value;
1197 0
1198 }
1199 );
1200
1201 $table->add (0, $row, new CFPlus::UI::Label valign => 0, align => 1, text => "Messages Window Size");
1202 $table->add (1, $row++, my $saycmd = new CFPlus::UI::Entry
1203 text => $CFG->{logview_max_par},
1204 tooltip => "This is maximum number of messages remembered in the <b>Messages</b> window. If the server "
1205 . "sends more messages than this number, older messages get removed to save memory and "
1206 . "computing time. A value of <b>0</b> disables this feature, but that is not recommended.",
1207 on_changed => sub {
1208 my ($self, $value) = @_;
1209 $LOGVIEW->{max_par} = $CFG->{logview_max_par} = $value*1;
1210 0
1211 },
1212 );
1213
1214 $table
818} 1215}
819 1216
820sub message_window { 1217sub message_window {
821 my $window = new CFClient::UI::FancyFrame 1218 my $window = new CFPlus::UI::Toplevel
822 name => "message_window", 1219 name => "message_window",
823 title => "Messages", 1220 title => "Messages",
824 border_bg => [1, 1, 1, 1], 1221 border_bg => [1, 1, 1, 1],
825 bg => [0, 0, 0, 0.75], 1222 x => "max",
826 user_w => int $::WIDTH / 3, 1223 y => 0,
1224 force_w => $::WIDTH * 0.4,
827 user_h => int $::HEIGHT / 5, 1225 force_h => $::HEIGHT * 0.5,
828 child => (my $vbox = new CFClient::UI::VBox); 1226 child => (my $vbox = new CFPlus::UI::VBox),
1227 has_close_button => 1;
829 1228
830 $vbox->add ($LOGVIEW); 1229 $vbox->add ($LOGVIEW);
831 1230
832 $vbox->add (my $input = new CFClient::UI::Entry 1231 $vbox->add (my $input = new CFPlus::UI::Entry
833 tooltip => "<b>Chat Box</b>. If you enter a text and press return/enter here, the current <i>communication command</i> " 1232 tooltip => "<b>Chat Box</b>. If you enter a text and press return/enter here, the current <i>communication command</i> "
834 . "from the client setup will be prepended (e.g. <b>shout</b>, <b>chat</b>...). " 1233 . "from the client setup will be prepended (e.g. <b>shout</b>, <b>chat</b>...). "
835 . "If you prepend a slash (/), you will submit a command instead (similar to IRC). " 1234 . "If you prepend a slash (/), you will submit a command instead (similar to IRC). "
836 . "A better way to submit commands (and the occasional chat command) is often the map command completer.", 1235 . "A better way to submit commands (and the occasional chat command) is often the map command completer.",
837 connect_focus_in => sub { 1236 on_focus_in => sub {
838 my ($input, $prev_focus) = @_; 1237 my ($input, $prev_focus) = @_;
839 1238
840 delete $input->{refocus_map}; 1239 delete $input->{refocus_map};
841 1240
842 if ($prev_focus == $MAPWIDGET && $input->{auto_activated}) { 1241 if ($prev_focus == $MAPWIDGET && $input->{auto_activated}) {
843 $input->{refocus_map} = 1; 1242 $input->{refocus_map} = 1;
844 } 1243 }
845 delete $input->{auto_activated}; 1244 delete $input->{auto_activated};
1245
1246 0
846 }, 1247 },
847 connect_activate => sub { 1248 on_activate => sub {
848 my ($input, $text) = @_; 1249 my ($input, $text) = @_;
849 $input->set_text (''); 1250 $input->set_text ('');
850 1251
851 if ($text =~ /^\/(.*)/) { 1252 if ($text =~ /^\/(.*)/) {
852 $::CONN->user_send ($1); 1253 $::CONN->user_send ($1);
856 } 1257 }
857 if ($input->{refocus_map}) { 1258 if ($input->{refocus_map}) {
858 delete $input->{refocus_map}; 1259 delete $input->{refocus_map};
859 $MAPWIDGET->focus_in 1260 $MAPWIDGET->focus_in
860 } 1261 }
1262
1263 0
861 }, 1264 },
862 connect_escape => sub { 1265 on_escape => sub {
863 $MAPWIDGET->focus_in 1266 $MAPWIDGET->grab_focus;
1267
1268 0
864 }, 1269 },
865 ); 1270 );
866 1271
867 $CONSOLE = { 1272 $CONSOLE = {
868 window => $window, 1273 window => $window,
869 input => $input 1274 input => $input,
870 }; 1275 };
871 1276
872 $window 1277 $window
1278}
1279
1280sub autopickup_setup {
1281 my $table = new CFPlus::UI::Table;
1282
1283 for (
1284 ["General", 0, 0,
1285 ["Enable autopickup" => PICKUP_NEWMODE, \$PICKUP_ENABLE],
1286 ["Inhibit autopickup" => PICKUP_INHIBIT],
1287 ["Stop before pickup" => PICKUP_STOP],
1288 ["Debug autopickup" => PICKUP_DEBUG],
1289 ],
1290 ["Weapons", 0, 6,
1291 ["All weapons" => PICKUP_ALLWEAPON],
1292 ["Missile weapons" => PICKUP_MISSILEWEAPON],
1293 ["Bows" => PICKUP_BOW],
1294 ["Arrows" => PICKUP_ARROW],
1295 ],
1296 ["Armour", 0, 12,
1297 ["Helmets" => PICKUP_HELMET],
1298 ["Shields" => PICKUP_SHIELD],
1299 ["Body Armour" => PICKUP_ARMOUR],
1300 ["Boots" => PICKUP_BOOTS],
1301 ["Gloves" => PICKUP_GLOVES],
1302 ["Cloaks" => PICKUP_CLOAK],
1303 ],
1304
1305 ["Readables", 2, 0,
1306 ["Spellbooks" => PICKUP_SPELLBOOK],
1307 ["Skillscrolls" => PICKUP_SKILLSCROLL],
1308 ["Normal Books/Scrolls" => PICKUP_READABLES],
1309 ],
1310 ["Misc", 2, 5,
1311 ["Food" => PICKUP_FOOD],
1312 ["Drinks" => PICKUP_DRINK],
1313 ["Valuables (Money, Gems)" => PICKUP_VALUABLES],
1314 ["Keys" => PICKUP_KEY],
1315 ["Magical Items" => PICKUP_MAGICAL],
1316 ["Potions" => PICKUP_POTION],
1317 ["Magic Devices" => PICKUP_MAGIC_DEVICE],
1318 ["Ignore cursed" => PICKUP_NOT_CURSED],
1319 ["Jewelery" => PICKUP_JEWELS],
1320 ["Flesh" => PICKUP_FLESH],
1321 ],
1322 ["Weight/Value ratio", 2, 17]
1323 )
1324 {
1325 my ($title, $x, $y, @bits) = @$_;
1326 $table->add ($x, $y, new CFPlus::UI::Label text => $title, align => 1, fg => [1, 1, 0]);
1327
1328 for (@bits) {
1329 ++$y;
1330
1331 my $mask = $_->[1];
1332 $table->add ($x , $y, new CFPlus::UI::Label text => $_->[0], align => 1, expand => 1);
1333 $table->add ($x+1, $y, my $checkbox = new CFPlus::UI::CheckBox
1334 state => $::CFG->{pickup} & $mask,
1335 on_changed => sub {
1336 my ($box, $value) = @_;
1337
1338 if ($value) {
1339 $::CFG->{pickup} |= $mask;
1340 } else {
1341 $::CFG->{pickup} &= ~$mask;
1342 }
1343
1344 $::CONN->send_command ("pickup $::CFG->{pickup}")
1345 if defined $::CONN;
1346
1347 0
1348 });
1349
1350 ${$_->[2]} = $checkbox if $_->[2];
1351 }
1352 }
1353
1354 $table->add (2, 18, new CFPlus::UI::ValSlider
1355 range => [$::CFG->{pickup} & 0xF, 0, 16, 1, 1],
1356 template => ">= 99",
1357 to_value => sub { ">= " . 5 * $_[0] },
1358 on_changed => sub {
1359 my ($slider, $value) = @_;
1360
1361 $::CFG->{pickup} &= ~0xF;
1362 $::CFG->{pickup} |= int $value
1363 if $value;
1364 1;
1365 });
1366
1367 $table->add (3, 18, new CFPlus::UI::Button
1368 text => "set",
1369 on_activate => sub {
1370 $::CONN->send_command ("pickup $::CFG->{pickup}")
1371 if defined $::CONN;
1372 0
1373 });
1374
1375 $table
1376}
1377
1378my %SORT_ORDER = (
1379 type => undef,
1380 mtime => sub {
1381 my $NOW = time;
1382 sort {
1383 my $atime = $a->{mtime} - $NOW; $atime = $atime < 5 * 60 ? int $atime / 60 : 6;
1384 my $btime = $b->{mtime} - $NOW; $btime = $btime < 5 * 60 ? int $btime / 60 : 6;
1385
1386 ($a->{flags} & F_LOCKED) <=> ($b->{flags} & F_LOCKED)
1387 or $btime <=> $atime
1388 or $a->{type} <=> $b->{type}
1389 } @_
1390 },
1391 weight => sub { sort {
1392 $a->{weight} * ($a->{nrof} || 1) <=> $b->{weight} * ($b->{nrof} || 1)
1393 or $a->{type} <=> $b->{type}
1394 } @_ },
1395);
1396
1397sub inventory_widget {
1398 my $hb = new CFPlus::UI::HBox homogeneous => 1;
1399
1400 $hb->add (my $vb1 = new CFPlus::UI::VBox);
1401 $vb1->add (new CFPlus::UI::Label align => 0, text => "Player");
1402
1403 $vb1->add (my $hb1 = new CFPlus::UI::HBox);
1404
1405 use sort 'stable';
1406
1407 $hb1->add (new CFPlus::UI::Selector
1408 value => $::CFG->{inv_sort},
1409 options => [
1410 [type => "Type/Name"],
1411 [mtime => "Recent/Normal/Locked"],
1412 [weight => "Weight/Type"],
1413 ],
1414 on_changed => sub {
1415 $::CFG->{inv_sort} = $_[1];
1416 $INV->set_sort_order ($SORT_ORDER{$_[1]});
1417 },
1418 );
1419 $hb1->add (new CFPlus::UI::Label text => "Weight: ", align => 1, expand => 1);
1420 #TODO# update to weigh/maxweight
1421 $hb1->add ($STATWIDS->{i_weight} = new CFPlus::UI::Label align => -1);
1422
1423 $vb1->add (my $sw1 = new CFPlus::UI::ScrolledWindow expand => 1, scroll_y => 1);
1424 $sw1->add ($INV = new CFPlus::UI::Inventory);
1425 $INV->set_sort_order ($SORT_ORDER{$::CFG->{inv_sort}});
1426
1427 $hb->add (my $vb2 = new CFPlus::UI::VBox);
1428
1429 $vb2->add ($INV_RIGHT_HB = new CFPlus::UI::HBox);
1430
1431 $vb2->add (my $sw2 = new CFPlus::UI::ScrolledWindow expand => 1, scroll_y => 1);
1432 $sw2->add ($INVR = new CFPlus::UI::Inventory);
1433
1434 # XXX: Call after $INVR = ... because set_opencont sets the items
1435 CFPlus::Protocol::set_opencont ($::CONN, 0, "Floor");
1436
1437 $hb
1438}
1439
1440sub toggle_player_page {
1441 my ($widget) = @_;
1442
1443 if ($PL_WINDOW->{visible} && $PL_NOTEBOOK->get_current_page == $widget) {
1444 $PL_WINDOW->hide;
1445 } else {
1446 $PL_NOTEBOOK->set_current_page ($widget);
1447 $PL_WINDOW->show;
1448 }
1449}
1450
1451sub player_window {
1452 my $plwin = $PL_WINDOW = new CFPlus::UI::Toplevel
1453 x => "center",
1454 y => "center",
1455 force_w => $WIDTH * 9/10,
1456 force_h => $HEIGHT * 9/10,
1457 title => "Player",
1458 name => "playerbook",
1459 has_close_button => 1
1460 ;
1461
1462 my $ntb =
1463 $PL_NOTEBOOK =
1464 new CFPlus::UI::Notebook expand => 1;
1465
1466 $ntb->add (
1467 "Statistics (F2)" => $STATS_PAGE = stats_window,
1468 "Shows statistics, where all your Stats and Resistances are shown."
1469 );
1470 $ntb->add (
1471 "Skills (F3)" => $SKILL_PAGE = skill_window,
1472 "Shows all your Skills."
1473 );
1474
1475 my $spellsw = $SPELL_PAGE = new CFPlus::UI::ScrolledWindow (expand => 1, scroll_y => 1);
1476 $spellsw->add ($SPELL_LIST = new CFPlus::UI::SpellList);
1477 $ntb->add (
1478 "Spellbook (F4)" => $spellsw,
1479 "Displays all spells you have and lets you edit keyboard shortcuts for them."
1480 );
1481 $ntb->add (
1482 "Inventory (F5)" => $INVENTORY_PAGE = inventory_widget,
1483 "Toggles the inventory window, where you can manage your loot (or treasures :). "
1484 . "You can also hit the <b>Tab</b>-key to show/hide the Inventory."
1485 );
1486 $ntb->add (Pickup => autopickup_setup,
1487 "Configure autopickup settings, i.e. which items you will pick up automatically when walking (or running) over them.");
1488
1489 $ntb->set_current_page ($INVENTORY_PAGE);
1490
1491 $plwin->add ($ntb);
1492 $plwin
1493}
1494
1495sub keyboard_setup {
1496 CFPlus::Macro::keyboard_setup
1497}
1498
1499sub help_window {
1500 my $win = new CFPlus::UI::Toplevel
1501 x => 'center',
1502 y => 'center',
1503 z => 4,
1504 name => 'doc_browser',
1505 force_w => int $WIDTH * 7/8,
1506 force_h => int $HEIGHT * 7/8,
1507 title => "Help Browser",
1508 has_close_button => 1;
1509
1510 $win->add (my $vbox = new CFPlus::UI::VBox);
1511
1512 $vbox->add (new CFPlus::UI::FancyFrame
1513 label => "Navigation",
1514 child => (my $buttons = new CFPlus::UI::HBox),
1515 );
1516 $vbox->add (my $viewer = new CFPlus::UI::TextScroller
1517 expand => 1, fontsize => 0.8, padding_x => 4, padding_y => 4);
1518
1519 my @history;
1520 my @future;
1521 my $curnode;
1522
1523 my $load_node; $load_node = sub {
1524 my ($node, $para) = @_;
1525
1526 $buttons->clear;
1527
1528 $buttons->add (new CFPlus::UI::Button
1529 text => "⇤",
1530 tooltip => "back to the starting page",
1531 on_activate => sub {
1532 unshift @future, [$curnode, $viewer->current_paragraph] if $curnode;
1533 unshift @future, @history;
1534 @history = ();
1535 $load_node->(@{shift @future});
1536 },
1537 );
1538
1539 if (@history) {
1540 $buttons->add (new CFPlus::UI::Button
1541 text => "⋘",
1542 tooltip => "back to <i>" . (CFPlus::asxml CFPlus::Pod::full_path $history[-1][0]) . "</i>",
1543 on_activate => sub {
1544 unshift @future, [$curnode, $viewer->current_paragraph] if $curnode;
1545 $load_node->(@{pop @history});
1546 },
1547 );
1548 }
1549
1550 if (@future) {
1551 $buttons->add (new CFPlus::UI::Button
1552 text => "â‹™",
1553 tooltip => "forward to <i>" . (CFPlus::asxml CFPlus::Pod::full_path $future[0][0]) . "</i>",
1554 on_activate => sub {
1555 push @history, [$curnode, $viewer->current_paragraph];
1556 $load_node->(@{shift @future});
1557 },
1558 );
1559 }
1560
1561 $buttons->add (new CFPlus::UI::Label text => " ");
1562
1563 my @path = CFPlus::Pod::full_path_of $node;
1564 pop @path; # drop current node
1565
1566 for my $node (@path) {
1567 $buttons->add (new CFPlus::UI::Button
1568 text => $node->{kw}[0],
1569 tooltip => "go to <i>" . (CFPlus::asxml CFPlus::Pod::full_path $node) . "</i>",
1570 on_activate => sub {
1571 push @history, [$curnode, $viewer->current_paragraph] if $curnode; @future = ();
1572 $load_node->($node);
1573 },
1574 );
1575 $buttons->add (new CFPlus::UI::Label text => "/");
1576 }
1577
1578 $buttons->add (new CFPlus::UI::Label text => $node->{kw}[0], padding_x => 4, padding_y => 4);
1579
1580 $curnode = $node;
1581
1582 $viewer->clear;
1583 $viewer->add_paragraph (CFPlus::Pod::as_paragraphs CFPlus::Pod::section_of $curnode);
1584 $viewer->scroll_to ($para);
1585 };
1586
1587 $load_node->(CFPlus::Pod::find pod => "mainpage");
1588
1589 $CFPlus::Pod::goto_document = sub {
1590 my (@path) = @_;
1591
1592 push @history, [$curnode, $viewer->current_paragraph] if $curnode; @future = ();
1593
1594 $load_node->((CFPlus::Pod::find @path)[0]);
1595 $win->show;
1596 };
1597
1598 $win
1599}
1600
1601sub open_string_query {
1602 my ($title, $cb, $txt, $tooltip) = @_;
1603 my $dialog = new CFPlus::UI::Toplevel
1604 x => "center",
1605 y => "center",
1606 z => 50,
1607 force_w => $WIDTH * 4/5,
1608 title => $title;
1609
1610 $dialog->add (
1611 my $e = new CFPlus::UI::Entry
1612 on_activate => sub { $cb->(@_); $dialog->hide; 0 },
1613 on_key_down => sub { $_[1]->{sym} == 27 and $dialog->hide; 0 },
1614 tooltip => $tooltip
1615 );
1616
1617 $e->grab_focus;
1618 $e->set_text ($txt) if $txt;
1619 $dialog->show;
873} 1620}
874 1621
875sub open_quit_dialog { 1622sub open_quit_dialog {
876 unless ($QUIT_DIALOG) { 1623 unless ($QUIT_DIALOG) {
1624 $QUIT_DIALOG = new CFPlus::UI::Toplevel
1625 x => "center",
1626 y => "center",
1627 z => 50,
1628 title => "Really Quit?",
1629 on_key_down => sub {
1630 my ($dialog, $ev) = @_;
1631 $ev->{sym} == 27 and $dialog->hide;
1632 }
1633 ;
877 1634
878 $QUIT_DIALOG = new CFClient::UI::FancyFrame title => "Really Quit?";
879
880 $QUIT_DIALOG->add (my $vb = new CFClient::UI::VBox expand => 1); 1635 $QUIT_DIALOG->add (my $vb = new CFPlus::UI::VBox expand => 1);
881 1636
882 $vb->add (new CFClient::UI::Label 1637 $vb->add (new CFPlus::UI::Label
883 text => "You should find a savebed and apply it first!", 1638 text => "You should find a savebed and apply it first!",
884 max_w => $WIDTH * 0.25, 1639 max_w => $WIDTH * 0.25,
885 ellipsize => 0, 1640 ellipsize => 0,
886 ); 1641 );
887 $vb->add (my $hb = new CFClient::UI::HBox expand => 1); 1642 $vb->add (my $hb = new CFPlus::UI::HBox expand => 1);
888 $hb->add (new CFClient::UI::Button 1643 $hb->add (new CFPlus::UI::Button
889 text => "Ok", 1644 text => "Ok",
890 expand => 1, 1645 expand => 1,
891 connect_activate => sub { $QUIT_DIALOG->hide }, 1646 on_activate => sub { $QUIT_DIALOG->hide; 0 },
892 ); 1647 );
893 $hb->add (new CFClient::UI::Button 1648 $hb->add (new CFPlus::UI::Button
894 text => "Quit anyway", 1649 text => "Quit anyway",
895 expand => 1, 1650 expand => 1,
896 connect_activate => sub { exit }, 1651 on_activate => sub { exit },
897 ); 1652 );
898
899 $QUIT_DIALOG->show_centered;
900 } else {
901 $QUIT_DIALOG->show_centered;
902 } 1653 }
903}
904 1654
905sub make_inventory_window { 1655 $QUIT_DIALOG->show;
906 my $invwin = new CFClient::UI::FancyFrame 1656 $QUIT_DIALOG->grab_focus;
907 user_w => $WIDTH * (7/8), user_h => $HEIGHT * (7/8), title => "Inventory", name => "inventory_window"; 1657}
908 1658
909 $invwin->add (my $hb = new CFClient::UI::HBox expand => 1); 1659sub show_tip_of_the_day {
1660 # find all tips
1661 my @tod = CFPlus::Pod::find tip_of_the_day => "*";
910 1662
911 $hb->add (my $vb1 = new CFClient::UI::VBox expand => 1); 1663 CFPlus::DB::get state => "tip_of_the_day", sub {
912 $vb1->add (my $lbl = new CFClient::UI::Label align => 0); 1664 my ($todindex) = @_;
913 $lbl->set_text ("Player"); 1665 $todindex = 0 if $todindex >= @tod;
914 $vb1->add ($INV = new CFClient::UI::Inventory expand => 1); 1666 CFPlus::DB::put state => tip_of_the_day => $todindex + 1, sub { };
915 1667
916 $hb->add (my $vb2 = new CFClient::UI::VBox expand => 1); 1668 # create dialog
917 $vb2->add (my $hb2 = new CFClient::UI::HBox); 1669 my $dialog;
918 $hb2->add (new CFClient::UI::Button 1670
1671 my $close = sub {
1672 $dialog->destroy;
1673 };
1674
1675 $dialog = new CFPlus::UI::Toplevel
1676 x => "center",
1677 y => "center",
1678 z => 3,
1679 name => 'tip_of_the_day',
1680 force_w => int $WIDTH * 4/9,
1681 force_h => int $WIDTH * 2/9,
1682 title => "Tip of the day #" . (1 + $todindex),
1683 child => my $vbox = new CFPlus::UI::VBox,
1684 has_close_button => 1,
1685 on_delete => $close,
1686 ;
1687
1688 $vbox->add (my $viewer = new CFPlus::UI::TextScroller
1689 expand => 1, fontsize => 0.8, padding_x => 4, padding_y => 4);
1690 $viewer->add_paragraph (CFPlus::Pod::as_paragraphs CFPlus::Pod::section_of $tod[$todindex]);
1691
1692 $vbox->add (my $table = new CFPlus::UI::Table col_expand => [0, 1]);
1693
1694 $table->add (0, 0, new CFPlus::UI::Button
919 text => "Close", 1695 text => "Close",
920 tooltip => "Close the currently open container (if one is open)", 1696 tooltip => "Close the tip of the day window. To never see it again, disable the tip of the day in the <b>Server Setup</b>.",
921 connect_activate => sub { 1697 on_activate => $close,
922 $CONN->send ("apply $CONN->{open_container}")
923 if $CONN->{open_container} != 0;
924 },
925 ); 1698 );
926 $hb2->add ($INVR_LBL = new CFClient::UI::Label align => 0);
927 1699
928 $INVR_LBL->set_text ("Floor"); 1700 $table->add (2, 0, new CFPlus::UI::Button
929 $vb2->add ($INVR = new CFClient::UI::Inventory expand => 1); 1701 text => "Next",
930 1702 tooltip => "Show the next <b>Tip of the day</b>.",
931 $invwin
932}
933
934sub make_help_window {
935 my $win = new CFClient::UI::FancyFrame
936 user_w => $WIDTH * (7/8), user_h => $HEIGHT * (7/8), title => "Documentation";
937
938 $win->add (my $vbox = new CFClient::UI::VBox);
939
940 $vbox->add (my $buttons = new CFClient::UI::HBox);
941 $vbox->add (my $viewer = new CFClient::UI::TextView expand => 1, fontsize => 0.8);
942
943 for (
944 [intro => "Introduction"],
945 [manual => "Manual"],
946 [command_help => "Commands"],
947 [skill_help => "Skills"],
948 ) {
949 my ($pod, $label) = @$_;
950
951 $buttons->add (new CFClient::UI::Button
952 text => $label,
953 connect_activate => sub { 1703 on_activate => sub {
954 my $parser = new Pod::POM; 1704 $close->();
955 my $pom = $parser->parse_file (CFClient::find_rcfile "pod/$pod.pod"); 1705 &show_tip_of_the_day;
956
957 $viewer->clear;
958
959 $viewer->add_paragraph ([1, 1, 1, 1], $_->[1], $_->[0])
960 for @{ CFClient::pod_to_pango_list $pom };
961
962 $viewer->set_offset (0);
963 }, 1706 },
964 ); 1707 );
1708
1709 $dialog->show;
965 } 1710 };
966
967 $viewer->add_paragraph ([1, 1, 0, 1], "<big>Use one of the buttons above to display a document.</big>");
968
969 $win
970} 1711}
971 1712
972sub sdl_init { 1713sub sdl_init {
973 CFClient::SDL_Init 1714 CFPlus::SDL_Init
974 and die "SDL::Init failed!\n"; 1715 and die "SDL::Init failed!\n";
975} 1716}
976 1717
977sub video_init { 1718sub video_init {
978 sdl_init; 1719 sdl_init;
983 1724
984 ($WIDTH, $HEIGHT) = @{ $SDL_MODES[$CFG->{sdl_mode}] }; 1725 ($WIDTH, $HEIGHT) = @{ $SDL_MODES[$CFG->{sdl_mode}] };
985 $FULLSCREEN = $CFG->{fullscreen}; 1726 $FULLSCREEN = $CFG->{fullscreen};
986 $FAST = $CFG->{fast}; 1727 $FAST = $CFG->{fast};
987 1728
988 CFClient::SDL_SetVideoMode $WIDTH, $HEIGHT, $FULLSCREEN 1729 CFPlus::SDL_SetVideoMode $WIDTH, $HEIGHT, $FULLSCREEN
989 or die "SDL_SetVideoMode failed: " . (CFClient::SDL_GetError) . "\n"; 1730 or die "SDL_SetVideoMode failed: " . (CFPlus::SDL_GetError) . "\n";
990 1731
991 $SDL_ACTIVE = 1; 1732 $SDL_ACTIVE = 1;
992 $LAST_REFRESH = time - 0.01; 1733 $LAST_REFRESH = time - 0.01;
993 1734
994 CFClient::OpenGL::init; 1735 CFPlus::OpenGL::init;
995 1736
996 $FONTSIZE = int $HEIGHT / 40 * $CFG->{gui_fontsize}; 1737 $FONTSIZE = int $HEIGHT / 40 * $CFG->{gui_fontsize};
997 1738
998 $CFClient::UI::ROOT->configure (0, 0, $WIDTH, $HEIGHT);#d# 1739 $CFPlus::UI::ROOT->configure (0, 0, $WIDTH, $HEIGHT);#d#
999 1740
1000 ############################################################################# 1741 #############################################################################
1001 1742
1002 if ($DEBUG_STATUS) { 1743 if ($DEBUG_STATUS) {
1003 CFClient::UI::rescale_widgets $WIDTH / $old_w, $HEIGHT / $old_h; 1744 CFPlus::UI::rescale_widgets $WIDTH / $old_w, $HEIGHT / $old_h;
1004 } else { 1745 } else {
1005 # create the widgets 1746 # create the widgets
1006 1747
1007 $DEBUG_STATUS = new CFClient::UI::Label padding => 0, z => 100, req_x => -1; 1748 $DEBUG_STATUS = new CFPlus::UI::Label
1749 padding => 0,
1750 z => 100,
1751 force_x => "max",
1752 force_y => 0;
1008 $DEBUG_STATUS->show; 1753 $DEBUG_STATUS->show;
1009 1754
1010 $STATUSBOX = new CFClient::UI::Statusbox; 1755 $STATUSBOX = new CFPlus::UI::Statusbox;
1011 $STATUSBOX->add ("Use <b>Alt-Enter</b> to toggle fullscreen mode", pri => -100, color => [1, 1, 1, 0.8]); 1756 $STATUSBOX->add ("Use <b>Alt-Enter</b> to toggle fullscreen mode", timeout => 864000, pri => -100, color => [1, 1, 1, 0.8]);
1012 1757
1013 (new CFClient::UI::Frame 1758 (new CFPlus::UI::Frame
1014 bg => [0, 0, 0, 0.4], 1759 bg => [0, 0, 0, 0.4],
1015 req_y => -1, 1760 force_x => 0,
1761 force_y => "max",
1016 child => $STATUSBOX, 1762 child => $STATUSBOX,
1017 )->show; 1763 )->show;
1018 1764
1019 CFClient::UI::FancyFrame->new ( 1765 CFPlus::UI::Toplevel->new (
1766 title => "Map",
1767 name => "mapmap",
1768 x => 0,
1769 y => $FONTSIZE + 8,
1020 border_bg => [1, 1, 1, 192/255], 1770 border_bg => [1, 1, 1, 192/255],
1021 bg => [1, 1, 1, 0], 1771 bg => [1, 1, 1, 0],
1022 child => ($MAPMAP = new CFClient::MapWidget::MapMap 1772 child => ($MAPMAP = new CFPlus::MapWidget::MapMap
1023 tooltip => "<b>Map</b>. On servers that support this feature, this will display an overview of the surrounding areas.", 1773 tooltip => "<b>Map</b>. On servers that support this feature, this will display an overview of the surrounding areas.",
1024 ), 1774 ),
1025 )->show; 1775 )->show;
1026 1776
1027 $MAPWIDGET = new CFClient::MapWidget; 1777 $MAPWIDGET = new CFPlus::MapWidget;
1028 $MAPWIDGET->connect (activate_console => sub { 1778 $MAPWIDGET->connect (activate_console => sub {
1029 my ($mapwidget, $preset) = @_; 1779 my ($mapwidget, $preset) = @_;
1030 1780
1031 if ($CONSOLE) { 1781 if ($CONSOLE) {
1032 $CONSOLE->{input}->{auto_activated} = 1; 1782 $CONSOLE->{input}->{auto_activated} = 1;
1033 $CONSOLE->{input}->focus_in; 1783 $CONSOLE->{input}->grab_focus;
1034 1784
1035 if ($preset && $CONSOLE->{input}->get_text eq '') { 1785 if ($preset && $CONSOLE->{input}->get_text eq '') {
1036 $CONSOLE->{input}->set_text ($preset); 1786 $CONSOLE->{input}->set_text ($preset);
1037 } 1787 }
1038 } 1788 }
1039 }); 1789 });
1040 $MAPWIDGET->show; 1790 $MAPWIDGET->show;
1041 $MAPWIDGET->focus_in; 1791 $MAPWIDGET->grab_focus;
1042 1792
1043 $LOGVIEW = new CFClient::UI::TextView 1793 $LOGVIEW = new CFPlus::UI::TextScroller
1044 expand => 1, 1794 expand => 1,
1045 font => $FONT_FIXED, 1795 font => $FONT_FIXED,
1046 fontsize => $::CFG->{log_fontsize}, 1796 fontsize => $::CFG->{log_fontsize},
1797 indent => -4,
1047 can_hover => 1, 1798 can_hover => 1,
1048 can_events => 1, 1799 can_events => 1,
1800 max_par => $CFG->{logview_max_par},
1049 tooltip => "<b>Server Log</b>. This text viewer contains all the messages sent by the server.", 1801 tooltip => "<b>Server Log</b>. This text viewer contains all recent messages sent by the server.",
1050 ; 1802 ;
1051 1803
1052 $BUTTONBAR = new CFClient::UI::HBox; 1804 $SETUP_DIALOG = new CFPlus::UI::Toplevel
1805 title => "Setup",
1806 name => "setup_dialog",
1807 x => 'center',
1808 y => 'center',
1809 z => 2,
1810 force_w => $::WIDTH * 0.6,
1811 force_h => $::HEIGHT * 0.6,
1812 has_close_button => 1,
1813 ;
1053 1814
1054 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Client Setup", other => client_setup, 1815 $METASERVER = metaserver_dialog;
1055 tooltip => "Toggles a dialog where you can configure various aspects of the client, such as graphics mode, performance, and audio options."); 1816
1056 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Server Setup", other => server_setup, 1817 $SETUP_DIALOG->add ($SETUP_NOTEBOOK = new CFPlus::UI::Notebook expand => 1, debug => 1,
1818 filter => new CFPlus::UI::ScrolledWindow expand => 1, scroll_y => 1);
1819
1820 $SETUP_NOTEBOOK->add (Server => $SETUP_SERVER = server_setup,
1057 tooltip => "Toggles a dialog where you can configure the server to play on, your username, password and other server-related options."); 1821 "Configure the server to play on, your username, password and other server-related options.");
1822 $SETUP_NOTEBOOK->add (Client => client_setup,
1823 "Configure various client-specific settings.");
1824 $SETUP_NOTEBOOK->add (Graphics => graphics_setup,
1825 "Configure the video mode, performance, fonts and other graphical aspects of the game.");
1826 $SETUP_NOTEBOOK->add (Audio => audio_setup,
1827 "Configure the use of audio, sound effects and background music.");
1828 $SETUP_NOTEBOOK->add (Keyboard => $SETUP_KEYBOARD = keyboard_setup,
1829 "Lets you define, edit and delete key bindings."
1830 . "There is a shortcut for making bindings: <b>Control-Insert</b> opens the binding editor "
1831 . "with nothing set and the recording started. After doing the actions you "
1832 . "want to record press <b>Insert</b> and you will be asked to press a key-combo. "
1833 . "After pressing the combo the binding will be saved automatically and the "
1834 . "binding editor closes");
1835 $SETUP_NOTEBOOK->add (Debug => debug_setup,
1836 "Some debuggin' options. Do not ask.");
1837
1838 $BUTTONBAR = new CFPlus::UI::Buttonbar x => 0, y => 0, z => 200; # put on top
1839
1840 $BUTTONBAR->add (new CFPlus::UI::Flopper text => "Setup", other => $SETUP_DIALOG,
1841 tooltip => "Toggles a dialog where you can configure all aspects of this client.");
1842
1058 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Message Window", other => message_window, 1843 $BUTTONBAR->add (new CFPlus::UI::Flopper text => "Message Window", other => $MESSAGE_WINDOW = message_window,
1059 tooltip => "Toggles the server message log, where the client collects <i>all</i> messages from the server."); 1844 tooltip => "Toggles the server message log, where the client collects <i>all</i> messages from the server.");
1060 1845
1061 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 1846 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
1062 1847
1063 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Stats Window", other => make_stats_window,
1064 tooltip => "Toggles the statistics window, where all your Stats and Resistances are being displayed at all times.");
1065 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Inventory", other => make_inventory_window, 1848 $BUTTONBAR->add (new CFPlus::UI::Flopper text => "Playerbook", other => player_window,
1066 tooltip => "Toggles the inventory window, where you can manage your loot (or treaures :)."); 1849 tooltip => "Toggles the player view, where you can manage Inventory, Spells, Skills and see your Stats.");
1067 1850
1068 $BUTTONBAR->add (new CFClient::UI::Button 1851 $BUTTONBAR->add (new CFPlus::UI::Button
1069 text => "Save Config", 1852 text => "Save Config",
1070 tooltip => "Saves the options chosen in the client setting, server settings and the window layout to be restored on later runs.", 1853 tooltip => "Saves the options chosen in the client setting, server settings and the window layout to be restored on later runs.",
1071 connect_activate => sub { 1854 on_activate => sub {
1072 $::CFG->{layout} = CFClient::UI::get_layout; 1855 $::CFG->{layout} = CFPlus::UI::get_layout;
1073 CFClient::write_cfg "$Crossfire::VARDIR/pclientrc"; 1856 CFPlus::write_cfg "$Crossfire::VARDIR/cfplusrc";
1074 status "Configuration Saved"; 1857 status "Configuration Saved";
1858 0
1075 }, 1859 },
1076 ); 1860 );
1077 1861
1078 $BUTTONBAR->add (new CFClient::UI::Flopper text => "Help!", other => make_help_window, 1862 $BUTTONBAR->add (new CFPlus::UI::Flopper text => "Help!", other => $HELP_WINDOW = help_window,
1079 tooltip => "View Documentation"); 1863 tooltip => "View Documentation");
1080 1864
1865
1081 $BUTTONBAR->add (new CFClient::UI::Button 1866 $BUTTONBAR->add (new CFPlus::UI::Button
1082 text => "Quit", 1867 text => "Quit",
1083 tooltip => "Terminates the program", 1868 tooltip => "Terminates the program",
1084 connect_activate => sub { 1869 on_activate => sub {
1085 if ($CONN) { 1870 if ($CONN) {
1086 open_quit_dialog; 1871 open_quit_dialog;
1087 } else { 1872 } else {
1088 exit; 1873 exit;
1089 } 1874 }
1875 0
1090 }, 1876 },
1091 ); 1877 );
1092 1878
1093 $BUTTONBAR->show; 1879 $BUTTONBAR->show;
1094 1880 $SETUP_DIALOG->show;
1095 $STATUSBOX->add ("Set video mode $WIDTH×$HEIGHT", timeout => 10, fg => [1, 1, 1, 0.5]);
1096
1097 # delay till geometry is constant
1098 $CFClient::UI::ROOT->on_post_alloc (startup => sub {
1099 $BUTTONBAR->{children}[1]->emit ("activate"); # pop up server setup
1100 my $widget = $GAUGES->{win};
1101 $widget->move (0, $HEIGHT - $widget->{h});#d# to in toplevel
1102 });
1103 force_refresh ();
1104 } 1881 }
1882
1883 $STATUSBOX->add ("Set video mode $WIDTH×$HEIGHT", timeout => 10, fg => [1, 1, 1, 0.5]);
1884}
1885
1886sub setup_build_button {
1887 my ($enabled) = @_;
1888 if ($enabled) {
1889 $BUILD_BUTTON->hide if $BUILD_BUTTON;
1890 $BUILD_BUTTON ||= new CFPlus::UI::Button
1891 text => "Build",
1892 tooltip => "Opens the ingame builder",
1893 on_activate => sub {
1894 if ($CONN) {
1895 $CONN->send_ext_req (builder_player_items => sub {
1896 open_ingame_editor ($_[0]) if exists $_[0]->{items};
1897 });
1898 }
1899 0
1900 };
1901 $BUTTONBAR->add ($BUILD_BUTTON);
1902 } else {
1903 $BUILD_BUTTON->hide if $BUILD_BUTTON;
1904 }
1905}
1906
1907sub open_ingame_editor {
1908 my ($msg) = @_;
1909
1910 my $win = new CFPlus::UI::Toplevel
1911 x => 0,
1912 y => 'center',
1913 z => 4,
1914 name => 'builder_window',
1915 force_w => int $WIDTH * 1/4,
1916 force_h => int $HEIGHT * 3/4,
1917 title => "In game builder",
1918 has_close_button => 1;
1919
1920 my $r = new CFPlus::UI::ScrolledWindow (
1921 expand => 1,
1922 scroll_y => 1
1923 );
1924 $r->add (my $vb = new CFPlus::UI::VBox);
1925 $win->add ($r);
1926
1927
1928 $vb->add (
1929 new CFPlus::UI::Button
1930 text => "Disable build mode",
1931 on_activate => sub { $::IN_BUILD_MODE = undef }
1932 );
1933 $vb->add (
1934 new CFPlus::UI::Button
1935 text => "ERASE",
1936 on_activate => sub { $::IN_BUILD_MODE = { do_erase => 1 } }
1937 );
1938
1939 for my $itemarchname (
1940 sort {
1941 $msg->{items}->{$a}->{build_arch_name}
1942 cmp $msg->{items}->{$b}->{build_arch_name}
1943 } keys %{$msg->{items}}
1944 ) {
1945 my $info = $msg->{items}->{$itemarchname};
1946 $vb->add (
1947 new CFPlus::UI::Button text => $info->{build_arch_name},
1948 on_activate => sub {
1949 $::IN_BUILD_MODE = { item => $itemarchname, info => $info };
1950
1951 if (grep { $msg->{items}->{$itemarchname}->{$_} } qw/has_connection has_name has_text/) {
1952 build_mode_query_arch_info ();
1953 }
1954 }
1955 );
1956 }
1957
1958 $win->show;
1959}
1960
1961sub build_mode_query_arch_info {
1962 my ($iteminfo) = $::IN_BUILD_MODE;
1963 my $itemarchname = $iteminfo->{item};
1964 my $info = $iteminfo->{info};
1965
1966 my $dialog = new CFPlus::UI::Toplevel
1967 x => "center",
1968 y => "center",
1969 z => 50,
1970 force_w => int $WIDTH * 1/2,
1971 title => "Enter information for placement of '$itemarchname'",
1972 has_close_button => 1;
1973
1974 $dialog->add (my $vb = new CFPlus::UI::VBox expand => 1);
1975
1976 $vb->add (my $table = new CFPlus::UI::Table expand => 1);
1977 my $row = 0;
1978 if ($info->{has_name}) {
1979 $table->add (0, $row, new CFPlus::UI::Label text => "Name:");
1980 $table->add (1, $row++, new CFPlus::UI::Entry expand => 1, on_changed => sub { $::IN_BUILD_MODE->{name} = $_[1]; 0 });
1981 }
1982 if ($info->{has_text}) {
1983 $table->add (0, $row, new CFPlus::UI::Label text => "Text:");
1984 $table->add (1, $row++, new CFPlus::UI::Entry expand => 1, on_changed => sub { $::IN_BUILD_MODE->{text} = $_[1]; 0 });
1985 }
1986 if ($info->{has_connection}) {
1987 $table->add (0, $row, new CFPlus::UI::Label text => "Connection ID:");
1988 $table->add (1, $row++,
1989 new CFPlus::UI::Entry
1990 expand => 1,
1991 on_changed => sub { $::IN_BUILD_MODE->{connection} = $_[1]; 0 },
1992 tooltip => "Enter the connection ID here. The connection ID connects actors like a lever to a gate or a magic ear to a gate"
1993 );
1994 }
1995
1996 $vb->add (my $hb = new CFPlus::UI::HBox expand => 1);
1997 $hb->add (new CFPlus::UI::Button
1998 text => "Close",
1999 expand => 1,
2000 on_activate => sub { $dialog->hide; 0 },
2001 );
2002 $dialog->show;
1105} 2003}
1106 2004
1107sub video_shutdown { 2005sub video_shutdown {
2006 CFPlus::OpenGL::shutdown;
2007
1108 undef $SDL_ACTIVE; 2008 undef $SDL_ACTIVE;
1109} 2009}
1110
1111my @bgmusic = qw(game1.ogg game2.ogg game3.ogg game5.ogg game6.ogg ross1.ogg ross2.ogg ross3.ogg ross4.ogg ross5.ogg); #d#
1112my $bgmusic;#TODO#hack#d#
1113 2010
1114sub audio_channel_finished { 2011sub audio_channel_finished {
1115 my ($channel) = @_; 2012 my ($channel) = @_;
1116 2013
1117 #warn "channel $channel finished\n";#d# 2014 #warn "channel $channel finished\n";#d#
1118} 2015}
1119 2016
2017sub audio_music_set {
2018 my ($songs) = @_;
2019
2020 my $count = @$songs;
2021 my @meta;
2022
2023 for my $name (@$songs) {
2024 CFPlus::DB::get resmap => $name, sub {
2025 my ($data) = @_;
2026
2027 if ($data) {
2028 $data = JSON::XS->new->utf8->decode ($data);
2029 $data->{path} = CFPlus::DB::path_of $name;
2030 push @meta, $data;
2031 }
2032
2033 unless (--$count) {
2034 if (@meta) {
2035 @MUSIC_WANT = @meta;
2036 &audio_music_changed ();
2037 }
2038 }
2039 };
2040 }
2041}
2042
2043sub audio_music_changed {
2044 return unless $CFG->{bgm_enable};
2045
2046 # default MUSIC_WANT == MUSIC_DEFAULT
2047 @MUSIC_WANT = { path => CFPlus::find_rcfile "music/$MUSIC_DEFAULT" } unless @MUSIC_WANT;
2048
2049 # if the currently playing song is acceptable, let it continue
2050 return if $MUSIC_PLAYING
2051 && grep $MUSIC_PLAYING->{path} eq $_->{path}, @MUSIC_WANT;
2052
2053 if ($MUSIC_PLAYING) {
2054 CFPlus::MixMusic::fade_out 1000;
2055 } else {
2056 my $music = $MUSIC_WANT [rand @MUSIC_WANT];
2057
2058 $MUSIC_PLAYING = $music;
2059
2060 $MUSIC_PLAYER = new_from_file CFPlus::MixMusic $music->{path};
2061 $MUSIC_PLAYER->play (0);
2062 }
2063}
2064
1120sub audio_music_finished { 2065sub audio_music_finished {
1121 return unless $CFG->{bgm_enable}; 2066 $MUSIC_PLAYING = undef;
2067 undef $MUSIC_PLAYER;
1122 2068
1123 # TODO: hack, do play loop and mood music 2069 audio_music_changed;
1124 $bgmusic = new_from_file CFClient::MixMusic CFClient::find_rcfile "music/$bgmusic[0]";
1125 $bgmusic->play (0);
1126
1127 push @bgmusic, shift @bgmusic;
1128} 2070}
1129 2071
1130sub audio_init { 2072sub audio_init {
1131 if ($CFG->{audio_enable}) { 2073 if ($CFG->{audio_enable}) {
1132 if (open my $fh, "<", CFClient::find_rcfile "sounds/config") { 2074 if (open my $fh, "<", CFPlus::find_rcfile "sounds/config") {
1133 $SDL_MIXER = !CFClient::Mix_OpenAudio; 2075 $SDL_MIXER = !CFPlus::Mix_OpenAudio;
1134 2076
1135 unless ($SDL_MIXER) { 2077 unless ($SDL_MIXER) {
1136 status "Unable to open sound device: there will be no sound"; 2078 status "Unable to open sound device: there will be no sound";
1137 return; 2079 return;
1138 } 2080 }
1139 2081
1140 CFClient::Mix_AllocateChannels 8; 2082 CFPlus::Mix_AllocateChannels 8;
1141 CFClient::MixMusic::volume $CFG->{bgm_volume} * 128; 2083 CFPlus::MixMusic::volume $CFG->{bgm_volume} * 128;
1142 2084
1143 audio_music_finished; 2085 audio_music_finished;
1144 2086
2087 local $_;
1145 while (<$fh>) { 2088 while (<$fh>) {
1146 next if /^\s*#/; 2089 next if /^\s*#/;
1147 next if /^\s*$/; 2090 next if /^\s*$/;
1148 2091
1149 my ($file, $volume, $event) = split /\s+/, $_, 3; 2092 my ($file, $volume, $event) = split /\s+/, $_, 3;
1150 2093
1151 push @SOUNDS, "$volume,$file"; 2094 push @SOUNDS, "$volume,$file";
1152 2095
1153 $AUDIO_CHUNKS{"$volume,$file"} ||= do { 2096 $AUDIO_CHUNKS{"$volume,$file"} ||= do {
1154 my $chunk = new_from_file CFClient::MixChunk CFClient::find_rcfile "sounds/$file"; 2097 my $chunk = new_from_file CFPlus::MixChunk CFPlus::find_rcfile "sounds/$file";
1155 $chunk->volume ($volume * 128 / 100); 2098 $chunk->volume ($volume * 128 / 100);
1156 $chunk 2099 $chunk
1157 }; 2100 };
1158 } 2101 }
1159 } else { 2102 } else {
1161 } 2104 }
1162 } 2105 }
1163} 2106}
1164 2107
1165sub audio_shutdown { 2108sub audio_shutdown {
1166 CFClient::Mix_CloseAudio if $SDL_MIXER; 2109 CFPlus::Mix_CloseAudio if $SDL_MIXER;
1167 undef $SDL_MIXER; 2110 undef $SDL_MIXER;
1168 @SOUNDS = (); 2111 @SOUNDS = ();
1169 %AUDIO_CHUNKS = (); 2112 %AUDIO_CHUNKS = ();
1170} 2113}
1171 2114
1176 2119
1177my %demo;#d# 2120my %demo;#d#
1178 2121
1179sub force_refresh { 2122sub force_refresh {
1180 $fps = $fps * 0.95 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.05; 2123 $fps = $fps * 0.95 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.05;
1181 debug sprintf "%3.2f", $fps; 2124 debug sprintf "%3.2f", $fps if $ENV{CFPLUS_DEBUG} & 4;
1182 2125
1183 $CFClient::UI::ROOT->draw; 2126 $CFPlus::UI::ROOT->draw;
1184 2127
1185 $WANT_REFRESH = 0; 2128 $WANT_REFRESH = 0;
1186 $CAN_REFRESH = 0; 2129 $CAN_REFRESH = 0;
1187 $LAST_REFRESH = $NOW; 2130 $LAST_REFRESH = $NOW;
1188 2131
11890 && do {
1190 # some weird model-drawing code, just a joke right now
1191 use CFClient::OpenGL;
1192
1193 $demo{t}{eye_auv} ||= new_from_file CFClient::Texture "eye2.png" or die;
1194 $demo{t}{body_auv} ||= new_from_file CFClient::Texture "body_auv3.png" or die;
1195 $demo{r} ||= do {
1196 my $mod = Compress::LZF::sthaw do { local $/; open my $fh, "<:raw:perlio", "dread.lz3"; <$fh> };
1197 $mod->{v} = pack "f*", @{$mod->{v}};
1198 $_ = [scalar @$_, pack "S!*", @$_]
1199 for values %{$mod->{g}};
1200 $mod
1201 };
1202
1203 my $r = $demo{r} or die;
1204
1205 glDepthMask 1;
1206 glClear GL_DEPTH_BUFFER_BIT;
1207 glEnable GL_TEXTURE_2D;
1208 glEnable GL_DEPTH_TEST;
1209 glEnable GL_CULL_FACE;
1210 glShadeModel $::FAST ? GL_FLAT : GL_SMOOTH;
1211
1212 glMatrixMode GL_PROJECTION;
1213 glLoadIdentity;
1214 glFrustum -1 * ($::WIDTH / $::HEIGHT), 1 * ($::WIDTH / $::HEIGHT), 1, -1, 1, 10000;
1215 #glOrtho 0, $::WIDTH, 0, $::HEIGHT, -10000, 10000;
1216 glMatrixMode GL_MODELVIEW;
1217 glLoadIdentity;
1218
1219 glPushMatrix;
1220 glTranslate 0, 0, -800;
1221 glScale 1, -1, 1;
1222 glRotate $NOW * 1000 % 36000 / 5, 0, 1, 0;
1223 glRotate $NOW * 1000 % 36000 / 6, 1, 0, 0;
1224 glRotate $NOW * 1000 % 36000 / 7, 0, 0, 1;
1225 glScale 50, 50, 50;
1226
1227 glInterleavedArrays GL_T2F_N3F_V3F, 0, $r->{v};
1228 while (my ($k, $v) = each %{$r->{g}}) {
1229 glBindTexture GL_TEXTURE_2D, ($demo{t}{$k}{name} or die);
1230 glDrawElements GL_TRIANGLES, $v->[0], GL_UNSIGNED_SHORT, $v->[1];
1231 }
1232
1233 glPopMatrix;
1234
1235 glShadeModel GL_FLAT;
1236 glDisable GL_DEPTH_TEST;
1237 glDisable GL_TEXTURE_2D;
1238 glDepthMask 0;
1239
1240 $WANT_REFRESH++;
1241};
1242
1243 CFClient::SDL_GL_SwapBuffers; 2132 CFPlus::SDL_GL_SwapBuffers;
1244} 2133}
1245 2134
1246my $refresh_watcher = Event->timer (after => 0, hard => 1, interval => 1 / $MAX_FPS, cb => sub { 2135my $refresh_watcher = Event->timer (after => 0, hard => 0, interval => 1 / $MAX_FPS, cb => sub {
1247 $NOW = time; 2136 $NOW = time;
1248 2137
1249 ($SDL_CB{$_->{type}} || sub { warn "unhandled event $_->{type}" })->($_) 2138 ($SDL_CB{$_->{type}} || sub { warn "unhandled event $_->{type}" })->($_)
1250 for CFClient::SDL_PollEvent; 2139 for CFPlus::SDL_PollEvent;
1251 2140
1252 if (%animate_object) { 2141 if (%animate_object) {
1253 $_->animate ($LAST_REFRESH - $NOW) for values %animate_object; 2142 $_->animate ($LAST_REFRESH - $NOW) for values %animate_object;
1254 $WANT_REFRESH++; 2143 $WANT_REFRESH++;
1255 } 2144 }
1279 $CONN->face_prefetch 2168 $CONN->face_prefetch
1280 if $CONN; 2169 if $CONN;
1281}); 2170});
1282 2171
1283%SDL_CB = ( 2172%SDL_CB = (
1284 CFClient::SDL_QUIT => sub { 2173 CFPlus::SDL_QUIT => sub {
1285 Event::unloop -1; 2174 exit;
1286 }, 2175 },
1287 CFClient::SDL_VIDEORESIZE => sub { 2176 CFPlus::SDL_VIDEORESIZE => sub {
1288 }, 2177 },
1289 CFClient::SDL_VIDEOEXPOSE => sub { 2178 CFPlus::SDL_VIDEOEXPOSE => sub {
1290 CFClient::UI::full_refresh; 2179 CFPlus::UI::full_refresh;
1291 }, 2180 },
1292 CFClient::SDL_ACTIVEEVENT => sub { 2181 CFPlus::SDL_ACTIVEEVENT => sub {
1293# printf "active %x %x\n", $SDL_EV->active_gain, $SDL_EV->active_state;#d# 2182# not useful, as APPACTIVE include sonly iconified state, not unmapped
2183# printf "active %x %x\n", $_[0]{gain}, $_[0]{state};#d#
2184# printf "A\n" if $_[0]{state} & CFPlus::SDL_APPACTIVE;
2185# printf "K\n" if $_[0]{state} & CFPlus::SDL_APPINPUTFOCUS;
2186# printf "M\n" if $_[0]{state} & CFPlus::SDL_APPMOUSEFOCUS;
1294 }, 2187 },
1295 CFClient::SDL_KEYDOWN => sub { 2188 CFPlus::SDL_KEYDOWN => sub {
1296 if ($_[0]{mod} & CFClient::KMOD_ALT && $_[0]{sym} == 13) { 2189 if ($_[0]{mod} & CFPlus::KMOD_ALT && $_[0]{sym} == 13) {
1297 # alt-enter 2190 # alt-enter
2191 $FULLSCREEN_ENABLE->toggle;
1298 video_shutdown; 2192 video_shutdown;
1299 $CFG->{fullscreen} = !$CFG->{fullscreen};
1300 video_init; 2193 video_init;
1301 } else { 2194 } else {
1302 CFClient::UI::feed_sdl_key_down_event ($_[0]); 2195 CFPlus::UI::feed_sdl_key_down_event ($_[0]);
1303 } 2196 }
1304 }, 2197 },
1305 CFClient::SDL_KEYUP => \&CFClient::UI::feed_sdl_key_up_event, 2198 CFPlus::SDL_KEYUP => \&CFPlus::UI::feed_sdl_key_up_event,
1306 CFClient::SDL_MOUSEMOTION => \&CFClient::UI::feed_sdl_motion_event, 2199 CFPlus::SDL_MOUSEMOTION => \&CFPlus::UI::feed_sdl_motion_event,
1307 CFClient::SDL_MOUSEBUTTONDOWN => \&CFClient::UI::feed_sdl_button_down_event, 2200 CFPlus::SDL_MOUSEBUTTONDOWN => \&CFPlus::UI::feed_sdl_button_down_event,
1308 CFClient::SDL_MOUSEBUTTONUP => \&CFClient::UI::feed_sdl_button_up_event, 2201 CFPlus::SDL_MOUSEBUTTONUP => \&CFPlus::UI::feed_sdl_button_up_event,
1309 CFClient::SDL_USEREVENT => sub { 2202 CFPlus::SDL_USEREVENT => sub {
1310 if ($_[0]{code} == 1) { 2203 if ($_[0]{code} == 1) {
1311 audio_channel_finished $_[0]{data1}; 2204 audio_channel_finished $_[0]{data1};
1312 } elsif ($_[0]{code} == 0) { 2205 } elsif ($_[0]{code} == 0) {
1313 audio_music_finished; 2206 audio_music_finished;
1314 } 2207 }
1318############################################################################# 2211#############################################################################
1319 2212
1320$SIG{INT} = $SIG{TERM} = sub { exit }; 2213$SIG{INT} = $SIG{TERM} = sub { exit };
1321 2214
1322{ 2215{
1323 local $SIG{__DIE__} = sub { CFClient::fatal $_[0] };
1324
1325 CFClient::read_cfg "$Crossfire::VARDIR/pclientrc"; 2216 CFPlus::read_cfg "$Crossfire::VARDIR/cfplusrc";
2217 CFPlus::DB::Server::run;
2218
1326 CFClient::UI::set_layout ($::CFG->{layout}); 2219 CFPlus::UI::set_layout ($::CFG->{layout});
1327 2220
1328 my %DEF_CFG = ( 2221 my %DEF_CFG = (
1329 sdl_mode => 0, 2222 sdl_mode => 0,
1330 width => 640, 2223 width => 640,
1331 height => 480, 2224 height => 480,
1332 fullscreen => 0, 2225 fullscreen => 0,
1333 fast => 0, 2226 fast => 0,
1334 map_scale => 1, 2227 map_scale => 1,
1335 fow_enable => 1, 2228 fow_enable => 1,
1336 fow_intensity => 0.45, 2229 fow_intensity => 0.45,
1337 fow_smooth => 0, 2230 fow_smooth => 0,
2231 map_smoothing => 1,
1338 gui_fontsize => 1, 2232 gui_fontsize => 1,
1339 log_fontsize => 1, 2233 log_fontsize => 0.7,
1340 gauge_fontsize=> 1, 2234 gauge_fontsize => 1,
1341 gauge_size => 0.35, 2235 gauge_size => 0.35,
1342 stat_fontsize => 1, 2236 stat_fontsize => 0.7,
1343 mapsize => 100, 2237 mapsize => 100,
1344 host => "crossfire.schmorp.de",
1345 say_command => 'say', 2238 say_command => 'chat',
1346 audio_enable => 1, 2239 audio_enable => 1,
1347 bgm_enable => 1, 2240 bgm_enable => 1,
1348 bgm_volume => 0.25, 2241 bgm_volume => 0.25,
1349 face_prefetch => 0, 2242 face_prefetch => 0,
1350 output_sync => 1, 2243 output_sync => 1,
1351 output_count => 1, 2244 output_count => 1,
2245 output_rate => "",
2246 pickup => 0,
2247 inv_sort => "mtime",
2248 default => "profile", # default profile
2249 show_tips => 1,
2250 logview_max_par => 1000,
2251 );
1352 ); 2252
1353
1354 while (my ($k, $v) = each %DEF_CFG) { 2253 while (my ($k, $v) = each %DEF_CFG) {
1355 $CFG->{$k} = $v unless exists $CFG->{$k}; 2254 $CFG->{$k} = $v unless exists $CFG->{$k};
1356 } 2255 }
1357 2256
2257 $CFG->{profile}{default}{host} ||= "crossfire.schmorp.de";
2258 $PROFILE = $CFG->{profile}{default};
2259
2260 # convert old bindings (only default profile matters)
2261 if (my $bindings = delete $PROFILE->{bindings}) {
2262 while (my ($mod, $syms) = each %$bindings) {
2263 while (my ($sym, $cmds) = each %$syms) {
2264 push @{ $PROFILE->{macro} }, {
2265 accelkey => [$mod*1, $sym*1],
2266 action => $cmds,
2267 };
2268 }
2269 }
2270 }
2271
1358 sdl_init; 2272 sdl_init;
1359 2273
1360 @SDL_MODES = reverse 2274 @SDL_MODES = reverse
1361 grep $_->[0] >= 640 && $_->[1] >= 480, 2275 grep $_->[0] >= 640 && $_->[1] >= 480,
1362 CFClient::SDL_ListModes; 2276 CFPlus::SDL_ListModes;
1363 2277
1364 @SDL_MODES or CFClient::fatal "Unable to find a usable video mode\n(hardware accelerated opengl fullscreen)"; 2278 @SDL_MODES or CFPlus::fatal "Unable to find a usable video mode\n(hardware accelerated opengl fullscreen)";
1365 2279
1366 $CFG->{sdl_mode} = 0 if $CFG->{sdl_mode} > @SDL_MODES; 2280 $CFG->{sdl_mode} = 0 if $CFG->{sdl_mode} > @SDL_MODES;
1367 2281
1368 { 2282 {
1369 my @fonts = map CFClient::find_rcfile "fonts/$_", qw( 2283 my @fonts = map CFPlus::find_rcfile "fonts/$_", qw(
1370 DejaVuSans.ttf 2284 DejaVuSans.ttf
1371 DejaVuSansMono.ttf 2285 DejaVuSansMono.ttf
1372 DejaVuSans-Bold.ttf 2286 DejaVuSans-Bold.ttf
1373 DejaVuSansMono-Bold.ttf 2287 DejaVuSansMono-Bold.ttf
1374 DejaVuSans-Oblique.ttf 2288 DejaVuSans-Oblique.ttf
1375 DejaVuSansMono-Oblique.ttf 2289 DejaVuSansMono-Oblique.ttf
1376 DejaVuSans-BoldOblique.ttf 2290 DejaVuSans-BoldOblique.ttf
1377 DejaVuSansMono-BoldOblique.ttf 2291 DejaVuSansMono-BoldOblique.ttf
1378 ); 2292 );
1379 2293
1380 CFClient::add_font $_ for @fonts; 2294 CFPlus::add_font $_ for @fonts;
1381 2295
1382 CFClient::pango_init; 2296 CFPlus::pango_init;
1383 2297
1384 $FONT_PROP = new_from_file CFClient::Font $fonts[0]; 2298 $FONT_PROP = new_from_file CFPlus::Font $fonts[0];
1385 $FONT_FIXED = new_from_file CFClient::Font $fonts[1]; 2299 $FONT_FIXED = new_from_file CFPlus::Font $fonts[1];
1386 2300
1387 $FONT_PROP->make_default; 2301 $FONT_PROP->make_default;
1388 } 2302 }
1389 2303
1390# compare mono (ft) vs. rgba (cairo) 2304# compare mono (ft) vs. rgba (cairo)
1391# ft - 1.8s, cairo 3s, even in alpha-only mode 2305# ft - 1.8s, cairo 3s, even in alpha-only mode
1392# for my $rgba (0..1) { 2306# for my $rgba (0..1) {
1393# my $t1 = Time::HiRes::time; 2307# my $t1 = Time::HiRes::time;
1394# for (1..1000) { 2308# for (1..1000) {
1395# my $layout = CFClient::Layout->new ($rgba); 2309# my $layout = CFPlus::Layout->new ($rgba);
1396# $layout->set_text ("hallo" x 100); 2310# $layout->set_text ("hallo" x 100);
1397# $layout->render; 2311# $layout->render;
1398# } 2312# }
1399# my $t2 = Time::HiRes::time; 2313# my $t2 = Time::HiRes::time;
1400# warn $t2-$t1; 2314# warn $t2-$t1;
1401# } 2315# }
1402 2316
2317 $startup_done->();
2318
1403 video_init; 2319 video_init;
1404 audio_init; 2320 audio_init;
1405} 2321}
1406 2322
2323show_tip_of_the_day if $CFG->{show_tips};
2324
1407Event::loop; 2325Event::loop;
2326#CFPlus::SDL_Quit;
2327#CFPlus::_exit 0;
1408 2328
1409END { CFClient::SDL_Quit } 2329END {
2330 CFPlus::SDL_Quit;
2331 CFPlus::DB::Server::stop;
2332}
1410 2333
1411=head1 NAME 2334=head1 NAME
1412 2335
1413pclient - A Crossfire+ and Crossfire game client 2336cfplus - A Crossfire+ and Crossfire game client
1414 2337
1415=head1 SYNOPSIS 2338=head1 SYNOPSIS
1416 2339
1417Just run it - no commandline arguments are supported. 2340Just run it - no commandline arguments are supported.
1418 2341
1419=head1 USAGE 2342=head1 USAGE
1420 2343
1421Pclient utilises OpenGL for all UI elements and the game. It is supposed to be used 2344cfplus utilises OpenGL for all UI elements and the game. It is supposed to be used
1422fullscreen and interactively. 2345fullscreen and interactively.
1423 2346
2347=head1 DEBUGGING
2348
2349
2350CFPLUS_DEBUG - environment variable
2351
2352 1 draw borders around widgets
2353 2 add low-level widget info to tooltips
2354 4 show fps
2355 8 suppress tooltips
2356
1424=head1 AUTHOR 2357=head1 AUTHOR
1425 2358
1426Marc Lehmann <crossfire@schmorp.de>, Robin Redeker <elmex@ta-sa.org> 2359Marc Lehmann <crossfire@schmorp.de>, Robin Redeker <elmex@ta-sa.org>
1427 2360
1428 2361

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines