File Coverage

blib/lib/Games/RolePlay/MapGen/Generator/XMLImport.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             # vi:tw=0 syntax=perl:
2              
3             package Games::RolePlay::MapGen::Generator::XMLImport;
4              
5 7     7   43 use common::sense;
  7         14  
  7         61  
6 7     7   393 use Carp;
  7         15  
  7         739  
7 7     7   6639 use parent q(Games::RolePlay::MapGen::Generator);
  7         3336  
  7         40  
8 7     7   6415 use Games::RolePlay::MapGen::Tools qw( _group _tile _door );
  7         27  
  7         985  
9 7     7   3696 use XML::XPath;
  0            
  0            
10             use XML::Parser;
11             use File::Spec;
12              
13             1;
14              
15             sub genmap {
16             my $this = shift;
17             my $opts = shift;
18              
19             my $xml_path = $INC{ 'Games/RolePlay/MapGen.pm' };
20             $xml_path =~ s/\.pm$//;
21              
22             my $xp;
23             if( my $input = $opts->{xml_input} ) {
24             $xp = XML::XPath->new( xml => $input );
25              
26             } elsif( exists $opts->{xml_input_file} ) {
27             open my $input, $opts->{xml_input_file} or croak "unable to open $opts->{xml_input_file}: $!";
28             $xp = XML::XPath->new( ioref => $input );
29              
30             } else {
31             croak "you must supply either XML (xml_input=>\$string) or a filename (xml_input_file=>\"something.xml\")"
32             }
33              
34             $xp->set_parser( XML::Parser->new(
35             ErrorContext => 2,
36             ParseParamEnt => 1,
37             Handlers=>{ExternEnt => sub {
38             my ($base, $name) = @_[1,2];
39             my $fname = ($base ? File::Spec->catfile($base, $name) : $name);
40              
41             # warn "base=$base; name=$name; fname=$fname";
42             # sleep 1;
43              
44             # my $fh;
45             # open $fh, $fname or
46             # open $fh, File::Spec->catfile($xml_path, $fname) or
47             # open $fh, File::Spec->catfile($xml_path, $name) or return undef;
48              
49             # $fh; # NOTE: this causes FAIL reports on various platforms almost at random
50              
51             open _XML_PARSER_REQUIRES_A_GLOBAL_GLOB, $fname or
52             open _XML_PARSER_REQUIRES_A_GLOBAL_GLOB, File::Spec->catfile($xml_path, $fname) or
53             open _XML_PARSER_REQUIRES_A_GLOBAL_GLOB, File::Spec->catfile($xml_path, $name) or return undef;
54              
55             *_XML_PARSER_REQUIRES_A_GLOBAL_GLOB;
56             }},
57             ));
58              
59             my $Mo = $xp->find('/MapGen/option');
60             for my $op ($Mo->get_nodelist) {
61             my $name = $xp->findvalue( '@name' => $op )->value;
62             my $val = $xp->findvalue( '@value' => $op )->value;
63              
64              
65             if( $val =~ m/:.*;/ ) {
66             my $h = {};
67              
68             $h->{$1} = $2 while $val =~ m/([\w\d]+):\s*([\.\w\d]+);/g;
69             $val = $h;
70              
71             } else {
72             $val = "$val";
73             }
74              
75             $opts->{$name} = $val;
76             }
77              
78             my @dirs = (qw(n s e w));
79              
80             my $map = [];
81             my $groups = [];
82              
83             my $maprows = $xp->find('/MapGen/map/row');
84             for my $row ($maprows->get_nodelist) {
85              
86             my $a = []; push @$map, $a;
87             my $y_pos = $xp->findvalue( '@ypos' => $row )->value;
88              
89             my $mapcols = $xp->find( tile => $row);
90             for my $tile ($mapcols->get_nodelist) {
91             my $x_pos = $xp->findvalue( '@xpos' => $tile )->value;
92             my $type = $xp->findvalue( '@type' => $tile )->value;
93              
94             my $t = &_tile( x=>$x_pos, y=>$y_pos );
95              
96             if( $type eq "wall" ) {
97             # type is undef for wall tiles
98             $t->{od} = { map {($_=>0)} @dirs };
99              
100             } else {
101             $t->{type} = $type;
102             $t->{od} = { map {($_=>1)} @dirs };
103             }
104              
105             push @$a, $t;
106              
107             my $mapclose = $xp->find( closure => $tile );
108             for my $closure ($mapclose->get_nodelist) {
109             my $type = $xp->findvalue( '@type' => $closure )->value;
110             my $dir = $xp->findvalue( '@dir' => $closure )->value;
111             $dir =~ s/^(\w)\w+/$1/;
112              
113             if( $type eq "wall" ) {
114             $t->{od}{$dir} = 0;
115              
116             } elsif( $type eq "door" ) {
117             if( $dir eq "n" or $dir eq "w" ) {
118             my $o_x = $x_pos - ($dir eq "w" ? 1:0);
119             my $o_y = $y_pos - ($dir eq "n" ? 1:0);
120             my $opposite = $map->[$o_y][$o_x];
121             my $opp = $Games::RolePlay::MapGen::opp{$dir};
122              
123             #
124             # stuck="no" secret="yes" major_open_dir="east"
125             # minor_open_dir="south" />
126              
127             my $d_locked = ($xp->findvalue( '@locked' => $closure ) eq "yes" ? 1:0);
128             my $d_stuck = ($xp->findvalue( '@stuck' => $closure ) eq "yes" ? 1:0);
129             my $d_secret = ($xp->findvalue( '@secret' => $closure ) eq "yes" ? 1:0);
130             my $d_open = ($xp->findvalue( '@open' => $closure ) eq "yes" ? 1:0);
131             my $d_majod = substr $xp->findvalue( '@major_open_dir' => $closure ), 0, 1;
132             my $d_minod = substr $xp->findvalue( '@minor_open_dir' => $closure ), 0, 1;
133              
134             $opposite->{od}{$opp} = $t->{od}{$dir} = &_door(
135             locked => $d_locked,
136             stuck => $d_stuck,
137             secret => $d_secret,
138             'open' => $d_open,
139             open_dir => {
140             major => $d_majod,
141             minor => $d_minod,
142             },
143             );
144             }
145              
146             } else {
147             die "hrm: closure type=$type";
148             }
149             }
150              
151             $opts->{t_cb}->(($x_pos+1,$y_pos+1), $tile) if exists $opts->{t_cb};
152             }
153             }
154              
155             my $tilegroups = $xp->find('/MapGen/tile_group');
156             for my $tile_group ($tilegroups->get_nodelist) {
157             my $t_name = $xp->findvalue( '@name' => $tile_group )->value;
158             my $t_type = $xp->findvalue( '@type' => $tile_group )->value;
159              
160             my $group = &_group;
161             $group->name( $t_name );
162             $group->type( $t_type );
163              
164             my $rectangles = $tile_group->find('rectangle');
165             for my $rec ($rectangles->get_nodelist) {
166             my @r_loc = split m/,/, $xp->findvalue( '@loc' => $rec );
167             my @r_size = split m/x/, $xp->findvalue( '@size' => $rec );
168              
169             $group->add_rectangle(\@r_loc, \@r_size, $map);
170             }
171              
172             push @$groups, $group;
173             }
174              
175             $map = new Games::RolePlay::MapGen::_interconnected_map( $map );
176              
177             return ($map, $groups);
178             }
179              
180             __END__