The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# vi:tw=0 syntax=perl:

package Games::RolePlay::MapGen::Generator::SubMap;

use common::sense;
use Carp;
use parent q(Games::RolePlay::MapGen::Generator);
use Games::RolePlay::MapGen::Tools qw( _group _tile _door );

1;

sub genmap {
    my $this = shift;
    my $opts = shift;

    my $map    = [];
    my $groups = [];

    my @X = ( sort {$a<=>$b} ($opts->{upper_left}[0], $opts->{lower_right}[0]) );
    my @Y = ( sort {$a<=>$b} ($opts->{upper_left}[1], $opts->{lower_right}[1]) );

    my $smap = $opts->{map_input}{_the_map};

    $opts->{$_} = $opts->{map_input}{$_} for qw(tile_size cell_size);
    $opts->{x_size} = my $xs = 2+($X[1]-$X[0])+1;
    $opts->{y_size} = my $ys = 2+($Y[1]-$Y[0])+1;
    $opts->{bounding_box} = $xs . "x" . $ys;

    for my $x ( 0 .. $xs-1 ) { my $y = 0;     $map->[ $y ][ $x ] = &_tile( x=>$x, y=>$y, type=>'fog' );
                                  $y = $ys-1; $map->[ $y ][ $x ] = &_tile( x=>$x, y=>$y, type=>'fog' ); }

    for my $y ( 1 .. $ys-2 ) { my $x = 0;     $map->[ $y ][ $x ] = &_tile( x=>$x, y=>$y, type=>'fog' );
                                  $x = $xs-1; $map->[ $y ][ $x ] = &_tile( x=>$x, y=>$y, type=>'fog' ); }

    ## DEBUG ## # disable mistakes:
    ## DEBUG ## tie @$_, "Games::RolePlay::MapGen::_disallow_autoviv", $_ for $map, @$map;

    for my $x1 ( $X[0] .. $X[1] ) { my $x2 = 1 + ($x1-$X[0]);
    for my $y1 ( $Y[0] .. $Y[1] ) { my $y2 = 1 + ($y1-$Y[0]);
        my $otile = $smap->[ $y1 ][ $x1 ];

        my $ntile = $map->[ $y2 ][ $x2 ] = &_tile( x=>$x2, y=>$y2, (exists $otile->{type} ? (type=>$otile->{type}) :()) );
        for my $d (qw(n e s w)) {
            my $ood = $otile->{od}{$d};

            my @ops = ($x2,$y2);
               $ops[0] ++ if $d eq "e";
               $ops[0] -- if $d eq "w";
               $ops[1] ++ if $d eq "s";
               $ops[1] -- if $d eq "n";

            ## DEBUG ## do { local $" = ","; warn "($x2,$y2):$d -> (@ops)" };

            my $opp = $Games::RolePlay::MapGen::opp{$d};
            if( my $nt = $map->[ $ops[1] ][ $ops[0] ] ) {
                if( ref $ood ) {
                    $nt->{od}{$opp} = $ntile->{od}{$d} = &_door(
                        map {($_ => $ood->{$_})} qw(locked stuck secret open),
                        open_dir => { map {($ood->{open_dir}{$_})} qw(major minor) },
                    );

                } elsif($ood) {
                    $nt->{od}{$opp} = $ntile->{od}{$d} = 1;
                }
            }
        }
    }}

    $map = new Games::RolePlay::MapGen::_interconnected_map( $map );
     
    for my $row (@$map) {
        for my $tile (@$row) {
            next unless $tile and exists $tile->{type} and $tile->{type} eq "fog";
            for my $d (qw(n w)) {
                if( my $n = $tile->{nb}{$d} ) {
                    next unless $n and exists $n->{type} and $n->{type} eq "fog";
                    my $o = $Games::RolePlay::MapGen::opp{$d};
                    $n->{od}{$o} = $tile->{od}{$d} = 1;
                }
            }
        }
    }

    return ($map, $groups);
}

__END__
# Below is stub documentation for your module. You better edit it!

=head1 NAME

Games::RolePlay::MapGen::Generator::SubMap - Given a MapGen object and some co-ordinates, generate a sub-map

=head1 SYNOPSIS

    use Games::RolePlay::MapGen;

    my $map = new Games::RolePlay::MapGen;
       $map->set_generator( "XMLImport" );
       $map->generate( xml_input_file => "map.xml" );

    my $sub_map = new Games::RolePlay::MapGen;
       $sub_map->set_generator( "SubMap" );
       $sub_map->generate( map_input => $map, upper_left=>[5,5], lower_right=>[10,10] );

The MapGen base object also knows a shortcut to perform the above:

    my $submap = Games::RolePlay::MapGen->sub_map($map, [5,5], [10,10]);

=head1 SEE ALSO

Games::RolePlay::MapGen

=cut