ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra/Deliantra/Map.pm
Revision: 1.29
Committed: Sat May 15 00:28:55 2010 UTC (14 years ago) by root
Branch: MAIN
CVS Tags: rel-2_01, HEAD
Changes since 1.28: +3 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Deliantra::Map - represent a crossfire map
4
5 =cut
6
7 package Deliantra::Map;
8
9 our $VERSION = '0.1';
10
11 use common::sense;
12
13 use Carp ();
14 use Deliantra;
15
16 use base 'Exporter';
17
18 sub new {
19 my ($class, $width, $height) = @_;
20
21 bless { info => { _name => 'map' }, 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 $_->{enter_x} = $_->{hp} if $_->{hp} && !$_->{enter_x}; delete $_->{hp};
42 $_->{enter_y} = $_->{sp} if $_->{sp} && !$_->{enter_y}; delete $_->{sp};
43
44 $meta{info} = $_;
45
46 $mapx = $_->{width} || $x;
47 $mapy = $_->{height} || $y;
48 } else {
49 push @{ $map->[$x][$y] }, $_;
50
51 # arch map is unreliable w.r.t. width and height
52 $mapx = $x + 1 if $mapx <= $x;
53 $mapy = $y + 1 if $mapy <= $y;
54 #$mapx = $a->{x} + 1, warn "$mapname: arch '$a->{_name}' outside map width at ($a->{x}|$a->{y})\n" if $mapx <= $a->{x};
55 #$mapy = $a->{y} + 1, warn "$mapname: arch '$a->{_name}' outside map height at ($a->{x}|$a->{y})\n" if $mapy <= $a->{y};
56 }
57 }
58
59 $meta{width} = $mapx;
60 $meta{height} = $mapy;
61 $meta{map} = $map;
62
63 bless \%meta, $class
64 }
65
66 sub new_pickmap {
67 my ($class, $archs, $width) = @_;
68
69 # sort archs alphabetically
70 my $archs = [ sort { $a->{_name} cmp $b->{_name} } @$archs ];
71
72 $width ||= 10; # default width
73
74 my $num = @$archs;
75 my $map = { };
76 # overall placement coords
77 my $x = 0;
78 my $y = 0;
79
80 my ($maxh, $maxw) = (0, 0); # maximum sizes, to set map width/height later
81 my $max_line_height = 1;
82
83 for (my $i = 0; $i < $num; $i++) {
84 # check whether this tile was already written (see below at (b))
85 unless (defined $map->{map}[$x][$y]) {
86 my ($x1, $y1, $x2, $y2) = arch_extents $archs->[$i];
87
88 if ($x + $x2 - $x1 + 1 > $width) {
89 $y += $max_line_height;
90 $max_line_height = 1;
91 $x = 0;
92 }
93
94 $map->{map}[$x - $x1][$y - $y1] = [{
95 _name => $archs->[$i]->{_name},
96 _atype => 'arch',
97 }];
98
99 $x += $x2 - $x1 + 1;
100
101 $max_line_height = List::Util::max $max_line_height, $y2 - $y1 + 1;
102
103 } else {
104 $i--;
105 }
106
107 $maxw = List::Util::max $maxw, $x;
108 $maxh = List::Util::max $maxh, $y + $max_line_height;
109 }
110
111 $map->{height} = $maxh;
112 $map->{width} = $maxw;
113
114 $map
115 }
116
117 sub resize {
118 my ($self, $width, $height) = @_;
119
120 $self->{width} = $width;
121 $self->{height} = $height;
122
123 # i am sure this can be done more elegantly
124 @{$self->{map}} = @{$self->{map}}[0 .. $width - 1];
125
126 for (@{$self->{map}}) {
127 @$_ = @$_[0 .. $height - 1];
128 }
129 }
130
131 sub as_archlist {
132 my ($self) = @_;
133
134 # wing map so we have no extra-map arches
135 $self->resize ($self->{width}, $self->{height});
136
137 my @arch;
138
139 for my $x (0 .. $self->{width} - 1) {
140 my $ass = $self->{map}[$x];
141 for my $y (0 .. $self->{height} - 1) {
142 for my $a (@{ $ass->[$y] || [] }) {
143 next if $a->{_virtual};
144
145 # note: big faces _may_ span map boundaries
146
147 my %a = %$a;
148 delete $a{x};
149 delete $a{y};
150 $a{x} = $x if $x;
151 $a{y} = $y if $y;
152
153 push @arch, \%a;
154 }
155 }
156 }
157
158 # now assemble meta info
159 if ($self->{info}) {
160 my %meta = %{$self->{info}};
161
162 $meta{width} = $self->{width};
163 $meta{height} = $self->{height};
164
165 unshift @arch, Deliantra::normalize_arch \%meta;
166 }
167
168 \@arch
169 }
170
171 sub as_mapstring {
172 my ($self) = @_;
173 my $arch = $self->as_archlist;
174 Deliantra::archlist_to_string ($arch)
175 }
176
177 sub write_file {
178 my ($self, $path) = @_;
179
180 open my $fh, ">:raw:utf8", "$path~" or Carp::croak "$path~: $!";
181 print $fh $self->as_mapstring or Carp::croak "$path~: $!";
182 close $fh or Carp::croak "$path~: $!";
183
184 if (stat $path) {
185 chmod +(stat _)[2] & 0777, "$path~";
186 chown +(stat _)[4,5], "$path~";
187 }
188
189 rename "$path~", $path;
190 }
191
192 =head1 AUTHOR
193
194 Marc Lehmann <schmorp@schmorp.de>
195 http://home.schmorp.de/
196
197 Robin Redeker <elmex@ta-sa.org>
198 http://www.ta-sa.org/
199
200 =cut
201
202 1