ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra/Deliantra/Map.pm
Revision: 1.27
Committed: Sun Oct 5 13:52:33 2008 UTC (15 years, 7 months ago) by elmex
Branch: MAIN
CVS Tags: rel-1_23
Changes since 1.26: +4 -1 lines
Log Message:
added unpaid flag for converters and fixed new_pickmap bug.

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3 root 1.26 Deliantra::Map - represent a crossfire map
4 root 1.1
5     =cut
6    
7 root 1.26 package Deliantra::Map;
8 root 1.1
9     our $VERSION = '0.1';
10    
11     use strict;
12    
13 root 1.2 use Carp ();
14 root 1.26 use Deliantra;
15 root 1.1
16     use base 'Exporter';
17    
18     sub new {
19     my ($class, $width, $height) = @_;
20    
21 elmex 1.8 bless { info => { _name => 'map' }, width => $width, height => $height }, $class
22 root 1.1 }
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 root 1.20 my $archs = [ sort { $a->{_name} cmp $b->{_name} } @$archs ];
68 root 1.1
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     # check whether this tile was already written (see below at (b))
82     unless (defined $map->{map}[$x][$y]) {
83 elmex 1.22 my ($x1, $y1, $x2, $y2) = arch_extents $archs->[$i];
84 root 1.1
85 root 1.5 if ($x + $x2 - $x1 + 1 > $width) {
86 root 1.1 $y += $max_line_height;
87     $max_line_height = 1;
88     $x = 0;
89     }
90    
91 elmex 1.27 $map->{map}[$x - $x1][$y - $y1] = [{
92     _name => $archs->[$i]->{_name},
93     _atype => 'arch',
94     }];
95 root 1.1
96 root 1.5 $x += $x2 - $x1 + 1;
97 root 1.1
98 root 1.5 $max_line_height = List::Util::max $max_line_height, $y2 - $y1 + 1;
99 root 1.1
100     } else {
101     $i--;
102     }
103    
104     $maxw = List::Util::max $maxw, $x;
105 root 1.7 $maxh = List::Util::max $maxh, $y + $max_line_height;
106 root 1.1 }
107    
108     $map->{height} = $maxh;
109     $map->{width} = $maxw;
110    
111 root 1.2 $map
112     }
113    
114     sub resize {
115     my ($self, $width, $height) = @_;
116    
117     $self->{width} = $width;
118     $self->{height} = $height;
119    
120     # i am sure this can be done more elegantly
121     @{$self->{map}} = @{$self->{map}}[0 .. $width - 1];
122    
123     for (@{$self->{map}}) {
124     @$_ = @$_[0 .. $height - 1];
125     }
126     }
127    
128     sub as_archlist {
129     my ($self) = @_;
130    
131     # wing map so we have no extra-map arches
132     $self->resize ($self->{width}, $self->{height});
133    
134     my @arch;
135    
136     for my $x (0 .. $self->{width} - 1) {
137     my $ass = $self->{map}[$x];
138     for my $y (0 .. $self->{height} - 1) {
139     for my $a (@{ $ass->[$y] || [] }) {
140 root 1.6 next if $a->{_virtual};
141    
142 root 1.2 # note: big faces _may_ span map boundaries
143    
144     my %a = %$a;
145     delete $a{x};
146     delete $a{y};
147     $a{x} = $x if $x;
148     $a{y} = $y if $y;
149    
150     push @arch, \%a;
151     }
152     }
153     }
154    
155     # now assemble meta info
156 root 1.18 if ($self->{info}) {
157     my %meta = %{$self->{info}};
158 root 1.2
159 root 1.18 $meta{width} = $self->{width};
160     $meta{height} = $self->{height};
161 root 1.4
162 root 1.26 unshift @arch, Deliantra::normalize_arch \%meta;
163 root 1.18 }
164 root 1.2
165     \@arch
166     }
167    
168     sub as_mapstring {
169     my ($self) = @_;
170     my $arch = $self->as_archlist;
171 root 1.26 Deliantra::archlist_to_string ($arch)
172 root 1.2 }
173    
174     sub write_file {
175     my ($self, $path) = @_;
176    
177 root 1.21 open my $fh, ">:raw:utf8", "$path~" or Carp::croak "$path~: $!";
178     print $fh $self->as_mapstring or Carp::croak "$path~: $!";
179     close $fh or Carp::croak "$path~: $!";
180 root 1.2
181 elmex 1.23 if (stat $path) {
182     chmod +(stat _)[2] & 0777, "$path~";
183     chown +(stat _)[4,5], "$path~";
184     }
185 root 1.19
186 root 1.2 rename "$path~", $path;
187 root 1.1 }
188    
189     =head1 AUTHOR
190    
191     Marc Lehmann <schmorp@schmorp.de>
192     http://home.schmorp.de/
193    
194     Robin Redeker <elmex@ta-sa.org>
195     http://www.ta-sa.org/
196    
197     =cut
198    
199     1