| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# vi:filetype=perl: |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package Games::RolePlay::MapGen::MapQueue; |
|
4
|
|
|
|
|
|
|
|
|
5
|
6
|
|
|
6
|
|
7338
|
use common::sense; |
|
|
6
|
|
|
|
|
14
|
|
|
|
6
|
|
|
|
|
43
|
|
|
6
|
6
|
|
|
6
|
|
577
|
use Carp; |
|
|
6
|
|
|
|
|
12
|
|
|
|
6
|
|
|
|
|
650
|
|
|
7
|
6
|
|
|
6
|
|
38
|
use Exporter; |
|
|
6
|
|
|
|
|
10
|
|
|
|
6
|
|
|
|
|
319
|
|
|
8
|
6
|
|
|
6
|
|
16481
|
use Math::Trig; |
|
|
6
|
|
|
|
|
156575
|
|
|
|
6
|
|
|
|
|
1668
|
|
|
9
|
6
|
|
|
6
|
|
7250
|
use Math::Round; |
|
|
6
|
|
|
|
|
96407
|
|
|
|
6
|
|
|
|
|
588
|
|
|
10
|
6
|
|
|
6
|
|
69
|
use List::Util qw(min max); |
|
|
6
|
|
|
|
|
12
|
|
|
|
6
|
|
|
|
|
761
|
|
|
11
|
6
|
|
|
6
|
|
36
|
use Storable qw(freeze thaw); |
|
|
6
|
|
|
|
|
11
|
|
|
|
6
|
|
|
|
|
498
|
|
|
12
|
|
|
|
|
|
|
use constant { |
|
13
|
6
|
|
|
|
|
1859
|
LOS_NO => 0, |
|
14
|
|
|
|
|
|
|
LOS_YES => 1, |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
LOS_NO_COVER => 0, |
|
17
|
|
|
|
|
|
|
LOS_COVER => 1, |
|
18
|
|
|
|
|
|
|
LOS_DOUBLE_COVER => 2, |
|
19
|
6
|
|
|
6
|
|
35
|
}; |
|
|
6
|
|
|
|
|
10
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
|
22
|
|
|
|
|
|
|
our @EXPORT = qw(LOS_NO LOS_YES LOS_NO_COVER LOS_IGNORABLE_COVER LOS_COVER LOS_DOUBLE_COVER); |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our $LOS_CREATURE_RADIUS = 0.19; # used for double-cover check |
|
25
|
|
|
|
|
|
|
our $LOS_LHS_BONUS = 0.05_777; # slight advantage for being closer to obstruction |
|
26
|
|
|
|
|
|
|
our $EXTRUDE_POINTS = 4; |
|
27
|
|
|
|
|
|
|
our $CLOS_MIN_ANGLE = deg2rad(9); # the minimum angle between our LOS and the closure where we can still tell if there's a door on that wall |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
*_line_of_sight = *_line_of_sight_xs; |
|
30
|
|
|
|
|
|
|
*_tight_line_of_sight = *_tight_line_of_sight_xs; |
|
31
|
|
|
|
|
|
|
*_ranged_cover = *_ranged_cover_xs; |
|
32
|
|
|
|
|
|
|
*_melee_cover = *_melee_cover_xs; |
|
33
|
|
|
|
|
|
|
*_closure_line_of_sight = *_closure_line_of_sight_xs; |
|
34
|
|
|
|
|
|
|
|
|
35
|
6
|
|
|
6
|
|
15630
|
use Memoize qw(memoize flush_cache); |
|
|
6
|
|
|
|
|
18373
|
|
|
|
6
|
|
|
|
|
5723
|
|
|
36
|
|
|
|
|
|
|
memoize( _line_of_sight => NORMALIZER => sub { "$_[0] @{$_[1]} @{$_[2]}" } ); |
|
37
|
|
|
|
|
|
|
memoize( _tight_line_of_sight => NORMALIZER => sub { "$_[0] @{$_[1]} @{$_[2]}" } ); |
|
38
|
|
|
|
|
|
|
memoize( _ranged_cover => NORMALIZER => sub { "$_[0] @{$_[1]} @{$_[2]}" } ); |
|
39
|
|
|
|
|
|
|
memoize( _melee_cover => NORMALIZER => sub { "$_[0] @{$_[1]} @{$_[2]}" } ); |
|
40
|
|
|
|
|
|
|
memoize( _ignorable_cover => NORMALIZER => sub { "$_[0] @{$_[1]} @{$_[2]}" } ); |
|
41
|
|
|
|
|
|
|
memoize( _locations_in_line_of_sight => NORMALIZER => sub { "$_[0] @{$_[1]}" } ); |
|
42
|
|
|
|
|
|
|
memoize( _locations_in_range_and_line_of_sight => NORMALIZER => sub { "$_[0] @{$_[1]} $_[2]" } ); |
|
43
|
|
|
|
|
|
|
memoize( _locations_in_path => NORMALIZER => sub { "$_[0] @{$_[1]} @{$_[2]}" } ); |
|
44
|
|
|
|
|
|
|
memoize( _closure_line_of_sight => NORMALIZER => sub { "$_[0] @{$_[1]} @{$_[2]}" } ); |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
our @toflush = qw( _line_of_sight _tight_line_of_sight _ranged_cover _melee_cover _ignorable_cover |
|
47
|
|
|
|
|
|
|
_locations_in_line_of_sight _locations_in_range_and_line_of_sight |
|
48
|
|
|
|
|
|
|
_locations_in_path _closure_line_of_sight ); |
|
49
|
|
|
|
|
|
|
|
|
50
|
6
|
|
|
6
|
|
65
|
use Games::RolePlay::MapGen; |
|
|
6
|
|
|
|
|
14
|
|
|
|
6
|
|
|
|
|
144498
|
|
|
51
|
|
|
|
|
|
|
require XSLoader; XSLoader::load('Games::RolePlay::MapGen', $Games::RolePlay::MapGen::VERSION); |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# new {{{ |
|
54
|
|
|
|
|
|
|
sub new { |
|
55
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
|
56
|
0
|
|
|
|
|
|
my $the_m = shift; |
|
57
|
0
|
|
|
|
|
|
my $this = bless { o=>{}, c=>[] }, $class; |
|
58
|
|
|
|
|
|
|
|
|
59
|
0
|
0
|
|
|
|
|
croak "where is _the_map?" unless ref $the_m; |
|
60
|
0
|
|
|
|
|
|
$the_m = $the_m->{_the_map}; |
|
61
|
0
|
|
|
|
|
|
$this->{_the_map} = $the_m; |
|
62
|
|
|
|
|
|
|
|
|
63
|
0
|
|
|
|
|
|
$this->{ym} = $#{ $the_m }; |
|
|
0
|
|
|
|
|
|
|
|
64
|
0
|
|
|
|
|
|
$this->{xm} = $#{ $the_m->[0] }; |
|
|
0
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
|
66
|
0
|
|
|
|
|
|
return $this; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
# }}} |
|
69
|
|
|
|
|
|
|
# retag {{{ |
|
70
|
|
|
|
|
|
|
sub retag { |
|
71
|
0
|
|
|
0
|
0
|
|
my $this = shift; |
|
72
|
|
|
|
|
|
|
|
|
73
|
0
|
|
|
|
|
|
my $tags = {}; |
|
74
|
0
|
|
|
|
|
|
for my $row ( 0 .. $this->{ym} ) { |
|
75
|
0
|
|
|
|
|
|
for my $col ( 0 .. $this->{xm} ) { |
|
76
|
0
|
|
|
|
|
|
my $rhs = [ $col, $row ]; |
|
77
|
|
|
|
|
|
|
|
|
78
|
0
|
0
|
|
|
|
|
for my $o (@{ $this->{c}[ $rhs->[1] ][ $rhs->[0] ] || [] }) { |
|
|
0
|
|
|
|
|
|
|
|
79
|
0
|
|
|
|
|
|
$tags->{"$o"} = $rhs; |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
|
|
84
|
0
|
|
|
|
|
|
$this->{l} = $tags; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
# }}} |
|
87
|
|
|
|
|
|
|
# flush {{{ |
|
88
|
|
|
|
|
|
|
sub flush { |
|
89
|
0
|
|
|
0
|
1
|
|
flush_cache($_) for @toflush |
|
90
|
|
|
|
|
|
|
} |
|
91
|
|
|
|
|
|
|
# }}} |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# _check_loc {{{ |
|
94
|
|
|
|
|
|
|
sub _check_loc { |
|
95
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
96
|
0
|
|
|
|
|
|
my $loc = shift; |
|
97
|
|
|
|
|
|
|
|
|
98
|
0
|
0
|
|
|
|
|
return 0 if @$loc != 2; |
|
99
|
0
|
0
|
|
|
|
|
return 0 if $loc->[0] < 0; |
|
100
|
0
|
0
|
|
|
|
|
return 0 if $loc->[1] < 0; |
|
101
|
0
|
0
|
|
|
|
|
return 0 if $loc->[0] > $this->{xm}; |
|
102
|
0
|
0
|
|
|
|
|
return 0 if $loc->[1] > $this->{ym}; |
|
103
|
|
|
|
|
|
|
|
|
104
|
0
|
|
|
|
|
|
my $type = $this->{_the_map}[ $loc->[1] ][ $loc->[0] ]{type}; |
|
105
|
0
|
0
|
|
|
|
|
return 0 unless $type; # the wall type is |
|
106
|
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
return $loc; |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
# }}} |
|
110
|
|
|
|
|
|
|
# _od_segments {{{ |
|
111
|
|
|
|
|
|
|
sub _od_segments { |
|
112
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
113
|
0
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
## DEBUG ## warn "SET\n<@$lhs> <@$rhs>\n"; |
|
116
|
|
|
|
|
|
|
|
|
117
|
0
|
|
|
|
|
|
my @X = sort {$a<=>$b} ($lhs->[0], $rhs->[0]); @X = ($X[0] .. $X[1]); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
118
|
0
|
|
|
|
|
|
my @Y = sort {$a<=>$b} ($lhs->[1], $rhs->[1]); @Y = ($Y[0] .. $Y[1]); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
|
|
120
|
0
|
0
|
|
|
|
|
my $x_dir = ($lhs->[0] < $rhs->[0] ? "e" : "w"); |
|
121
|
0
|
0
|
|
|
|
|
my $y_dir = ($lhs->[1] < $rhs->[1] ? "s" : "n"); |
|
122
|
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
|
my @od_segments = (); # the solid line segments we might have to pass through |
|
124
|
0
|
|
|
|
|
|
for my $x (@X[0 .. $#X]) { |
|
125
|
0
|
|
|
|
|
|
for my $y (@Y[0 .. $#Y]) { |
|
126
|
0
|
|
|
|
|
|
my $x_od = $this->{_the_map}[ $y ][ $x ]{od}{ $x_dir }; |
|
127
|
0
|
|
|
|
|
|
my $y_od = $this->{_the_map}[ $y ][ $x ]{od}{ $y_dir }; |
|
128
|
|
|
|
|
|
|
|
|
129
|
0
|
|
|
|
|
|
for( $x_od, $y_od ) { |
|
130
|
0
|
0
|
|
|
|
|
$_ = $_->{'open'} if ref $_; |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
0
|
0
|
0
|
|
|
|
unless( $x_od or $x == ($x_dir eq "e" ? $X[$#X]:$X[0]) ) { |
|
|
|
0
|
|
|
|
|
|
|
134
|
0
|
0
|
|
|
|
|
if( $x_dir eq "e" ) { push @od_segments, [[ $x+1, $y ] => [$x+1, $y+1]] } |
|
|
0
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
else { push @od_segments, [[ $x, $y ] => [$x, $y+1]] } |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
0
|
0
|
0
|
|
|
|
unless( $y_od or $y == ($y_dir eq "s" ? $Y[$#Y]:$Y[0]) ) { |
|
|
|
0
|
|
|
|
|
|
|
139
|
0
|
0
|
|
|
|
|
if( $y_dir eq "s" ) { push @od_segments, [[ $x, $y+1 ] => [$x+1, $y+1]] } |
|
|
0
|
|
|
|
|
|
|
|
140
|
0
|
|
|
|
|
|
else { push @od_segments, [[ $x, $y ] => [$x+1, $y ]] } |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
## DEBUG ## warn "(@{$_->[0]})->(@{$_->[1]})\n" for @od_segments; |
|
146
|
|
|
|
|
|
|
## DEBUG ## warn "DONE\n"; |
|
147
|
|
|
|
|
|
|
|
|
148
|
0
|
|
|
|
|
|
return @od_segments; |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
# }}} |
|
151
|
|
|
|
|
|
|
# _extrude_point {{{ |
|
152
|
|
|
|
|
|
|
sub _extrude_point { |
|
153
|
|
|
|
|
|
|
# extrude a point into a tile or a sub-tile |
|
154
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
155
|
0
|
|
|
|
|
|
my $point = shift; |
|
156
|
0
|
|
|
|
|
|
my $use_ocr = shift; # use our creature radius |
|
157
|
0
|
|
|
|
|
|
my $use_lhs = shift; # use our lhs bonus |
|
158
|
|
|
|
|
|
|
|
|
159
|
0
|
0
|
0
|
|
|
|
die "EXTRUDE_POINTS=$EXTRUDE_POINTS must be an even integer" unless $EXTRUDE_POINTS >= 2 and not $EXTRUDE_POINTS =~ m/\./ |
|
|
|
|
0
|
|
|
|
|
|
160
|
|
|
|
|
|
|
and not $EXTRUDE_POINTS & 1; # needed for closure_line_of_sight |
|
161
|
|
|
|
|
|
|
|
|
162
|
0
|
0
|
|
|
|
|
my $s = ($use_ocr ? 0.50-$LOS_CREATURE_RADIUS-($use_lhs ? $LOS_LHS_BONUS : 0) : 0.0001); |
|
|
|
0
|
|
|
|
|
|
|
163
|
0
|
0
|
|
|
|
|
my $e = ($use_ocr ? 0.50+$LOS_CREATURE_RADIUS+($use_lhs ? $LOS_LHS_BONUS : 0) : 0.9999); |
|
|
|
0
|
|
|
|
|
|
|
164
|
0
|
|
|
|
|
|
my $i = ( abs($s-$e) / ($EXTRUDE_POINTS-1) ); |
|
165
|
|
|
|
|
|
|
|
|
166
|
0
|
|
|
|
|
|
my @r = ( |
|
167
|
|
|
|
|
|
|
[$point->[0] + $s, $point->[1] + $s], |
|
168
|
|
|
|
|
|
|
[$point->[0] + $e, $point->[1] + $s], |
|
169
|
|
|
|
|
|
|
[$point->[0] + $s, $point->[1] + $e], |
|
170
|
|
|
|
|
|
|
[$point->[0] + $e, $point->[1] + $e], |
|
171
|
|
|
|
|
|
|
); |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
## DEBUG ## return @r; # psh> require "MapGen/MapQueue.pm"; d[ Games::RolePlay::MapGen::MapQueue->_extrude_point([5,5]) ] |
|
174
|
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
|
my $c = $s+$i; |
|
176
|
0
|
|
|
|
|
|
while( $c < $e ) { |
|
177
|
0
|
|
|
|
|
|
push @r, |
|
178
|
|
|
|
|
|
|
[$point->[0] + $c, $point->[1] + $s], |
|
179
|
|
|
|
|
|
|
[$point->[0] + $s, $point->[1] + $c], |
|
180
|
|
|
|
|
|
|
[$point->[0] + $c, $point->[1] + $e], |
|
181
|
|
|
|
|
|
|
[$point->[0] + $e, $point->[1] + $c], |
|
182
|
0
|
|
|
|
|
|
;$c += $i; |
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# use Data::Dumper; $Data::Dumper::Indent = $Data::Dumper::Sortkeys = 0; |
|
186
|
|
|
|
|
|
|
# warn Dumper([$s, $e, $i, \@r]); |
|
187
|
|
|
|
|
|
|
|
|
188
|
0
|
|
|
|
|
|
my %h; |
|
189
|
0
|
|
|
|
|
|
return grep {my $x = not $h{"@$_"}; $h{"@$_"}=1; $x} @r; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
# }}} |
|
192
|
|
|
|
|
|
|
# _tight_line_of_sight_xs {{{ |
|
193
|
|
|
|
|
|
|
sub _tight_line_of_sight_xs { |
|
194
|
|
|
|
|
|
|
my $this = shift; |
|
195
|
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
return LOS_YES if "@$lhs" eq "@$rhs"; |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
my @ods = $this->_od_segments(@_); |
|
200
|
|
|
|
|
|
|
my @lhs = $this->_extrude_point( $lhs, 1,1 ); # ocr,lhs |
|
201
|
|
|
|
|
|
|
my @rhs = $this->_extrude_point( $rhs, 1,0 ); |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
return LOS_YES if &Games::RolePlay::MapGen::MapQueue::any_any_los_loop(\@lhs, \@rhs, \@ods); |
|
204
|
|
|
|
|
|
|
return LOS_NO; |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
# }}} |
|
207
|
|
|
|
|
|
|
# _tight_line_of_sight_pl {{{ |
|
208
|
|
|
|
|
|
|
sub _tight_line_of_sight_pl { |
|
209
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
210
|
0
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
211
|
|
|
|
|
|
|
|
|
212
|
0
|
0
|
|
|
|
|
return LOS_YES if "@$lhs" eq "@$rhs"; |
|
213
|
|
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
|
my @od_segments = $this->_od_segments(@_); |
|
215
|
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
my @lhs = $this->_extrude_point( $lhs, 1,1 ); # ocr,lhs |
|
217
|
0
|
|
|
|
|
|
my @rhs = $this->_extrude_point( $rhs, 1,0 ); |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
##---------------- LOS CALC |
|
220
|
0
|
|
|
|
|
|
my $line = 0; |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
## DEBUG ## warn "SET\n"; |
|
223
|
|
|
|
|
|
|
## DEBUG ## warn "\@target: <@$rhs>\n"; |
|
224
|
|
|
|
|
|
|
## DEBUG ## warn "wall: (@{$_->[0]})->(@{$_->[1]})\n" for @od_segments; |
|
225
|
|
|
|
|
|
|
LOS_CHECK: |
|
226
|
0
|
|
|
|
|
|
for my $l (@lhs) { |
|
227
|
0
|
|
|
|
|
|
for my $r (@rhs) { |
|
228
|
0
|
|
|
|
|
|
my $this_line = 1; |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
OD_CHECK: |
|
231
|
0
|
|
|
|
|
|
for my $od_segment (@od_segments) { |
|
232
|
0
|
0
|
|
|
|
|
if( $this->_line_segments_intersect( (map {@$_} @$od_segment) => (@$l=>@$r) ) ) { |
|
|
0
|
|
|
|
|
|
|
|
233
|
0
|
|
|
|
|
|
$this_line = 0; |
|
234
|
|
|
|
|
|
|
|
|
235
|
0
|
|
|
|
|
|
last OD_CHECK; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
0
|
0
|
|
|
|
|
if( $this_line ) { |
|
240
|
|
|
|
|
|
|
## DEBUG ## warn "LOS: (@$l)->(@$r)\n"; |
|
241
|
0
|
|
|
|
|
|
$line = 1; |
|
242
|
0
|
|
|
|
|
|
last LOS_CHECK; |
|
243
|
|
|
|
|
|
|
} |
|
244
|
|
|
|
|
|
|
}} |
|
245
|
|
|
|
|
|
|
## DEBUG ## warn "DONE\n"; |
|
246
|
|
|
|
|
|
|
|
|
247
|
0
|
0
|
|
|
|
|
return LOS_NO unless $line; |
|
248
|
0
|
|
|
|
|
|
return LOS_YES; # cover needs to be double checked |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
# }}} |
|
251
|
|
|
|
|
|
|
# _line_of_sight_xs {{{ |
|
252
|
|
|
|
|
|
|
sub _line_of_sight_xs { |
|
253
|
|
|
|
|
|
|
my $this = shift; |
|
254
|
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
return LOS_YES if "@$lhs" eq "@$rhs"; |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
my @ods = $this->_od_segments(@_); |
|
259
|
|
|
|
|
|
|
my @lhs = $this->_extrude_point( $lhs, 0,0 ); # ocr,lhs |
|
260
|
|
|
|
|
|
|
my @rhs = $this->_extrude_point( $rhs, 0,0 ); |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
return LOS_YES if &Games::RolePlay::MapGen::MapQueue::any_any_los_loop(\@lhs, \@rhs, \@ods); |
|
263
|
|
|
|
|
|
|
return LOS_NO; |
|
264
|
|
|
|
|
|
|
} |
|
265
|
|
|
|
|
|
|
# }}} |
|
266
|
|
|
|
|
|
|
# _line_of_sight_pl {{{ |
|
267
|
|
|
|
|
|
|
sub _line_of_sight_pl { |
|
268
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
269
|
0
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
270
|
|
|
|
|
|
|
|
|
271
|
0
|
0
|
|
|
|
|
return LOS_YES if "@$lhs" eq "@$rhs"; |
|
272
|
|
|
|
|
|
|
|
|
273
|
0
|
|
|
|
|
|
my @od_segments = $this->_od_segments(@_); |
|
274
|
|
|
|
|
|
|
|
|
275
|
0
|
|
|
|
|
|
my @lhs = $this->_extrude_point( $lhs, 0,0 ); # ocr,lhs |
|
276
|
0
|
|
|
|
|
|
my @rhs = $this->_extrude_point( $rhs, 0,0 ); |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
# warn "LHS: " . join(" ", map(sprintf('<%9.6f, %9.6f>', @$_), @lhs)); |
|
279
|
|
|
|
|
|
|
# warn "RHS: " . join(" ", map(sprintf('[%9.6f, %9.6f]', @$_), @rhs)); |
|
280
|
|
|
|
|
|
|
# warn "ODS: " . join(" ", map(sprintf('(%9.6f, %9.6f)->(%9.6f, %9.6f)', @{$_->[0]}, @{$_->[1]}), @od_segments)); |
|
281
|
|
|
|
|
|
|
|
|
282
|
0
|
|
|
|
|
|
my $line = 0; |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
## DEBUG ## warn "---------- LOS @$lhs => @$rhs\n"; |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
LOS_CHECK: |
|
287
|
0
|
|
|
|
|
|
for my $l (@lhs) { |
|
288
|
0
|
|
|
|
|
|
for my $r (@rhs) { |
|
289
|
0
|
|
|
|
|
|
my $this_line = 1; |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
OD_CHECK: |
|
292
|
0
|
|
|
|
|
|
for my $od_segment (@od_segments) { |
|
293
|
0
|
0
|
|
|
|
|
if( $this->_line_segments_intersect( (map {@$_} @$od_segment) => (@$l=>@$r) ) ) { |
|
|
0
|
|
|
|
|
|
|
|
294
|
0
|
|
|
|
|
|
$this_line = 0; |
|
295
|
|
|
|
|
|
|
|
|
296
|
0
|
|
|
|
|
|
last OD_CHECK; |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
} |
|
299
|
|
|
|
|
|
|
|
|
300
|
0
|
0
|
|
|
|
|
if( $this_line ) { |
|
301
|
|
|
|
|
|
|
## DEBUG ## warn "\tfound: (@$l)->(@$r)\n"; |
|
302
|
0
|
|
|
|
|
|
$line = 1; |
|
303
|
0
|
|
|
|
|
|
last LOS_CHECK; |
|
304
|
|
|
|
|
|
|
} |
|
305
|
|
|
|
|
|
|
## DEBUG ## else { warn "\treject: (@$l)->(@$r)\n"; } |
|
306
|
|
|
|
|
|
|
}} |
|
307
|
|
|
|
|
|
|
|
|
308
|
0
|
0
|
|
|
|
|
return LOS_NO unless $line; |
|
309
|
0
|
|
|
|
|
|
return LOS_YES; # cover needs to be double checked |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
# }}} |
|
312
|
|
|
|
|
|
|
# _ranged_cover_pl {{{ |
|
313
|
|
|
|
|
|
|
sub _ranged_cover_pl { |
|
314
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
315
|
0
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
316
|
|
|
|
|
|
|
|
|
317
|
0
|
0
|
|
|
|
|
return LOS_NO_COVER if "@$lhs" eq "@$rhs"; |
|
318
|
|
|
|
|
|
|
|
|
319
|
0
|
|
|
|
|
|
my @od_segments = $this->_od_segments(@_); |
|
320
|
|
|
|
|
|
|
|
|
321
|
0
|
|
|
|
|
|
my @lhs = $this->_extrude_point( $lhs, 0,0 ); # ocr,lhs |
|
322
|
0
|
|
|
|
|
|
my @rhs = $this->_extrude_point( $rhs, 0,0 ); |
|
323
|
|
|
|
|
|
|
|
|
324
|
0
|
|
|
|
|
|
for my $l (@lhs) { |
|
325
|
0
|
|
|
|
|
|
my $cover = 0; |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
## DEBUG ## warn "SET\n"; |
|
328
|
|
|
|
|
|
|
## DEBUG ## warn "<@$lhs> <@$rhs>\n"; |
|
329
|
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
|
RCRHS: for my $r (@rhs) { |
|
331
|
0
|
|
|
|
|
|
for my $od_segment (@od_segments) { |
|
332
|
0
|
0
|
|
|
|
|
if( $this->_line_segments_intersect( (map {@$_} @$od_segment) => (@$l=>@$r) ) ) { |
|
|
0
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
## DEBUG ## warn "SET\n<@$lhs> <@$rhs>\n"; |
|
334
|
|
|
|
|
|
|
## DEBUG ## warn "(@{$od_segment->[0]})->(@{$od_segment->[1]}) (@$l)->(@$r)\n"; |
|
335
|
|
|
|
|
|
|
## DEBUG ## warn "DONE\n"; |
|
336
|
0
|
|
|
|
|
|
$cover = 1; |
|
337
|
0
|
|
|
|
|
|
last RCRHS; |
|
338
|
|
|
|
|
|
|
} |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
## DEBUG ## warn "DONE\n"; |
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# for ranged cover, if we can find even one lhs corner that can see all the rhs corners |
|
345
|
|
|
|
|
|
|
# then we return LOS_NO_COVER; |
|
346
|
0
|
0
|
|
|
|
|
unless( $cover ) { |
|
347
|
|
|
|
|
|
|
## DEBUG ## warn "\e[32m here(@$l) \e[m"; |
|
348
|
|
|
|
|
|
|
# NOTE: this cover-upgrade _not_ d20 rules: |
|
349
|
0
|
0
|
|
|
|
|
return LOS_COVER unless $this->_tight_line_of_sight( $lhs => $rhs ); |
|
350
|
0
|
|
|
|
|
|
return LOS_NO_COVER; |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
} |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
## DEBUG ## warn "\e[32m here(---) \e[m"; |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# NOTE: this cover-upgrade is _not_ d20 rules: |
|
357
|
0
|
0
|
|
|
|
|
return LOS_DOUBLE_COVER unless $this->_tight_line_of_sight( $lhs => $rhs ); |
|
358
|
0
|
|
|
|
|
|
return LOS_COVER; |
|
359
|
|
|
|
|
|
|
} |
|
360
|
|
|
|
|
|
|
# }}} |
|
361
|
|
|
|
|
|
|
# _ranged_cover_xs {{{ |
|
362
|
|
|
|
|
|
|
sub _ranged_cover_xs { |
|
363
|
|
|
|
|
|
|
my $this = shift; |
|
364
|
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
return LOS_NO_COVER if "@$lhs" eq "@$rhs"; |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
my @ods = $this->_od_segments(@_); |
|
369
|
|
|
|
|
|
|
my @lhs = $this->_extrude_point( $lhs, 0,0 ); # ocr,lhs |
|
370
|
|
|
|
|
|
|
my @rhs = $this->_extrude_point( $rhs, 0,0 ); |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
if( &Games::RolePlay::MapGen::MapQueue::any_all_los_loop(\@lhs, \@rhs, \@ods) ) { |
|
373
|
|
|
|
|
|
|
## DEBUG ## warn "\e[31m here(@@@) \e[m"; |
|
374
|
|
|
|
|
|
|
return LOS_COVER unless $this->_tight_line_of_sight( $lhs => $rhs ); |
|
375
|
|
|
|
|
|
|
return LOS_NO_COVER; |
|
376
|
|
|
|
|
|
|
} |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
## DEBUG ## warn "\e[31m here(---) \e[m"; |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
return LOS_DOUBLE_COVER unless $this->_tight_line_of_sight( $lhs => $rhs ); |
|
381
|
|
|
|
|
|
|
return LOS_COVER; |
|
382
|
|
|
|
|
|
|
} |
|
383
|
|
|
|
|
|
|
# }}} |
|
384
|
|
|
|
|
|
|
# _melee_cover_pl {{{ |
|
385
|
|
|
|
|
|
|
sub _melee_cover_pl { |
|
386
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
387
|
0
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
# NOTE: Let the caller figure this out? Different creatures have different |
|
390
|
|
|
|
|
|
|
# reach and reach weapons should be using ranged_cover() anyway. On the |
|
391
|
|
|
|
|
|
|
# other hand, this map-logic doesn't even begin to consider creatures that |
|
392
|
|
|
|
|
|
|
# take up more than one tile... |
|
393
|
|
|
|
|
|
|
|
|
394
|
0
|
0
|
|
|
|
|
return LOS_NO_COVER if abs($lhs->[0]-$rhs->[0]) > 1; |
|
395
|
0
|
0
|
|
|
|
|
return LOS_NO_COVER if abs($lhs->[1]-$rhs->[1]) > 1; |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# end_NOTE |
|
398
|
|
|
|
|
|
|
|
|
399
|
0
|
|
|
|
|
|
my @od_segments = $this->_od_segments(@_); |
|
400
|
|
|
|
|
|
|
|
|
401
|
0
|
|
|
|
|
|
my @lhs = $this->_extrude_point( $lhs, 0,0 ); # ocr,lhs |
|
402
|
0
|
|
|
|
|
|
my @rhs = $this->_extrude_point( $rhs, 0,0 ); |
|
403
|
|
|
|
|
|
|
|
|
404
|
0
|
|
|
|
|
|
for my $l (@lhs) { |
|
405
|
0
|
|
|
|
|
|
for my $r (@rhs) { |
|
406
|
0
|
|
|
|
|
|
my $cover = 0; |
|
407
|
|
|
|
|
|
|
|
|
408
|
0
|
|
|
|
|
|
for my $od_segment (@od_segments) { |
|
409
|
0
|
0
|
|
|
|
|
if( $this->_line_segments_intersect( (map {@$_} @$od_segment) => (@$l=>@$r) ) ) { |
|
|
0
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
# This short circuits quickly half the time (on average). If |
|
411
|
|
|
|
|
|
|
# there's cover from any corner it counds as melee cover! |
|
412
|
0
|
|
|
|
|
|
return LOS_COVER; |
|
413
|
|
|
|
|
|
|
} |
|
414
|
|
|
|
|
|
|
} |
|
415
|
|
|
|
|
|
|
}} |
|
416
|
|
|
|
|
|
|
|
|
417
|
0
|
|
|
|
|
|
return LOS_NO_COVER; |
|
418
|
|
|
|
|
|
|
} |
|
419
|
|
|
|
|
|
|
# }}} |
|
420
|
|
|
|
|
|
|
# _melee_cover_xs {{{ |
|
421
|
|
|
|
|
|
|
sub _melee_cover_xs { |
|
422
|
|
|
|
|
|
|
my $this = shift; |
|
423
|
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
return LOS_NO_COVER if abs($lhs->[0]-$rhs->[0]) > 1; |
|
426
|
|
|
|
|
|
|
return LOS_NO_COVER if abs($lhs->[1]-$rhs->[1]) > 1; |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
my @ods = $this->_od_segments(@_); |
|
429
|
|
|
|
|
|
|
my @lhs = $this->_extrude_point( $lhs, 0,0 ); # ocr,lhs |
|
430
|
|
|
|
|
|
|
my @rhs = $this->_extrude_point( $rhs, 0,0 ); |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
return LOS_COVER |
|
433
|
|
|
|
|
|
|
if &Games::RolePlay::MapGen::MapQueue::any_any_intersect_loop(\@lhs, \@rhs, \@ods); |
|
434
|
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
return LOS_NO_COVER; |
|
436
|
|
|
|
|
|
|
} |
|
437
|
|
|
|
|
|
|
# }}} |
|
438
|
|
|
|
|
|
|
# _closure_line_of_sight_pl {{{ |
|
439
|
|
|
|
|
|
|
sub _closure_line_of_sight_pl { |
|
440
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
441
|
0
|
|
|
|
|
|
my $lhs = shift; |
|
442
|
0
|
|
|
|
|
|
my $rhsd = shift; |
|
443
|
|
|
|
|
|
|
|
|
444
|
0
|
|
|
|
|
|
my $s = (0.0001); |
|
445
|
0
|
|
|
|
|
|
my $e = (0.9999); |
|
446
|
0
|
|
|
|
|
|
my $i = (abs($s-$e) / ($EXTRUDE_POINTS-1)); |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
# NOTE: We build a row of points just "this side" of the door using (@c,$b) |
|
449
|
|
|
|
|
|
|
# for n/s doors or ($b,@c) for e/w ones. When we're done, there's a row of |
|
450
|
|
|
|
|
|
|
# points in the @rhs, built from @c and $b. |
|
451
|
|
|
|
|
|
|
|
|
452
|
0
|
|
|
|
|
|
my @c = ($s); $c[@c] = $c[$#c] + $i while $c[$#c] < $e; |
|
|
0
|
|
|
|
|
|
|
|
453
|
0
|
|
|
|
|
|
my $b; |
|
454
|
|
|
|
|
|
|
|
|
455
|
0
|
0
|
|
|
|
|
if( $rhsd->[2] eq "n" ) { $b = $rhsd->[1] + ($lhs->[1]>=$rhsd->[1] ? 0.01 : -0.01) } # slightly more or less than 0 |
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
456
|
0
|
0
|
|
|
|
|
elsif( $rhsd->[2] eq "s" ) { $b = $rhsd->[1] + ($lhs->[1]<=$rhsd->[1] ? 0.99 : 1.01) } # slightly more or less than 1 |
|
457
|
0
|
0
|
|
|
|
|
elsif( $rhsd->[2] eq "e" ) { $b = $rhsd->[0] + ($lhs->[0]<=$rhsd->[0] ? 0.99 : 1.01) } |
|
458
|
0
|
0
|
|
|
|
|
elsif( $rhsd->[2] eq "w" ) { $b = $rhsd->[0] + ($lhs->[0]>=$rhsd->[0] ? 0.01 : -0.01) } |
|
459
|
|
|
|
|
|
|
|
|
460
|
0
|
|
|
|
|
|
my @rhs; |
|
461
|
0
|
0
|
|
|
|
|
if( $rhsd->[2] eq "n" ) { @rhs = map {[ $rhsd->[0]+$_, $b ]} @c } |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
462
|
0
|
|
|
|
|
|
elsif( $rhsd->[2] eq "s" ) { @rhs = map {[ $rhsd->[0]+$_, $b ]} @c } |
|
|
0
|
|
|
|
|
|
|
|
463
|
0
|
|
|
|
|
|
elsif( $rhsd->[2] eq "e" ) { @rhs = map {[ $b, $rhsd->[1]+$_ ]} @c } |
|
|
0
|
|
|
|
|
|
|
|
464
|
0
|
|
|
|
|
|
elsif( $rhsd->[2] eq "w" ) { @rhs = map {[ $b, $rhsd->[1]+$_ ]} @c } |
|
|
0
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
|
|
466
|
0
|
|
|
|
|
|
my $v = [ $rhs[-1][0]-$rhs[0][0], $rhs[-1][1]-$rhs[0][1] ]; # vector @origin describing the line-segment named @rhs |
|
467
|
0
|
|
|
|
|
|
my $mv = sqrt( $v->[0]**2 + $v->[1]**2 ); |
|
468
|
0
|
|
|
|
|
|
$v = [ map { $_/$mv } @$v ]; # unit vector describing the line-segment named @rhs |
|
|
0
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
|
|
470
|
0
|
|
|
|
|
|
my $c = [ $rhsd->[0] + $v->[0]/2, $rhsd->[1] + $v->[1]/2 ]; # center of the line-segment named $rhsd |
|
471
|
0
|
0
|
|
|
|
|
$c->[0] ++ if $rhsd->[2] eq "e"; # which does require some minor correction |
|
472
|
0
|
0
|
|
|
|
|
$c->[1] ++ if $rhsd->[2] eq "s"; |
|
473
|
|
|
|
|
|
|
|
|
474
|
0
|
|
|
|
|
|
my @od_segments = $this->_od_segments($lhs, [$rhs[0][0],$rhs[0][1]]); # line segments possibly in the way |
|
475
|
|
|
|
|
|
|
|
|
476
|
0
|
|
|
|
|
|
my @lhs = |
|
477
|
|
|
|
|
|
|
grep { |
|
478
|
0
|
|
|
|
|
|
my $l = $_; |
|
479
|
0
|
|
|
|
|
|
my $ok = 1; |
|
480
|
0
|
|
|
|
|
|
for my $r (@rhs) { |
|
481
|
0
|
|
|
|
|
|
for my $od_segment (@od_segments) { |
|
482
|
0
|
0
|
|
|
|
|
if( my @i = $this->_line_segments_intersect( (map {@$_} @$od_segment) => (@$l=>@$r) ) ) { |
|
|
0
|
|
|
|
|
|
|
|
483
|
0
|
|
|
|
|
|
$ok = 0; |
|
484
|
0
|
|
|
|
|
|
last; |
|
485
|
|
|
|
|
|
|
} |
|
486
|
|
|
|
|
|
|
} |
|
487
|
|
|
|
|
|
|
} |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
$ok |
|
490
|
|
|
|
|
|
|
|
|
491
|
0
|
|
|
|
|
|
} grep { |
|
492
|
0
|
|
|
|
|
|
my $ab; |
|
493
|
0
|
|
|
|
|
|
my $od = $this->{_the_map}[ $rhsd->[1] ][ $rhsd->[0] ]{od}{ $rhsd->[2] }; |
|
494
|
0
|
|
|
|
|
|
my $rf = ref $od; |
|
495
|
0
|
0
|
0
|
|
|
|
if( ($od and not $rf) or ($rf and $od->{'open'}) ) { |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
496
|
0
|
|
|
|
|
|
$ab = 360; |
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
} else { |
|
499
|
0
|
|
|
|
|
|
my $u = [ $c->[0]-$_->[0], $c->[1]-$_->[1] ]; # the line-segment from the $_ to the center of the closure |
|
500
|
0
|
|
|
|
|
|
my $mu = sqrt( $u->[0]**2 + $u->[1]**2 ); |
|
501
|
0
|
|
|
|
|
|
$u = [ map { abs $_/$mu } @$u ]; # unit vector of $u -- er, the totally positive version anyway |
|
|
0
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
# We wish to exclude points that are within a certain arc. |
|
504
|
|
|
|
|
|
|
# Anything within $CLOS_MIN_ANGLE degrees of the wall plane |
|
505
|
|
|
|
|
|
|
# we're searching is defined to be an akward search angle |
|
506
|
|
|
|
|
|
|
|
|
507
|
0
|
|
|
|
|
|
my $cab = $v->[0]*$u->[0] + $v->[1]*$u->[1]; |
|
508
|
|
|
|
|
|
|
|
|
509
|
0
|
|
|
|
|
|
$ab = acos( $cab ); |
|
510
|
|
|
|
|
|
|
} |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
# $ab, hopefully, contains the angle between the vectors |
|
513
|
0
|
|
|
|
|
|
$ab >= $CLOS_MIN_ANGLE; |
|
514
|
|
|
|
|
|
|
} |
|
515
|
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
# All the points around the edge of the source tile. We do not need to |
|
517
|
|
|
|
|
|
|
# worry about any lhs being in the same line segment as the rhs since |
|
518
|
|
|
|
|
|
|
# none of them should be $c and all of them will have too small of an |
|
519
|
|
|
|
|
|
|
# angle between -- this assumes EXTRUDE_POINTS is even, which is now |
|
520
|
|
|
|
|
|
|
# enforced in _ex_p |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
($this->_extrude_point( $lhs, 0,0 ), [$lhs->[0]+0.5,$lhs->[1]+0.5]); |
|
523
|
|
|
|
|
|
|
|
|
524
|
0
|
0
|
|
|
|
|
my $min = (@lhs ? min map { my $l = $_; (max map { sqrt(($l->[0]-$_->[0])**2 + ($l->[1]-$_->[1])**2) } @rhs) } @lhs : 0); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
525
|
0
|
|
|
|
|
|
return $min; |
|
526
|
|
|
|
|
|
|
} |
|
527
|
|
|
|
|
|
|
# }}} |
|
528
|
|
|
|
|
|
|
# _closure_line_of_sight_xs {{{ |
|
529
|
|
|
|
|
|
|
sub _closure_line_of_sight_xs { |
|
530
|
|
|
|
|
|
|
my $this = shift; |
|
531
|
|
|
|
|
|
|
my $lhs = shift; |
|
532
|
|
|
|
|
|
|
my $rhsd = shift; |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
my $s = (0.0001); |
|
535
|
|
|
|
|
|
|
my $e = (0.9999); |
|
536
|
|
|
|
|
|
|
my $i = (abs($s-$e) / ($EXTRUDE_POINTS-1)); |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
# NOTE: We build a row of points just "this side" of the door using (@c,$b) |
|
539
|
|
|
|
|
|
|
# for n/s doors or ($b,@c) for e/w ones. When we're done, there's a row of |
|
540
|
|
|
|
|
|
|
# points in the @rhs, built from @c and $b. |
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
my @c = ($s); $c[@c] = $c[$#c] + $i while $c[$#c] < $e; |
|
543
|
|
|
|
|
|
|
my $b; |
|
544
|
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
if( $rhsd->[2] eq "n" ) { $b = $rhsd->[1] + ($lhs->[1]>=$rhsd->[1] ? 0.01 : -0.01) } # slightly more or less than 0 |
|
546
|
|
|
|
|
|
|
elsif( $rhsd->[2] eq "s" ) { $b = $rhsd->[1] + ($lhs->[1]<=$rhsd->[1] ? 0.99 : 1.01) } # slightly more or less than 1 |
|
547
|
|
|
|
|
|
|
elsif( $rhsd->[2] eq "e" ) { $b = $rhsd->[0] + ($lhs->[0]<=$rhsd->[0] ? 0.99 : 1.01) } |
|
548
|
|
|
|
|
|
|
elsif( $rhsd->[2] eq "w" ) { $b = $rhsd->[0] + ($lhs->[0]>=$rhsd->[0] ? 0.01 : -0.01) } |
|
549
|
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
my @rhs; # we don't know what the rhs is until we figure out where the door is in relation to the $lhs |
|
551
|
|
|
|
|
|
|
if( $rhsd->[2] eq "n" ) { @rhs = map {[ $rhsd->[0]+$_, $b ]} @c } |
|
552
|
|
|
|
|
|
|
elsif( $rhsd->[2] eq "s" ) { @rhs = map {[ $rhsd->[0]+$_, $b ]} @c } |
|
553
|
|
|
|
|
|
|
elsif( $rhsd->[2] eq "e" ) { @rhs = map {[ $b, $rhsd->[1]+$_ ]} @c } |
|
554
|
|
|
|
|
|
|
elsif( $rhsd->[2] eq "w" ) { @rhs = map {[ $b, $rhsd->[1]+$_ ]} @c } |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
my $v = [ $rhs[-1][0]-$rhs[0][0], $rhs[-1][1]-$rhs[0][1] ]; # vector @origin describing the line-segment named @rhs |
|
557
|
|
|
|
|
|
|
my $mv = sqrt( $v->[0]**2 + $v->[1]**2 ); |
|
558
|
|
|
|
|
|
|
$v = [ map { $_/$mv } @$v ]; # unit vector describing the line-segment named @rhs |
|
559
|
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
my $c = [ $rhsd->[0] + $v->[0]/2, $rhsd->[1] + $v->[1]/2 ]; # center of the line-segment named $rhsd |
|
561
|
|
|
|
|
|
|
$c->[0] ++ if $rhsd->[2] eq "e"; # which does require some minor correction |
|
562
|
|
|
|
|
|
|
$c->[1] ++ if $rhsd->[2] eq "s"; |
|
563
|
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
my @ods = $this->_od_segments($lhs, [$rhs[0][0],$rhs[0][1]]); # line segments possibly in the way |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
my @lhs = grep { &Games::RolePlay::MapGen::MapQueue::any_all_los_loop([$_], \@rhs, \@ods) } |
|
567
|
|
|
|
|
|
|
grep { |
|
568
|
|
|
|
|
|
|
my $ab; |
|
569
|
|
|
|
|
|
|
my $od = $this->{_the_map}[ $rhsd->[1] ][ $rhsd->[0] ]{od}{ $rhsd->[2] }; |
|
570
|
|
|
|
|
|
|
my $rf = ref $od; |
|
571
|
|
|
|
|
|
|
if( ($od and not $rf) or ($rf and $od->{'open'}) ) { |
|
572
|
|
|
|
|
|
|
$ab = 360; |
|
573
|
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
} else { |
|
575
|
|
|
|
|
|
|
my $u = [ $c->[0]-$_->[0], $c->[1]-$_->[1] ]; # the line-segment from the $_ to the center of the closure |
|
576
|
|
|
|
|
|
|
my $mu = sqrt( $u->[0]**2 + $u->[1]**2 ); |
|
577
|
|
|
|
|
|
|
$u = [ map { abs $_/$mu } @$u ]; # unit vector of $u -- er, the totally positive version anyway |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
# We wish to exclude points that are within a certain arc. |
|
580
|
|
|
|
|
|
|
# Anything within $CLOS_MIN_ANGLE degrees of the wall plane |
|
581
|
|
|
|
|
|
|
# we're searching is defined to be an akward search angle |
|
582
|
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
my $cab = $v->[0]*$u->[0] + $v->[1]*$u->[1]; |
|
584
|
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
$ab = acos( $cab ); |
|
586
|
|
|
|
|
|
|
} |
|
587
|
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
# $ab, hopefully, contains the angle between the vectors |
|
589
|
|
|
|
|
|
|
$ab >= $CLOS_MIN_ANGLE; |
|
590
|
|
|
|
|
|
|
} |
|
591
|
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
# All the points around the edge of the source tile. We do not need to |
|
593
|
|
|
|
|
|
|
# worry about any lhs being in the same line segment as the rhs since |
|
594
|
|
|
|
|
|
|
# none of them should be $c and all of them will have too small of an |
|
595
|
|
|
|
|
|
|
# angle between -- this assumes EXTRUDE_POINTS is even, which is now |
|
596
|
|
|
|
|
|
|
# enforced in _ex_p |
|
597
|
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
($this->_extrude_point( $lhs, 0,0 ), [$lhs->[0]+0.5,$lhs->[1]+0.5]); |
|
599
|
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
my $min = (@lhs ? min map { my $l = $_; (max map { sqrt(($l->[0]-$_->[0])**2 + ($l->[1]-$_->[1])**2) } @rhs) } @lhs : 0); |
|
601
|
|
|
|
|
|
|
return $min; |
|
602
|
|
|
|
|
|
|
} |
|
603
|
|
|
|
|
|
|
# }}} |
|
604
|
|
|
|
|
|
|
# _mxb_of_sight (returns m and b of y=mx+b fame) {{{ |
|
605
|
|
|
|
|
|
|
sub _mxb_of_sight { |
|
606
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
607
|
0
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
608
|
|
|
|
|
|
|
|
|
609
|
0
|
0
|
|
|
|
|
return if "@$lhs" eq "@$rhs"; |
|
610
|
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
## DEBUG ## warn "---------- MXB @$lhs => @$rhs\n"; |
|
612
|
|
|
|
|
|
|
|
|
613
|
0
|
|
|
|
|
|
my @od_segments = $this->_od_segments(@_); |
|
614
|
|
|
|
|
|
|
|
|
615
|
0
|
|
|
|
|
|
my @lhs = $this->_extrude_point( $lhs, 0,0 ); # ocr,lh |
|
616
|
0
|
|
|
|
|
|
my @rhs = $this->_extrude_point( $rhs, 0,0 ); |
|
617
|
|
|
|
|
|
|
|
|
618
|
0
|
|
|
|
|
|
for my $l (sort { $this->_ldistance($a=>$rhs) <=> $this->_ldistance($b=>$rhs) } @lhs) { |
|
|
0
|
|
|
|
|
|
|
|
619
|
0
|
|
|
|
|
|
for my $r (sort { $this->_ldistance($a=>$l) <=> $this->_ldistance($b=>$l) } @rhs) { |
|
|
0
|
|
|
|
|
|
|
|
620
|
0
|
|
|
|
|
|
my $this_line = 1; |
|
621
|
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
OD_CHECK: |
|
623
|
0
|
|
|
|
|
|
for my $od_segment (@od_segments) { |
|
624
|
0
|
0
|
|
|
|
|
if( $this->_line_segments_intersect( (map {@$_} @$od_segment) => (@$l=>@$r) ) ) { |
|
|
0
|
|
|
|
|
|
|
|
625
|
0
|
|
|
|
|
|
$this_line = 0; |
|
626
|
|
|
|
|
|
|
|
|
627
|
0
|
|
|
|
|
|
last OD_CHECK; |
|
628
|
|
|
|
|
|
|
} |
|
629
|
|
|
|
|
|
|
} |
|
630
|
|
|
|
|
|
|
|
|
631
|
0
|
0
|
|
|
|
|
if( $this_line ) { |
|
632
|
0
|
|
|
|
|
|
my $d = ($r->[0]-$l->[0]); |
|
633
|
0
|
0
|
|
|
|
|
my $m = ($d != 0 ? ( ($r->[1]-$l->[1]) / $d ) : undef ); |
|
634
|
0
|
0
|
|
|
|
|
my $b = (defined $m ? ($l->[1] - ($m*$l->[0])) : 0); |
|
635
|
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
## DEBUG ## warn "\tfound: (@$l)->(@$r)\n"; |
|
637
|
|
|
|
|
|
|
|
|
638
|
0
|
|
|
|
|
|
return ($m, $b, $l, $r); |
|
639
|
|
|
|
|
|
|
} |
|
640
|
|
|
|
|
|
|
## DEBUG ## else { warn "\treject: (@$l)->(@$r)\n"; } |
|
641
|
|
|
|
|
|
|
}} |
|
642
|
|
|
|
|
|
|
|
|
643
|
0
|
|
|
|
|
|
return; |
|
644
|
|
|
|
|
|
|
} |
|
645
|
|
|
|
|
|
|
# }}} |
|
646
|
|
|
|
|
|
|
# _ignorable_cover {{{ |
|
647
|
|
|
|
|
|
|
sub _ignorable_cover { |
|
648
|
|
|
|
|
|
|
my $this = shift; |
|
649
|
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
650
|
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
warn "ignorable cover isn't actually calculated"; |
|
652
|
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
return 0; |
|
654
|
|
|
|
|
|
|
} |
|
655
|
|
|
|
|
|
|
# }}} |
|
656
|
|
|
|
|
|
|
# _ldistance {{{ |
|
657
|
|
|
|
|
|
|
sub _ldistance { |
|
658
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
659
|
0
|
|
|
|
|
|
my ($lhs, $rhs) = @_; |
|
660
|
|
|
|
|
|
|
|
|
661
|
0
|
|
|
|
|
|
return sqrt ( (($lhs->[0]-$rhs->[0]) ** 2) + (($lhs->[1]-$rhs->[1]) ** 2) ); |
|
662
|
|
|
|
|
|
|
} |
|
663
|
|
|
|
|
|
|
# }}} |
|
664
|
|
|
|
|
|
|
# _locations_in_line_of_sight {{{ |
|
665
|
|
|
|
|
|
|
sub _locations_in_line_of_sight { |
|
666
|
|
|
|
|
|
|
my $this = shift; |
|
667
|
|
|
|
|
|
|
my $init = shift; |
|
668
|
|
|
|
|
|
|
my @loc = (); |
|
669
|
|
|
|
|
|
|
my @new = ($init); |
|
670
|
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
my %checked = ( "@$init" => 1 ); |
|
672
|
|
|
|
|
|
|
while( @new ) { |
|
673
|
|
|
|
|
|
|
my @very_new = (); |
|
674
|
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
for my $i (@new) { |
|
676
|
|
|
|
|
|
|
for my $j ( [$i->[0]+1, $i->[1]], [$i->[0]-1, $i->[1]], [$i->[0], $i->[1]+1], [$i->[0], $i->[1]-1] ) { |
|
677
|
|
|
|
|
|
|
next if $checked{"@$j"}; $checked{"@$j"} = 1; |
|
678
|
|
|
|
|
|
|
next unless $this->_check_loc($j); |
|
679
|
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
push @very_new, $j if $this->_line_of_sight( $init => $j ); |
|
681
|
|
|
|
|
|
|
} |
|
682
|
|
|
|
|
|
|
} |
|
683
|
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
push @loc, @new; |
|
685
|
|
|
|
|
|
|
@new = @very_new; |
|
686
|
|
|
|
|
|
|
} |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
return @loc; |
|
689
|
|
|
|
|
|
|
} |
|
690
|
|
|
|
|
|
|
# }}} |
|
691
|
|
|
|
|
|
|
# _locations_in_range_and_line_of_sight {{{ |
|
692
|
|
|
|
|
|
|
sub _locations_in_range_and_line_of_sight { |
|
693
|
|
|
|
|
|
|
my $this = shift; |
|
694
|
|
|
|
|
|
|
my $init = shift; |
|
695
|
|
|
|
|
|
|
my $range = shift; |
|
696
|
|
|
|
|
|
|
my @loc = (); |
|
697
|
|
|
|
|
|
|
my @new = ($init); |
|
698
|
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
my %checked = ( "@$init" => 1 ); |
|
700
|
|
|
|
|
|
|
while( @new ) { |
|
701
|
|
|
|
|
|
|
my @very_new = (); |
|
702
|
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
for my $i (@new) { |
|
704
|
|
|
|
|
|
|
for my $j ( [$i->[0]+1, $i->[1]], [$i->[0]-1, $i->[1]], [$i->[0], $i->[1]+1], [$i->[0], $i->[1]-1] ) { |
|
705
|
|
|
|
|
|
|
next if $checked{"@$j"}; $checked{"@$j"} = 1; |
|
706
|
|
|
|
|
|
|
next unless $this->_check_loc($j); |
|
707
|
|
|
|
|
|
|
next unless sqrt( ($init->[0]-$j->[0])**2 + ($init->[1]-$j->[1])**2) <= $range; |
|
708
|
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
push @very_new, $j if $this->_line_of_sight( $init => $j ); |
|
710
|
|
|
|
|
|
|
} |
|
711
|
|
|
|
|
|
|
} |
|
712
|
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
push @loc, @new; |
|
714
|
|
|
|
|
|
|
@new = @very_new; |
|
715
|
|
|
|
|
|
|
} |
|
716
|
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
return @loc; |
|
718
|
|
|
|
|
|
|
} |
|
719
|
|
|
|
|
|
|
# }}} |
|
720
|
|
|
|
|
|
|
# _objs_at_location {{{ |
|
721
|
|
|
|
|
|
|
sub _objs_at_location { |
|
722
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
723
|
0
|
|
|
|
|
|
my $loc = shift; |
|
724
|
0
|
0
|
|
|
|
|
my @itm = @{ $this->{c}[ $loc->[1] ][ $loc->[0] ] || [] }; |
|
|
0
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
|
|
726
|
0
|
|
|
|
|
|
return @itm; # this is a copy, so it's silly to use wantarray... |
|
727
|
|
|
|
|
|
|
} |
|
728
|
|
|
|
|
|
|
# }}} |
|
729
|
|
|
|
|
|
|
# _locations_in_path {{{ |
|
730
|
|
|
|
|
|
|
sub _locations_in_path { |
|
731
|
|
|
|
|
|
|
my $this = shift; |
|
732
|
|
|
|
|
|
|
my $lhs = shift; |
|
733
|
|
|
|
|
|
|
my $rhs = shift; |
|
734
|
|
|
|
|
|
|
my @path = (); |
|
735
|
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
return ([@$lhs],[@$rhs]) if "@$lhs" eq "@$rhs"; |
|
737
|
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
my ($m, $b, $p0, $p1) = $this->_mxb_of_sight($lhs => $rhs); |
|
739
|
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
## DEBUG ## warn "m=$m; b=$b; p0=(@$p0); p1=(@$p1)"; |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
my $ranger = sub { |
|
743
|
|
|
|
|
|
|
my ($l, $r) = @_; |
|
744
|
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
return ( $l<$r ? ($l+1 .. $r-1) : (reverse ($r+1 .. $l-1)) ); |
|
746
|
|
|
|
|
|
|
}; |
|
747
|
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
push @path, [@$lhs]; |
|
749
|
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
if( not defined $m ) { |
|
751
|
|
|
|
|
|
|
for my $y ( $ranger->($lhs->[1] => $rhs->[1]) ) { |
|
752
|
|
|
|
|
|
|
my $x = $lhs->[0]; # == $rhs->[0] |
|
753
|
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
push @path, [$x,$y]; |
|
755
|
|
|
|
|
|
|
} |
|
756
|
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
} elsif( (abs $m) > 1 ) { |
|
758
|
|
|
|
|
|
|
for my $y ( $ranger->($lhs->[1] => $rhs->[1]) ) { |
|
759
|
|
|
|
|
|
|
my $z = (($y+0.5)-$b)/$m; |
|
760
|
|
|
|
|
|
|
my $x = round($z-0.5); |
|
761
|
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
push @path, [$x,$y]; |
|
763
|
|
|
|
|
|
|
} |
|
764
|
|
|
|
|
|
|
} elsif( $m == 0 ) { |
|
765
|
|
|
|
|
|
|
for my $x ( $ranger->($lhs->[0] => $rhs->[0]) ) { |
|
766
|
|
|
|
|
|
|
my $y = round($b); |
|
767
|
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
push @path, [$x,$y]; |
|
769
|
|
|
|
|
|
|
} |
|
770
|
|
|
|
|
|
|
|
|
771
|
|
|
|
|
|
|
} else { |
|
772
|
|
|
|
|
|
|
for my $x ( $ranger->($lhs->[0] => $rhs->[0]) ) { |
|
773
|
|
|
|
|
|
|
my $z = ($m * ($x+0.5)) + $b; |
|
774
|
|
|
|
|
|
|
my $y = round($z-0.5); |
|
775
|
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
push @path, [$x,$y]; |
|
777
|
|
|
|
|
|
|
} |
|
778
|
|
|
|
|
|
|
} |
|
779
|
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
push @path, [@$rhs]; |
|
781
|
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
for my $list ([+1, reverse 0 .. $#path-1], [-1, 1 .. $#path]) { my $ni = shift @$list; |
|
783
|
|
|
|
|
|
|
for my $i (@$list) { |
|
784
|
|
|
|
|
|
|
my $changes = 0; |
|
785
|
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
for my $j (0,1) { |
|
787
|
|
|
|
|
|
|
my $A = $path[$i][$j]; |
|
788
|
|
|
|
|
|
|
my $d = $path[$i+$ni][$j] - $A; |
|
789
|
|
|
|
|
|
|
my $md = abs $d; |
|
790
|
|
|
|
|
|
|
if( $md > 1 ) { |
|
791
|
|
|
|
|
|
|
$A += $d/$md; |
|
792
|
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
## DEBUG ## warn (($j==0 ? "X":"Y") . "-CHANGE($i,$j)::(@{$path[$i]})[$j] = $A\n"); |
|
794
|
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
$path[$i][$j] = $A; |
|
796
|
|
|
|
|
|
|
$changes ++; |
|
797
|
|
|
|
|
|
|
} |
|
798
|
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
## DEBUG ## else { warn (($j==0 ? "X":"Y") . "-!NO!CHANGE($i,$j)::(@{$path[$i]})[$j] = $A; md=$md; d=$d\n"); } |
|
800
|
|
|
|
|
|
|
} |
|
801
|
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
last unless $changes; |
|
803
|
|
|
|
|
|
|
}} |
|
804
|
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
DIAG_ORDEAL: { |
|
806
|
|
|
|
|
|
|
my $map = $this->{_the_map}; |
|
807
|
|
|
|
|
|
|
for my $i ( 0 .. $#path-1 ) { |
|
808
|
|
|
|
|
|
|
my $j = $i + 1; |
|
809
|
|
|
|
|
|
|
my ($lhs, $rhs) = ($path[$i], $path[$j]); |
|
810
|
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
if( $lhs->[0] != $rhs->[0] and $lhs->[1] != $rhs->[1] ) { |
|
812
|
|
|
|
|
|
|
# NOTE: a diagonal move is illegal if there's a "corner" in the way phb p. 147 |
|
813
|
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
LHS_DIAG_VIOLATION: { |
|
815
|
|
|
|
|
|
|
my $lod = $map->[ $lhs->[1] ][ $lhs->[0] ]{od}; |
|
816
|
|
|
|
|
|
|
my $xdir = ($lhs->[0]<$rhs->[0] ? 'e':'w'); my $xo = $lod->{$xdir}; $xo = 1 if ref $xo and $xo->{'open'}; |
|
817
|
|
|
|
|
|
|
my $ydir = ($lhs->[1]<$rhs->[1] ? 's':'n'); my $yo = $lod->{$ydir}; $yo = 1 if ref $yo and $yo->{'open'}; |
|
818
|
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
if( not $yo ) { |
|
820
|
|
|
|
|
|
|
if( $i == 0 or ($path[$i-1][0] != $lhs->[0]) ) { |
|
821
|
|
|
|
|
|
|
splice @path, $j, 0, [ $rhs->[0], $lhs->[1] ]; # 0-width inserts at $j |
|
822
|
|
|
|
|
|
|
redo DIAG_ORDEAL; |
|
823
|
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
} else { |
|
825
|
|
|
|
|
|
|
$lhs->[0] = $rhs->[0]; |
|
826
|
|
|
|
|
|
|
} |
|
827
|
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
} elsif( not $xo ) { |
|
829
|
|
|
|
|
|
|
if( $i == 0 or ($path[$i-1][1] != $lhs->[1]) ) { |
|
830
|
|
|
|
|
|
|
splice @path, $j, 0, [ $lhs->[0], $rhs->[1] ]; # 0-width inserts at $j |
|
831
|
|
|
|
|
|
|
redo DIAG_ORDEAL; |
|
832
|
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
} else { |
|
834
|
|
|
|
|
|
|
$lhs->[1] = $rhs->[1]; |
|
835
|
|
|
|
|
|
|
} |
|
836
|
|
|
|
|
|
|
} |
|
837
|
|
|
|
|
|
|
} |
|
838
|
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
RHS_DIAG_VIOLATION: { |
|
840
|
|
|
|
|
|
|
my $lod = $map->[ $rhs->[1] ][ $rhs->[0] ]{od}; |
|
841
|
|
|
|
|
|
|
my $xdir = ($lhs->[0]<$rhs->[0] ? 'w':'e'); my $xo = $lod->{$xdir}; $xo = 1 if ref $xo and $xo->{'open'}; |
|
842
|
|
|
|
|
|
|
my $ydir = ($lhs->[1]<$rhs->[1] ? 'n':'s'); my $yo = $lod->{$ydir}; $yo = 1 if ref $yo and $yo->{'open'}; |
|
843
|
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
if( not $yo ) { |
|
845
|
|
|
|
|
|
|
if( $j == $#path or ($path[$j+1][0] != $rhs->[0] ) ) { |
|
846
|
|
|
|
|
|
|
splice @path, $j, 0, [ $lhs->[0], $rhs->[1] ]; # 0-width inserts at $j |
|
847
|
|
|
|
|
|
|
redo DIAG_ORDEAL; |
|
848
|
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
} else { |
|
850
|
|
|
|
|
|
|
$rhs->[0] = $lhs->[0]; |
|
851
|
|
|
|
|
|
|
} |
|
852
|
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
} elsif( not $xo ) { |
|
854
|
|
|
|
|
|
|
if( $j == $#path or ($path[$j+1][1] != $rhs->[1] ) ) { |
|
855
|
|
|
|
|
|
|
splice @path, $j, 0, [ $rhs->[0], $lhs->[1] ]; # 0-width inserts at $j |
|
856
|
|
|
|
|
|
|
redo DIAG_ORDEAL; |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
} else { |
|
859
|
|
|
|
|
|
|
$rhs->[1] = $lhs->[1]; |
|
860
|
|
|
|
|
|
|
} |
|
861
|
|
|
|
|
|
|
} |
|
862
|
|
|
|
|
|
|
} |
|
863
|
|
|
|
|
|
|
} |
|
864
|
|
|
|
|
|
|
} |
|
865
|
|
|
|
|
|
|
} |
|
866
|
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
return @path; |
|
868
|
|
|
|
|
|
|
} |
|
869
|
|
|
|
|
|
|
# }}} |
|
870
|
|
|
|
|
|
|
# _door {{{ |
|
871
|
|
|
|
|
|
|
sub _door { |
|
872
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
873
|
0
|
0
|
|
|
|
|
my $door = shift; return unless ref $door; |
|
|
0
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
|
|
875
|
0
|
|
|
|
|
|
for my $y ( 0 .. $this->{ym} ) { |
|
876
|
0
|
|
|
|
|
|
for my $x ( 0 .. $this->{xm} ) { |
|
877
|
0
|
|
|
|
|
|
my $tile = $this->{_the_map}[$y][$x]; |
|
878
|
|
|
|
|
|
|
|
|
879
|
0
|
|
|
|
|
|
for my $d (qw(n e s w)) { |
|
880
|
0
|
0
|
|
|
|
|
if( $door == $tile->{od}{$d} ) { |
|
881
|
0
|
|
|
|
|
|
my $nb = $tile->{nb}{$d}; |
|
882
|
|
|
|
|
|
|
|
|
883
|
0
|
|
|
|
|
|
return [$x,$y,$d]; |
|
884
|
|
|
|
|
|
|
} |
|
885
|
|
|
|
|
|
|
} |
|
886
|
|
|
|
|
|
|
} |
|
887
|
|
|
|
|
|
|
} |
|
888
|
|
|
|
|
|
|
|
|
889
|
0
|
|
|
|
|
|
return; |
|
890
|
|
|
|
|
|
|
} |
|
891
|
|
|
|
|
|
|
# }}} |
|
892
|
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
# _line_segments_intersect {{{ |
|
894
|
|
|
|
|
|
|
sub _line_segments_intersect { |
|
895
|
0
|
|
|
0
|
|
|
my $this = shift; |
|
896
|
|
|
|
|
|
|
# this is http://perlmonks.org/?node_id=253983 |
|
897
|
|
|
|
|
|
|
|
|
898
|
0
|
|
|
|
|
|
my ( $ax,$ay, $bx,$by, $cx,$cy, $dx,$dy ) = @_; |
|
899
|
|
|
|
|
|
|
# printf STDERR "[pl] A(%9.6f,%9.6f) B(%9.6f,%9.6f) C(%9.6f,%9.6f) D(%9.6f,%9.6f)", $ax,$ay, $bx,$by, $cx,$cy, $dx,$dy; |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
# P = p*A + (1-p)*B |
|
902
|
|
|
|
|
|
|
# Q = q*C + (1-q)*D |
|
903
|
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
# for p=0, P=A, and for p=1, P=B |
|
905
|
|
|
|
|
|
|
# for 0<=p<=1, P is on the line segment between A and B |
|
906
|
|
|
|
|
|
|
|
|
907
|
|
|
|
|
|
|
# find p,q such than P=Q |
|
908
|
|
|
|
|
|
|
# (... lengthy derivation ...) |
|
909
|
|
|
|
|
|
|
|
|
910
|
0
|
|
|
|
|
|
my $d = ($ax-$bx)*($cy-$dy) - ($ay-$by)*($cx-$dx); |
|
911
|
|
|
|
|
|
|
# printf STDERR " d=$d"; |
|
912
|
|
|
|
|
|
|
|
|
913
|
0
|
0
|
0
|
|
|
|
if( $cx == $dx and $cy == $dy ) { |
|
914
|
|
|
|
|
|
|
# 6/25/7 we're a point on the rhs ... apparently this happens when you remove the extrude shortcutting |
|
915
|
|
|
|
|
|
|
|
|
916
|
0
|
0
|
0
|
|
|
|
if( $ay == $by and $cy == $ay ) { |
|
|
|
0
|
0
|
|
|
|
|
|
917
|
0
|
0
|
0
|
|
|
|
return ($cx, $cy) if $ax <= $cx and $cx <= $bx; |
|
918
|
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
} elsif( $ax == $bx and $cx == $ax ) { |
|
920
|
0
|
0
|
0
|
|
|
|
return ($cx, $cy) if $ay <= $cy and $cy <= $by; |
|
921
|
|
|
|
|
|
|
} |
|
922
|
|
|
|
|
|
|
|
|
923
|
0
|
|
|
|
|
|
die "probably a bug"; |
|
924
|
|
|
|
|
|
|
} |
|
925
|
|
|
|
|
|
|
|
|
926
|
0
|
0
|
|
|
|
|
if( $d == 0 ) { |
|
927
|
|
|
|
|
|
|
# d=0 when len(C->D)==0 !! |
|
928
|
0
|
|
|
|
|
|
for my $l ([$ax,$ay], [$bx, $by]) { |
|
929
|
0
|
|
|
|
|
|
for my $r ([$cx,$cy], [$dx, $dy]) { |
|
930
|
0
|
0
|
0
|
|
|
|
return (@$l) if $l->[0] == $r->[0] and $l->[1] == $r->[1]; |
|
931
|
|
|
|
|
|
|
}} |
|
932
|
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
# NOTE: another huge bug from 6/23/7 !! This vertical overlap was totally overlooked before. |
|
934
|
|
|
|
|
|
|
# This is arguably not the most efficient way to check it, but it's literally better than *nothing* |
|
935
|
0
|
0
|
0
|
|
|
|
if( abs($ax-$bx)<0.0001 and abs($bx-$cx)<0.0001 and abs($cx-$dx)<0.0001 ) { |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
936
|
0
|
0
|
0
|
|
|
|
return ($cx,$cy) if $ay <= $cy and $cy <= $by; |
|
937
|
0
|
0
|
0
|
|
|
|
return ($dx,$dy) if $ay <= $dy and $dy <= $by; |
|
938
|
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
# 6/25/7 -- sorta the same deal as above, but horizontal |
|
940
|
|
|
|
|
|
|
} elsif( abs($ay-$by)<0.0001 and abs($by-$cy)<0.0001 and abs($cy-$dy)<0.0001 ) { |
|
941
|
0
|
0
|
0
|
|
|
|
return ($cx,$cy) if $ax <= $cx and $cx <= $bx; |
|
942
|
0
|
0
|
0
|
|
|
|
return ($dx,$dy) if $ax <= $dx and $dx <= $bx; |
|
943
|
|
|
|
|
|
|
} |
|
944
|
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
## DEBUG ## warn "\t\tlsi p=||\n"; |
|
946
|
0
|
|
|
|
|
|
return; # probably parallel |
|
947
|
|
|
|
|
|
|
} |
|
948
|
|
|
|
|
|
|
|
|
949
|
0
|
|
|
|
|
|
my $p = ( ($by-$dy)*($cx-$dx) - ($bx-$dx)*($cy-$dy) ) / $d; |
|
950
|
|
|
|
|
|
|
# printf STDERR " p=$p"; |
|
951
|
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
## NOTE: this was an effin hard bug to find... |
|
953
|
|
|
|
|
|
|
## my @w = ( ( ($p <= 1) ? 1:0 ), ( ($p == 1) ? 1:0 ), ( ($p != 1) ? 1:0 ), ( ($p - 1) ),); |
|
954
|
|
|
|
|
|
|
## warn "\t\tlsi p=$p (@w)\n"; |
|
955
|
|
|
|
|
|
|
## lsi p-1 = 2.22044604925031e-16 = 1? No, not actually, sometimes... |
|
956
|
|
|
|
|
|
|
|
|
957
|
0
|
0
|
|
|
|
|
$p = 0 if abs($p) < 0.00001; # fixed 6/23/7 |
|
958
|
0
|
0
|
|
|
|
|
$p = 1 if abs($p-1) < 0.00001; |
|
959
|
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
# printf STDERR " p=$p\n"; |
|
961
|
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
## DEBUG ## warn "\t\tlsi p=$p\n"; |
|
963
|
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
# we probably don't need to find q because we already restricted the domain/range above |
|
965
|
0
|
0
|
0
|
|
|
|
return unless $p >= 0 and $p <= 1; |
|
966
|
|
|
|
|
|
|
|
|
967
|
0
|
|
|
|
|
|
my $px = $p*$ax + (1-$p)*$bx; |
|
968
|
0
|
|
|
|
|
|
my $py = $p*$ay + (1-$p)*$by; |
|
969
|
|
|
|
|
|
|
|
|
970
|
0
|
|
|
|
|
|
return ($px, $py); |
|
971
|
|
|
|
|
|
|
} |
|
972
|
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
# NOTE: simply uncomment these to get verbose LSI results |
|
974
|
|
|
|
|
|
|
## DEBUG ## *debug_lsi = *_line_segments_intersect; |
|
975
|
|
|
|
|
|
|
## DEBUG ## sub replacer { my @ret = &debug_lsi(@_); warn "\t\tLSI(@ret)\n"; return @ret; } |
|
976
|
|
|
|
|
|
|
## DEBUG ## *_line_segments_intersect = *replacer; |
|
977
|
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
# }}} |
|
979
|
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
# location {{{ |
|
981
|
|
|
|
|
|
|
sub location { |
|
982
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
983
|
0
|
|
|
|
|
|
my $that = shift; |
|
984
|
|
|
|
|
|
|
|
|
985
|
0
|
0
|
|
|
|
|
croak "that object/tag ($that) isn't on the map" unless exists $this->{l}{$that}; |
|
986
|
|
|
|
|
|
|
|
|
987
|
0
|
|
|
|
|
|
my $l = $this->{l}{$that}; |
|
988
|
0
|
0
|
|
|
|
|
return (wantarray ? @$l : $l); |
|
989
|
|
|
|
|
|
|
} |
|
990
|
|
|
|
|
|
|
# }}} |
|
991
|
|
|
|
|
|
|
# lline_of_sight {{{ |
|
992
|
|
|
|
|
|
|
sub lline_of_sight { |
|
993
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
994
|
|
|
|
|
|
|
|
|
995
|
0
|
0
|
|
|
|
|
croak "you should provide 4 arguments to line_of_sight()" unless @_ == 4; |
|
996
|
|
|
|
|
|
|
|
|
997
|
0
|
|
|
|
|
|
my @lhs = @_[0 .. 1]; |
|
998
|
0
|
|
|
|
|
|
my @rhs = @_[2 .. 3]; |
|
999
|
|
|
|
|
|
|
|
|
1000
|
0
|
0
|
|
|
|
|
croak "the first two arguments to lline_of_sight() do not appear to form a sane map location" unless $this->_check_loc(\@lhs); |
|
1001
|
0
|
0
|
|
|
|
|
croak "the last two arguments to lline_of_sight() do not appear to form a sane map location" unless $this->_check_loc(\@rhs); |
|
1002
|
|
|
|
|
|
|
|
|
1003
|
0
|
|
|
|
|
|
return $this->_line_of_sight(\@lhs, \@rhs); |
|
1004
|
|
|
|
|
|
|
} |
|
1005
|
|
|
|
|
|
|
# }}} |
|
1006
|
|
|
|
|
|
|
# ldistance {{{ |
|
1007
|
|
|
|
|
|
|
sub ldistance { |
|
1008
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1009
|
|
|
|
|
|
|
|
|
1010
|
0
|
0
|
|
|
|
|
croak "you should provide 4 arguments to ldistance()" unless @_ == 4; |
|
1011
|
|
|
|
|
|
|
|
|
1012
|
0
|
|
|
|
|
|
my @lhs = @_[0 .. 1]; |
|
1013
|
0
|
|
|
|
|
|
my @rhs = @_[2 .. 3]; |
|
1014
|
|
|
|
|
|
|
|
|
1015
|
0
|
0
|
|
|
|
|
croak "the first two arguments to ldistance() do not appear to form a sane map location" unless $this->_check_loc(\@lhs); |
|
1016
|
0
|
0
|
|
|
|
|
croak "the last two arguments to ldistance() do not appear to form a sane map location" unless $this->_check_loc(\@rhs); |
|
1017
|
|
|
|
|
|
|
|
|
1018
|
0
|
0
|
|
|
|
|
if( $_[4] ) { |
|
1019
|
0
|
|
|
|
|
|
my @r = ($this->_ldistance(\@lhs, \@rhs), $this->_line_of_sight(\@lhs, \@rhs)); |
|
1020
|
0
|
0
|
|
|
|
|
return (wantarray ? @r : \@r); |
|
1021
|
|
|
|
|
|
|
} |
|
1022
|
|
|
|
|
|
|
|
|
1023
|
0
|
0
|
|
|
|
|
return undef unless $this->_line_of_sight(\@lhs => \@rhs); |
|
1024
|
0
|
|
|
|
|
|
return $this->_ldistance(\@lhs => \@rhs); |
|
1025
|
|
|
|
|
|
|
} |
|
1026
|
|
|
|
|
|
|
# }}} |
|
1027
|
|
|
|
|
|
|
# distance {{{ |
|
1028
|
|
|
|
|
|
|
sub distance { |
|
1029
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1030
|
0
|
0
|
|
|
|
|
my $lhs = shift; croak "the lhs=$lhs isn't on the map" unless exists $this->{l}{$lhs}; |
|
|
0
|
|
|
|
|
|
|
|
1031
|
0
|
0
|
|
|
|
|
my $rhs = shift; croak "the rhs=$rhs isn't on the map" unless exists $this->{l}{$rhs}; |
|
|
0
|
|
|
|
|
|
|
|
1032
|
0
|
|
|
|
|
|
my $los = shift; |
|
1033
|
|
|
|
|
|
|
|
|
1034
|
0
|
|
|
|
|
|
$lhs = $this->{l}{$lhs}; |
|
1035
|
0
|
|
|
|
|
|
$rhs = $this->{l}{$rhs}; |
|
1036
|
|
|
|
|
|
|
|
|
1037
|
0
|
0
|
|
|
|
|
if( $los ) { |
|
1038
|
0
|
|
|
|
|
|
my @r = ($this->_ldistance($lhs, $rhs), $this->_line_of_sight($lhs, $rhs)); |
|
1039
|
0
|
0
|
|
|
|
|
return (wantarray ? @r : \@r); |
|
1040
|
|
|
|
|
|
|
} |
|
1041
|
|
|
|
|
|
|
|
|
1042
|
0
|
0
|
|
|
|
|
return undef unless $this->_line_of_sight($lhs, $rhs); |
|
1043
|
0
|
|
|
|
|
|
return $this->_ldistance($lhs, $rhs); |
|
1044
|
|
|
|
|
|
|
} |
|
1045
|
|
|
|
|
|
|
# }}} |
|
1046
|
|
|
|
|
|
|
# line_of_sight {{{ |
|
1047
|
|
|
|
|
|
|
sub line_of_sight { |
|
1048
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1049
|
|
|
|
|
|
|
|
|
1050
|
0
|
0
|
|
|
|
|
croak "you should provide 2 arguments to line_of_sight()" unless @_ == 2; |
|
1051
|
|
|
|
|
|
|
|
|
1052
|
0
|
|
|
|
|
|
my $lhs = shift; $lhs = "$lhs"; |
|
|
0
|
|
|
|
|
|
|
|
1053
|
0
|
|
|
|
|
|
my $rhs = shift; $rhs = "$rhs"; |
|
|
0
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
|
|
1055
|
0
|
0
|
|
|
|
|
croak "the first argument to line_of_sight() does not appear to be on the map" unless ($lhs = $this->{l}{$lhs}); |
|
1056
|
0
|
0
|
|
|
|
|
croak "the last argument to line_of_sight() does not appear to be on the map" unless ($rhs = $this->{l}{$rhs}); |
|
1057
|
|
|
|
|
|
|
|
|
1058
|
0
|
|
|
|
|
|
return $this->_line_of_sight($lhs, $rhs); |
|
1059
|
|
|
|
|
|
|
} |
|
1060
|
|
|
|
|
|
|
# }}} |
|
1061
|
|
|
|
|
|
|
# closure_line_of_sight {{{ |
|
1062
|
|
|
|
|
|
|
sub closure_line_of_sight { |
|
1063
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1064
|
|
|
|
|
|
|
|
|
1065
|
0
|
0
|
|
|
|
|
croak "you should provide 2 arguments to closure_line_of_sight()" unless @_ == 2; |
|
1066
|
|
|
|
|
|
|
|
|
1067
|
0
|
|
|
|
|
|
my $lhs = shift; $lhs = "$lhs"; |
|
|
0
|
|
|
|
|
|
|
|
1068
|
0
|
|
|
|
|
|
my $rhs = shift; |
|
1069
|
|
|
|
|
|
|
|
|
1070
|
0
|
0
|
|
|
|
|
croak "the first argument to closure_line_of_sight() does not appear to be on the map" unless ($lhs = $this->{l}{$lhs}); |
|
1071
|
0
|
0
|
|
|
|
|
croak "the last argument to closure_line_of_sight() does not appear to be a door" unless ($rhs = $this->_door($rhs)); |
|
1072
|
|
|
|
|
|
|
# it definitely does have to be a door so we can get the direction! ... for arbitrary closures you must use |
|
1073
|
|
|
|
|
|
|
# closure_lline_of_sight. :( |
|
1074
|
|
|
|
|
|
|
|
|
1075
|
0
|
|
|
|
|
|
return $this->_closure_line_of_sight($lhs, $rhs); |
|
1076
|
|
|
|
|
|
|
} |
|
1077
|
|
|
|
|
|
|
# }}} |
|
1078
|
|
|
|
|
|
|
# closure_lline_of_sight {{{ |
|
1079
|
|
|
|
|
|
|
sub closure_lline_of_sight { |
|
1080
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1081
|
|
|
|
|
|
|
|
|
1082
|
0
|
0
|
|
|
|
|
croak "you should provide 5 arguments to closure_lline_of_sight()" unless @_ == 5; |
|
1083
|
|
|
|
|
|
|
|
|
1084
|
0
|
|
|
|
|
|
my @lhs = @_[0 .. 1]; |
|
1085
|
0
|
|
|
|
|
|
my @rhs = @_[2 .. 3]; |
|
1086
|
0
|
|
|
|
|
|
my $dir = $_[4]; |
|
1087
|
|
|
|
|
|
|
|
|
1088
|
0
|
0
|
|
|
|
|
croak "the first two arguments to closeure_lline_of_sight() do not appear to form a sane map location" unless $this->_check_loc(\@lhs); |
|
1089
|
0
|
0
|
|
|
|
|
croak "the second two arguments to closeure_lline_of_sight() do not appear to form a sane map location" unless $this->_check_loc(\@rhs); |
|
1090
|
0
|
0
|
|
|
|
|
croak "the fifth argument to closure_lline_of_sight() should be a map direction (ie, n s e w)" unless $dir =~ m/^[nsew]\z/; |
|
1091
|
|
|
|
|
|
|
|
|
1092
|
0
|
|
|
|
|
|
return $this->_closure_line_of_sight(\@lhs, [@rhs, $dir]); |
|
1093
|
|
|
|
|
|
|
} |
|
1094
|
|
|
|
|
|
|
# }}} |
|
1095
|
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
# {{{ sub build_queue_from_hash |
|
1097
|
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
################## |
|
1099
|
|
|
|
|
|
|
# XXX: experimental, undocumented, crazy thing, do not use, may change |
|
1100
|
|
|
|
|
|
|
###### |
|
1101
|
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
sub build_queue_from_hash { |
|
1103
|
0
|
|
|
0
|
0
|
|
my $this = shift; |
|
1104
|
0
|
0
|
0
|
|
|
|
my $that = @_==1 && ref($_[0])eq"HASH" ? $_[0] : { @_ }; |
|
1105
|
|
|
|
|
|
|
|
|
1106
|
0
|
|
|
|
|
|
delete $this->{l}; |
|
1107
|
0
|
|
|
|
|
|
delete $this->{c}; |
|
1108
|
|
|
|
|
|
|
|
|
1109
|
0
|
|
|
|
|
|
for my $k (keys %$that) { |
|
1110
|
0
|
|
|
|
|
|
$this->{l} = $k; |
|
1111
|
0
|
|
|
|
|
|
my $loc = $that->{$k}{l}; |
|
1112
|
0
|
|
|
|
|
|
my $itm = $that->{$k}{i}; |
|
1113
|
|
|
|
|
|
|
|
|
1114
|
0
|
|
|
|
|
|
push @{$this->{c}[ $loc->[1] ][ $loc->[0] ]}, $itm; |
|
|
0
|
|
|
|
|
|
|
|
1115
|
|
|
|
|
|
|
} |
|
1116
|
|
|
|
|
|
|
} |
|
1117
|
|
|
|
|
|
|
|
|
1118
|
|
|
|
|
|
|
# }}} |
|
1119
|
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
# add {{{ |
|
1121
|
|
|
|
|
|
|
sub add { |
|
1122
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1123
|
0
|
0
|
|
|
|
|
my $that = shift or croak "place what?"; my $tag = "$that"; |
|
|
0
|
|
|
|
|
|
|
|
1124
|
0
|
|
|
|
|
|
my @loc = @_; |
|
1125
|
|
|
|
|
|
|
|
|
1126
|
0
|
0
|
|
|
|
|
croak "that object/tag ($tag) appears to already be on the map" if exists $this->{l}{$tag}; |
|
1127
|
0
|
0
|
|
|
|
|
croak "that location (@loc) makes no sense" unless $this->_check_loc(\@loc); |
|
1128
|
|
|
|
|
|
|
|
|
1129
|
0
|
|
|
|
|
|
$this->{l}{$tag} = \@loc; |
|
1130
|
0
|
|
|
|
|
|
push @{ $this->{c}[ $loc[1] ][ $loc[0] ] }, $that; |
|
|
0
|
|
|
|
|
|
|
|
1131
|
|
|
|
|
|
|
} |
|
1132
|
|
|
|
|
|
|
# }}} |
|
1133
|
|
|
|
|
|
|
# remove {{{ |
|
1134
|
|
|
|
|
|
|
sub remove { |
|
1135
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1136
|
0
|
|
|
|
|
|
my $that = shift; my $tag = "$that"; |
|
|
0
|
|
|
|
|
|
|
|
1137
|
|
|
|
|
|
|
|
|
1138
|
0
|
0
|
|
|
|
|
croak "that object/tag ($tag) isn't on the map" unless exists $this->{l}{$tag}; |
|
1139
|
|
|
|
|
|
|
|
|
1140
|
0
|
|
|
|
|
|
my @loc = @{ delete $this->{l}{$tag} }; |
|
|
0
|
|
|
|
|
|
|
|
1141
|
0
|
|
|
|
|
|
my $itm = $this->{c}[ $loc[1] ][ $loc[0] ]; |
|
1142
|
|
|
|
|
|
|
|
|
1143
|
0
|
|
|
|
|
|
@$itm = ( grep {$_ ne $tag} @$itm ); |
|
|
0
|
|
|
|
|
|
|
|
1144
|
|
|
|
|
|
|
} |
|
1145
|
|
|
|
|
|
|
# }}} |
|
1146
|
|
|
|
|
|
|
# replace {{{ |
|
1147
|
|
|
|
|
|
|
sub replace { |
|
1148
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1149
|
0
|
|
|
|
|
|
my $that = shift; my $tag = "$that"; |
|
|
0
|
|
|
|
|
|
|
|
1150
|
0
|
|
|
|
|
|
my @loc = @_; |
|
1151
|
|
|
|
|
|
|
|
|
1152
|
0
|
0
|
|
|
|
|
croak "that location (@loc) makes no sense" unless $this->_check_loc(\@loc); |
|
1153
|
|
|
|
|
|
|
|
|
1154
|
0
|
0
|
|
|
|
|
$this->remove($tag) if exists $this->{l}{$tag}; |
|
1155
|
0
|
|
|
|
|
|
$this->add($that => @loc); |
|
1156
|
|
|
|
|
|
|
} |
|
1157
|
|
|
|
|
|
|
# }}} |
|
1158
|
|
|
|
|
|
|
# {{{ is_on_map |
|
1159
|
|
|
|
|
|
|
sub is_on_map { |
|
1160
|
0
|
|
|
0
|
0
|
|
my $this = shift; |
|
1161
|
0
|
|
|
|
|
|
my $that = shift; |
|
1162
|
|
|
|
|
|
|
|
|
1163
|
0
|
0
|
|
|
|
|
return exists($this->{l}{$that}) ? 1:0; |
|
1164
|
|
|
|
|
|
|
} |
|
1165
|
|
|
|
|
|
|
|
|
1166
|
|
|
|
|
|
|
# }}} |
|
1167
|
|
|
|
|
|
|
|
|
1168
|
|
|
|
|
|
|
# objs_at_location {{{ |
|
1169
|
|
|
|
|
|
|
sub objs_at_location { |
|
1170
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1171
|
0
|
0
|
|
|
|
|
my $loc = $this->_check_loc(\@_) or croak "that location (@_) makes no sense"; |
|
1172
|
|
|
|
|
|
|
|
|
1173
|
0
|
|
|
|
|
|
return $this->_objs_at_location( $loc ); |
|
1174
|
|
|
|
|
|
|
} |
|
1175
|
|
|
|
|
|
|
*objects_at_location = *objs_at_location; |
|
1176
|
|
|
|
|
|
|
# }}} |
|
1177
|
|
|
|
|
|
|
# objs_in_line_of_sight {{{ |
|
1178
|
|
|
|
|
|
|
sub objs_in_line_of_sight { |
|
1179
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1180
|
0
|
0
|
|
|
|
|
my $loc = $this->_check_loc(\@_) or croak "that location (@_) makes no sense"; |
|
1181
|
0
|
|
|
|
|
|
my @ret = (); |
|
1182
|
|
|
|
|
|
|
|
|
1183
|
0
|
|
|
|
|
|
for my $l ($this->_locations_in_line_of_sight($loc)) { |
|
1184
|
0
|
0
|
|
|
|
|
push @ret, @{ $this->{c}[ $l->[1] ][ $l->[0] ] || [] }; |
|
|
0
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
} |
|
1186
|
|
|
|
|
|
|
|
|
1187
|
0
|
|
|
|
|
|
return @ret; |
|
1188
|
|
|
|
|
|
|
} |
|
1189
|
|
|
|
|
|
|
*objects_in_line_of_sight = *objs_in_line_of_sight; |
|
1190
|
|
|
|
|
|
|
# }}} |
|
1191
|
|
|
|
|
|
|
# objs {{{ |
|
1192
|
|
|
|
|
|
|
sub objs { |
|
1193
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1194
|
0
|
|
|
|
|
|
my @ret = (); |
|
1195
|
|
|
|
|
|
|
|
|
1196
|
0
|
|
|
|
|
|
for my $row ( 0 .. $this->{ym} ) { |
|
1197
|
0
|
|
|
|
|
|
for my $col ( 0 .. $this->{xm} ) { |
|
1198
|
|
|
|
|
|
|
|
|
1199
|
0
|
0
|
|
|
|
|
push @ret, @{ $this->{c}[ $row ][ $col ] || [] }; |
|
|
0
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
} |
|
1201
|
|
|
|
|
|
|
} |
|
1202
|
|
|
|
|
|
|
|
|
1203
|
0
|
|
|
|
|
|
return @ret; |
|
1204
|
|
|
|
|
|
|
} |
|
1205
|
|
|
|
|
|
|
*objects = *objs; |
|
1206
|
|
|
|
|
|
|
# }}} |
|
1207
|
|
|
|
|
|
|
# objs_with_locations {{{ |
|
1208
|
|
|
|
|
|
|
sub objs_with_locations { |
|
1209
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1210
|
0
|
|
|
|
|
|
my @ret = (); |
|
1211
|
|
|
|
|
|
|
|
|
1212
|
0
|
|
|
|
|
|
for my $row ( 0 .. $this->{ym} ) { |
|
1213
|
0
|
|
|
|
|
|
for my $col ( 0 .. $this->{xm} ) { |
|
1214
|
0
|
|
|
|
|
|
my $loc = [ $col, $row ]; |
|
1215
|
|
|
|
|
|
|
|
|
1216
|
0
|
0
|
|
|
|
|
my @junk = @{ $this->{c}[ $loc->[1] ][ $loc->[0] ] || [] }; |
|
|
0
|
|
|
|
|
|
|
|
1217
|
|
|
|
|
|
|
|
|
1218
|
0
|
0
|
|
|
|
|
push @ret, [ $loc => \@junk ] if @junk; |
|
1219
|
|
|
|
|
|
|
} |
|
1220
|
|
|
|
|
|
|
} |
|
1221
|
|
|
|
|
|
|
|
|
1222
|
0
|
|
|
|
|
|
return @ret; |
|
1223
|
|
|
|
|
|
|
} |
|
1224
|
|
|
|
|
|
|
*objects_with_locations = *objs_with_locations; |
|
1225
|
|
|
|
|
|
|
# }}} |
|
1226
|
|
|
|
|
|
|
|
|
1227
|
|
|
|
|
|
|
# random_open_location {{{ |
|
1228
|
|
|
|
|
|
|
sub random_open_location { |
|
1229
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1230
|
0
|
|
|
|
|
|
my @l = $this->all_open_locations; |
|
1231
|
0
|
|
|
|
|
|
my $i = int rand int @l; |
|
1232
|
|
|
|
|
|
|
|
|
1233
|
0
|
0
|
|
|
|
|
return unless @l; |
|
1234
|
0
|
0
|
|
|
|
|
return (wantarray ? @{$l[$i]}:$l[$i]); |
|
|
0
|
|
|
|
|
|
|
|
1235
|
|
|
|
|
|
|
} |
|
1236
|
|
|
|
|
|
|
# }}} |
|
1237
|
|
|
|
|
|
|
# all_open_locations {{{ |
|
1238
|
|
|
|
|
|
|
sub all_open_locations { |
|
1239
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1240
|
0
|
|
|
|
|
|
my ($X, $Y) = ($this->{xm}+1, $this->{ym}+1); |
|
1241
|
0
|
|
|
|
|
|
my @ret = (); |
|
1242
|
|
|
|
|
|
|
|
|
1243
|
0
|
|
|
|
|
|
for my $x ( 0 .. $this->{xm} ) { |
|
1244
|
0
|
|
|
|
|
|
for my $y ( 0 .. $this->{ym} ) { |
|
1245
|
0
|
0
|
|
|
|
|
push @ret, [$x, $y] if defined $this->{_the_map}[ $y ][ $x ]{type}; # the wall type is |
|
1246
|
|
|
|
|
|
|
}} |
|
1247
|
|
|
|
|
|
|
|
|
1248
|
0
|
0
|
|
|
|
|
return (wantarray ? @ret:\@ret); |
|
1249
|
|
|
|
|
|
|
} |
|
1250
|
|
|
|
|
|
|
# }}} |
|
1251
|
|
|
|
|
|
|
# locations_in_line_of_sight {{{ |
|
1252
|
|
|
|
|
|
|
sub locations_in_line_of_sight { |
|
1253
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1254
|
0
|
0
|
|
|
|
|
my @init = @_; $this->_check_loc(\@init) or croak "that location (@_) doesn't make any sense"; |
|
|
0
|
|
|
|
|
|
|
|
1255
|
|
|
|
|
|
|
|
|
1256
|
0
|
|
|
|
|
|
return $this->_locations_in_line_of_sight(\@init); |
|
1257
|
|
|
|
|
|
|
} |
|
1258
|
|
|
|
|
|
|
# }}} |
|
1259
|
|
|
|
|
|
|
# locations_in_range_and_line_of_sight {{{ |
|
1260
|
|
|
|
|
|
|
sub locations_in_range_and_line_of_sight { |
|
1261
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1262
|
0
|
0
|
|
|
|
|
my @init = splice @_,0,2; $this->_check_loc(\@init) or croak "that location (@_) doesn't make any sense"; |
|
|
0
|
|
|
|
|
|
|
|
1263
|
0
|
|
0
|
|
|
|
my $range = shift || 0; |
|
1264
|
|
|
|
|
|
|
|
|
1265
|
0
|
0
|
|
|
|
|
croak "range should be greater than 0" unless $range > 0; |
|
1266
|
|
|
|
|
|
|
|
|
1267
|
0
|
|
|
|
|
|
return $this->_locations_in_range_and_line_of_sight(\@init, $range); |
|
1268
|
|
|
|
|
|
|
} |
|
1269
|
|
|
|
|
|
|
# }}} |
|
1270
|
|
|
|
|
|
|
# locations_in_path {{{ |
|
1271
|
|
|
|
|
|
|
sub locations_in_path { |
|
1272
|
0
|
0
|
|
0
|
1
|
|
my $this = shift; croak "you should provide 4 arguments to locations_in_path()" unless @_ == 4; |
|
|
0
|
|
|
|
|
|
|
|
1273
|
0
|
0
|
|
|
|
|
my @lhs = @_[0 .. 1]; $this->_check_loc(\@lhs) or croak "the first two arguments to locations_in_path() (@_) don't make any sense"; |
|
|
0
|
|
|
|
|
|
|
|
1274
|
0
|
0
|
|
|
|
|
my @rhs = @_[2 .. 3]; $this->_check_loc(\@rhs) or croak "the second two arguments to locations_in_path() (@_) don't make any sense"; |
|
|
0
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
|
|
1276
|
0
|
0
|
|
|
|
|
croak "the target location doesn't appear to be visible from the source" |
|
1277
|
|
|
|
|
|
|
unless $this->_line_of_sight(\@lhs => \@rhs); |
|
1278
|
|
|
|
|
|
|
|
|
1279
|
0
|
|
|
|
|
|
return $this->_locations_in_path(\@lhs => \@rhs); |
|
1280
|
|
|
|
|
|
|
} |
|
1281
|
|
|
|
|
|
|
# }}} |
|
1282
|
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
# ranged_cover {{{ |
|
1284
|
|
|
|
|
|
|
sub ranged_cover { |
|
1285
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1286
|
0
|
0
|
|
|
|
|
my @l = @_[0 .. 1]; $this->_check_loc(\@l) or croak "the left location (@l) doesn't make any sense"; |
|
|
0
|
|
|
|
|
|
|
|
1287
|
0
|
0
|
|
|
|
|
my @r = @_[2 .. 3]; $this->_check_loc(\@r) or croak "the right location (@r) doesn't make any sense"; |
|
|
0
|
|
|
|
|
|
|
|
1288
|
|
|
|
|
|
|
|
|
1289
|
0
|
|
|
|
|
|
return $this->_ranged_cover(\@l=>\@r); |
|
1290
|
|
|
|
|
|
|
} |
|
1291
|
|
|
|
|
|
|
# }}} |
|
1292
|
|
|
|
|
|
|
# melee_cover {{{ |
|
1293
|
|
|
|
|
|
|
sub melee_cover { |
|
1294
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1295
|
0
|
0
|
|
|
|
|
my @l = @_[0 .. 1]; $this->_check_loc(\@l) or croak "the left location (@l) doesn't make any sense"; |
|
|
0
|
|
|
|
|
|
|
|
1296
|
0
|
0
|
|
|
|
|
my @r = @_[2 .. 3]; $this->_check_loc(\@r) or croak "the right location (@r) doesn't make any sense"; |
|
|
0
|
|
|
|
|
|
|
|
1297
|
|
|
|
|
|
|
|
|
1298
|
0
|
|
|
|
|
|
return $this->_melee_cover(\@r=>\@l); |
|
1299
|
|
|
|
|
|
|
} |
|
1300
|
|
|
|
|
|
|
# }}} |
|
1301
|
|
|
|
|
|
|
# ignorable_cover {{{ |
|
1302
|
|
|
|
|
|
|
sub ignorable_cover { |
|
1303
|
0
|
|
|
0
|
0
|
|
my $this = shift; |
|
1304
|
0
|
0
|
|
|
|
|
my @l = @_[0 .. 1]; $this->_check_loc(\@l) or croak "the left location (@l) doesn't make any sense"; |
|
|
0
|
|
|
|
|
|
|
|
1305
|
0
|
0
|
|
|
|
|
my @r = @_[2 .. 3]; $this->_check_loc(\@r) or croak "the right location (@r) doesn't make any sense"; |
|
|
0
|
|
|
|
|
|
|
|
1306
|
|
|
|
|
|
|
|
|
1307
|
0
|
|
|
|
|
|
return $this->_ignorable_cover(\@r=>\@l); |
|
1308
|
|
|
|
|
|
|
} |
|
1309
|
|
|
|
|
|
|
# }}} |
|
1310
|
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
# is_open {{{ |
|
1312
|
|
|
|
|
|
|
sub is_open { |
|
1313
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1314
|
0
|
|
|
|
|
|
my @loc = @_[0 .. 1]; |
|
1315
|
|
|
|
|
|
|
|
|
1316
|
0
|
|
|
|
|
|
return $this->_check_loc(\@loc); |
|
1317
|
|
|
|
|
|
|
} |
|
1318
|
|
|
|
|
|
|
# }}} |
|
1319
|
|
|
|
|
|
|
# is_door_open {{{ |
|
1320
|
|
|
|
|
|
|
sub is_door_open { |
|
1321
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1322
|
0
|
|
|
|
|
|
my @loc = @_[0 .. 1]; |
|
1323
|
0
|
0
|
|
|
|
|
my $dir = lc $_[2]; $dir = $1 if $dir =~ m/^([nsew])./i; |
|
|
0
|
|
|
|
|
|
|
|
1324
|
0
|
|
|
|
|
|
my $door; |
|
1325
|
|
|
|
|
|
|
|
|
1326
|
0
|
0
|
|
|
|
|
croak "that location doesn't make sense" unless $this->_check_loc(\@loc); |
|
1327
|
0
|
0
|
|
|
|
|
croak "there isn't a door there" unless ref ($door = $this->{_the_map}[ $loc[1] ][ $loc[0] ]{od}{$dir}); |
|
1328
|
|
|
|
|
|
|
|
|
1329
|
0
|
|
|
|
|
|
return $door->{'open'}; |
|
1330
|
|
|
|
|
|
|
} |
|
1331
|
|
|
|
|
|
|
# }}} |
|
1332
|
|
|
|
|
|
|
# is_door {{{ |
|
1333
|
|
|
|
|
|
|
sub is_door { |
|
1334
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1335
|
0
|
|
|
|
|
|
my @loc = @_[0 .. 1]; |
|
1336
|
0
|
0
|
|
|
|
|
my $dir = lc $_[2]; $dir = $1 if $dir =~ m/^([nsew])./i; |
|
|
0
|
|
|
|
|
|
|
|
1337
|
|
|
|
|
|
|
|
|
1338
|
0
|
0
|
|
|
|
|
croak "that location doesn't make sense" unless $this->_check_loc(\@loc); |
|
1339
|
0
|
0
|
|
|
|
|
return 1 if ref $this->{_the_map}[ $loc[1] ][ $loc[0] ]{od}{ $dir }; |
|
1340
|
0
|
|
|
|
|
|
return 0; |
|
1341
|
|
|
|
|
|
|
} |
|
1342
|
|
|
|
|
|
|
# }}} |
|
1343
|
|
|
|
|
|
|
# open_door {{{ |
|
1344
|
|
|
|
|
|
|
sub open_door { |
|
1345
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1346
|
0
|
|
|
|
|
|
my @loc = @_[0 .. 1]; |
|
1347
|
0
|
0
|
|
|
|
|
my $dir = lc $_[2]; $dir = $1 if $dir =~ m/^([nsew])./i; |
|
|
0
|
|
|
|
|
|
|
|
1348
|
0
|
|
|
|
|
|
my $door; |
|
1349
|
|
|
|
|
|
|
|
|
1350
|
0
|
0
|
|
|
|
|
croak "that location doesn't make sense" unless $this->_check_loc(\@loc); |
|
1351
|
0
|
0
|
|
|
|
|
croak "there isn't a door there" unless ref ($door = $this->{_the_map}[ $loc[1] ][ $loc[0] ]{od}{$dir}); |
|
1352
|
0
|
0
|
|
|
|
|
croak "that door is already open" if $door->{'open'}; |
|
1353
|
|
|
|
|
|
|
|
|
1354
|
0
|
|
|
|
|
|
$door->{'open'} = 1; |
|
1355
|
0
|
|
|
|
|
|
$this->flush; |
|
1356
|
|
|
|
|
|
|
} |
|
1357
|
|
|
|
|
|
|
# }}} |
|
1358
|
|
|
|
|
|
|
# close_door {{{ |
|
1359
|
|
|
|
|
|
|
sub close_door { |
|
1360
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1361
|
0
|
|
|
|
|
|
my @loc = @_[0 .. 1]; |
|
1362
|
0
|
0
|
|
|
|
|
my $dir = lc $_[2]; $dir = $1 if $dir =~ m/^([nsew])./i; |
|
|
0
|
|
|
|
|
|
|
|
1363
|
0
|
|
|
|
|
|
my $door; |
|
1364
|
|
|
|
|
|
|
|
|
1365
|
0
|
0
|
|
|
|
|
croak "that location doesn't make sense" unless $this->_check_loc(\@loc); |
|
1366
|
0
|
0
|
|
|
|
|
croak "there isn't a door there" unless ref ($door = $this->{_the_map}[ $loc[1] ][ $loc[0] ]{od}{$dir}); |
|
1367
|
0
|
0
|
|
|
|
|
croak "that door isn't open" unless $door->{'open'}; |
|
1368
|
|
|
|
|
|
|
|
|
1369
|
0
|
|
|
|
|
|
$door->{'open'} = 0; |
|
1370
|
0
|
|
|
|
|
|
$this->flush; |
|
1371
|
|
|
|
|
|
|
} |
|
1372
|
|
|
|
|
|
|
# }}} |
|
1373
|
|
|
|
|
|
|
# map_range {{{ |
|
1374
|
|
|
|
|
|
|
sub map_range { |
|
1375
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1376
|
|
|
|
|
|
|
|
|
1377
|
0
|
0
|
|
|
|
|
return ( 0 .. $this->{xm} ) if wantarray; |
|
1378
|
0
|
|
|
|
|
|
return $this->{xm}; |
|
1379
|
|
|
|
|
|
|
} |
|
1380
|
|
|
|
|
|
|
# }}} |
|
1381
|
|
|
|
|
|
|
# map_domain {{{ |
|
1382
|
|
|
|
|
|
|
sub map_domain { |
|
1383
|
0
|
|
|
0
|
1
|
|
my $this = shift; |
|
1384
|
|
|
|
|
|
|
|
|
1385
|
0
|
0
|
|
|
|
|
return ( 0 .. $this->{ym} ) if wantarray; |
|
1386
|
0
|
|
|
|
|
|
return $this->{ym}; |
|
1387
|
|
|
|
|
|
|
} |
|
1388
|
|
|
|
|
|
|
# }}} |
|
1389
|
|
|
|
|
|
|
|
|
1390
|
|
|
|
|
|
|
# {{{ FREEZE_THAW_HOOKS |
|
1391
|
|
|
|
|
|
|
FREEZE_THAW_HOOKS: { |
|
1392
|
|
|
|
|
|
|
my $going; |
|
1393
|
|
|
|
|
|
|
sub STORABLE_freeze { |
|
1394
|
0
|
0
|
|
0
|
0
|
|
return if $going; |
|
1395
|
0
|
|
|
|
|
|
my $this = shift; |
|
1396
|
0
|
|
|
|
|
|
$going = 1; |
|
1397
|
0
|
|
|
|
|
|
my $str = freeze($this); |
|
1398
|
0
|
|
|
|
|
|
$going = 0; |
|
1399
|
0
|
|
|
|
|
|
return $str; |
|
1400
|
|
|
|
|
|
|
} |
|
1401
|
|
|
|
|
|
|
|
|
1402
|
|
|
|
|
|
|
sub STORABLE_thaw { |
|
1403
|
0
|
|
|
0
|
0
|
|
my $this = shift; |
|
1404
|
0
|
|
|
|
|
|
%$this = %{ thaw($_[1]) }; |
|
|
0
|
|
|
|
|
|
|
|
1405
|
0
|
|
|
|
|
|
$this->retag; |
|
1406
|
|
|
|
|
|
|
} |
|
1407
|
|
|
|
|
|
|
} |
|
1408
|
|
|
|
|
|
|
|
|
1409
|
|
|
|
|
|
|
# }}} |
|
1410
|
|
|
|
|
|
|
|
|
1411
|
|
|
|
|
|
|
1; |