ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/Deliantra/Deliantra/Map.pm
Revision: 1.25
Committed: Thu Aug 31 21:09:33 2006 UTC (17 years, 9 months ago) by elmex
Branch: MAIN
CVS Tags: rel-0_92, rel-0_91, rel-0_96, rel-0_97, rel-0_98, rel-0_99, rel-1_11, rel-1_13, rel-1_12, rel-2_2, rel-2_0, rel-2_1, rel-1_1, rel-1_0, rel-0_9
Changes since 1.24: +1 -85 lines
Log Message:
loading and saving of arches and a better documentation in types.xml for safe ground

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 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.22 $map->{map}[$x - $x1][$y - $y1] = [$archs->[$i]];
92 root 1.1
93 root 1.5 $x += $x2 - $x1 + 1;
94 root 1.1
95 root 1.5 $max_line_height = List::Util::max $max_line_height, $y2 - $y1 + 1;
96 root 1.1
97     } else {
98     $i--;
99     }
100    
101     $maxw = List::Util::max $maxw, $x;
102 root 1.7 $maxh = List::Util::max $maxh, $y + $max_line_height;
103 root 1.1 }
104    
105     $map->{height} = $maxh;
106     $map->{width} = $maxw;
107    
108 root 1.2 $map
109     }
110    
111     sub resize {
112     my ($self, $width, $height) = @_;
113    
114     $self->{width} = $width;
115     $self->{height} = $height;
116    
117     # i am sure this can be done more elegantly
118     @{$self->{map}} = @{$self->{map}}[0 .. $width - 1];
119    
120     for (@{$self->{map}}) {
121     @$_ = @$_[0 .. $height - 1];
122     }
123     }
124    
125     sub as_archlist {
126     my ($self) = @_;
127    
128     # wing map so we have no extra-map arches
129     $self->resize ($self->{width}, $self->{height});
130    
131     my @arch;
132    
133     for my $x (0 .. $self->{width} - 1) {
134     my $ass = $self->{map}[$x];
135     for my $y (0 .. $self->{height} - 1) {
136     for my $a (@{ $ass->[$y] || [] }) {
137 root 1.6 next if $a->{_virtual};
138    
139 root 1.2 # note: big faces _may_ span map boundaries
140    
141     my %a = %$a;
142     delete $a{x};
143     delete $a{y};
144     $a{x} = $x if $x;
145     $a{y} = $y if $y;
146    
147     push @arch, \%a;
148     }
149     }
150     }
151    
152     # now assemble meta info
153 root 1.18 if ($self->{info}) {
154     my %meta = %{$self->{info}};
155 root 1.2
156 root 1.18 $meta{width} = $self->{width};
157     $meta{height} = $self->{height};
158 root 1.4
159 root 1.18 unshift @arch, Crossfire::normalize_arch \%meta;
160     }
161 root 1.2
162     \@arch
163     }
164    
165     sub as_mapstring {
166     my ($self) = @_;
167     my $arch = $self->as_archlist;
168 elmex 1.25 Crossfire::archlist_to_string ($arch)
169 root 1.2 }
170    
171     sub write_file {
172     my ($self, $path) = @_;
173    
174 root 1.21 open my $fh, ">:raw:utf8", "$path~" or Carp::croak "$path~: $!";
175     print $fh $self->as_mapstring or Carp::croak "$path~: $!";
176     close $fh or Carp::croak "$path~: $!";
177 root 1.2
178 elmex 1.23 if (stat $path) {
179     chmod +(stat _)[2] & 0777, "$path~";
180     chown +(stat _)[4,5], "$path~";
181     }
182 root 1.19
183 root 1.2 rename "$path~", $path;
184 root 1.1 }
185    
186     =head1 AUTHOR
187    
188     Marc Lehmann <schmorp@schmorp.de>
189     http://home.schmorp.de/
190    
191     Robin Redeker <elmex@ta-sa.org>
192     http://www.ta-sa.org/
193    
194     =cut
195    
196     1