ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC.pm
Revision: 1.83
Committed: Wed May 31 07:40:33 2006 UTC (17 years, 11 months ago) by root
Branch: MAIN
Changes since 1.82: +0 -1 lines
Log Message:
fix output-count/sync setting

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