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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines