ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra/Deliantra.pm
Revision: 1.13
Committed: Thu Feb 9 20:54:42 2006 UTC (18 years, 3 months ago) by root
Branch: MAIN
Changes since 1.12: +17 -3 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 elmex 1.1 =head1 NAME
2    
3     Crossfire - Crossfire maphandling
4    
5     =cut
6    
7 root 1.4 package Crossfire;
8    
9 elmex 1.3 our $VERSION = '0.1';
10 elmex 1.1
11     use strict;
12    
13 root 1.7 use base 'Exporter';
14    
15 root 1.13 use Carp ();
16 elmex 1.1 use Storable;
17    
18 elmex 1.11 #XXX: The map_* procedures scream for a map-object
19    
20     our @EXPORT =
21 root 1.12 qw(read_pak read_arch $ARCH TILESIZE editor_archs
22     arch_extends
23 elmex 1.11 map_get_tile_stack map_push_tile_stack map_pop_tile_stack
24     );
25 root 1.7
26 root 1.4 our $LIB = $ENV{CROSSFIRE_LIBDIR}
27 root 1.13 or Carp::croak "\$CROSSFIRE_LIBDIR must be set\n";
28 elmex 1.1
29 root 1.7 sub TILESIZE (){ 32 }
30 elmex 1.1
31 root 1.4 our $ARCH;
32 elmex 1.1
33 root 1.13 our %FIELD_MULTILINE = (
34     msg => "endmsg",
35     );
36    
37     # not used yet, maybe alphabetical is ok
38     our @FIELD_ORDER = (qw(name name_pl));
39    
40     # not used yet, AND NOT CHECKED, should also be BY TYPE
41     our %FIELD_NORMALIZE = (
42     "enter_x" => "hp",
43     "enter_y" => "sp",
44     );
45    
46 root 1.4 sub read_pak($;$) {
47     my ($path, $cache) = @_;
48 elmex 1.1
49     eval {
50 root 1.4 defined $cache
51     && -M $cache < -M $path
52     && Storable::retrieve $cache
53 elmex 1.1 } or do {
54     my %pak;
55    
56     open my $fh, "<:raw", $path
57 root 1.13 or Carp::croak "$_[0]: $!";
58 elmex 1.1 while (<$fh>) {
59     my ($type, $id, $len, $path) = split;
60     $path =~ s/.*\///;
61     read $fh, $pak{$path}, $len;
62     }
63    
64 root 1.4 Storable::nstore \%pak, $cache
65     if defined $cache;
66 elmex 1.1
67     \%pak
68     }
69     }
70    
71     sub read_arch($;$) {
72 root 1.4 my ($path, $cache) = @_;
73    
74     eval {
75     defined $cache
76     && -M $cache < -M $path
77     && Storable::retrieve $cache
78     } or do {
79     my %arc;
80     my ($more, $prev);
81    
82     open my $fh, "<:raw", $path
83 root 1.13 or Carp::croak "$path: $!";
84 elmex 1.1
85 root 1.4 my $parse_block; $parse_block = sub {
86     my %arc = @_;
87 elmex 1.2
88 root 1.4 while (<$fh>) {
89     s/\s+$//;
90     if (/^end$/i) {
91     last;
92     } elsif (/^arch (\S+)$/) {
93     push @{ $arc{inventory} }, $parse_block->(_name => $1);
94     } elsif (/^lore$/) {
95     while (<$fh>) {
96     last if /^endlore\s*$/i;
97     $arc{lore} .= $_;
98     }
99     } elsif (/^msg$/) {
100     while (<$fh>) {
101     last if /^endmsg\s*$/i;
102     $arc{msg} .= $_;
103     }
104     } elsif (/^(\S+)\s*(.*)$/) {
105     $arc{lc $1} = $2;
106     } elsif (/^\s*($|#)/) {
107     #
108     } else {
109     warn "$path: unparsable line '$_' in arch $arc{_name}";
110     }
111     }
112 elmex 1.1
113 root 1.4 \%arc
114     };
115 elmex 1.1
116     while (<$fh>) {
117     s/\s+$//;
118 root 1.4 if (/^more$/i) {
119     $more = $prev;
120     } elsif (/^object (\S+)$/i) {
121     my $name = $1;
122     my $arc = $parse_block->(_name => $name);
123    
124     if ($more) {
125     $more->{more} = $arc;
126     } else {
127     $arc{$name} = $arc;
128 elmex 1.1 }
129 root 1.4 $prev = $arc;
130     $more = undef;
131     } elsif (/^arch (\S+)$/i) {
132     push @{ $arc{arch} }, $parse_block->(_name => $1);
133 elmex 1.1 } elsif (/^\s*($|#)/) {
134     #
135     } else {
136 root 1.4 warn "$path: unparseable top-level line '$_'";
137 elmex 1.1 }
138     }
139    
140 root 1.4 undef $parse_block; # work around bug in perl not freeing $fh etc.
141 elmex 1.2
142 root 1.4 Storable::nstore \%arc, $cache
143     if defined $cache;
144 elmex 1.1
145 root 1.4 \%arc
146 elmex 1.2 }
147 elmex 1.1 }
148    
149 elmex 1.11 # returns the arch/object stack from a tile on a map
150     sub map_get_tile_stack {
151     my ($map, $x, $y) = @_;
152     my $as;
153    
154     if ($x > 0 || $x < $map->{width}
155     || $y > 0 || $y < $map->{height}) {
156    
157     $as = $map->{map}{map}[$x][$y] || [];
158     }
159    
160     return $as;
161     }
162    
163     # pop the topmost arch/object from the stack of a tile on a map
164     sub map_pop_tile_stack {
165     my ($map, $x, $y) = @_;
166    
167     if ($x > 0 || $x < $map->{width}
168     || $y > 0 || $y < $map->{height}) {
169    
170     pop @{$map->{map}{map}[$x][$y]};
171     }
172     }
173    
174     # pushes the arch/object on the stack of a tile on a map
175     sub map_push_tile_stack {
176     my ($map, $x, $y, $arch) = @_;
177    
178     if ($x > 0 || $x < $map->{width}
179     || $y > 0 || $y < $map->{height}) {
180    
181     push @{$map->{map}{map}[$x][$y]}, $arch;
182     }
183     }
184    
185    
186 elmex 1.10 # put all archs into a hash with editor_face as it's key
187     # NOTE: the arrays in the hash values are references to
188     # the archs from $ARCH
189     sub editor_archs {
190     my %paths;
191    
192     for (keys %$ARCH) {
193     my $arch = $ARCH->{$_};
194     push @{$paths{$arch->{editor_folder}}}, \$arch;
195     }
196    
197     return \%paths;
198     }
199    
200     # arch_extends determines how the arch looks like on the map,
201     # bigfaces, linked faces and single faces are handled here
202     # it returns (<xoffset>, <yoffset>, <width>, <height>)
203     # NOTE: non rectangular linked faces are not considered
204     sub arch_extends {
205     my ($a) = @_;
206    
207     my $TC = \%Crossfire::Tilecache::TILECACHE;
208    
209     my $facename =
210     $a->{face} || $ARCH->{$a->{_name}}->{face}
211     or return ();
212    
213     my $tile = $TC->{$facename}
214     or (warn "no gfx found for arch '$facename' in arch_size ()"), return;
215    
216     if ($tile->{w} > 1 || $tile->{h} > 1) {
217     # bigfaces
218     return (0, 0, $tile->{w}, $tile->{h});
219    
220     } elsif ($a->{more}) {
221     # linked faces
222     my ($miw, $mih, $maw, $mah) = (0, 0, 0, 0);
223     do {
224     $miw > (0 + $a->{x}) and $miw = $a->{x};
225     $mih > (0 + $a->{y}) and $mih = $a->{y};
226     $maw < (0 + $a->{x}) and $maw = $a->{x};
227     $mah < (0 + $a->{y}) and $mah = $a->{y};
228     } while $a = $a->{more};
229    
230     return ($miw, $mih, ($maw - $miw) + 1, ($mah - $mih) + 1)
231    
232     } else {
233     # single face
234     return (0, 0, 1, 1);
235     }
236     }
237    
238 root 1.4 sub init($) {
239     my ($cachedir) = @_;
240 elmex 1.1
241 root 1.4 $ARCH = read_arch "$LIB/archetypes", "$cachedir/archetypes.pst";
242 elmex 1.1 }
243    
244     =head1 AUTHOR
245    
246     Marc Lehmann <schmorp@schmorp.de>
247     http://home.schmorp.de/
248    
249     Robin Redeker <elmex@ta-sa.org>
250     http://www.ta-sa.org/
251    
252     =cut
253 root 1.4
254     1