ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC.pm
Revision: 1.82
Committed: Wed May 31 07:13:50 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.81: +1 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3 root 1.22 CFClient - undocumented utility garbage for our crossfire client
4 root 1.1
5     =head1 SYNOPSIS
6    
7 root 1.22 use CFClient;
8 root 1.1
9     =head1 DESCRIPTION
10    
11     =over 4
12    
13     =cut
14    
15 root 1.22 package CFClient;
16 root 1.1
17     BEGIN {
18     $VERSION = '0.1';
19    
20 root 1.2 use XSLoader;
21 root 1.22 XSLoader::load "CFClient", $VERSION;
22 root 1.1 }
23    
24 root 1.62 use utf8;
25    
26 root 1.43 use Carp ();
27 root 1.52 use AnyEvent ();
28 root 1.34 use BerkeleyDB;
29 root 1.52
30 root 1.5 sub find_rcfile($) {
31     my $path;
32    
33 root 1.46 for (grep !ref, @INC) {
34 root 1.22 $path = "$_/CFClient/resources/$_[0]";
35 root 1.5 return $path if -r $path;
36     }
37    
38     die "FATAL: can't find required file $_[0]\n";
39     }
40    
41     sub read_cfg {
42     my ($file) = @_;
43    
44     open CFG, $file
45     or return;
46    
47     my $CFG;
48    
49     local $/;
50     $CFG = eval <CFG>;
51    
52     $::CFG = $CFG;
53    
54     close CFG;
55     }
56    
57     sub write_cfg {
58     my ($file) = @_;
59    
60     open CFG, ">$file"
61     or return;
62    
63     {
64 elmex 1.9 require Data::Dumper;
65 root 1.5 local $Data::Dumper::Purity = 1;
66     $::CFG->{VERSION} = $::VERSION;
67     print CFG Data::Dumper->Dump ([$::CFG], [qw/CFG/]);
68     }
69    
70     close CFG;
71     }
72    
73 root 1.75 mkdir "$Crossfire::VARDIR/cfplus", 0777;
74 root 1.34
75 root 1.77 our $DB_ENV;
76    
77 root 1.76 {
78     use strict;
79    
80 root 1.77 my $recover = $BerkeleyDB::db_version >= 4.4
81     ? eval "DB_REGISTER | DB_RECOVER"
82     : 0;
83 root 1.82 warn $recover;
84 root 1.77
85     $DB_ENV = new BerkeleyDB::Env
86 root 1.76 -Home => "$Crossfire::VARDIR/cfplus",
87     -Cachesize => 1_000_000,
88     -ErrFile => "$Crossfire::VARDIR/cfplus/errorlog.txt",
89 root 1.39 # -ErrPrefix => "DATABASE",
90 root 1.76 -Verbose => 1,
91 root 1.77 -Flags => DB_CREATE | DB_RECOVER | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_TXN | $recover,
92 root 1.78 -SetFlags => DB_AUTO_COMMIT | DB_LOG_AUTOREMOVE,
93 root 1.76 or die "unable to create/open database home $Crossfire::VARDIR/cfplus: $BerkeleyDB::Error";
94     }
95 root 1.34
96     sub db_table($) {
97 root 1.38 my ($table) = @_;
98    
99     $table =~ s/([^a-zA-Z0-9_\-])/sprintf "=%x=", ord $1/ge;
100 root 1.76
101 root 1.34 new CFClient::Database
102     -Env => $DB_ENV,
103 root 1.38 -Filename => $table,
104     # -Filename => "database",
105     # -Subname => $table,
106 root 1.51 -Property => DB_CHKSUM,
107 root 1.34 -Flags => DB_CREATE | DB_UPGRADE,
108 root 1.76 or die "unable to create/open database table $_[0]: $BerkeleyDB::Error"
109 root 1.34 }
110    
111 root 1.52 sub pod_to_pango($) {
112     my ($pom) = @_;
113    
114     $pom->present ("CFClient::PodToPango")
115     }
116    
117 root 1.60 sub pod_to_pango_list($) {
118     my ($pom) = @_;
119    
120     [
121     map s/^(\s*)// && [40 * length $1, length $_ ? $_ : " "],
122     split /\n/, $pom->present ("CFClient::PodToPango")
123     ]
124     }
125    
126 root 1.52 package CFClient::PodToPango;
127    
128     use base Pod::POM::View::Text;
129    
130     our $indent = 0;
131    
132     *view_seq_code =
133     *view_seq_bold = sub { "<b>$_[1]</b>" };
134     *view_seq_italic = sub { "<i>$_[1]</i>" };
135     *view_seq_space =
136     *view_seq_link =
137     *view_seq_index = sub { CFClient::UI::Label::escape ($_[1]) };
138    
139     sub view_seq_text {
140     my $text = $_[1];
141     $text =~ s/\s+/ /g;
142     CFClient::UI::Label::escape ($text)
143     }
144    
145     sub view_item {
146     ("\t" x ($indent / 4))
147     . $_[1]->title->present ($_[0])
148     . "\n"
149     . $_[1]->content->present ($_[0])
150     }
151    
152 root 1.53 sub view_verbatim {
153     (join "",
154 root 1.69 map +("\t" x ($indent / 2)) . "<tt>$_</tt>\n",
155 root 1.53 split /\n/, CFClient::UI::Label::escape ($_[1]))
156     . "\n"
157     }
158    
159 root 1.52 sub view_textblock {
160     ("\t" x ($indent / 2)) . "$_[1]\n\n"
161     }
162    
163 root 1.60 sub view_head1 {
164 root 1.69 "\n\n<span foreground='#ffff00' size='x-large'>" . $_[1]->title->present ($_[0]) . "</span>\n\n"
165 root 1.60 . $_[1]->content->present ($_[0])
166     };
167    
168 root 1.52 sub view_head2 {
169 root 1.69 "\n<span foreground='#ccccff' size='large'>" . $_[1]->title->present ($_[0]) . "</span>\n\n"
170     . $_[1]->content->present ($_[0])
171     };
172    
173     sub view_head3 {
174     "\n<span size='large'>" . $_[1]->title->present ($_[0]) . "</span>\n\n"
175 root 1.52 . $_[1]->content->present ($_[0])
176     };
177    
178     sub view_over {
179     local $indent = $indent + $_[1]->indent;
180     $_[1]->content->present ($_[0])
181     }
182    
183 root 1.34 package CFClient::Database;
184    
185     our @ISA = BerkeleyDB::Btree::;
186    
187     sub get($$) {
188     my $data;
189    
190     $_[0]->db_get ($_[1], $data) == 0
191     ? $data
192 root 1.37 : ()
193 root 1.34 }
194    
195     my %DB_SYNC;
196    
197     sub put($$$) {
198     my ($db, $key, $data) = @_;
199    
200 root 1.37 $DB_SYNC{$db} = AnyEvent->timer (after => 5, cb => sub { $db->db_sync });
201 root 1.34
202 root 1.37 $db->db_put ($key => $data)
203 root 1.34 }
204    
205 root 1.62 package CFClient::Item;
206    
207 root 1.71 use strict;
208     use Crossfire::Protocol::Constants;
209    
210 root 1.62 sub desc_string {
211     my ($self) = @_;
212    
213     my $desc =
214     $self->{nrof} < 2
215     ? $self->{name}
216     : "$self->{nrof} × $self->{name_pl}";
217    
218 root 1.71 $self->{flags} & F_OPEN
219 root 1.62 and $desc .= " (open)";
220 root 1.71 $self->{flags} & F_APPLIED
221 root 1.62 and $desc .= " (applied)";
222 root 1.71 $self->{flags} & F_UNPAID
223 root 1.62 and $desc .= " (unpaid)";
224 root 1.71 $self->{flags} & F_MAGIC
225 root 1.62 and $desc .= " (magic)";
226 root 1.71 $self->{flags} & F_CURSED
227 root 1.62 and $desc .= " (cursed)";
228 root 1.71 $self->{flags} & F_DAMNED
229 root 1.62 and $desc .= " (damned)";
230 root 1.71 $self->{flags} & F_LOCKED
231 root 1.62 and $desc .= " *";
232    
233     $desc
234     }
235    
236     sub weight_string {
237     my ($self) = @_;
238    
239     my $weight = ($self->{nrof} || 1) * $self->{weight};
240    
241     $weight < 0 ? "?" : $weight * 0.001
242     }
243    
244     sub update_widgets {
245     my ($self) = @_;
246    
247 root 1.63 my $button_cb = sub {
248     my (undef, $ev, $x, $y) = @_;
249    
250     if (($ev->{mod} & CFClient::KMOD_SHIFT) && $ev->{button} == 1) {
251     my $targ = $::CONN->{player}{tag};
252    
253     if ($self->{container} == $::CONN->{player}{tag}) {
254 elmex 1.64 $targ = $::CONN->{open_container};
255 root 1.63 }
256    
257 root 1.79 $::CONN->send ("move $targ $self->{tag} 0")
258     if $targ || !($self->{flags} & F_LOCKED);
259 root 1.63 } elsif ($ev->{button} == 1) {
260     $::CONN->send ("examine $self->{tag}");
261     } elsif ($ev->{button} == 2) {
262     $::CONN->send ("apply $self->{tag}");
263     } elsif ($ev->{button} == 3) {
264     my @menu_items = (
265     ["examine", sub { $::CONN->send ("examine $self->{tag}") }],
266     ["mark", sub { $::CONN->send ("mark ". pack "N", $self->{tag}) }],
267     ["apply", sub { $::CONN->send ("apply $self->{tag}") }],
268     (
269 root 1.71 $self->{flags} & F_LOCKED
270 root 1.63 ? (
271     ["unlock", sub { $::CONN->send ("lock " . pack "CN", 0, $self->{tag}) }],
272     )
273     : (
274     ["lock", sub { $::CONN->send ("lock " . pack "CN", 1, $self->{tag}) }],
275 elmex 1.64 ["drop", sub { $::CONN->send ("move $::CONN->{open_container} $self->{tag} 0") }],
276 root 1.63 )
277     ),
278     );
279    
280     CFClient::UI::Menu->new (items => \@menu_items)->popup ($ev);
281     }
282    
283     1
284     };
285    
286 root 1.62 my $tooltip_std = "<small>"
287     . "Left click - examine item\n"
288     . "Shift-Left click - " . ($self->{container} ? "move or drop" : "take") . " item\n"
289     . "Middle click - apply\n"
290     . "Right click - further options"
291     . "</small>\n";
292    
293 root 1.63 $self->{face_widget} ||= new CFClient::UI::Face
294     can_events => 1,
295     can_hover => 1,
296 root 1.67 anim => $self->{anim},
297 root 1.66 animspeed => $self->{animspeed}, # TODO# must be set at creation time
298 root 1.72 on_button_down => $button_cb,
299 root 1.63 ;
300 root 1.62 $self->{face_widget}{face} = $self->{face};
301     $self->{face_widget}{anim} = $self->{anim};
302 root 1.65 $self->{face_widget}{animspeed} = $self->{animspeed};
303 root 1.62 $self->{face_widget}->set_tooltip (
304     "<b>Face/Animation.</b>\n"
305     . "Item uses face #$self->{face}. "
306     . ($self->{animspeed} ? "Item uses animation #$self->{anim} at " . (1 / $self->{animspeed}) . "fps. " : "Item is not animated. ")
307     . "\n\n$tooltip_std"
308     );
309    
310 root 1.63 $self->{desc_widget} ||= new CFClient::UI::Label
311     can_events => 1,
312     can_hover => 1,
313     ellipsise => 2,
314 root 1.68 align => -1,
315 root 1.72 on_button_down => $button_cb,
316 root 1.63 ;
317     my $desc = CFClient::Item::desc_string $self;
318     $self->{desc_widget}->set_text ($desc);
319     $self->{desc_widget}->set_tooltip ("<b>$desc</b>.\n$tooltip_std");
320    
321     $self->{weight_widget} ||= new CFClient::UI::Label
322     can_events => 1,
323     can_hover => 1,
324     ellipsise => 0,
325 root 1.68 align => 0,
326 root 1.72 on_button_down => $button_cb,
327 root 1.63 ;
328 root 1.62 $self->{weight_widget}->set_text (CFClient::Item::weight_string $self);
329    
330     $self->{weight_widget}->set_tooltip (
331     "<b>Weight</b>.\n"
332     . ($self->{weight} >= 0 ? "One item weighs $self->{weight}g. " : "You have no idea how much this weighs. ")
333     . ($self->{nrof} ? "You have $self->{nrof} of it. " : "Item cannot stack with others of it's kind. ")
334     . "\n\n$tooltip_std"
335     );
336     }
337    
338 elmex 1.81 package CFClient::Binder;
339 elmex 1.73
340     my @ALLOWED_MODIFIER_KEYS = (
341 elmex 1.81 (CFClient::SDLK_LSHIFT),
342     (CFClient::SDLK_LCTRL ),
343     (CFClient::SDLK_LALT ),
344     (CFClient::SDLK_LMETA ),
345    
346     (CFClient::SDLK_RSHIFT),
347     (CFClient::SDLK_RCTRL ),
348     (CFClient::SDLK_RALT ),
349     (CFClient::SDLK_RMETA ),
350 elmex 1.73 );
351    
352     my %ALLOWED_MODIFIERS = (
353     (CFClient::KMOD_LSHIFT) => "LSHIFT",
354     (CFClient::KMOD_LCTRL ) => "LCTRL",
355     (CFClient::KMOD_LALT ) => "LALT",
356     (CFClient::KMOD_LMETA ) => "LMETA",
357    
358     (CFClient::KMOD_RSHIFT) => "RSHIFT",
359     (CFClient::KMOD_RCTRL ) => "RCTRL",
360     (CFClient::KMOD_RALT ) => "RALT",
361     (CFClient::KMOD_RMETA ) => "RMETA",
362     );
363    
364     my %DIRECT_BIND_CHARS = map { $_ => 1 } qw/0 1 2 3 4 5 6 7 8 9/;
365     my @DIRECT_BIND_KEYS = (
366     CFClient::SDLK_F1,
367     CFClient::SDLK_F2,
368     CFClient::SDLK_F3,
369     CFClient::SDLK_F4,
370     CFClient::SDLK_F5,
371     CFClient::SDLK_F6,
372     CFClient::SDLK_F7,
373     CFClient::SDLK_F8,
374     CFClient::SDLK_F9,
375     CFClient::SDLK_F10,
376     CFClient::SDLK_F11,
377     CFClient::SDLK_F12,
378     CFClient::SDLK_F13,
379     CFClient::SDLK_F14,
380     CFClient::SDLK_F15,
381     );
382    
383     # this binding dialog asks for a key-combo to be pressed
384 elmex 1.81 # and if successful it calls the $cb with $mod and $sym as args.
385 elmex 1.73 sub open_binding_dialog {
386 elmex 1.81 my ($cb) = @_;
387 elmex 1.73
388     my $w = new CFClient::UI::FancyFrame
389 elmex 1.80 title => "Bind Action",
390     x => "center",
391     y => "center";
392 elmex 1.73
393     $w->add (my $vb = new CFClient::UI::VBox);
394     $vb->add (new CFClient::UI::Label
395     text => "Press a modifier (CTRL, ALT and/or SHIFT) and a key."
396     ."You can only bind 0-9 and F1-F15 without modifiers."
397     );
398     $vb->add (my $entry = new CFClient::UI::Entry
399     text => "",
400     on_key_down => sub {
401     my ($entry, $ev) = @_;
402    
403     my $mod = $ev->{mod};
404     my $sym = $ev->{sym};
405    
406     # XXX: This seems a little bit hackisch to me, but i have to ignore them
407     if (grep { $_ == $sym } @ALLOWED_MODIFIER_KEYS) {
408     return;
409     }
410    
411     if ($mod == CFClient::KMOD_NONE
412     and not $DIRECT_BIND_CHARS{chr ($ev->{unicode})}
413     and not grep { $sym == $_ } @DIRECT_BIND_KEYS)
414     {
415     $::STATUSBOX->add (
416     "Can't bind key ".CFClient::SDL_GetKeyName ($sym)
417     ." directly without modifier! It would damage the completer handling."
418     );
419     return;
420     }
421    
422     $entry->focus_out;
423    
424 elmex 1.81 $cb->($mod, $sym);
425 elmex 1.73
426     $w->destroy
427     });
428    
429     $entry->focus_in;
430     $w->show;
431     }
432    
433     sub keycombo_to_name {
434     my ($mod, $sym) = @_;
435    
436     my $mods = join '+',
437     map { $ALLOWED_MODIFIERS{$_} }
438 elmex 1.81 grep { ($_ + 0) & ($mod + 0) }
439 elmex 1.73 keys %ALLOWED_MODIFIERS;
440     $mods .= "+" if $mods ne '';
441    
442     return $mods . CFClient::SDL_GetKeyName ($sym);
443     }
444    
445 root 1.1 1;
446    
447     =back
448    
449     =head1 AUTHOR
450    
451     Marc Lehmann <schmorp@schmorp.de>
452     http://home.schmorp.de/
453    
454     =cut
455