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

# Content
1 =head1 NAME
2
3 Crossfire - Crossfire maphandling
4
5 =cut
6
7 package Crossfire;
8
9 our $VERSION = '0.1';
10
11 use strict;
12
13 use base 'Exporter';
14
15 use Carp ();
16 use Storable;
17
18 #XXX: The map_* procedures scream for a map-object
19
20 our @EXPORT =
21 qw(read_pak read_arch $ARCH TILESIZE editor_archs
22 arch_extends
23 map_get_tile_stack map_push_tile_stack map_pop_tile_stack
24 );
25
26 our $LIB = $ENV{CROSSFIRE_LIBDIR}
27 or Carp::croak "\$CROSSFIRE_LIBDIR must be set\n";
28
29 sub TILESIZE (){ 32 }
30
31 our $ARCH;
32
33 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 sub read_pak($;$) {
47 my ($path, $cache) = @_;
48
49 eval {
50 defined $cache
51 && -M $cache < -M $path
52 && Storable::retrieve $cache
53 } or do {
54 my %pak;
55
56 open my $fh, "<:raw", $path
57 or Carp::croak "$_[0]: $!";
58 while (<$fh>) {
59 my ($type, $id, $len, $path) = split;
60 $path =~ s/.*\///;
61 read $fh, $pak{$path}, $len;
62 }
63
64 Storable::nstore \%pak, $cache
65 if defined $cache;
66
67 \%pak
68 }
69 }
70
71 sub read_arch($;$) {
72 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 or Carp::croak "$path: $!";
84
85 my $parse_block; $parse_block = sub {
86 my %arc = @_;
87
88 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
113 \%arc
114 };
115
116 while (<$fh>) {
117 s/\s+$//;
118 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 }
129 $prev = $arc;
130 $more = undef;
131 } elsif (/^arch (\S+)$/i) {
132 push @{ $arc{arch} }, $parse_block->(_name => $1);
133 } elsif (/^\s*($|#)/) {
134 #
135 } else {
136 warn "$path: unparseable top-level line '$_'";
137 }
138 }
139
140 undef $parse_block; # work around bug in perl not freeing $fh etc.
141
142 Storable::nstore \%arc, $cache
143 if defined $cache;
144
145 \%arc
146 }
147 }
148
149 # 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 # 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 sub init($) {
239 my ($cachedir) = @_;
240
241 $ARCH = read_arch "$LIB/archetypes", "$cachedir/archetypes.pst";
242 }
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
254 1