ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/bin/cfplus
Revision: 1.45
Committed: Fri Jun 2 16:52:49 2006 UTC (17 years, 11 months ago) by elmex
Branch: MAIN
Changes since 1.44: +24 -13 lines
Log Message:
pickup layout chnged again

File Contents

# User Rev Content
1 root 1.1 #!/opt/bin/perl
2    
3     use strict;
4     use utf8;
5    
6     # do things only needed for single-binary version (par)
7     BEGIN {
8     if (%PAR::LibCache) {
9     @INC = grep ref, @INC; # weed out all paths except pars loader refs
10    
11     while (my ($filename, $zip) = each %PAR::LibCache) {
12     for ($zip->memberNames) {
13     next unless /^\/root\/(.*)/;
14     $zip->extractMember ($_, "$ENV{PAR_TEMP}/$1")
15     unless -e "$ENV{PAR_TEMP}/$1";
16     }
17     }
18    
19     # TODO: pango-rc file, anybody?
20    
21     unshift @INC, $ENV{PAR_TEMP};
22     }
23     }
24    
25     # need to do it again because that pile of garbage called PAR nukes it before main
26     unshift @INC, $ENV{PAR_TEMP}
27     if %PAR::LibCache;
28    
29     use Time::HiRes 'time';
30     use Pod::POM;
31     use Event;
32    
33     use Crossfire;
34 root 1.12 use Crossfire::Protocol::Constants;
35 root 1.1
36     use Compress::LZF;
37    
38     use CFClient;
39 root 1.10 use CFClient::OpenGL ();
40 root 1.11 use CFClient::Protocol;
41 root 1.1 use CFClient::UI;
42     use CFClient::MapWidget;
43    
44     $Event::DIED = sub {
45     # TODO: display dialog box or so
46     CFClient::error $_[1];
47     };
48    
49     #$SIG{__WARN__} = sub { Carp::cluck $_[0] };#d#
50    
51     our $VERSION = '0.1';
52    
53     my $MAX_FPS = 60;
54     my $MIN_FPS = 5; # unused as of yet
55    
56     our $META_SERVER = "crossfire.real-time.com:13326";
57    
58     our $LAST_REFRESH;
59     our $NOW;
60    
61     our $CFG;
62     our $CONN;
63     our $FAST; # fast, low-quality mode, possibly useful for software-rendering
64    
65     our $WANT_REFRESH;
66     our $CAN_REFRESH;
67    
68     our @SDL_MODES;
69     our $WIDTH;
70     our $HEIGHT;
71     our $FULLSCREEN;
72     our $FONTSIZE;
73    
74     our $FONT_PROP;
75     our $FONT_FIXED;
76    
77     our $MAP;
78     our $MAPMAP;
79     our $MAPWIDGET;
80     our $BUTTONBAR;
81     our $LOGVIEW;
82     our $CONSOLE;
83     our $METASERVER;
84     our $LOGIN_BUTTON;
85     our $QUIT_DIALOG;
86 root 1.40 our $HOST_ENTRY;
87 root 1.23 our $SERVER_SETUP;
88 root 1.1
89     our $FLOORBOX;
90     our $GAUGES;
91     our $STATWIDS;
92    
93     our $SDL_ACTIVE;
94     our %SDL_CB;
95    
96     our $SDL_MIXER;
97     our @SOUNDS; # event => file mapping
98     our %AUDIO_CHUNKS; # audio files
99    
100     our $ALT_ENTER_MESSAGE;
101     our $STATUSBOX;
102     our $DEBUG_STATUS;
103    
104 root 1.23 our $INV_WINDOW;
105 root 1.1 our $INV;
106     our $INVR;
107 elmex 1.27 our $INV_RIGHT_HB;
108 root 1.1
109 elmex 1.24 our $BIND_WINDOW;
110 elmex 1.34 our $BIND_EDITOR;
111 elmex 1.24
112 elmex 1.38 our $SPELL_LIST;
113 elmex 1.43 our $PICKUP_CFG;
114 elmex 1.38
115 root 1.1 sub status {
116     $STATUSBOX->add (CFClient::UI::Label::escape $_[0], pri => -10, group => "status", timeout => 10, fg => [1, 1, 0, 1]);
117     }
118    
119     sub debug {
120     $DEBUG_STATUS->set_text ($_[0]);
121     }
122    
123     sub start_game {
124     status "logging in...";
125    
126 root 1.23 $LOGIN_BUTTON->set_text ("Logout");
127     $SERVER_SETUP->hide;
128    
129 root 1.1 my $mapsize = List::Util::min 32, List::Util::max 11, int $WIDTH * $CFG->{mapsize} * 0.01 / 32;
130    
131 root 1.11 my ($host, $port) = split /:/, $CFG->{host};
132    
133 root 1.1 $MAP = new CFClient::Map $mapsize, $mapsize;
134    
135     $CONN = eval {
136 root 1.11 new CFClient::Protocol
137 root 1.1 host => $host,
138     port => $port || 13327,
139     user => $CFG->{user},
140     pass => $CFG->{password},
141     mapw => $mapsize,
142     maph => $mapsize,
143 root 1.11
144     map_widget => $MAPWIDGET,
145     logview => $LOGVIEW,
146     statusbox => $STATUSBOX,
147     map => $MAP,
148     mapmap => $MAPMAP,
149    
150     sound_play => sub {
151     my ($x, $y, $soundnum, $type) = @_;
152    
153     $SDL_MIXER
154     or return;
155    
156     my $chunk = $AUDIO_CHUNKS{$SOUNDS[$soundnum]}
157     or return;
158    
159     $chunk->play;
160     },
161 root 1.1 };
162    
163     if ($CONN) {
164     CFClient::lowdelay fileno $CONN->{fh};
165    
166     status "login successful";
167     } else {
168     status "unable to connect";
169     stop_game();
170     }
171     }
172    
173     sub stop_game {
174 root 1.23 $LOGIN_BUTTON->set_text ("Login");
175     $SERVER_SETUP->show;
176     $INV_WINDOW->hide;
177     $LOGVIEW->hide;
178    
179 root 1.1 return unless $CONN;
180    
181     status "connection closed";
182 root 1.23
183 root 1.1 $CONN->destroy;
184     $CONN = 0; # false, does not autovivify
185     }
186    
187     sub client_setup {
188     my $dialog = new CFClient::UI::FancyFrame
189 root 1.30 x => 1,
190     y => $HEIGHT * (1/8),
191     name => "client_setup",
192 root 1.1 title => "Client Setup",
193     child => (my $vbox = new CFClient::UI::VBox);
194 root 1.30
195 root 1.1 $vbox->add (my $table = new CFClient::UI::Table expand => 1, col_expand => [0, 1]);
196    
197     $table->add (0, 0, new CFClient::UI::Label valign => 0, align => 1, text => "Video Mode");
198     $table->add (1, 0, my $hbox = new CFClient::UI::HBox);
199    
200 root 1.31 $hbox->add (my $mode_slider = new CFClient::UI::Slider force_w => $WIDTH * 0.1, expand => 1, range => [$CFG->{sdl_mode}, 0, $#SDL_MODES, 0, 1]);
201 root 1.1 $hbox->add (my $mode_label = new CFClient::UI::Label align => 0, valign => 0, height => 0.8, template => "9999x9999");
202    
203     $mode_slider->connect (changed => sub {
204     my ($self, $value) = @_;
205    
206     $CFG->{sdl_mode} = $self->{range}[0] = $value = int $value;
207     $mode_label->set_text (sprintf "%dx%d", @{$SDL_MODES[$value]});
208     });
209     $mode_slider->emit (changed => $mode_slider->{range}[0]);
210    
211     my $row = 1;
212    
213     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fullscreen");
214     $table->add (1, $row++, new CFClient::UI::CheckBox
215     state => $CFG->{fullscreen},
216     tooltip => "Bring the client into fullscreen mode.",
217 root 1.18 on_changed => sub {
218 root 1.1 my ($self, $value) = @_;
219     $CFG->{fullscreen} = $value;
220     }
221     );
222    
223     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fast & Ugly");
224     $table->add (1, $row++, new CFClient::UI::CheckBox
225     state => $CFG->{fast},
226     tooltip => "Lower the visual quality considerably to speed up rendering.",
227 root 1.18 on_changed => sub {
228 root 1.1 my ($self, $value) = @_;
229     $CFG->{fast} = $value;
230     }
231     );
232    
233     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Map Scale");
234     $table->add (1, $row++, new CFClient::UI::Slider
235     range => [(log $CFG->{map_scale}) / (log 2), -3, 1, 0, 1],
236     tooltip => "Enlarge or shrink the displayed map. Changes are instant.",
237 root 1.18 on_changed => sub {
238 root 1.1 my ($self, $value) = @_;
239     $CFG->{map_scale} = 2 ** $value;
240     }
241     );
242    
243     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Fog of War");
244     $table->add (1, $row++, new CFClient::UI::CheckBox
245     state => $CFG->{fow_enable},
246     tooltip => "<b>Fog-of-War</b> marks areas that cannot be seen by the player. Changes are instant.",
247 root 1.18 on_changed => sub {
248 root 1.1 my ($self, $value) = @_;
249     $CFG->{fow_enable} = $value;
250     }
251     );
252    
253     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "FoW Intensity");
254     $table->add (1, $row++, new CFClient::UI::Slider
255     range => [$CFG->{fow_intensity}, 0, 1, 0, 1 / 256],
256     tooltip => "<b>Fog of War Lightness.</b> The higher the intensity, the lighter the Fog-of-War color. Changes are instant.",
257 root 1.18 on_changed => sub {
258 root 1.1 my ($self, $value) = @_;
259     $CFG->{fow_intensity} = $value;
260     }
261     );
262    
263     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "FoW Smooth");
264     $table->add (1, $row++, new CFClient::UI::CheckBox
265     state => $CFG->{fow_smooth},
266     tooltip => "Smooth the Fog-of-War a bit to make it more realistic. Changes are instant.",
267 root 1.18 on_changed => sub {
268 root 1.1 my ($self, $value) = @_;
269     $CFG->{fow_smooth} = $value;
270 root 1.15 status "Fog of War smoothing requires OpenGL 1.2 or higher" if $CFClient::OpenGL::GL_VERSION < 1.2;
271 root 1.1 }
272     );
273    
274     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "GUI Fontsize");
275     $table->add (1, $row++, new CFClient::UI::Slider
276     range => [$CFG->{gui_fontsize}, 0.5, 2, 0, 0.1],
277     tooltip => "The base font size used by most GUI elements that do not have their own setting.",
278 root 1.18 on_changed => sub { $CFG->{gui_fontsize} = $_[1] },
279 root 1.1 );
280    
281     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Message Fontsize");
282     $table->add (1, $row++, new CFClient::UI::Slider
283     range => [$CFG->{log_fontsize}, 0.5, 2, 0, 0.1],
284     tooltip => "The font size used by the <b>message/server log</b> window only. Changes are instant.",
285 root 1.18 on_changed => sub { $LOGVIEW->set_fontsize ($CFG->{log_fontsize} = $_[1]) },
286 root 1.1 );
287    
288     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Stats Fontsize");
289    
290     $table->add (1, $row++, new CFClient::UI::Slider
291     range => [$CFG->{stat_fontsize}, 0.5, 2, 0, 0.1],
292     tooltip => "The font size used by the <b>statistics window</b> only. Changes are instant.",
293 root 1.18 on_changed => sub {
294 root 1.1 $CFG->{stat_fontsize} = $_[1];
295     &set_stats_window_fontsize;
296     }
297     );
298    
299     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Gauge fontsize");
300     $table->add (1, $row++, new CFClient::UI::Slider
301     range => [$CFG->{gauge_fontsize}, 0.5, 2, 0, 0.1],
302     tooltip => "Adjusts the fontsize of the gauges at the bottom right. Changes are instant.",
303 root 1.18 on_changed => sub {
304 root 1.1 $CFG->{gauge_fontsize} = $_[1];
305     &set_gauge_window_fontsize;
306     }
307     );
308    
309     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Gauge size");
310     $table->add (1, $row++, new CFClient::UI::Slider
311 root 1.18 range => [$CFG->{gauge_size}, 0.2, 0.8],
312     tooltip => "Adjust the size of the stats gauges at the bottom right. Changes are instant.",
313     on_changed => sub {
314 root 1.1 $CFG->{gauge_size} = $_[1];
315     $GAUGES->{win}->set_size ($WIDTH, int $HEIGHT * $CFG->{gauge_size});
316     }
317     );
318    
319     $table->add (1, $row++, new CFClient::UI::Button
320     expand => 1, align => 0, text => "Apply",
321     tooltip => "Apply the video settings",
322 root 1.18 on_activate => sub {
323 root 1.1 video_shutdown ();
324     video_init ();
325     }
326     );
327    
328     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Audio Enable");
329     $table->add (1, $row++, new CFClient::UI::CheckBox
330     state => $CFG->{audio_enable},
331     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.",
332 root 1.18 on_changed => sub {
333 root 1.1 $CFG->{audio_enable} = $_[1];
334     }
335     );
336     # $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Effects Volume");
337 root 1.18 # $table->add (1, 8, new CFClient::UI::Slider range => [$CFG->{effects_volume}, 0, 128, 1], on_changed => sub {
338 root 1.1 # $CFG->{effects_volume} = $_[1];
339     # });
340     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Background Music");
341     $table->add (1, $row++, my $hbox = new CFClient::UI::HBox);
342     $hbox->add (new CFClient::UI::CheckBox
343     expand => 1, state => $CFG->{bgm_enable},
344     tooltip => "If enabled, playing of background music is enabled. If disabled, no background music will be played.",
345 root 1.18 on_changed => sub {
346 root 1.1 $CFG->{bgm_enable} = $_[1];
347     }
348     );
349     $hbox->add (new CFClient::UI::Slider
350     expand => 1, range => [$CFG->{bgm_volume}, 0, 1, 0, 1/128],
351     tooltip => "The volume of the background music. Changes are instant.",
352 root 1.18 on_changed => sub {
353 root 1.1 $CFG->{bgm_volume} = $_[1];
354     CFClient::MixMusic::volume $_[1] * 128;
355     }
356     );
357    
358     $table->add (1, $row++, new CFClient::UI::Button
359     expand => 1, align => 0, text => "Apply",
360     tooltip => "Apply the audio settings",
361 root 1.18 on_activate => sub {
362 root 1.1 audio_shutdown ();
363     audio_init ();
364     }
365     );
366    
367     $table->add (0, $row, new CFClient::UI::Label valign => 0, align => 1, text => "Chat Command");
368     $table->add (1, $row++, my $saycmd = new CFClient::UI::Entry
369     text => $CFG->{say_command},
370     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. "
371     . "Usually you want to enter something like 'say' or 'shout' or 'gsay' here. "
372     . "But you could also set it to <b>tell <i>playername</i></b> to only chat with that user.",
373 root 1.18 on_changed => sub {
374 root 1.1 my ($self, $value) = @_;
375     $CFG->{say_command} = $value;
376     }
377     );
378    
379     $dialog
380     }
381    
382     sub set_stats_window_fontsize {
383     for (values %{$STATWIDS}) {
384     $_->set_fontsize ($::CFG->{stat_fontsize});
385     }
386     }
387    
388     sub set_gauge_window_fontsize {
389     for (map { $GAUGES->{$_} } grep { $_ ne 'win' } keys %{$GAUGES}) {
390     $_->set_fontsize ($::CFG->{gauge_fontsize});
391     }
392     }
393    
394     sub make_gauge_window {
395     my $gh = int $HEIGHT * $CFG->{gauge_size};
396    
397     my $win = new CFClient::UI::Frame (
398 root 1.30 force_x => 0,
399     force_y => "max",
400     force_w => $WIDTH,
401     force_h => $gh,
402 root 1.1 );
403    
404     $win->add (my $hbox = new CFClient::UI::HBox
405     children => [
406     (new CFClient::UI::HBox expand => 1),
407     (new CFClient::UI::VBox children => [
408     (new CFClient::UI::Empty expand => 1),
409 root 1.2 (new CFClient::UI::Frame bg => [0, 0, 0, 0.4], child => ($FLOORBOX = new CFClient::UI::Table)),
410 root 1.1 ]),
411     (my $vbox = new CFClient::UI::VBox),
412     ],
413     );
414    
415     $vbox->add (new CFClient::UI::HBox
416     expand => 1,
417     children => [
418     (new CFClient::UI::Empty expand => 1),
419     (my $hb = new CFClient::UI::HBox),
420     ],
421     );
422    
423     $hb->add (my $hg = new CFClient::UI::Gauge type => 'hp',
424     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.");
425     $hb->add (my $mg = new CFClient::UI::Gauge type => 'mana',
426     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.");
427     $hb->add (my $gg = new CFClient::UI::Gauge type => 'grace',
428     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.");
429     $hb->add (my $fg = new CFClient::UI::Gauge type => 'food',
430     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.");
431    
432     $vbox->add (my $exp = new CFClient::UI::Label valign => 0, align => 1, can_hover => 1, can_events => 1,
433     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.");
434     $vbox->add (my $rng = new CFClient::UI::Label valign => 0, align => 1, can_hover => 1, can_events => 1,
435     tooltip => "<b>Ranged attack</b> - how you attack when you press shift-cursor (spell, skill, weapon etc.)");
436    
437     $GAUGES = {
438     exp => $exp, win => $win, range => $rng,
439     food => $fg, mana => $mg, hp => $hg, grace => $gg
440     };
441    
442     &set_gauge_window_fontsize;
443    
444     $win
445     }
446    
447 elmex 1.24
448 root 1.1 sub make_stats_window {
449 elmex 1.19 my $tgw = new CFClient::UI::FancyFrame
450 root 1.30 y => $HEIGHT * (2/8),
451     x => "max",
452 elmex 1.19 title => "Stats",
453 root 1.30 name => "stats_window";
454 root 1.1
455     $tgw->add (new CFClient::UI::Window child => my $vb = new CFClient::UI::VBox);
456     $vb->add ($STATWIDS->{title} = new CFClient::UI::Label valign => 0, align => -1, text => "Title:", expand => 1,
457     can_hover => 1, can_events => 1,
458     tooltip => "Your name and title. You can change your title by using the <b>title</b> command, if supported by the server.");
459     $vb->add ($STATWIDS->{map} = new CFClient::UI::Label valign => 0, align => -1, text => "Map:", expand => 1,
460     can_hover => 1, can_events => 1,
461     tooltip => "The map you are currently on (if supported by the server).");
462    
463 elmex 1.5 $vb->add (my $hb0 = new CFClient::UI::HBox);
464     $hb0->add ($STATWIDS->{weight} = new CFClient::UI::Label valign => 0, align => -1, text => "Weight:", expand => 1,
465     can_hover => 1, can_events => 1,
466 root 1.15 tooltip => "The weight of the player including all inventory items.");
467 elmex 1.5 $hb0->add ($STATWIDS->{m_weight} = new CFClient::UI::Label valign => 0, align => -1, text => "Max weight:", expand => 1,
468     can_hover => 1, can_events => 1,
469 root 1.15 tooltip => "The weight limit: you cannot carry more than this.");
470 elmex 1.5
471    
472 root 1.1 $vb->add (my $hb = new CFClient::UI::HBox expand => 1);
473     $hb->add (my $tbl = new CFClient::UI::Table expand => 1);
474    
475     my $color2 = [1, 1, 0];
476    
477     for (
478     [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"],
479     [0, 1, st_dex => "Dex", 30, "<b>Dexterity</b>, your physical agility. Determines chance of being hit and affects armor class and speed"],
480     [0, 2, st_con => "Con", 30, "<b>Constitution</b>, physical health and toughness. Determines how many healthpoints you can have"],
481     [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"],
482     [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"],
483     [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"],
484     [0, 6, st_cha => "Cha", 30, "<b>Charisma</b>, how well you are received by NPCs. Affects buying and selling prices in shops."],
485    
486     [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."],
487     [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."],
488     [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."],
489     [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."],
490     [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."],
491     [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."],
492     ) {
493     my ($col, $row, $id, $label, $template, $tooltip) = @$_;
494    
495     $tbl->add ($col , $row, $STATWIDS->{$id} = new CFClient::UI::Label
496     font => $FONT_FIXED, can_hover => 1, can_events => 1, valign => 0, align => +1, template => $template, tooltip => $tooltip);
497     $tbl->add ($col + 1, $row, $STATWIDS->{"$id\_lbl"} = new CFClient::UI::Label
498     font => $FONT_FIXED, can_hover => 1, can_events => 1, fg => $color2, valign => 0, align => -1, text => $label, tooltip => $tooltip);
499     }
500    
501     $hb->add (my $tbl2 = new CFClient::UI::Table expand => 1);
502    
503     my $row = 0;
504     my $col = 0;
505    
506     my %resist_names = (
507     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.)",
508     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.)",
509     conf => "<b>Confusion</b> (If you are hit by confusion you will move into random directions, and likely into monsters.)",
510     fire => "<b>Fire</b> (just your resistance to fire spells like burning hands, dragonbreath, meteor swarm fire, ...)",
511     depl => "<b>Depletion</b> (some monsters and other effects can cause stats depletion)",
512     magic => "<b>Magic</b> (resistance to magic spells like magic missile or similar)",
513     drain => "<b>Draining</b> (some monsters (e.g. vampires) and other effects can steal experience)",
514     acid => "<b>Acid</b> (resistance to acid, acid hurts pretty much and also corrodes your weapons)",
515     pois => "<b>Poison</b> (resistance to getting poisoned)",
516     para => "<b>Paralysation</b> (this resistance affects the chance you get paralysed)",
517     deat => "<b>Death</b> (resistance against death spells)",
518     phys => "<b>Physical</b> (this is the resistance against physical attacks, like when a monster hit you in melee combat)",
519     blind => "<b>Blind</b> (blind resistance affects the chance of a successful blinding attack)",
520     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)",
521     tund => "<b>Turn undead</b> (affects your resistancy to various forms of 'turn undead' spells. Only relevant when you are, in fact, undead...",
522     elec => "<b>Electricity</b> (resistance against electricity, spells like large lightning, small lightning, ...)",
523     cold => "<b>Cold</b> (this is your resistance against cold spells like icestorm, snowstorm, ...)",
524     ghit => "<b>Ghost hit</b> (special attack used by ghosts and ghost-like beings)",
525     );
526     for (qw/slow holyw conf fire depl magic
527     drain acid pois para deat phys
528     blind fear tund elec cold ghit/)
529     {
530     $tbl2->add ($col, $row,
531     $STATWIDS->{"res_$_"} =
532     new CFClient::UI::Label
533     font => $FONT_FIXED,
534     template => "-100%",
535     align => +1,
536     valign => 0,
537     can_events => 1,
538     can_hover => 1,
539     tooltip => $resist_names{$_},
540     );
541     $tbl2->add ($col + 1, $row, new CFClient::UI::Image
542     font => $FONT_FIXED,
543     can_hover => 1,
544     can_events => 1,
545     image => "ui/resist/resist_$_.png",
546     tooltip => $resist_names{$_},
547     );
548    
549     $row++;
550     if ($row % 6 == 0) {
551     $col += 2;
552     $row = 0;
553     }
554     }
555    
556     &set_stats_window_fontsize;
557     update_stats_window ({});
558    
559     $tgw
560     }
561    
562     sub formsep {
563     reverse join ",", grep length, split /(...)/, reverse $_[0] * 1
564     }
565    
566     sub update_stats_window {
567     my ($stats) = @_;
568    
569 root 1.12 # I love text protocols...
570    
571     my $hp = $stats->{+CS_STAT_HP} * 1;
572     my $hp_m = $stats->{+CS_STAT_MAXHP} * 1;
573     my $sp = $stats->{+CS_STAT_SP} * 1;
574     my $sp_m = $stats->{+CS_STAT_MAXSP} * 1;
575     my $fo = $stats->{+CS_STAT_FOOD} * 1;
576 root 1.1 my $fo_m = 999;
577 root 1.12 my $gr = $stats->{+CS_STAT_GRACE} * 1;
578     my $gr_m = $stats->{+CS_STAT_MAXGRACE} * 1;
579 root 1.1
580     $GAUGES->{hp} ->set_value ($hp, $hp_m);
581     $GAUGES->{mana} ->set_value ($sp, $sp_m);
582     $GAUGES->{food} ->set_value ($fo, $fo_m);
583     $GAUGES->{grace} ->set_value ($gr, $gr_m);
584 root 1.12 $GAUGES->{exp} ->set_text ("Exp: " . (formsep $stats->{+CS_STAT_EXP64})
585     . " (lvl " . ($stats->{+CS_STAT_LEVEL} * 1) . ")");
586     my $rng = $stats->{+CS_STAT_RANGE};
587 root 1.1 $rng =~ s/^Range: //; # thank you so much dear server
588     $GAUGES->{range} ->set_text ("Rng: " . $rng);
589 root 1.12 my $title = $stats->{+CS_STAT_TITLE};
590 root 1.1 $title =~ s/^Player: //;
591     $STATWIDS->{title} ->set_text ("Title: " . $title);
592    
593 root 1.12 $STATWIDS->{st_str} ->set_text (sprintf "%d" , $stats->{+CS_STAT_STR});
594     $STATWIDS->{st_dex} ->set_text (sprintf "%d" , $stats->{+CS_STAT_DEX});
595     $STATWIDS->{st_con} ->set_text (sprintf "%d" , $stats->{+CS_STAT_CON});
596     $STATWIDS->{st_int} ->set_text (sprintf "%d" , $stats->{+CS_STAT_INT});
597     $STATWIDS->{st_wis} ->set_text (sprintf "%d" , $stats->{+CS_STAT_WIS});
598     $STATWIDS->{st_pow} ->set_text (sprintf "%d" , $stats->{+CS_STAT_POW});
599     $STATWIDS->{st_cha} ->set_text (sprintf "%d" , $stats->{+CS_STAT_CHA});
600     $STATWIDS->{st_wc} ->set_text (sprintf "%d" , $stats->{+CS_STAT_WC});
601     $STATWIDS->{st_ac} ->set_text (sprintf "%d" , $stats->{+CS_STAT_AC});
602     $STATWIDS->{st_dam} ->set_text (sprintf "%d" , $stats->{+CS_STAT_DAM});
603     $STATWIDS->{st_arm} ->set_text (sprintf "%d" , $stats->{+CS_STAT_ARMOUR});
604     $STATWIDS->{st_spd} ->set_text (sprintf "%.1f", $stats->{+CS_STAT_SPEED});
605     $STATWIDS->{st_wspd}->set_text (sprintf "%.1f", $stats->{+CS_STAT_WEAP_SP});
606 root 1.1
607 root 1.12 $STATWIDS->{m_weight}->set_text (sprintf "Max weight: %.1fkg", $stats->{+CS_STAT_WEIGHT_LIM} / 1000);
608 elmex 1.5
609 root 1.12 # TODO: replace by CS_STAT_RES_xxx constants
610 root 1.1 my %tbl = (
611     phys => 100,
612     magic => 101,
613     fire => 102,
614     elec => 103,
615     cold => 104,
616     conf => 105,
617     acid => 106,
618     drain => 107,
619     ghit => 108,
620     pois => 109,
621     slow => 110,
622     para => 111,
623     tund => 112,
624     fear => 113,
625     depl => 113,
626     deat => 115,
627     holyw => 116,
628 root 1.12 blind => 117,
629 root 1.1 );
630    
631 root 1.12 $STATWIDS->{"res_$_"}->set_text (sprintf "%d%", $stats->{$tbl{$_}})
632     for keys %tbl;
633 root 1.1 }
634    
635     my $METASERVER_ATIME;
636    
637     sub update_metaserver {
638     return if $METASERVER_ATIME > time;
639     $METASERVER_ATIME = time + 60;
640    
641     my $table = $METASERVER->{table};
642     $table->clear;
643     $table->add (0, 0, my $label = new CFClient::UI::Label max_w => $WIDTH * 0.8, text => "fetching server list...");
644    
645     my $buf;
646    
647     my $fh = new IO::Socket::INET PeerHost => $META_SERVER, Blocking => 0;
648    
649     unless ($fh) {
650     $label->set_text ("unable to contact metaserver: $!");
651     return;
652     }
653    
654     Event->io (fd => $fh, poll => 'r', cb => sub {
655     my $res = sysread $fh, $buf, 8192, length $buf;
656    
657     if (!defined $res) {
658     $_[0]->w->cancel;
659     $label->set_text ("error while retrieving server list: $!");
660     } elsif ($res == 0) {
661     $_[0]->w->cancel;
662     status "server list retrieved";
663    
664     utf8::decode $buf if utf8::valid $buf;
665    
666     $table->clear;
667    
668     my @col = qw(Use #Users Host Uptime Version Description);
669     $table->add ($_, 0, new CFClient::UI::Label align => 0, fg => [1, 1, 0], text => $col[$_])
670     for 0 .. $#col;
671    
672     my @align = qw(1 0 1 1 -1);
673    
674     my $y = 0;
675     for my $m (sort { $b->[3] <=> $a->[3] } map [split /\|/], split /\015?\012/, $buf) {
676     my ($ip, $last, $host, $users, $version, $desc, $ibytes, $obytes, $uptime) = @$m;
677    
678     for ($desc) {
679     s/<br>/\n/gi;
680     s/<li>/\n· /gi;
681     s/<.*?>//sgi;
682     s/&/&amp;/g;
683     s/</&lt;/g;
684     s/>/&gt;/g;
685     }
686    
687     $uptime = sprintf "%dd %02d:%02d:%02d",
688     (int $m->[8] / 86400),
689     (int $m->[8] / 3600) % 24,
690     (int $m->[8] / 60) % 60,
691     $m->[8] % 60;
692    
693     $m = [$users, $host, $uptime, $version, $desc];
694    
695     $y++;
696    
697     $table->add (0, $y, new CFClient::UI::VBox children => [
698 root 1.18 (new CFClient::UI::Button text => "Use", on_activate => sub {
699 root 1.40 $HOST_ENTRY->set_text ($CFG->{host} = $host);
700     $METASERVER->toggle_visibility;
701 root 1.1 }),
702     (new CFClient::UI::Empty expand => 1),
703     ]);
704    
705     $table->add ($_ + 1, $y, new CFClient::UI::Label
706     ellipsise => 0, align => $align[$_], text => $m->[$_], fontsize => 0.8)
707     for 0 .. $#$m;
708     }
709     }
710     });
711     }
712    
713 root 1.40 sub metaserver_dialog {
714     my $dialog = new CFClient::UI::FancyFrame
715     title => "Server List",
716 root 1.41 name => 'metaserver_dialog',
717 root 1.40 x => 'center',
718     y => 'center',
719     child => (my $vbox = new CFClient::UI::VBox),
720     on_visibility_change => sub {
721     update_metaserver if $_[1];
722     },
723     ;
724    
725     $vbox->add ($dialog->{table} = new CFClient::UI::Table);
726    
727     $dialog
728     }
729    
730 root 1.1 sub server_setup {
731 root 1.23 my $dialog = $SERVER_SETUP = new CFClient::UI::FancyFrame
732 root 1.30 x => "center",
733     y => "center",
734     name => "server_setup",
735     title => "Server Setup",
736     child => (my $vbox = new CFClient::UI::VBox),
737 root 1.21 ;
738 elmex 1.19
739 root 1.1 $vbox->add (my $table = new CFClient::UI::Table expand => 1, col_expand => [0, 1]);
740     $table->add (0, 2, new CFClient::UI::Label valign => 0, align => 1, text => "Host:Port");
741    
742     {
743     $table->add (1, 2, my $vbox = new CFClient::UI::VBox);
744    
745     $vbox->add (
746 root 1.40 $HOST_ENTRY = new CFClient::UI::Entry
747 root 1.1 expand => 1,
748     text => $CFG->{host},
749     tooltip => "The hostname or ip address of the Crossfire(+) server to connect to",
750 root 1.18 on_changed => sub {
751 root 1.1 my ($self, $value) = @_;
752     $CFG->{host} = $value;
753     }
754     );
755    
756     $METASERVER = metaserver_dialog;
757    
758 root 1.40 $vbox->add (new CFClient::UI::Button
759     expand => 1,
760     text => "Server List",
761     other => $METASERVER,
762 root 1.1 tooltip => "Show a list of available crossfire servers",
763 root 1.40 on_activate => sub { $METASERVER->toggle_visibility },
764 root 1.1 );
765     }
766    
767     $table->add (0, 4, new CFClient::UI::Label valign => 0, align => 1, text => "Username");
768     $table->add (1, 4, new CFClient::UI::Entry
769     text => $CFG->{user},
770     tooltip => "The name of your character on the server",
771 root 1.18 on_changed => sub {
772 root 1.1 my ($self, $value) = @_;
773     $CFG->{user} = $value;
774     }
775     );
776    
777     $table->add (0, 5, new CFClient::UI::Label valign => 0, align => 1, text => "Password");
778     $table->add (1, 5, new CFClient::UI::Entry
779     text => $CFG->{password},
780     hidden => 1,
781     tooltip => "The password for your character",
782 root 1.18 on_changed => sub {
783 root 1.1 my ($self, $value) = @_;
784     $CFG->{password} = $value;
785     }
786     );
787    
788     $table->add (0, 7, new CFClient::UI::Label valign => 0, align => 1, text => "Map Size");
789     $table->add (1, 7, new CFClient::UI::Slider
790 root 1.30 force_w => 100,
791 root 1.1 range => [$CFG->{mapsize}, 10, 100, 0, 1],
792     tooltip => "This is the size of the portion of the map update the server sends you. "
793     . "If you set this to a high value you will be able to see further, "
794     . "but you also increase bandwidth requirements and latency. "
795     . "This option is only used once at log-in.",
796 root 1.18 on_changed => sub {
797 root 1.1 my ($self, $value) = @_;
798    
799     $CFG->{mapsize} = $self->{range}[0] = $value = int $value;
800     },
801     );
802    
803     $table->add (0, 8, new CFClient::UI::Label valign => 0, align => 1, text => "Face Prefetch");
804     $table->add (1, 8, new CFClient::UI::CheckBox
805     state => $CFG->{face_prefetch},
806     tooltip => "<b>Background Image Prefetch</b>\n\n"
807     . "If enabled, the client automatically pre-fetches images from the server. "
808     . "This might increase or create lag, but increases the chances "
809     . "of faces being ready for display when you encounter them. "
810     . "It also uses up server bandwidth on every connect, "
811     . "so only set it if you really need to prefetch images. "
812     . "This option can be set and unset any time.",
813 root 1.18 on_changed => sub { $CFG->{face_prefetch} = $_[1] },
814 root 1.1 );
815    
816     $table->add (0, 9, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Count");
817     $table->add (1, 9, new CFClient::UI::Entry
818     text => $CFG->{output_count},
819     tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.",
820 root 1.18 on_changed => sub { $CFG->{output_count} = $_[1] },
821 root 1.1 );
822    
823     $table->add (0, 10, new CFClient::UI::Label valign => 0, align => 1, text => "Output-Sync");
824     $table->add (1, 10, new CFClient::UI::Entry
825     text => $CFG->{output_sync},
826     tooltip => "Should be set to 1 unless you know what you are doing. This option is only used once at log-in.",
827 root 1.18 on_changed => sub { $CFG->{output_sync} = $_[1] },
828 root 1.1 );
829    
830     $table->add (1, 11, $LOGIN_BUTTON = new CFClient::UI::Button
831     expand => 1,
832     align => 0,
833     text => "Login",
834 root 1.18 on_activate => sub {
835 root 1.1 $CONN ? stop_game
836     : start_game;
837     },
838     );
839    
840     $dialog
841     }
842    
843     sub message_window {
844     my $window = new CFClient::UI::FancyFrame
845 elmex 1.16 name => "message_window",
846 root 1.1 title => "Messages",
847     border_bg => [1, 1, 1, 1],
848     bg => [0, 0, 0, 0.75],
849 root 1.30 x => "max",
850     y => 0,
851     force_w => $::WIDTH / 3,
852     force_h => $::HEIGHT / 5,
853 root 1.1 child => (my $vbox = new CFClient::UI::VBox);
854    
855     $vbox->add ($LOGVIEW);
856    
857     $vbox->add (my $input = new CFClient::UI::Entry
858     tooltip => "<b>Chat Box</b>. If you enter a text and press return/enter here, the current <i>communication command</i> "
859     . "from the client setup will be prepended (e.g. <b>shout</b>, <b>chat</b>...). "
860     . "If you prepend a slash (/), you will submit a command instead (similar to IRC). "
861     . "A better way to submit commands (and the occasional chat command) is often the map command completer.",
862 root 1.18 on_focus_in => sub {
863 root 1.1 my ($input, $prev_focus) = @_;
864    
865     delete $input->{refocus_map};
866    
867     if ($prev_focus == $MAPWIDGET && $input->{auto_activated}) {
868     $input->{refocus_map} = 1;
869     }
870     delete $input->{auto_activated};
871     },
872 root 1.18 on_activate => sub {
873 root 1.1 my ($input, $text) = @_;
874     $input->set_text ('');
875    
876 elmex 1.24 if ($text =~ /^\/bind\s+(.*)$/) {
877 elmex 1.34 CFClient::Binder::open_binding_dialog (sub {
878     my ($mod, $sym) = @_;
879     $::CFG->{bindings}->{$mod}->{$sym} = [$1];
880     });
881 elmex 1.24 } elsif ($text =~ /^\/(.*)/) {
882 root 1.1 $::CONN->user_send ($1);
883     } else {
884     my $say_cmd = $::CFG->{say_command} || 'say';
885     $::CONN->user_send ("$say_cmd $text");
886     }
887     if ($input->{refocus_map}) {
888     delete $input->{refocus_map};
889     $MAPWIDGET->focus_in
890     }
891     },
892 root 1.18 on_escape => sub {
893 root 1.1 $MAPWIDGET->focus_in
894     },
895     );
896    
897     $CONSOLE = {
898     window => $window,
899 root 1.30 input => $input,
900 root 1.1 };
901    
902     $window
903     }
904    
905     sub open_quit_dialog {
906     unless ($QUIT_DIALOG) {
907 root 1.30 $QUIT_DIALOG = new CFClient::UI::FancyFrame
908     x => "center",
909     y => "center",
910     title => "Really Quit?",
911     ;
912 root 1.1
913     $QUIT_DIALOG->add (my $vb = new CFClient::UI::VBox expand => 1);
914    
915     $vb->add (new CFClient::UI::Label
916     text => "You should find a savebed and apply it first!",
917     max_w => $WIDTH * 0.25,
918     ellipsize => 0,
919     );
920     $vb->add (my $hb = new CFClient::UI::HBox expand => 1);
921     $hb->add (new CFClient::UI::Button
922     text => "Ok",
923     expand => 1,
924 root 1.18 on_activate => sub { $QUIT_DIALOG->hide },
925 root 1.1 );
926     $hb->add (new CFClient::UI::Button
927     text => "Quit anyway",
928     expand => 1,
929 root 1.18 on_activate => sub { exit },
930 root 1.1 );
931 root 1.21 }
932 root 1.1
933 root 1.21 $QUIT_DIALOG->show;
934 root 1.1 }
935    
936 elmex 1.43 sub make_pickup_cfg_window {
937     $PICKUP_CFG = new CFClient::UI::FancyFrame
938 elmex 1.44 title => "Autopickup configuration",
939 elmex 1.43 x => "center",
940     y => "center",
941 elmex 1.45 force_w => $WIDTH * 6/10,
942 elmex 1.43 force_h => $HEIGHT * 9/10;
943    
944 elmex 1.45
945     $PICKUP_CFG->add (my $vb = new CFClient::UI::VBox);
946     $vb->add (my $gen_tbl = new CFClient::UI::Table expand => 1);
947     $vb->add (my $hb = new CFClient::UI::HBox expand => 1);
948     $hb->add (my $ltbl = new CFClient::UI::Table expand => 1);
949     $hb->add (my $rtbl = new CFClient::UI::Table expand => 1);
950    
951     my $tbl = 0;
952 elmex 1.43 my $tblrow = 0;
953 elmex 1.44
954 elmex 1.43 for (
955 elmex 1.45 ["General", $gen_tbl],
956     ["Enable autopickup" => CFClient::Pickup::PU_NEWMODE],
957 elmex 1.43 ["Inhibit autopickup" => CFClient::Pickup::PU_INHIBIT],
958     ["Stop before pickup" => CFClient::Pickup::PU_STOP],
959     ["Debug autopickup" => CFClient::Pickup::PU_DEBUG],
960 elmex 1.45 ["Weapons", $ltbl],
961 elmex 1.43 ["All weapons" => CFClient::Pickup::PU_ALLWEAPON],
962     ["Missile weapons" => CFClient::Pickup::PU_MISSILEWEAPON],
963     ["Bows" => CFClient::Pickup::PU_BOW],
964     ["Arrows" => CFClient::Pickup::PU_ARROW],
965     ["Armour"],
966     ["Helmets" => CFClient::Pickup::PU_HELMET],
967     ["Shields" => CFClient::Pickup::PU_SHIELD],
968     ["Body Armour" => CFClient::Pickup::PU_ARMOUR],
969     ["Boots" => CFClient::Pickup::PU_BOOTS],
970     ["Gloves" => CFClient::Pickup::PU_GLOVES],
971     ["Cloaks" => CFClient::Pickup::PU_CLOAK],
972 elmex 1.45 ["Readables", $rtbl],
973 elmex 1.43 ["Spellbooks" => CFClient::Pickup::PU_SPELLBOOK],
974     ["Skillscrolls" => CFClient::Pickup::PU_SKILLSCROLL],
975     ["Normal Books/Scrolls" => CFClient::Pickup::PU_READABLES],
976     ["Misc"],
977     ["Food" => CFClient::Pickup::PU_FOOD],
978     ["Drinks" => CFClient::Pickup::PU_DRINK],
979     ["Valuables (Money, Gems)" => CFClient::Pickup::PU_VALUABLES],
980     ["Keys" => CFClient::Pickup::PU_KEY],
981     ["Magical Items" => CFClient::Pickup::PU_MAGICAL],
982     ["Potions" => CFClient::Pickup::PU_POTION],
983     ["Magic Devices" => CFClient::Pickup::PU_MAGIC_DEVICE],
984     ["Ignore cursed" => CFClient::Pickup::PU_NOT_CURSED],
985     ["Jewelery" => CFClient::Pickup::PU_JEWELS],
986     )
987     {
988 elmex 1.45 if (ref $_->[1]) {
989     $tbl = $_->[1];
990     $tblrow = 0;
991     $tbl->add (0, $tblrow++, new CFClient::UI::Label text => $_->[0], align => -1);
992     } elsif (not defined $_->[1]) {
993     $tbl->add (0, $tblrow++, new CFClient::UI::Label text => $_->[0], align => -1);
994 elmex 1.43 } else {
995     my $mask = $_->[1];
996 elmex 1.45 $tbl->add (0, $tblrow, new CFClient::UI::Label text => $_->[0], align => 1, expand => 1);
997 elmex 1.43 $tbl->add (1, $tblrow++, new CFClient::UI::CheckBox
998     state => $CFG->{pickup} & $mask,
999     on_changed => sub {
1000     my ($box, $value) = @_;
1001     if ($value) {
1002 elmex 1.45 $::CFG->{pickup} |= $mask;
1003 elmex 1.43 } else {
1004 elmex 1.45 $::CFG->{pickup} = $::CFG->{pickup} & ~$mask;
1005 elmex 1.43 }
1006 elmex 1.45 $::CONN->send (sprintf "command pickup %u", $::CFG->{pickup})
1007     if defined $::CONN;
1008 elmex 1.43 });
1009     }
1010     }
1011    
1012     $PICKUP_CFG
1013     }
1014    
1015 root 1.1 sub make_inventory_window {
1016 root 1.23 my $invwin = $INV_WINDOW = new CFClient::UI::FancyFrame
1017 root 1.32 x => "center",
1018     y => "center",
1019     force_w => $WIDTH * 9/10,
1020     force_h => $HEIGHT * 9/10,
1021     title => "Inventory",
1022 root 1.21 ;
1023 root 1.1
1024 root 1.21 $invwin->add (my $hb = new CFClient::UI::HBox homogeneous => 1);
1025 root 1.1
1026 root 1.21 $hb->add (my $vb1 = new CFClient::UI::VBox);
1027     $vb1->add (new CFClient::UI::Label align => 0, text => "Player");
1028     $vb1->add ($INV = new CFClient::UI::Inventory expand => 1);
1029 root 1.1
1030 root 1.21 $hb->add (my $vb2 = new CFClient::UI::VBox);
1031 elmex 1.17
1032 elmex 1.27 $vb2->add ($INV_RIGHT_HB = new CFClient::UI::HBox);
1033 elmex 1.14
1034 root 1.1 $vb2->add ($INVR = new CFClient::UI::Inventory expand => 1);
1035    
1036 elmex 1.27 # XXX: Call after $INVR = ... because set_opencont sets the items
1037     CFClient::Protocol::set_opencont ($::CONN, 0, "Floor");
1038    
1039 root 1.1 $invwin
1040     }
1041    
1042 elmex 1.38 sub make_spell_list {
1043     $SPELL_LIST = new CFClient::UI::SpellList
1044     force_w => $WIDTH * (9/10),
1045     force_h => $HEIGHT * (9/10);
1046     $SPELL_LIST
1047     }
1048    
1049 elmex 1.24 sub make_binding_window {
1050     my $binding_list = new CFClient::UI::VBox;
1051    
1052 elmex 1.34 my $refresh;
1053     $refresh = sub {
1054 elmex 1.24 $binding_list->clear ();
1055    
1056     for my $mod (keys %{$::CFG->{bindings}}) {
1057     for my $sym (keys %{$::CFG->{bindings}->{$mod}}) {
1058     my $cmds = $::CFG->{bindings}->{$mod}->{$sym};
1059     next unless ref $cmds eq 'ARRAY' and @$cmds > 0;
1060    
1061     my $lbl = join "; ", @$cmds;
1062 elmex 1.34 my $nam = CFClient::Binder::keycombo_to_name ($mod, $sym);
1063 elmex 1.24 $binding_list->add (my $hb = new CFClient::UI::HBox);
1064     $hb->add (new CFClient::UI::Button
1065 elmex 1.25 text => "delete",
1066 elmex 1.34 tooltip => "Deletes the binding",
1067 elmex 1.24 on_activate => sub {
1068     $binding_list->remove ($hb);
1069     delete $::CFG->{bindings}->{$mod}->{$sym};
1070     });
1071 elmex 1.34
1072     $hb->add (new CFClient::UI::Button
1073     text => "edit",
1074     tooltip => "Edits the binding",
1075     on_activate => sub {
1076     $::BIND_EDITOR->set_binding (
1077     $mod, $sym, $::CFG->{bindings}->{$mod}->{$sym},
1078     sub {
1079     my ($nmod, $nsym, $ncmds) = @_;
1080     delete $::CFG->{bindings}->{$mod}->{$sym};
1081     $::CFG->{bindings}->{$nmod}->{$nsym} = $ncmds;
1082     $refresh->();
1083     $::BIND_WINDOW->show;
1084     },
1085     sub {
1086     $::BIND_WINDOW->show;
1087     });
1088     $::BIND_EDITOR->show;
1089     $::BIND_WINDOW->hide;
1090     });
1091    
1092     $hb->add (new CFClient::UI::Label text => "(Key: $nam)");
1093 elmex 1.24 $hb->add (new CFClient::UI::Label text => $lbl, expand => 1);
1094     }
1095     }
1096     };
1097    
1098     $BIND_WINDOW = new CFClient::UI::FancyFrame
1099     title => "Bindings",
1100 root 1.30 x => "center",
1101     y => "center",
1102     def_w => int $WIDTH * 9/10,
1103     def_h => int $HEIGHT * 9/10,
1104 elmex 1.24 on_visibility_change => sub {
1105     my ($self, $visible) = @_;
1106 root 1.30 $refresh->() if $visible;
1107 elmex 1.24 };
1108    
1109 elmex 1.34 $BIND_WINDOW->add (my $vb = new CFClient::UI::VBox);
1110 elmex 1.35 $vb->add ($binding_list);
1111     $vb->add (my $hb = new CFClient::UI::HBox);
1112     $hb->add (new CFClient::UI::Button
1113 elmex 1.34 text => "record new",
1114 elmex 1.35 expand => 1,
1115 elmex 1.34 tooltip => "This button opens the binding editor with an empty binding.",
1116     on_activate => sub {
1117     $::BIND_EDITOR->set_binding (undef, undef, [],
1118     sub {
1119     my ($mod, $sym, $cmds) = @_;
1120     $::CFG->{bindings}->{$mod}->{$sym} = $cmds;
1121     $refresh->();
1122     $::BIND_WINDOW->show;
1123     },
1124     sub {
1125     $::BIND_WINDOW->show;
1126     });
1127     $::BIND_WINDOW->hide;
1128     $::BIND_EDITOR->show;
1129     },
1130     );
1131 elmex 1.35 $hb->add (new CFClient::UI::Button
1132     text => "close",
1133     tooltip => "Closes the binding window",
1134     expand => 1,
1135     on_activate => sub {
1136     $::BIND_WINDOW->hide;
1137     }
1138     );
1139    
1140 elmex 1.24 $refresh->();
1141     $BIND_WINDOW
1142     }
1143    
1144 root 1.1 sub make_help_window {
1145     my $win = new CFClient::UI::FancyFrame
1146 root 1.41 x => 'center',
1147     y => 'center',
1148     name => 'doc_browser',
1149     force_w => int $WIDTH * 7/8,
1150     force_h => int $HEIGHT * 7/8,
1151     title => "Documentation";
1152 root 1.1
1153     $win->add (my $vbox = new CFClient::UI::VBox);
1154    
1155     $vbox->add (my $buttons = new CFClient::UI::HBox);
1156     $vbox->add (my $viewer = new CFClient::UI::TextView expand => 1, fontsize => 0.8);
1157    
1158     for (
1159     [intro => "Introduction"],
1160     [manual => "Manual"],
1161     [command_help => "Commands"],
1162     [skill_help => "Skills"],
1163     ) {
1164     my ($pod, $label) = @$_;
1165    
1166     $buttons->add (new CFClient::UI::Button
1167     text => $label,
1168 root 1.18 on_activate => sub {
1169 root 1.1 my $parser = new Pod::POM;
1170     my $pom = $parser->parse_file (CFClient::find_rcfile "pod/$pod.pod");
1171    
1172     $viewer->clear;
1173    
1174     $viewer->add_paragraph ([1, 1, 1, 1], $_->[1], $_->[0])
1175     for @{ CFClient::pod_to_pango_list $pom };
1176    
1177     $viewer->set_offset (0);
1178     },
1179     );
1180     }
1181    
1182     $viewer->add_paragraph ([1, 1, 0, 1], "<big>Use one of the buttons above to display a document.</big>");
1183    
1184     $win
1185     }
1186    
1187     sub sdl_init {
1188     CFClient::SDL_Init
1189     and die "SDL::Init failed!\n";
1190     }
1191    
1192     sub video_init {
1193     sdl_init;
1194    
1195     $CFG->{sdl_mode} = 0 if $CFG->{sdl_mode} >= @SDL_MODES;
1196    
1197     my ($old_w, $old_h) = ($WIDTH, $HEIGHT);
1198    
1199     ($WIDTH, $HEIGHT) = @{ $SDL_MODES[$CFG->{sdl_mode}] };
1200     $FULLSCREEN = $CFG->{fullscreen};
1201     $FAST = $CFG->{fast};
1202    
1203     CFClient::SDL_SetVideoMode $WIDTH, $HEIGHT, $FULLSCREEN
1204     or die "SDL_SetVideoMode failed: " . (CFClient::SDL_GetError) . "\n";
1205    
1206     $SDL_ACTIVE = 1;
1207     $LAST_REFRESH = time - 0.01;
1208    
1209 root 1.10 CFClient::OpenGL::init;
1210 root 1.1
1211     $FONTSIZE = int $HEIGHT / 40 * $CFG->{gui_fontsize};
1212    
1213     $CFClient::UI::ROOT->configure (0, 0, $WIDTH, $HEIGHT);#d#
1214    
1215     #############################################################################
1216    
1217     if ($DEBUG_STATUS) {
1218     CFClient::UI::rescale_widgets $WIDTH / $old_w, $HEIGHT / $old_h;
1219     } else {
1220     # create the widgets
1221    
1222 root 1.30 $DEBUG_STATUS = new CFClient::UI::Label
1223     padding => 0,
1224     z => 100,
1225     force_x => "max",
1226     force_y => 0;
1227 root 1.1 $DEBUG_STATUS->show;
1228 elmex 1.34
1229     $BIND_EDITOR = new CFClient::UI::BindEditor (x => "max", y => 0);
1230    
1231 root 1.1 $STATUSBOX = new CFClient::UI::Statusbox;
1232     $STATUSBOX->add ("Use <b>Alt-Enter</b> to toggle fullscreen mode", pri => -100, color => [1, 1, 1, 0.8]);
1233    
1234     (new CFClient::UI::Frame
1235     bg => [0, 0, 0, 0.4],
1236 root 1.30 force_x => 0,
1237     force_y => "max",
1238 root 1.1 child => $STATUSBOX,
1239     )->show;
1240    
1241     CFClient::UI::FancyFrame->new (
1242 root 1.42 title => "Mini Map",
1243     name => "mapmap",
1244 root 1.30 x => 0,
1245     y => $FONTSIZE + 8,
1246 root 1.1 border_bg => [1, 1, 1, 192/255],
1247     bg => [1, 1, 1, 0],
1248     child => ($MAPMAP = new CFClient::MapWidget::MapMap
1249     tooltip => "<b>Map</b>. On servers that support this feature, this will display an overview of the surrounding areas.",
1250     ),
1251     )->show;
1252    
1253     $MAPWIDGET = new CFClient::MapWidget;
1254     $MAPWIDGET->connect (activate_console => sub {
1255     my ($mapwidget, $preset) = @_;
1256    
1257     if ($CONSOLE) {
1258     $CONSOLE->{input}->{auto_activated} = 1;
1259     $CONSOLE->{input}->focus_in;
1260    
1261     if ($preset && $CONSOLE->{input}->get_text eq '') {
1262     $CONSOLE->{input}->set_text ($preset);
1263     }
1264     }
1265     });
1266     $MAPWIDGET->show;
1267     $MAPWIDGET->focus_in;
1268    
1269     $LOGVIEW = new CFClient::UI::TextView
1270     expand => 1,
1271     font => $FONT_FIXED,
1272     fontsize => $::CFG->{log_fontsize},
1273     can_hover => 1,
1274     can_events => 1,
1275     tooltip => "<b>Server Log</b>. This text viewer contains all the messages sent by the server.",
1276     ;
1277    
1278 root 1.30 $BUTTONBAR = new CFClient::UI::HBox x => 0, y => 0;
1279 root 1.1
1280     $BUTTONBAR->add (new CFClient::UI::Flopper text => "Client Setup", other => client_setup,
1281     tooltip => "Toggles a dialog where you can configure various aspects of the client, such as graphics mode, performance, and audio options.");
1282     $BUTTONBAR->add (new CFClient::UI::Flopper text => "Server Setup", other => server_setup,
1283     tooltip => "Toggles a dialog where you can configure the server to play on, your username, password and other server-related options.");
1284     $BUTTONBAR->add (new CFClient::UI::Flopper text => "Message Window", other => message_window,
1285     tooltip => "Toggles the server message log, where the client collects <i>all</i> messages from the server.");
1286    
1287     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
1288    
1289     $BUTTONBAR->add (new CFClient::UI::Flopper text => "Stats Window", other => make_stats_window,
1290     tooltip => "Toggles the statistics window, where all your Stats and Resistances are being displayed at all times.");
1291     $BUTTONBAR->add (new CFClient::UI::Flopper text => "Inventory", other => make_inventory_window,
1292 elmex 1.36 tooltip => "Toggles the inventory window, where you can manage your loot (or treaures :)."
1293     ."You can also hit the Tab-key to show/hide the Inventory.");
1294 root 1.1
1295     $BUTTONBAR->add (new CFClient::UI::Button
1296     text => "Save Config",
1297     tooltip => "Saves the options chosen in the client setting, server settings and the window layout to be restored on later runs.",
1298 root 1.18 on_activate => sub {
1299 elmex 1.16 $::CFG->{layout} = CFClient::UI::get_layout;
1300 root 1.28 CFClient::write_cfg "$Crossfire::VARDIR/cfplusrc";
1301 root 1.1 status "Configuration Saved";
1302     },
1303     );
1304    
1305     $BUTTONBAR->add (new CFClient::UI::Flopper text => "Help!", other => make_help_window,
1306     tooltip => "View Documentation");
1307    
1308 elmex 1.24 $BUTTONBAR->add (new CFClient::UI::Flopper
1309     text => "Bindings",
1310     other => make_binding_window,
1311 elmex 1.35 tooltip =>
1312     "Lets you define, edit and delete bindings."
1313     ."There is a shortcut for making bindings: LCTRL+Insert opens the binding editor "
1314     ."with nothing set and the recording started. After doing the actions you "
1315     ."want to record press Insert and you will be asked to press a key-combo."
1316     ."After pressing the combo the binding will be saved automatically and the "
1317 elmex 1.38 ."binding editor closes");
1318    
1319     $BUTTONBAR->add (new CFClient::UI::Flopper
1320     text => "Spells",
1321     other => make_spell_list,
1322     tooltip => "The spell list");
1323 elmex 1.24
1324 elmex 1.43 $BUTTONBAR->add (new CFClient::UI::Flopper
1325     text => "Pickup",
1326     other => make_pickup_cfg_window,
1327     tooltip => "The pickup dialog");
1328    
1329    
1330 root 1.1 $BUTTONBAR->add (new CFClient::UI::Button
1331 root 1.18 text => "Quit",
1332     tooltip => "Terminates the program",
1333     on_activate => sub {
1334 root 1.1 if ($CONN) {
1335     open_quit_dialog;
1336     } else {
1337     exit;
1338     }
1339     },
1340     );
1341    
1342     $BUTTONBAR->show;
1343 root 1.30 $SERVER_SETUP->show;
1344 root 1.1
1345     $STATUSBOX->add ("Set video mode $WIDTH×$HEIGHT", timeout => 10, fg => [1, 1, 1, 0.5]);
1346     }
1347     }
1348    
1349     sub video_shutdown {
1350     undef $SDL_ACTIVE;
1351     }
1352    
1353     my @bgmusic = qw(game1.ogg game2.ogg game3.ogg game5.ogg game6.ogg ross1.ogg ross2.ogg ross3.ogg ross4.ogg ross5.ogg); #d#
1354     my $bgmusic;#TODO#hack#d#
1355    
1356     sub audio_channel_finished {
1357     my ($channel) = @_;
1358    
1359     #warn "channel $channel finished\n";#d#
1360     }
1361    
1362     sub audio_music_finished {
1363     return unless $CFG->{bgm_enable};
1364    
1365     # TODO: hack, do play loop and mood music
1366     $bgmusic = new_from_file CFClient::MixMusic CFClient::find_rcfile "music/$bgmusic[0]";
1367     $bgmusic->play (0);
1368    
1369     push @bgmusic, shift @bgmusic;
1370     }
1371    
1372     sub audio_init {
1373     if ($CFG->{audio_enable}) {
1374     if (open my $fh, "<", CFClient::find_rcfile "sounds/config") {
1375     $SDL_MIXER = !CFClient::Mix_OpenAudio;
1376    
1377     unless ($SDL_MIXER) {
1378     status "Unable to open sound device: there will be no sound";
1379     return;
1380     }
1381    
1382     CFClient::Mix_AllocateChannels 8;
1383     CFClient::MixMusic::volume $CFG->{bgm_volume} * 128;
1384    
1385     audio_music_finished;
1386    
1387     while (<$fh>) {
1388     next if /^\s*#/;
1389     next if /^\s*$/;
1390    
1391     my ($file, $volume, $event) = split /\s+/, $_, 3;
1392    
1393     push @SOUNDS, "$volume,$file";
1394    
1395     $AUDIO_CHUNKS{"$volume,$file"} ||= do {
1396     my $chunk = new_from_file CFClient::MixChunk CFClient::find_rcfile "sounds/$file";
1397     $chunk->volume ($volume * 128 / 100);
1398     $chunk
1399     };
1400     }
1401     } else {
1402     status "unable to open sound config: $!";
1403     }
1404     }
1405     }
1406    
1407     sub audio_shutdown {
1408     CFClient::Mix_CloseAudio if $SDL_MIXER;
1409     undef $SDL_MIXER;
1410     @SOUNDS = ();
1411     %AUDIO_CHUNKS = ();
1412     }
1413    
1414     my %animate_object;
1415     my $animate_timer;
1416    
1417     my $fps = 9;
1418    
1419     my %demo;#d#
1420    
1421     sub force_refresh {
1422     $fps = $fps * 0.95 + 1 / (($NOW - $LAST_REFRESH) || 0.1) * 0.05;
1423 root 1.33 debug sprintf "%3.2f", $fps if $ENV{CFPLUS_DEBUG} & 4;
1424 root 1.1
1425     $CFClient::UI::ROOT->draw;
1426    
1427     $WANT_REFRESH = 0;
1428     $CAN_REFRESH = 0;
1429     $LAST_REFRESH = $NOW;
1430    
1431     0 && do {
1432     # some weird model-drawing code, just a joke right now
1433     use CFClient::OpenGL;
1434    
1435     $demo{t}{eye_auv} ||= new_from_file CFClient::Texture "eye2.png" or die;
1436     $demo{t}{body_auv} ||= new_from_file CFClient::Texture "body_auv3.png" or die;
1437     $demo{r} ||= do {
1438     my $mod = Compress::LZF::sthaw do { local $/; open my $fh, "<:raw:perlio", "dread.lz3"; <$fh> };
1439     $mod->{v} = pack "f*", @{$mod->{v}};
1440     $_ = [scalar @$_, pack "S!*", @$_]
1441     for values %{$mod->{g}};
1442     $mod
1443     };
1444    
1445     my $r = $demo{r} or die;
1446    
1447     glDepthMask 1;
1448     glClear GL_DEPTH_BUFFER_BIT;
1449     glEnable GL_TEXTURE_2D;
1450     glEnable GL_DEPTH_TEST;
1451     glEnable GL_CULL_FACE;
1452     glShadeModel $::FAST ? GL_FLAT : GL_SMOOTH;
1453    
1454     glMatrixMode GL_PROJECTION;
1455     glLoadIdentity;
1456     glFrustum -1 * ($::WIDTH / $::HEIGHT), 1 * ($::WIDTH / $::HEIGHT), 1, -1, 1, 10000;
1457     #glOrtho 0, $::WIDTH, 0, $::HEIGHT, -10000, 10000;
1458     glMatrixMode GL_MODELVIEW;
1459     glLoadIdentity;
1460    
1461     glPushMatrix;
1462     glTranslate 0, 0, -800;
1463     glScale 1, -1, 1;
1464     glRotate $NOW * 1000 % 36000 / 5, 0, 1, 0;
1465     glRotate $NOW * 1000 % 36000 / 6, 1, 0, 0;
1466     glRotate $NOW * 1000 % 36000 / 7, 0, 0, 1;
1467     glScale 50, 50, 50;
1468    
1469     glInterleavedArrays GL_T2F_N3F_V3F, 0, $r->{v};
1470     while (my ($k, $v) = each %{$r->{g}}) {
1471     glBindTexture GL_TEXTURE_2D, ($demo{t}{$k}{name} or die);
1472     glDrawElements GL_TRIANGLES, $v->[0], GL_UNSIGNED_SHORT, $v->[1];
1473     }
1474    
1475     glPopMatrix;
1476    
1477     glShadeModel GL_FLAT;
1478     glDisable GL_DEPTH_TEST;
1479     glDisable GL_TEXTURE_2D;
1480     glDepthMask 0;
1481    
1482     $WANT_REFRESH++;
1483     };
1484    
1485     CFClient::SDL_GL_SwapBuffers;
1486     }
1487    
1488     my $refresh_watcher = Event->timer (after => 0, hard => 1, interval => 1 / $MAX_FPS, cb => sub {
1489     $NOW = time;
1490    
1491     ($SDL_CB{$_->{type}} || sub { warn "unhandled event $_->{type}" })->($_)
1492     for CFClient::SDL_PollEvent;
1493    
1494     if (%animate_object) {
1495     $_->animate ($LAST_REFRESH - $NOW) for values %animate_object;
1496     $WANT_REFRESH++;
1497     }
1498    
1499     if ($WANT_REFRESH) {
1500     force_refresh;
1501     } else {
1502     $CAN_REFRESH = 1;
1503     }
1504     });
1505    
1506     sub animation_start {
1507     my ($widget) = @_;
1508     $animate_object{$widget} = $widget;
1509     }
1510    
1511     sub animation_stop {
1512     my ($widget) = @_;
1513     delete $animate_object{$widget};
1514     }
1515    
1516     # check once/second for faces that need to be prefetched
1517     # this should, of course, only run on demand, but
1518     # SDL forces worse things on us....
1519    
1520     Event->timer (after => 1, interval => 0.25, cb => sub {
1521     $CONN->face_prefetch
1522     if $CONN;
1523     });
1524    
1525     %SDL_CB = (
1526     CFClient::SDL_QUIT => sub {
1527     Event::unloop -1;
1528     },
1529     CFClient::SDL_VIDEORESIZE => sub {
1530     },
1531     CFClient::SDL_VIDEOEXPOSE => sub {
1532     CFClient::UI::full_refresh;
1533     },
1534     CFClient::SDL_ACTIVEEVENT => sub {
1535     # printf "active %x %x\n", $SDL_EV->active_gain, $SDL_EV->active_state;#d#
1536     },
1537     CFClient::SDL_KEYDOWN => sub {
1538     if ($_[0]{mod} & CFClient::KMOD_ALT && $_[0]{sym} == 13) {
1539     # alt-enter
1540     video_shutdown;
1541     $CFG->{fullscreen} = !$CFG->{fullscreen};
1542     video_init;
1543     } else {
1544     CFClient::UI::feed_sdl_key_down_event ($_[0]);
1545     }
1546     },
1547     CFClient::SDL_KEYUP => \&CFClient::UI::feed_sdl_key_up_event,
1548     CFClient::SDL_MOUSEMOTION => \&CFClient::UI::feed_sdl_motion_event,
1549     CFClient::SDL_MOUSEBUTTONDOWN => \&CFClient::UI::feed_sdl_button_down_event,
1550     CFClient::SDL_MOUSEBUTTONUP => \&CFClient::UI::feed_sdl_button_up_event,
1551     CFClient::SDL_USEREVENT => sub {
1552     if ($_[0]{code} == 1) {
1553     audio_channel_finished $_[0]{data1};
1554     } elsif ($_[0]{code} == 0) {
1555     audio_music_finished;
1556     }
1557     },
1558     );
1559    
1560     #############################################################################
1561    
1562     $SIG{INT} = $SIG{TERM} = sub { exit };
1563    
1564     {
1565 root 1.29 local $SIG{__DIE__} = sub { CFClient::fatal $_[0] if defined $^S && !$^S };
1566 root 1.1
1567 root 1.28 CFClient::read_cfg "$Crossfire::VARDIR/cfplusrc";
1568 elmex 1.16 CFClient::UI::set_layout ($::CFG->{layout});
1569 root 1.1
1570     my %DEF_CFG = (
1571     sdl_mode => 0,
1572     width => 640,
1573     height => 480,
1574     fullscreen => 0,
1575     fast => 0,
1576     map_scale => 1,
1577     fow_enable => 1,
1578     fow_intensity => 0.45,
1579     fow_smooth => 0,
1580     gui_fontsize => 1,
1581     log_fontsize => 1,
1582     gauge_fontsize=> 1,
1583     gauge_size => 0.35,
1584     stat_fontsize => 1,
1585     mapsize => 100,
1586     host => "crossfire.schmorp.de",
1587     say_command => 'say',
1588     audio_enable => 1,
1589     bgm_enable => 1,
1590     bgm_volume => 0.25,
1591     face_prefetch => 0,
1592     output_sync => 1,
1593     output_count => 1,
1594     );
1595    
1596     while (my ($k, $v) = each %DEF_CFG) {
1597     $CFG->{$k} = $v unless exists $CFG->{$k};
1598     }
1599    
1600     sdl_init;
1601    
1602     @SDL_MODES = reverse
1603     grep $_->[0] >= 640 && $_->[1] >= 480,
1604     CFClient::SDL_ListModes;
1605    
1606     @SDL_MODES or CFClient::fatal "Unable to find a usable video mode\n(hardware accelerated opengl fullscreen)";
1607    
1608     $CFG->{sdl_mode} = 0 if $CFG->{sdl_mode} > @SDL_MODES;
1609    
1610     {
1611     my @fonts = map CFClient::find_rcfile "fonts/$_", qw(
1612     DejaVuSans.ttf
1613     DejaVuSansMono.ttf
1614     DejaVuSans-Bold.ttf
1615     DejaVuSansMono-Bold.ttf
1616     DejaVuSans-Oblique.ttf
1617     DejaVuSansMono-Oblique.ttf
1618     DejaVuSans-BoldOblique.ttf
1619     DejaVuSansMono-BoldOblique.ttf
1620     );
1621    
1622     CFClient::add_font $_ for @fonts;
1623    
1624     CFClient::pango_init;
1625    
1626     $FONT_PROP = new_from_file CFClient::Font $fonts[0];
1627     $FONT_FIXED = new_from_file CFClient::Font $fonts[1];
1628    
1629     $FONT_PROP->make_default;
1630     }
1631    
1632     # compare mono (ft) vs. rgba (cairo)
1633     # ft - 1.8s, cairo 3s, even in alpha-only mode
1634     # for my $rgba (0..1) {
1635     # my $t1 = Time::HiRes::time;
1636     # for (1..1000) {
1637     # my $layout = CFClient::Layout->new ($rgba);
1638     # $layout->set_text ("hallo" x 100);
1639     # $layout->render;
1640     # }
1641     # my $t2 = Time::HiRes::time;
1642     # warn $t2-$t1;
1643     # }
1644    
1645     video_init;
1646     audio_init;
1647     }
1648    
1649     Event::loop;
1650    
1651     END { CFClient::SDL_Quit }
1652    
1653     =head1 NAME
1654    
1655 root 1.28 cfplus - A Crossfire+ and Crossfire game client
1656 root 1.1
1657     =head1 SYNOPSIS
1658    
1659     Just run it - no commandline arguments are supported.
1660    
1661     =head1 USAGE
1662    
1663 root 1.28 cfplus utilises OpenGL for all UI elements and the game. It is supposed to be used
1664 root 1.1 fullscreen and interactively.
1665    
1666 root 1.39 =head1 DEBUGGING
1667    
1668    
1669     CFPLUS_DEBUG - environment variable
1670    
1671     1 draw borders around widgets
1672     2 add low-level widget info to tooltips
1673     4 show fps
1674     8 suppress tooltips
1675    
1676 root 1.1 =head1 AUTHOR
1677    
1678     Marc Lehmann <crossfire@schmorp.de>, Robin Redeker <elmex@ta-sa.org>
1679    
1680    
1681