File Coverage

blib/lib/Games/RolePlay/MapGen.pm
Criterion Covered Total %
statement 124 174 71.2
branch 49 96 51.0
condition 5 12 41.6
subroutine 14 18 77.7
pod 1 11 9.0
total 193 311 62.0


line stmt bran cond sub pod time code
1             # vi:tw=0 syntax=perl:
2              
3             package Games::RolePlay::MapGen;
4              
5 22     22   215877 use Carp;
  22         55  
  22         1748  
6 22     22   47747 use Storable;
  22         100985  
  22         1848  
7 22     22   25728 use common::sense;
  22         210  
  22         129  
8              
9             our $VERSION = '1.5008';
10              
11             our $AUTOLOAD;
12              
13             our %opp = (n=>"s", e=>"w", s=>"n", w=>"e");
14             our %full = (n=>"north", e=>"east", s=>"south", w=>"west");
15              
16             # known_opts {{{
17             our %known_opts = (
18             generator => "Basic",
19             exporter => "Text",
20             bounding_box => "50x50",
21             tile_size => 10,
22             cell_size => "20x20",
23              
24             nocolor => 0, # for the text map generator
25              
26             num_rooms => "1d4+1",
27             min_room_size => "2x2",
28             max_room_size => "7x7",
29              
30             sparseness => 10,
31             same_way_percent => 90,
32             same_node_percent => 30,
33             remove_deadend_percent => 60,
34             );
35             # }}}
36              
37             # _check_mod_path {{{
38             sub _check_mod_path {
39 0     0   0 my $this = shift;
40 0         0 my $omod = shift;
41 0         0 $omod =~ s/\:\:/\//g;
42              
43 0         0 for my $mod ($omod, map {$_ . "::$omod"} "Games::RolePlay::MapGen::Generator", "Games::RolePlay::MapGen::GeneratorPlugin",
  0         0  
44             "Games::RolePlay::MapGen::Exporter", "Games::RolePlay::MapGen::ExporterPlugin") {
45              
46 0 0       0 return $mod if eval "require $mod";
47             }
48              
49 0         0 return;
50             }
51             # }}}
52             # _check_opts {{{
53             sub _check_opts {
54 26     26   59 my $this = shift;
55 26         102 my @e = ();
56              
57             # warn "checking known_opts";
58 26         214 for my $k (keys %known_opts) {
59 364 100       2929 "set_$k"->($this, $known_opts{$k} ) unless defined $this->{$k};
60             }
61              
62 26         166 for my $k ( keys %$this ) {
63 398 100       859 unless( exists $known_opts{$k} ) {
64 34 100       147 next if $k eq "objs";
65 8 50       36 next if $k eq "_the_map";
66 8 50       33 next if $k eq "_the_groups";
67              
68 8         35 push @e, "unrecognized option: '$k'";
69             }
70             }
71              
72 26 100       163 return "ERROR:\n\t" . join("\n\t", @e) . "\n" if @e;
73 18         99 return;
74             }
75             # }}}
76              
77             # AUTOLOAD {{{
78             sub AUTOLOAD {
79 263     263   599 my $this = shift;
80 263         342 my $sub = $AUTOLOAD;
81              
82             # sub set_generator
83             # sub set_exporter
84              
85 263 100       1909 if( $sub =~ m/MapGen\:\:set_(generator|exporter)$/ ) {
    100          
    50          
86 50         117 my $type = $1;
87 50         90 my $modu = shift;
88              
89 50 50       315 delete $this->{objs}{$type} if $this->{objs}{$type};
90              
91 50         194 my $module = "Games::RolePlay::MapGen::" . (ucfirst $type) . "::$modu";
92 50 50       78 croak "Couldn't locate module \"$modu\" during execution of $sub() $@" unless eval { "require $module" };
  50         176  
93              
94             # NOTE: why does this not have {objs}? 5/12/8
95 50         824 $this->{$type} = $module;
96              
97 50         163 return;
98              
99             } elsif( $sub =~ m/MapGen\:\:add_(generator|exporter)_plugin$/ ) {
100 6         16 my $type = $1;
101 6         11 my $plug = shift;
102              
103 6         27 my $newn = "Games::RolePlay::MapGen::" . (ucfirst $type) . "Plugin::$plug";
104 6 50       9 croak "Couldn't locate module \"$plug\" during execution of $sub()" unless eval { "require $newn" };
  6         21  
105              
106 6         10 push @{ $this->{plugins}{$type} }, $newn;
  6         21  
107              
108 6         47 return;
109              
110             } elsif( $sub =~ m/MapGen\:\:set_([\w\d\_]+)$/ ) {
111 207         398 my $n = $1;
112              
113 207 100       713 croak "ERROR: set_$n() unknown setting during execution of $sub()" unless exists $known_opts{$n};
114              
115 206         962 $this->{$n} = shift;
116              
117 206         339 for my $o (qw(generator exporter)) {
118 412 100       1301 if( my $oo = $this->{objs}{$o} ) {
119              
120             # NOTE: how does this->{$n} relate to this->{objs}{$n} ... 5/12/8
121 20         75 $oo->{o}{$n} = $this->{$n};
122             }
123             }
124              
125 206         806 return;
126             }
127              
128 0         0 croak "ERROR: function $sub() not found";
129             }
130 0     0   0 sub DESTROY {}
131             # }}}
132             # new {{{
133             sub new {
134 18     18 1 9003 my $class = shift;
135 18         55 my @opts = @_;
136 18 100 66     212 my $opts = ( (@opts == 1 and ref($opts[0]) eq "HASH") ? {%{$opts[0]}} : {@opts} );
  10         56  
137 18         169 my $this = bless $opts, $class;
138              
139 18 50       99 if( my $e = $this->_check_opts ) { croak $e }
  0         0  
140              
141 18         98 return $this;
142             }
143             # }}}
144              
145             # save_map {{{
146             sub save_map {
147 5     5 0 21 my $this = shift;
148 5         10 my $filename = shift;
149              
150 5         33 $this->{_the_map}->disconnect_map;
151              
152 5         8 my $str;
153 5 100       30 if( $filename ) {
154 1         7 Storable::store($this, $filename);
155              
156             } else {
157 4         26 $str = Storable::freeze($this);
158             }
159              
160 5         152 $this->{_the_map}->interconnect_map;
161              
162 5         301 return $str;
163             }
164             # }}}
165             # load_map {{{
166             sub load_map {
167 5     5 0 96 my $this = shift;
168 5         19 my $filename = shift;
169              
170 5 100       360 if( -f $filename ) {
171 1 50       2 eval { %$this = %{ Storable::retrieve( $filename ) } }
  1         4  
  1         6  
172             or die "ERROR while evaluating saved map from file: $@";
173              
174             } else {
175 4 50       11 eval { %$this = %{ Storable::thaw( $filename ) } }
  4         8  
  4         24  
176             or die "ERROR while evaluating saved map from string: $@";
177             }
178              
179 5         11393 require Games::RolePlay::MapGen::Tools; # This would already be loaded if we were the blessed ref that did the saving
180 5         41 $this->{_the_map}->interconnect_map; # bit it wouldn't be loaded otherwise!
181             }
182             # }}}
183             # legacy_load_map {{{
184             sub legacy_load_map {
185 0     0 0 0 my $this = shift;
186 0         0 my $filename = shift;
187              
188 0 0       0 open my $load, "$filename" or die "couldn't open $filename for read: $!";
189 0         0 local $/ = undef;
190 0         0 my $entire_file = <$load>;
191 0         0 close $load;
192              
193 0         0 eval $entire_file;
194 0 0       0 die "ERROR while evaluating saved map: $@" if $@;
195              
196 0         0 require Games::RolePlay::MapGen::Tools; # This would already be loaded if we were the blessed ref that did the saving
197 0         0 $this->{_the_map}->interconnect_map; # bit it wouldn't be loaded otherwise!
198             }
199             # }}}
200             # generate {{{
201             sub generate {
202 15     15 0 1066 my $this = shift;
203 15         36 my $err;
204              
205             __MADE_GEN_OBJ:
206 23 100       131 if( my $gen = $this->{objs}{generator} ) {
207 8         18 my $new_opts;
208              
209 8         128 ($this->{_the_map}, $this->{_the_groups}, $new_opts) = $gen->go( @_ );
210              
211 8 50 33     92 if( $new_opts and keys %$new_opts ) {
212 8         41 for my $k (keys %$new_opts) {
213 140         266 $this->{$k} = $new_opts->{$k};
214             }
215             }
216              
217 8         142 return;
218              
219             } else {
220 15 50       60 die "ERROR: problem creating new generator object" if $err;
221             }
222              
223 15         3254 eval qq( require $this->{generator} );
224 15 100       2798 croak "ERROR locating generator module:\n\t$@\n " if $@;
225              
226 8         25 my $obj;
227 8 100 66     77 my @opts = map(($_=>$this->{$_}), grep {defined $this->{$_} and $_ ne "objs" and $_ ne "plugins" } keys %$this);
  116         922  
228              
229 8         1179 eval qq( \$obj = new $this->{generator} (\@opts); );
230 8 50       71 if( $@ ) {
231 0 0       0 die "ERROR generating generator:\n\t$@\n " if $@ =~ m/ERROR/;
232 0 0       0 croak "ERROR generating generator:\n\t$@\n " if $@;
233             }
234              
235 8         22 $obj->add_plugin( $_ ) for @{ $this->{plugins}{generator} };
  8         240  
236              
237 8         35 $this->{objs}{generator} = $obj;
238 8         19 $err = 1;
239              
240 8         40 $this->_check_opts; # plugins, generators and exporters can add default options
241              
242 8         36 goto __MADE_GEN_OBJ;
243             }
244             # }}}
245             # export {{{
246             sub export {
247 2     2 0 15 my $this = shift;
248 2         4 my $err;
249              
250             __MADE_VIS_OBJ:
251 2 50       53 if( my $vis = $this->{objs}{exporter} ) {
252              
253 0 0       0 return $vis->go( _the_map => $this->{_the_map}, _the_groups => $this->{_the_groups}, (@_==1 ? (fname=>$_[0]) : @_) );
254              
255             } else {
256 2 50       14 die "problem creating new exporter object" if $err;
257             }
258              
259 2         269 eval qq( require $this->{exporter} );
260 2 50       758 croak "ERROR locating exporter module:\n\t$@\n " if $@;
261              
262 0         0 my $obj;
263 0 0 0     0 my @opts = map(($_=>$this->{$_}), grep {defined $this->{$_} and $_ ne "objs" and $_ ne "plugins" } keys %$this);
  0         0  
264              
265 0         0 eval qq( \$obj = new $this->{exporter} (\@opts); );
266 0 0       0 if( $@ ) {
267 0 0       0 die "ERROR generating exporter:\n\t$@\n " if $@ =~ m/ERROR/;
268 0 0       0 croak "ERROR generating exporter:\n\t$@\n " if $@;
269             }
270              
271 0         0 $this->{objs}{exporter} = $obj;
272 0         0 $err = 1;
273              
274 0         0 $this->_check_opts; # plugins, generators and exporters can add default options
275              
276 0         0 goto __MADE_VIS_OBJ;
277             }
278             # }}}
279              
280             # import_xml {{{
281             sub import_xml {
282 3     3 0 507 my $this = shift;
283 3 50       10 my $that = shift; croak "no such file that=$that" unless -f $that;
  3         104  
284              
285 3 50       29 $this = $this->new unless ref $this;
286              
287 3         16 $this->set_generator( "XMLImport" );
288 3 50       49 if( -f $that ) {
289 3         25 $this->generate( xml_input_file => $that, @_ );
290              
291             } else {
292 0         0 $this->generate( xml_input => $that, @_ );
293             }
294 0         0 $this;
295             }
296             # }}}
297             # sub_map {{{
298             sub sub_map {
299 0     0 0 0 my $this = shift;
300 0 0       0 my $that = shift; croak "that's not a map" unless ref $that;
  0         0  
301 0 0       0 my $ul = shift; croak "upper left should be an arrayref two tuple" unless 2==eval {@$ul};
  0         0  
  0         0  
302 0 0       0 my $lr = shift; croak "lower right should be an arrayref two tuple" unless 2==eval {@$lr};
  0         0  
  0         0  
303              
304 0 0       0 $this = $this->new unless ref $this;
305 0         0 $this->set_generator( "SubMap" );
306 0         0 $this->generate( map_input => $that, upper_left=>$ul, lower_right=>$lr );
307 0         0 $this;
308             }
309             # }}}
310             # size {{{
311             sub size {
312 1     1 0 10 my $this = shift;
313 1         4 my $map = $this->{_the_map};
314              
315 1         2 my $x = @{$map->[0]};
  1         4  
316 1         6 my $y = @$map;
317              
318 1 50       7 return ($x, $y) if wantarray;
319 0         0 return [$x, $y];
320             }
321             # }}}
322              
323             # {{{ FREEZE_THAW_HOOKS
324             FREEZE_THAW_HOOKS: {
325             my $going;
326             sub STORABLE_freeze {
327 6 100   6 0 15041 return if $going;
328 3         10 my $this = shift;
329 3         6 $going = 1;
330 3         21 my $str = $this->save_map;
331 3         15 $going = 0;
332 3         1073 return $str;
333             }
334              
335             sub STORABLE_thaw {
336 3     3 0 476 my $this = shift;
337 3         22 $this->load_map($_[1]);
338             }
339             }
340              
341             # }}}
342              
343             1;
344              
345             __END__