ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra/Deliantra/Map.pm
Revision: 1.7
Committed: Wed Mar 15 02:44:26 2006 UTC (18 years, 2 months ago) by root
Branch: MAIN
Changes since 1.6: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     Crossfire::Map - represent a crossfire map
4    
5     =cut
6    
7     package Crossfire::Map;
8    
9     our $VERSION = '0.1';
10    
11     use strict;
12    
13 root 1.2 use Carp ();
14 root 1.1 use Crossfire;
15    
16     use base 'Exporter';
17    
18     sub new {
19     my ($class, $width, $height) = @_;
20    
21     bless { width => $width, height => $height }, $class
22     }
23    
24     sub new_from_file {
25     new_from_archlist {$_[0]} read_arch $_[1]
26     }
27    
28     sub new_from_archlist {
29     my ($class, $mapa) = @_;
30    
31     my %meta;
32    
33     my ($mapx, $mapy);
34    
35     my $map;
36    
37     for (@{ $mapa->{arch} }) {
38     my ($x, $y) = (delete $_->{x}, delete $_->{y});
39    
40     if ($_->{_name} eq "map") {
41     $meta{info} = $_;
42    
43     $mapx = $_->{width} || $x;
44     $mapy = $_->{height} || $y;
45     } else {
46     push @{ $map->[$x][$y] }, $_;
47    
48     # arch map is unreliable w.r.t. width and height
49     $mapx = $x + 1 if $mapx <= $x;
50     $mapy = $y + 1 if $mapy <= $y;
51     #$mapx = $a->{x} + 1, warn "$mapname: arch '$a->{_name}' outside map width at ($a->{x}|$a->{y})\n" if $mapx <= $a->{x};
52     #$mapy = $a->{y} + 1, warn "$mapname: arch '$a->{_name}' outside map height at ($a->{x}|$a->{y})\n" if $mapy <= $a->{y};
53     }
54     }
55    
56     $meta{width} = $mapx;
57     $meta{height} = $mapy;
58     $meta{map} = $map;
59    
60     bless \%meta, $class
61     }
62    
63     sub new_pickmap {
64     my ($class, $archs, $width) = @_;
65    
66     # sort archs alphabetically
67     my $archs = [ sort { ${$a}->{_name} cmp ${$b}->{_name} } @$archs ];
68    
69     $width ||= 10; # default width
70    
71     my $num = @$archs;
72     my $map = { };
73     # overall placement coords
74     my $x = 0;
75     my $y = 0;
76    
77     my ($maxh, $maxw) = (0, 0); # maximum sizes, to set map width/height later
78     my $max_line_height = 1;
79    
80     for (my $i = 0; $i < $num; $i++) {
81     defined ${$archs->[$i]}->{face} or next;
82    
83     # check whether this tile was already written (see below at (b))
84     unless (defined $map->{map}[$x][$y]) {
85 root 1.5 my ($x1, $y1, $x2, $y2) = arch_extents ${$archs->[$i]};
86 root 1.1
87 root 1.5 if ($x + $x2 - $x1 + 1 > $width) {
88 root 1.1 $y += $max_line_height;
89     $max_line_height = 1;
90     $x = 0;
91     }
92    
93 root 1.5 $map->{map}[$x - $x1][$y - $y1] = [${$archs->[$i]}];
94 root 1.1
95 root 1.5 $x += $x2 - $x1 + 1;
96 root 1.1
97 root 1.5 $max_line_height = List::Util::max $max_line_height, $y2 - $y1 + 1;
98 root 1.1
99     } else {
100     $i--;
101     }
102    
103     $maxw = List::Util::max $maxw, $x;
104 root 1.7 $maxh = List::Util::max $maxh, $y + $max_line_height;
105 root 1.1 }
106    
107     $map->{height} = $maxh;
108     $map->{width} = $maxw;
109    
110 root 1.2 $map
111     }
112    
113     sub resize {
114     my ($self, $width, $height) = @_;
115    
116     $self->{width} = $width;
117     $self->{height} = $height;
118    
119     # i am sure this can be done more elegantly
120     @{$self->{map}} = @{$self->{map}}[0 .. $width - 1];
121    
122     for (@{$self->{map}}) {
123     @$_ = @$_[0 .. $height - 1];
124     }
125     }
126    
127     sub as_archlist {
128     my ($self) = @_;
129    
130     # wing map so we have no extra-map arches
131     $self->resize ($self->{width}, $self->{height});
132    
133     my @arch;
134    
135     for my $x (0 .. $self->{width} - 1) {
136     my $ass = $self->{map}[$x];
137     for my $y (0 .. $self->{height} - 1) {
138     for my $a (@{ $ass->[$y] || [] }) {
139 root 1.6 next if $a->{_virtual};
140    
141 root 1.2 # note: big faces _may_ span map boundaries
142    
143     my %a = %$a;
144     delete $a{x};
145     delete $a{y};
146     $a{x} = $x if $x;
147     $a{y} = $y if $y;
148    
149     push @arch, \%a;
150     }
151     }
152     }
153    
154     # now assemble meta info
155     my %meta = %{$self->{info}};
156    
157 root 1.4 $meta{width} = $self->{width};
158     $meta{height} = $self->{height};
159    
160     unshift @arch, Crossfire::normalize_arch \%meta;
161 root 1.2
162     \@arch
163     }
164    
165     sub as_mapstring {
166     my ($self) = @_;
167    
168     my $arch = $self->as_archlist;
169    
170     my $str;
171    
172     my $append; $append = sub {
173     my %a = %{$_[0]};
174    
175 root 1.4 Crossfire::normalize_arch \%a;
176    
177 root 1.2 $str .= "arch " . (delete $a{_name}) . "\n";
178    
179 root 1.3 my $inv = delete $a{arch};
180 root 1.2
181 root 1.3 # put inventory last
182 root 1.2 for my $k (sort keys %a) {
183 root 1.6 next if $k =~ /^_/; # ignore our _-keys
184    
185 root 1.2 if (my $end = $Crossfire::FIELD_MULTILINE{$k}) {
186     $a{$k} =~ s/\n$//;
187     $str .= "$k\n$a{$k}\n$end\n";
188     } else {
189     $str .= "$k $a{$k}\n";
190     }
191     }
192    
193 root 1.3 if ($inv) {
194     $append->($_) for @$inv;
195     }
196    
197 root 1.2 $str .= "end\n";
198    
199     };
200    
201     for (@$arch) {
202     $append->($_);
203     }
204    
205     $str
206     }
207    
208     sub write_file {
209     my ($self, $path) = @_;
210    
211     open my $fh, ">", "$path~" or Carp::croak "$path~: $!";
212     print $fh $self->as_mapstring or Carp::croak "$path~: $!";
213     close $fh or Carp::croak "$path~: $!";
214    
215     rename "$path~", $path;
216 root 1.1 }
217    
218     =head1 AUTHOR
219    
220     Marc Lehmann <schmorp@schmorp.de>
221     http://home.schmorp.de/
222    
223     Robin Redeker <elmex@ta-sa.org>
224     http://www.ta-sa.org/
225    
226     =cut
227    
228     1