ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra-Client/DC.pm
Revision: 1.84
Committed: Wed May 31 12:44:17 2006 UTC (17 years, 11 months ago) by elmex
Branch: MAIN
Changes since 1.83: +33 -5 lines
Log Message:
implemented dropping/moving of a specific count of items

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 elmex 1.84 my $last_enter_count = 1;
210    
211 root 1.62 sub desc_string {
212     my ($self) = @_;
213    
214     my $desc =
215     $self->{nrof} < 2
216     ? $self->{name}
217     : "$self->{nrof} × $self->{name_pl}";
218    
219 root 1.71 $self->{flags} & F_OPEN
220 root 1.62 and $desc .= " (open)";
221 root 1.71 $self->{flags} & F_APPLIED
222 root 1.62 and $desc .= " (applied)";
223 root 1.71 $self->{flags} & F_UNPAID
224 root 1.62 and $desc .= " (unpaid)";
225 root 1.71 $self->{flags} & F_MAGIC
226 root 1.62 and $desc .= " (magic)";
227 root 1.71 $self->{flags} & F_CURSED
228 root 1.62 and $desc .= " (cursed)";
229 root 1.71 $self->{flags} & F_DAMNED
230 root 1.62 and $desc .= " (damned)";
231 root 1.71 $self->{flags} & F_LOCKED
232 root 1.62 and $desc .= " *";
233    
234     $desc
235     }
236    
237     sub weight_string {
238     my ($self) = @_;
239    
240     my $weight = ($self->{nrof} || 1) * $self->{weight};
241    
242     $weight < 0 ? "?" : $weight * 0.001
243     }
244    
245 elmex 1.84 sub do_n_dialog {
246     my ($cb) = @_;
247    
248     my $w = new CFClient::UI::FancyFrame;
249     $w->add (my $vb = new CFClient::UI::VBox x => "center", y => "center");
250     $vb->add (new CFClient::UI::Label text => "Enter item count:");
251     $vb->add (my $entry = new CFClient::UI::Entry
252     text => $last_enter_count,
253     on_activate => sub {
254     my ($entry) = @_;
255     $last_enter_count = $entry->get_text;
256     $cb->($last_enter_count);
257     $w->hide;
258     $w = undef;
259     }
260     );
261     $entry->focus_in;
262     $w->show;
263    
264     }
265    
266 root 1.62 sub update_widgets {
267     my ($self) = @_;
268    
269 root 1.63 my $button_cb = sub {
270     my (undef, $ev, $x, $y) = @_;
271    
272 elmex 1.84 my $targ = $::CONN->{player}{tag};
273 root 1.63
274 elmex 1.84 if ($self->{container} == $::CONN->{player}{tag}) {
275     $targ = $::CONN->{open_container};
276     }
277 root 1.63
278 elmex 1.84 if (($ev->{mod} & CFClient::KMOD_SHIFT) && $ev->{button} == 1) {
279 root 1.79 $::CONN->send ("move $targ $self->{tag} 0")
280     if $targ || !($self->{flags} & F_LOCKED);
281 root 1.63 } elsif ($ev->{button} == 1) {
282     $::CONN->send ("examine $self->{tag}");
283     } elsif ($ev->{button} == 2) {
284     $::CONN->send ("apply $self->{tag}");
285     } elsif ($ev->{button} == 3) {
286     my @menu_items = (
287     ["examine", sub { $::CONN->send ("examine $self->{tag}") }],
288     ["mark", sub { $::CONN->send ("mark ". pack "N", $self->{tag}) }],
289     ["apply", sub { $::CONN->send ("apply $self->{tag}") }],
290     (
291 root 1.71 $self->{flags} & F_LOCKED
292 root 1.63 ? (
293     ["unlock", sub { $::CONN->send ("lock " . pack "CN", 0, $self->{tag}) }],
294     )
295     : (
296     ["lock", sub { $::CONN->send ("lock " . pack "CN", 1, $self->{tag}) }],
297 elmex 1.64 ["drop", sub { $::CONN->send ("move $::CONN->{open_container} $self->{tag} 0") }],
298 elmex 1.84 ["move n",
299     sub {
300     do_n_dialog (sub { $::CONN->send ("move $targ $self->{tag} $_[0]") })
301     }
302     ]
303 root 1.63 )
304     ),
305     );
306    
307     CFClient::UI::Menu->new (items => \@menu_items)->popup ($ev);
308     }
309    
310     1
311     };
312    
313 root 1.62 my $tooltip_std = "<small>"
314     . "Left click - examine item\n"
315     . "Shift-Left click - " . ($self->{container} ? "move or drop" : "take") . " item\n"
316     . "Middle click - apply\n"
317     . "Right click - further options"
318     . "</small>\n";
319    
320 root 1.63 $self->{face_widget} ||= new CFClient::UI::Face
321     can_events => 1,
322     can_hover => 1,
323 root 1.67 anim => $self->{anim},
324 root 1.66 animspeed => $self->{animspeed}, # TODO# must be set at creation time
325 root 1.72 on_button_down => $button_cb,
326 root 1.63 ;
327 root 1.62 $self->{face_widget}{face} = $self->{face};
328     $self->{face_widget}{anim} = $self->{anim};
329 root 1.65 $self->{face_widget}{animspeed} = $self->{animspeed};
330 root 1.62 $self->{face_widget}->set_tooltip (
331     "<b>Face/Animation.</b>\n"
332     . "Item uses face #$self->{face}. "
333     . ($self->{animspeed} ? "Item uses animation #$self->{anim} at " . (1 / $self->{animspeed}) . "fps. " : "Item is not animated. ")
334     . "\n\n$tooltip_std"
335     );
336    
337 root 1.63 $self->{desc_widget} ||= new CFClient::UI::Label
338     can_events => 1,
339     can_hover => 1,
340     ellipsise => 2,
341 root 1.68 align => -1,
342 root 1.72 on_button_down => $button_cb,
343 root 1.63 ;
344     my $desc = CFClient::Item::desc_string $self;
345     $self->{desc_widget}->set_text ($desc);
346     $self->{desc_widget}->set_tooltip ("<b>$desc</b>.\n$tooltip_std");
347    
348     $self->{weight_widget} ||= new CFClient::UI::Label
349     can_events => 1,
350     can_hover => 1,
351     ellipsise => 0,
352 root 1.68 align => 0,
353 root 1.72 on_button_down => $button_cb,
354 root 1.63 ;
355 root 1.62 $self->{weight_widget}->set_text (CFClient::Item::weight_string $self);
356    
357     $self->{weight_widget}->set_tooltip (
358     "<b>Weight</b>.\n"
359     . ($self->{weight} >= 0 ? "One item weighs $self->{weight}g. " : "You have no idea how much this weighs. ")
360     . ($self->{nrof} ? "You have $self->{nrof} of it. " : "Item cannot stack with others of it's kind. ")
361     . "\n\n$tooltip_std"
362     );
363     }
364    
365 elmex 1.81 package CFClient::Binder;
366 elmex 1.73
367     my @ALLOWED_MODIFIER_KEYS = (
368 elmex 1.81 (CFClient::SDLK_LSHIFT),
369     (CFClient::SDLK_LCTRL ),
370     (CFClient::SDLK_LALT ),
371     (CFClient::SDLK_LMETA ),
372    
373     (CFClient::SDLK_RSHIFT),
374     (CFClient::SDLK_RCTRL ),
375     (CFClient::SDLK_RALT ),
376     (CFClient::SDLK_RMETA ),
377 elmex 1.73 );
378    
379     my %ALLOWED_MODIFIERS = (
380     (CFClient::KMOD_LSHIFT) => "LSHIFT",
381     (CFClient::KMOD_LCTRL ) => "LCTRL",
382     (CFClient::KMOD_LALT ) => "LALT",
383     (CFClient::KMOD_LMETA ) => "LMETA",
384    
385     (CFClient::KMOD_RSHIFT) => "RSHIFT",
386     (CFClient::KMOD_RCTRL ) => "RCTRL",
387     (CFClient::KMOD_RALT ) => "RALT",
388     (CFClient::KMOD_RMETA ) => "RMETA",
389     );
390    
391     my %DIRECT_BIND_CHARS = map { $_ => 1 } qw/0 1 2 3 4 5 6 7 8 9/;
392     my @DIRECT_BIND_KEYS = (
393     CFClient::SDLK_F1,
394     CFClient::SDLK_F2,
395     CFClient::SDLK_F3,
396     CFClient::SDLK_F4,
397     CFClient::SDLK_F5,
398     CFClient::SDLK_F6,
399     CFClient::SDLK_F7,
400     CFClient::SDLK_F8,
401     CFClient::SDLK_F9,
402     CFClient::SDLK_F10,
403     CFClient::SDLK_F11,
404     CFClient::SDLK_F12,
405     CFClient::SDLK_F13,
406     CFClient::SDLK_F14,
407     CFClient::SDLK_F15,
408     );
409    
410     # this binding dialog asks for a key-combo to be pressed
411 elmex 1.81 # and if successful it calls the $cb with $mod and $sym as args.
412 elmex 1.73 sub open_binding_dialog {
413 elmex 1.81 my ($cb) = @_;
414 elmex 1.73
415     my $w = new CFClient::UI::FancyFrame
416 elmex 1.80 title => "Bind Action",
417     x => "center",
418     y => "center";
419 elmex 1.73
420     $w->add (my $vb = new CFClient::UI::VBox);
421     $vb->add (new CFClient::UI::Label
422     text => "Press a modifier (CTRL, ALT and/or SHIFT) and a key."
423     ."You can only bind 0-9 and F1-F15 without modifiers."
424     );
425     $vb->add (my $entry = new CFClient::UI::Entry
426     text => "",
427     on_key_down => sub {
428     my ($entry, $ev) = @_;
429    
430     my $mod = $ev->{mod};
431     my $sym = $ev->{sym};
432    
433     # XXX: This seems a little bit hackisch to me, but i have to ignore them
434     if (grep { $_ == $sym } @ALLOWED_MODIFIER_KEYS) {
435     return;
436     }
437    
438     if ($mod == CFClient::KMOD_NONE
439     and not $DIRECT_BIND_CHARS{chr ($ev->{unicode})}
440     and not grep { $sym == $_ } @DIRECT_BIND_KEYS)
441     {
442     $::STATUSBOX->add (
443     "Can't bind key ".CFClient::SDL_GetKeyName ($sym)
444     ." directly without modifier! It would damage the completer handling."
445     );
446     return;
447     }
448    
449     $entry->focus_out;
450    
451 elmex 1.81 $cb->($mod, $sym);
452 elmex 1.73
453     $w->destroy
454     });
455    
456     $entry->focus_in;
457     $w->show;
458     }
459    
460     sub keycombo_to_name {
461     my ($mod, $sym) = @_;
462    
463     my $mods = join '+',
464     map { $ALLOWED_MODIFIERS{$_} }
465 elmex 1.81 grep { ($_ + 0) & ($mod + 0) }
466 elmex 1.73 keys %ALLOWED_MODIFIERS;
467     $mods .= "+" if $mods ne '';
468    
469     return $mods . CFClient::SDL_GetKeyName ($sym);
470     }
471    
472 root 1.1 1;
473    
474     =back
475    
476     =head1 AUTHOR
477    
478     Marc Lehmann <schmorp@schmorp.de>
479     http://home.schmorp.de/
480    
481     =cut
482