ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra/Deliantra.pm
(Generate patch)

Comparing deliantra/Deliantra/Deliantra.pm (file contents):
Revision 1.85 by root, Wed Feb 7 00:44:18 2007 UTC vs.
Revision 1.104 by root, Mon Apr 16 12:32:30 2007 UTC

4 4
5=cut 5=cut
6 6
7package Crossfire; 7package Crossfire;
8 8
9our $VERSION = '0.96'; 9our $VERSION = '0.98';
10 10
11use strict; 11use strict;
12 12
13use base 'Exporter'; 13use base 'Exporter';
14 14
19 19
20our @EXPORT = qw( 20our @EXPORT = qw(
21 read_pak read_arch *ARCH TILESIZE $TILE *FACE editor_archs arch_extents 21 read_pak read_arch *ARCH TILESIZE $TILE *FACE editor_archs arch_extents
22); 22);
23 23
24use JSON::Syck (); #TODO#d# replace by JSON::PC when it becomes available == working 24use JSON::XS qw(from_json to_json);
25
26sub from_json($) {
27 $JSON::Syck::ImplicitUnicode = 1;
28 JSON::Syck::Load $_[0]
29}
30
31sub to_json($) {
32 $JSON::Syck::ImplicitUnicode = 0;
33 JSON::Syck::Dump $_[0]
34}
35 25
36our $LIB = $ENV{CROSSFIRE_LIBDIR}; 26our $LIB = $ENV{CROSSFIRE_LIBDIR};
37 27
38our $VARDIR = $ENV{HOME} ? "$ENV{HOME}/.crossfire" 28our $VARDIR = $ENV{HOME} ? "$ENV{HOME}/.crossfire"
39 : $ENV{AppData} ? "$ENV{APPDATA}/crossfire" 29 : $ENV{AppData} ? "$ENV{APPDATA}/crossfire"
58 qw(move_type move_block move_allow move_on move_off move_slow); 48 qw(move_type move_block move_allow move_on move_off move_slow);
59 49
60# same as in server save routine, to (hopefully) be compatible 50# same as in server save routine, to (hopefully) be compatible
61# to the other editors. 51# to the other editors.
62our @FIELD_ORDER_MAP = (qw( 52our @FIELD_ORDER_MAP = (qw(
53 file_format_version
63 name attach swap_time reset_timeout fixed_resettime difficulty region 54 name attach swap_time reset_timeout fixed_resettime difficulty region
64 shopitems shopgreed shopmin shopmax shoprace 55 shopitems shopgreed shopmin shopmax shoprace
65 darkness width height enter_x enter_y msg maplore 56 darkness width height enter_x enter_y msg maplore
66 unique template 57 unique template
67 outdoor temp pressure humid windspeed winddir sky nosmooth 58 outdoor temp pressure humid windspeed winddir sky nosmooth
70 61
71our @FIELD_ORDER = (qw( 62our @FIELD_ORDER = (qw(
72 elevation 63 elevation
73 64
74 name name_pl custom_name attach title race 65 name name_pl custom_name attach title race
75 slaying skill msg lore other_arch face 66 slaying skill msg lore other_arch
76 #todo-events
77 animation is_animated 67 face animation is_animated
68 magicmap smoothlevel smoothface
78 str dex con wis pow cha int 69 str dex con wis pow cha int
79 hp maxhp sp maxsp grace maxgrace 70 hp maxhp sp maxsp grace maxgrace
80 exp perm_exp expmul 71 exp perm_exp expmul
81 food dam luck wc ac x y speed speed_left move_state attack_movement 72 food dam luck wc ac x y speed speed_left move_state attack_movement
82 nrof level direction type subtype attacktype 73 nrof level direction type subtype attacktype
138sub MOVE_FLY_HIGH (){ 0x04 } 129sub MOVE_FLY_HIGH (){ 0x04 }
139sub MOVE_FLYING (){ 0x06 } 130sub MOVE_FLYING (){ 0x06 }
140sub MOVE_SWIM (){ 0x08 } 131sub MOVE_SWIM (){ 0x08 }
141sub MOVE_BOAT (){ 0x10 } 132sub MOVE_BOAT (){ 0x10 }
142sub MOVE_KNOWN (){ 0x1f } # all of above 133sub MOVE_KNOWN (){ 0x1f } # all of above
143sub MOVE_ALLBIT (){ 0x10000 }
144sub MOVE_ALL (){ 0x1001f } # very special value, more PITA 134sub MOVE_ALL (){ 0x10000 } # very special value
135
136our %MOVE_TYPE = (
137 walk => MOVE_WALK,
138 fly_low => MOVE_FLY_LOW,
139 fly_high => MOVE_FLY_HIGH,
140 flying => MOVE_FLYING,
141 swim => MOVE_SWIM,
142 boat => MOVE_BOAT,
143 all => MOVE_ALL,
144);
145
146our @MOVE_TYPE = qw(all walk flying fly_low fly_high swim boat);
147
148{
149 package Crossfire::MoveType;
150
151 use overload
152 '=' => sub { bless [@{$_[0]}], ref $_[0] },
153 '""' => \&as_string,
154 '>=' => sub { $_[0][0] & $MOVE_TYPE{$_[1]} ? $_[0][1] & $MOVE_TYPE{$_[1]} : undef },
155 '+=' => sub { $_[0][0] |= $MOVE_TYPE{$_[1]}; $_[0][1] |= $MOVE_TYPE{$_[1]}; &normalise },
156 '-=' => sub { $_[0][0] |= $MOVE_TYPE{$_[1]}; $_[0][1] &= ~$MOVE_TYPE{$_[1]}; &normalise },
157 '/=' => sub { $_[0][0] &= ~$MOVE_TYPE{$_[1]}; &normalise },
158 'x=' => sub {
159 my $cur = $_[0] >= $_[1];
160 if (!defined $cur) {
161 if ($_[0] >= "all") {
162 $_[0] -= $_[1];
163 } else {
164 $_[0] += $_[1];
165 }
166 } elsif ($cur) {
167 $_[0] -= $_[1];
168 } else {
169 $_[0] /= $_[1];
170 }
171
172 $_[0]
173 },
174 'eq' => sub { "$_[0]" eq "$_[1]" },
175 'ne' => sub { "$_[0]" ne "$_[1]" },
176 ;
177}
178
179sub Crossfire::MoveType::new {
180 my ($class, $string) = @_;
181
182 my $mask;
183 my $value;
184
185 if ($string =~ /^\s*\d+\s*$/) {
186 $mask = MOVE_ALL;
187 $value = $string+0;
188 } else {
189 for (split /\s+/, lc $string) {
190 if (s/^-//) {
191 $mask |= $MOVE_TYPE{$_};
192 $value &= ~$MOVE_TYPE{$_};
193 } else {
194 $mask |= $MOVE_TYPE{$_};
195 $value |= $MOVE_TYPE{$_};
196 }
197 }
198 }
199
200 (bless [$mask, $value], $class)->normalise
201}
202
203sub Crossfire::MoveType::normalise {
204 my ($self) = @_;
205
206 if ($self->[0] & MOVE_ALL) {
207 my $mask = ~(($self->[1] & MOVE_ALL ? $self->[1] : ~$self->[1]) & $self->[0] & ~MOVE_ALL);
208 $self->[0] &= $mask;
209 $self->[1] &= $mask;
210 }
211
212 $self->[1] &= $self->[0];
213
214 $self
215}
216
217sub Crossfire::MoveType::as_string {
218 my ($self) = @_;
219
220 my @res;
221
222 my ($mask, $value) = @$self;
223
224 for (@Crossfire::MOVE_TYPE) {
225 my $bit = $Crossfire::MOVE_TYPE{$_};
226 if (($mask & $bit) == $bit && (($value & $bit) == $bit || ($value & $bit) == 0)) {
227 $mask &= ~$bit;
228 push @res, $value & $bit ? $_ : "-$_";
229 }
230 }
231
232 join " ", @res
233}
145 234
146sub load_ref($) { 235sub load_ref($) {
147 my ($path) = @_; 236 my ($path) = @_;
148 237
149 open my $fh, "<:raw:perlio", $path 238 open my $fh, "<:raw:perlio", $path
253 } else { 342 } else {
254 warn "object $ob->{_name} has unknown material ($ob->{material}) set.\n"; 343 warn "object $ob->{_name} has unknown material ($ob->{material}) set.\n";
255 } 344 }
256 } 345 }
257 346
347 # color_fg is used as default for magicmap if magicmap does not exist
348 $ob->{magicmap} ||= delete $ob->{color_fg} if exists $ob->{color_fg};
349
258 # nuke outdated or never supported fields 350 # nuke outdated or never supported fields
259 delete @$ob{qw( 351 delete @$ob{qw(
260 can_knockback can_parry can_impale can_cut can_dam_armour 352 can_knockback can_parry can_impale can_cut can_dam_armour
261 can_apply pass_thru can_pass_thru 353 can_apply pass_thru can_pass_thru color_bg color_fg
262 )}; 354 )};
263 355
264 if (my $mask = delete $ob->{immune} ) { _add_resist $ob, $mask, 100; } 356 if (my $mask = delete $ob->{immune} ) { _add_resist $ob, $mask, 100; }
265 if (my $mask = delete $ob->{protected} ) { _add_resist $ob, $mask, 30; } 357 if (my $mask = delete $ob->{protected} ) { _add_resist $ob, $mask, 30; }
266 if (my $mask = delete $ob->{vulnerable}) { _add_resist $ob, $mask, -100; } 358 if (my $mask = delete $ob->{vulnerable}) { _add_resist $ob, $mask, -100; }
267 359
268 # convert movement strings to bitsets 360 # convert movement strings to bitsets
269 for my $attr (keys %FIELD_MOVEMENT) { 361 for my $attr (keys %FIELD_MOVEMENT) {
270 next unless exists $ob->{$attr}; 362 next unless exists $ob->{$attr};
271 363
272 $ob->{$attr} = MOVE_ALL if $ob->{$attr} == 255; #d# compatibility 364 $ob->{$attr} = new Crossfire::MoveType $ob->{$attr};
273
274 next if $ob->{$attr} =~ /^\d+$/;
275
276 my $flags = 0;
277
278 # assume list
279 for my $flag (map lc, split /\s+/, $ob->{$attr}) {
280 $flags |= MOVE_WALK if $flag eq "walk";
281 $flags |= MOVE_FLY_LOW if $flag eq "fly_low";
282 $flags |= MOVE_FLY_HIGH if $flag eq "fly_high";
283 $flags |= MOVE_FLYING if $flag eq "flying";
284 $flags |= MOVE_SWIM if $flag eq "swim";
285 $flags |= MOVE_BOAT if $flag eq "boat";
286 $flags |= MOVE_ALL if $flag eq "all";
287
288 $flags &= ~MOVE_WALK if $flag eq "-walk";
289 $flags &= ~MOVE_FLY_LOW if $flag eq "-fly_low";
290 $flags &= ~MOVE_FLY_HIGH if $flag eq "-fly_high";
291 $flags &= ~MOVE_FLYING if $flag eq "-flying";
292 $flags &= ~MOVE_SWIM if $flag eq "-swim";
293 $flags &= ~MOVE_BOAT if $flag eq "-boat";
294 $flags &= ~MOVE_ALL if $flag eq "-all";
295 }
296
297 $ob->{$attr} = $flags;
298 } 365 }
299 366
300 # convert outdated movement flags to new movement sets 367 # convert outdated movement flags to new movement sets
301 if (defined (my $v = delete $ob->{no_pass})) { 368 if (defined (my $v = delete $ob->{no_pass})) {
302 $ob->{move_block} = $v ? MOVE_ALL : 0; 369 $ob->{move_block} = new Crossfire::MoveType $v ? "all" : "";
303 } 370 }
304 if (defined (my $v = delete $ob->{slow_move})) { 371 if (defined (my $v = delete $ob->{slow_move})) {
305 $ob->{move_slow} |= MOVE_WALK; 372 $ob->{move_slow} += "walk";
306 $ob->{move_slow_penalty} = $v; 373 $ob->{move_slow_penalty} = $v;
307 } 374 }
308 if (defined (my $v = delete $ob->{walk_on})) { 375 if (defined (my $v = delete $ob->{walk_on})) {
309 $ob->{move_on} = MOVE_ALL unless exists $ob->{move_on}; 376 $ob->{move_on} ||= new Crossfire::MoveType; if ($v) { $ob->{move_on} += "walk" } else { $ob->{move_on} -= "walk" }
310 $ob->{move_on} = $v ? $ob->{move_on} | MOVE_WALK
311 : $ob->{move_on} & ~MOVE_WALK;
312 } 377 }
313 if (defined (my $v = delete $ob->{walk_off})) { 378 if (defined (my $v = delete $ob->{walk_off})) {
314 $ob->{move_off} = MOVE_ALL unless exists $ob->{move_off}; 379 $ob->{move_off} ||= new Crossfire::MoveType; if ($v) { $ob->{move_off} += "walk" } else { $ob->{move_off} -= "walk" }
315 $ob->{move_off} = $v ? $ob->{move_off} | MOVE_WALK
316 : $ob->{move_off} & ~MOVE_WALK;
317 } 380 }
318 if (defined (my $v = delete $ob->{fly_on})) { 381 if (defined (my $v = delete $ob->{fly_on})) {
319 $ob->{move_on} = MOVE_ALL unless exists $ob->{move_on}; 382 $ob->{move_on} ||= new Crossfire::MoveType; if ($v) { $ob->{move_on} += "fly_low" } else { $ob->{move_on} -= "fly_low" }
320 $ob->{move_on} = $v ? $ob->{move_on} | MOVE_FLY_LOW
321 : $ob->{move_on} & ~MOVE_FLY_LOW;
322 } 383 }
323 if (defined (my $v = delete $ob->{fly_off})) { 384 if (defined (my $v = delete $ob->{fly_off})) {
324 $ob->{move_off} = MOVE_ALL unless exists $ob->{move_off}; 385 $ob->{move_off} ||= new Crossfire::MoveType; if ($v) { $ob->{move_off} += "fly_low" } else { $ob->{move_off} -= "fly_low" }
325 $ob->{move_off} = $v ? $ob->{move_off} | MOVE_FLY_LOW
326 : $ob->{move_off} & ~MOVE_FLY_LOW;
327 } 386 }
328 if (defined (my $v = delete $ob->{flying})) { 387 if (defined (my $v = delete $ob->{flying})) {
329 $ob->{move_type} = MOVE_ALL unless exists $ob->{move_type}; 388 $ob->{move_type} ||= new Crossfire::MoveType; if ($v) { $ob->{move_type} += "fly_low" } else { $ob->{move_type} -= "fly_low" }
330 $ob->{move_type} = $v ? $ob->{move_type} | MOVE_FLY_LOW
331 : $ob->{move_type} & ~MOVE_FLY_LOW;
332 } 389 }
333 390
334 # convert idiotic event_xxx things into objects 391 # convert idiotic event_xxx things into objects
335 while (my ($event, $subtype) = each %EVENT_TYPE) { 392 while (my ($event, $subtype) = each %EVENT_TYPE) {
336 if (exists $ob->{"event_${event}_plugin"}) { 393 if (exists $ob->{"event_${event}_plugin"}) {
567 624
568 my $inv = delete $a{inventory}; 625 my $inv = delete $a{inventory};
569 my $more = delete $a{more}; # arches do not support 'more', but old maps can contain some 626 my $more = delete $a{more}; # arches do not support 'more', but old maps can contain some
570 my $anim = delete $a{anim}; 627 my $anim = delete $a{anim};
571 628
629 if ($a{_atype} eq 'object') {
630 $str .= join "\n", "anim", @$anim, "mina\n"
631 if $anim;
632 }
633
572 my @kv; 634 my @kv;
573 635
574 for ($a{_name} eq "map" 636 for ($a{_name} eq "map"
575 ? @Crossfire::FIELD_ORDER_MAP 637 ? @Crossfire::FIELD_ORDER_MAP
576 : @Crossfire::FIELD_ORDER) { 638 : @Crossfire::FIELD_ORDER) {
587 my ($k, $v) = @$_; 649 my ($k, $v) = @$_;
588 650
589 if (my $end = $Crossfire::FIELD_MULTILINE{$k}) { 651 if (my $end = $Crossfire::FIELD_MULTILINE{$k}) {
590 $v =~ s/\n$//; 652 $v =~ s/\n$//;
591 $str .= "$k\n$v\n$end\n"; 653 $str .= "$k\n$v\n$end\n";
592 } elsif (exists $Crossfire::FIELD_MOVEMENT{$k}) {
593 if ($v & ~Crossfire::MOVE_ALL or !$v) {
594 $str .= "$k $v\n";
595
596 } elsif ($v & Crossfire::MOVE_ALLBIT) {
597 $str .= "$k all";
598
599 $str .= " -walk" unless $v & Crossfire::MOVE_WALK;
600 $str .= " -fly_low" unless $v & Crossfire::MOVE_FLY_LOW;
601 $str .= " -fly_high" unless $v & Crossfire::MOVE_FLY_HIGH;
602 $str .= " -swim" unless $v & Crossfire::MOVE_SWIM;
603 $str .= " -boat" unless $v & Crossfire::MOVE_BOAT;
604
605 $str .= "\n";
606
607 } else {
608 $str .= $k;
609
610 $str .= " walk" if $v & Crossfire::MOVE_WALK;
611 $str .= " fly_low" if $v & Crossfire::MOVE_FLY_LOW;
612 $str .= " fly_high" if $v & Crossfire::MOVE_FLY_HIGH;
613 $str .= " swim" if $v & Crossfire::MOVE_SWIM;
614 $str .= " boat" if $v & Crossfire::MOVE_BOAT;
615
616 $str .= "\n";
617 }
618 } else { 654 } else {
619 $str .= "$k $v\n"; 655 $str .= "$k $v\n";
620 } 656 }
621 } 657 }
622 658
623 if ($inv) { 659 if ($inv) {
624 $append->($_) for @$inv; 660 $append->($_) for @$inv;
625 }
626
627 if ($a{_atype} eq 'object') {
628 $str .= join "\n", "anim", @$anim, "mina\n"
629 if $anim;
630 } 661 }
631 662
632 $str .= "end\n"; 663 $str .= "end\n";
633 664
634 if ($a{_atype} eq 'object') { 665 if ($a{_atype} eq 'object') {
795 ]; 826 ];
796 827
797 $attr 828 $attr
798} 829}
799 830
800sub arch_edit_sections {
801# if (edit_type == IGUIConstants.TILE_EDIT_NONE)
802# edit_type = 0;
803# else if (edit_type != 0) {
804# // all flags from 'check_type' must be unset in this arch because they get recalculated now
805# edit_type &= ~check_type;
806# }
807#
808# }
809# if ((check_type & IGUIConstants.TILE_EDIT_MONSTER) != 0 &&
810# getAttributeValue("alive", defarch) == 1 &&
811# (getAttributeValue("monster", defarch) == 1 ||
812# getAttributeValue("generator", defarch) == 1)) {
813# // Monster: monsters/npcs/generators
814# edit_type |= IGUIConstants.TILE_EDIT_MONSTER;
815# }
816# if ((check_type & IGUIConstants.TILE_EDIT_WALL) != 0 &&
817# arch_type == 0 && getAttributeValue("no_pass", defarch) == 1) {
818# // Walls
819# edit_type |= IGUIConstants.TILE_EDIT_WALL;
820# }
821# if ((check_type & IGUIConstants.TILE_EDIT_CONNECTED) != 0 &&
822# getAttributeValue("connected", defarch) != 0) {
823# // Connected Objects
824# edit_type |= IGUIConstants.TILE_EDIT_CONNECTED;
825# }
826# if ((check_type & IGUIConstants.TILE_EDIT_EXIT) != 0 &&
827# arch_type == 66 || arch_type == 41 || arch_type == 95) {
828# // Exit: teleporter/exit/trapdoors
829# edit_type |= IGUIConstants.TILE_EDIT_EXIT;
830# }
831# if ((check_type & IGUIConstants.TILE_EDIT_TREASURE) != 0 &&
832# getAttributeValue("no_pick", defarch) == 0 && (arch_type == 4 ||
833# arch_type == 5 || arch_type == 36 || arch_type == 60 ||
834# arch_type == 85 || arch_type == 111 || arch_type == 123 ||
835# arch_type == 124 || arch_type == 130)) {
836# // Treasure: randomtreasure/money/gems/potions/spellbooks/scrolls
837# edit_type |= IGUIConstants.TILE_EDIT_TREASURE;
838# }
839# if ((check_type & IGUIConstants.TILE_EDIT_DOOR) != 0 &&
840# arch_type == 20 || arch_type == 23 || arch_type == 26 ||
841# arch_type == 91 || arch_type == 21 || arch_type == 24) {
842# // Door: door/special door/gates + keys
843# edit_type |= IGUIConstants.TILE_EDIT_DOOR;
844# }
845# if ((check_type & IGUIConstants.TILE_EDIT_EQUIP) != 0 &&
846# getAttributeValue("no_pick", defarch) == 0 && ((arch_type >= 13 &&
847# arch_type <= 16) || arch_type == 33 || arch_type == 34 ||
848# arch_type == 35 || arch_type == 39 || arch_type == 70 ||
849# arch_type == 87 || arch_type == 99 || arch_type == 100 ||
850# arch_type == 104 || arch_type == 109 || arch_type == 113 ||
851# arch_type == 122 || arch_type == 3)) {
852# // Equipment: weapons/armour/wands/rods
853# edit_type |= IGUIConstants.TILE_EDIT_EQUIP;
854# }
855#
856# return(edit_type);
857#
858#
859}
860
861sub cache_file($$&&) { 831sub cache_file($$&&) {
862 my ($src, $cache, $load, $create) = @_; 832 my ($src, $cache, $load, $create) = @_;
863 833
864 my ($size, $mtime) = (stat $src)[7,9] 834 my ($size, $mtime) = (stat $src)[7,9]
865 or Carp::croak "$src: $!"; 835 or Carp::croak "$src: $!";
913 }, sub { 883 }, sub {
914 read_arch "$LIB/archetypes" 884 read_arch "$LIB/archetypes"
915 }; 885 };
916} 886}
917 887
888sub construct_tilecache_pb {
889 my ($idx, $cache) = @_;
890
891 my $pb = new Gtk2::Gdk::Pixbuf "rgb", 1, 8, 64 * TILESIZE, TILESIZE * int +($idx + 63) / 64;
892
893 while (my ($name, $tile) = each %$cache) {
894 my $tpb = delete $tile->{pb};
895 my $ofs = $tile->{idx};
896
897 for my $x (0 .. $tile->{w} - 1) {
898 for my $y (0 .. $tile->{h} - 1) {
899 my $idx = $ofs + $x + $y * $tile->{w};
900 $tpb->copy_area ($x * TILESIZE, $y * TILESIZE, TILESIZE, TILESIZE,
901 $pb, ($idx % 64) * TILESIZE, TILESIZE * int $idx / 64);
902 }
903 }
904 }
905
906 $pb->save ("$VARDIR/tilecache.png", "png", compression => 1);
907
908 $cache
909}
910
911sub use_tilecache {
912 my ($face) = @_;
913 $TILE = new_from_file Gtk2::Gdk::Pixbuf "$VARDIR/tilecache.png"
914 or die "$VARDIR/tilecache.png: $!";
915 *FACE = $_[0];
916}
917
918=item load_tilecache 918=item load_tilecache
919 919
920(Re-)Load %TILE and %FACE. 920(Re-)Load %TILE and %FACE.
921 921
922=cut 922=cut
923 923
924sub load_tilecache() { 924sub load_tilecache() {
925 require Gtk2; 925 require Gtk2;
926 926
927 if (-e "$LIB/crossfire.0") { # Crossfire1 version
927 cache_file "$LIB/crossfire.0", "$VARDIR/tilecache.pst", sub { 928 cache_file "$LIB/crossfire.0", "$VARDIR/tilecache.pst", \&use_tilecache,
928 $TILE = new_from_file Gtk2::Gdk::Pixbuf "$VARDIR/tilecache.png" 929 sub {
929 or die "$VARDIR/tilecache.png: $!";
930 *FACE = $_[0];
931 }, sub {
932 my $tile = read_pak "$LIB/crossfire.0"; 930 my $tile = read_pak "$LIB/crossfire.0";
933 931
934 my %cache; 932 my %cache;
935 933
936 my $idx = 0; 934 my $idx = 0;
937 935
938 for my $name (sort keys %$tile) { 936 for my $name (sort keys %$tile) {
939 my $pb = new Gtk2::Gdk::PixbufLoader; 937 my $pb = new Gtk2::Gdk::PixbufLoader;
940 $pb->write ($tile->{$name}); 938 $pb->write ($tile->{$name});
941 $pb->close; 939 $pb->close;
942 my $pb = $pb->get_pixbuf; 940 my $pb = $pb->get_pixbuf;
943 941
944 my $tile = $cache{$name} = { 942 my $tile = $cache{$name} = {
945 pb => $pb, 943 pb => $pb,
946 idx => $idx, 944 idx => $idx,
947 w => int $pb->get_width / TILESIZE, 945 w => int $pb->get_width / TILESIZE,
948 h => int $pb->get_height / TILESIZE, 946 h => int $pb->get_height / TILESIZE,
947 };
948
949 $idx += $tile->{w} * $tile->{h};
950 }
951
952 construct_tilecache_pb $idx, \%cache;
953
954 \%cache
949 }; 955 };
956
957 } else { # Crossfire+ version
958 cache_file "$LIB/facedata", "$VARDIR/tilecache.pst", \&use_tilecache,
959 sub {
960 my %cache;
961 my $facedata = Storable::retrieve "$LIB/facedata";
962
963 $facedata->{version} == 2
964 or die "$LIB/facedata: version mismatch, cannot proceed.";
965
966 my $faces = $facedata->{faceinfo};
967 my $idx = 0;
968
969 for (sort keys %$faces) {
970 my ($face, $info) = ($_, $faces->{$_});
971
972 my $pb = new Gtk2::Gdk::PixbufLoader;
973 $pb->write ($info->{data32});
974 $pb->close;
975 my $pb = $pb->get_pixbuf;
976
977 my $tile = $cache{$face} = {
978 pb => $pb,
979 idx => $idx,
980 w => int $pb->get_width / TILESIZE,
981 h => int $pb->get_height / TILESIZE,
950 982 };
951 983
952 $idx += $tile->{w} * $tile->{h}; 984 $idx += $tile->{w} * $tile->{h};
953 }
954
955 my $pb = new Gtk2::Gdk::Pixbuf "rgb", 1, 8, 64 * TILESIZE, TILESIZE * int +($idx + 63) / 64;
956
957 while (my ($name, $tile) = each %cache) {
958 my $tpb = delete $tile->{pb};
959 my $ofs = $tile->{idx};
960
961 for my $x (0 .. $tile->{w} - 1) {
962 for my $y (0 .. $tile->{h} - 1) {
963 my $idx = $ofs + $x + $y * $tile->{w};
964 $tpb->copy_area ($x * TILESIZE, $y * TILESIZE, TILESIZE, TILESIZE,
965 $pb, ($idx % 64) * TILESIZE, TILESIZE * int $idx / 64);
966 } 985 }
986
987 construct_tilecache_pb $idx, \%cache;
988
989 \%cache
967 } 990 };
968 }
969
970 $pb->save ("$VARDIR/tilecache.png", "png", compression => 1);
971
972 \%cache
973 }; 991 }
974} 992}
975 993
976=head1 AUTHOR 994=head1 AUTHOR
977 995
978 Marc Lehmann <schmorp@schmorp.de> 996 Marc Lehmann <schmorp@schmorp.de>

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines