| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Games::Roguelike::World; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# purpose of library: |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# keep track of map/location |
|
6
|
|
|
|
|
|
|
# convenience for collision, line of sight, path-finding |
|
7
|
|
|
|
|
|
|
# assume some roguelike concepts (mobs/items) |
|
8
|
|
|
|
|
|
|
# allow someone to make 7-day rl's in 7-days |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 NAME |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Games::Roguelike::World - Roguelike World |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
package myWorld; |
|
17
|
|
|
|
|
|
|
use base 'Games::Roguelike::World'; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
$r = myWorld->new(w=>80,h=>50,dispw=>40,disph=>18); # creates a world with specified width/height & map display width/height |
|
20
|
|
|
|
|
|
|
$r->area(new Games::Roguelike::Area(name=>'1')); # create a new area in this world called "1" |
|
21
|
|
|
|
|
|
|
$r->area->genmaze2(); # make a cavelike maze |
|
22
|
|
|
|
|
|
|
$char = Games::Roguelike::Mob->new($r->area, sym=>'@', pov=>8); # add a mobile object with symbol '@' |
|
23
|
|
|
|
|
|
|
$r->setvp($char); # set viewpoint to be from $char's perspective |
|
24
|
|
|
|
|
|
|
$r->drawmap(); # draw the active area map from the current perspective |
|
25
|
|
|
|
|
|
|
while (!((my $c = $r->getch()) eq 'q')) { |
|
26
|
|
|
|
|
|
|
$char->kbdmove($c); |
|
27
|
|
|
|
|
|
|
$r->drawmap(); |
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
General pupose object which pulls together field of view, item, mob handling and map drawing code. |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
* contains a hash of Games::Roguelike::Area's for each "level" or "region" in the game |
|
35
|
|
|
|
|
|
|
* uses the Games::Roguelike::Console library to draw the current area |
|
36
|
|
|
|
|
|
|
* assumes the user will be using overridden Games::Roguelike::Mob's as characters in the game |
|
37
|
|
|
|
|
|
|
* assumes the user will be using overridden Games::Roguelike::Item's as items in the game |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=head2 METHODS |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=over 4 |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=cut |
|
44
|
|
|
|
|
|
|
|
|
45
|
3
|
|
|
3
|
|
30027
|
use strict; |
|
|
3
|
|
|
|
|
9
|
|
|
|
3
|
|
|
|
|
145
|
|
|
46
|
3
|
|
|
3
|
|
600
|
use Games::Roguelike::Utils qw(:all); |
|
|
3
|
|
|
|
|
13
|
|
|
|
3
|
|
|
|
|
1496
|
|
|
47
|
3
|
|
|
3
|
|
300
|
use Games::Roguelike::Console; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
141
|
|
|
48
|
3
|
|
|
3
|
|
19
|
use Games::Roguelike::Mob; |
|
|
3
|
|
|
|
|
8
|
|
|
|
3
|
|
|
|
|
78
|
|
|
49
|
|
|
|
|
|
|
|
|
50
|
3
|
|
|
3
|
|
9413
|
use Math::Trig; |
|
|
3
|
|
|
|
|
130200
|
|
|
|
3
|
|
|
|
|
689
|
|
|
51
|
3
|
|
|
3
|
|
42
|
use Data::Dumper; |
|
|
3
|
|
|
|
|
7
|
|
|
|
3
|
|
|
|
|
158
|
|
|
52
|
3
|
|
|
3
|
|
19
|
use Carp qw(croak confess carp); |
|
|
3
|
|
|
|
|
8
|
|
|
|
3
|
|
|
|
|
13227
|
|
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
our $AUTOLOAD; |
|
55
|
|
|
|
|
|
|
our $VERSION = '0.4.' . [qw$Revision: 256 $]->[1]; |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=item new(OPT1=>VAL1, OPT2=>VAL2...) |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Options can also all be set/get as class accessors: |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
vp => undef # Games::Roguelike::Mob that is the 'viewpoint' |
|
62
|
|
|
|
|
|
|
dispx, dispy => (0,1) # x/y location, of the map |
|
63
|
|
|
|
|
|
|
dispw, disph => (60,24) # width & height of the map |
|
64
|
|
|
|
|
|
|
msgx, msgy => (0,0) # x/y location of the "scrolling message box" |
|
65
|
|
|
|
|
|
|
msgw, msgh => (60, 1) # width & height of the "scrolling message box" |
|
66
|
|
|
|
|
|
|
maxlog => 80, # maximum number of rows stored message log |
|
67
|
|
|
|
|
|
|
msgoldcolor => 'gray', # color of non-curent messages (if left blank, color is left alone) |
|
68
|
|
|
|
|
|
|
wsym => '#', # default wall symbol |
|
69
|
|
|
|
|
|
|
fsym => '.', # default floor symbol |
|
70
|
|
|
|
|
|
|
dsym => '+', # default door symbol |
|
71
|
|
|
|
|
|
|
debugmap => 0, # turn on map coordinate display |
|
72
|
|
|
|
|
|
|
debug => 0, # debug level (higher = more) |
|
73
|
|
|
|
|
|
|
noview => '#+', # list of symbols that block view |
|
74
|
|
|
|
|
|
|
nomove => '#', # list of symbols that block movement |
|
75
|
|
|
|
|
|
|
area => undef, # Games::Roguelike::Area that contains the currrent map |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
None of these features have to be used, and can be easily ignored or overridden. |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
=cut |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub new { |
|
82
|
5
|
|
|
5
|
1
|
15381
|
my $pkg = shift; |
|
83
|
5
|
50
|
|
|
|
31
|
croak "usage: Games::Roguelike::World->new()" unless $pkg; |
|
84
|
|
|
|
|
|
|
|
|
85
|
5
|
|
|
|
|
19
|
my $self = bless {}, $pkg; |
|
86
|
5
|
|
|
|
|
45
|
$self->init(@_); |
|
87
|
5
|
|
|
|
|
92
|
return $self; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub init { |
|
91
|
5
|
|
|
5
|
0
|
10
|
my $self = shift; |
|
92
|
|
|
|
|
|
|
|
|
93
|
5
|
|
|
|
|
53
|
$self->{hasmem} = 1; |
|
94
|
5
|
|
|
|
|
17
|
$self->{dispy} = 1; |
|
95
|
5
|
|
|
|
|
16
|
$self->{dispx} = 0; |
|
96
|
5
|
|
|
|
|
14
|
$self->{h} = 40; |
|
97
|
5
|
|
|
|
|
14
|
$self->{w} = 80; |
|
98
|
5
|
|
|
|
|
15
|
$self->{maxlog} = 80; |
|
99
|
5
|
|
|
|
|
12
|
$self->{msgx} = 0; |
|
100
|
5
|
|
|
|
|
19
|
$self->{msgoldcolor} = 'gray'; |
|
101
|
5
|
|
|
|
|
16
|
$self->{msgy} = 0; |
|
102
|
5
|
|
|
|
|
11
|
$self->{msgh} = 1; |
|
103
|
5
|
|
|
|
|
28
|
$self->{noview} = '#+'; |
|
104
|
5
|
|
|
|
|
15
|
$self->{wsym} = '#'; # default wall symbol |
|
105
|
5
|
|
|
|
|
12
|
$self->{fsym} = '.'; # default floor symbol |
|
106
|
5
|
|
|
|
|
17
|
$self->{dsym} = '+'; |
|
107
|
5
|
|
|
|
|
11
|
$self->{debugmap} = 0; |
|
108
|
5
|
|
|
|
|
20
|
$self->{vp} = undef; |
|
109
|
5
|
|
|
|
|
15
|
$self->{dn} = 0; |
|
110
|
5
|
|
|
|
|
16
|
$self->{memcolor} = 'gray'; |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# allow all of the above to be overridden by params |
|
113
|
5
|
|
|
|
|
43
|
while( my ($k, $v) = splice(@_, 0, 2)) { |
|
114
|
16
|
|
|
|
|
58
|
$self->{$k} = $v; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
5
|
50
|
|
|
|
28
|
$self->{nomove} = $self->{wsym} unless $self->{nomove}; # by default, can't move through walls |
|
118
|
5
|
100
|
|
|
|
31
|
$self->{disph} = min(24, $self->{h}) unless $self->{disph}; # default display sizes |
|
119
|
5
|
100
|
|
|
|
26
|
$self->{dispw} = min(60,$self->{w}) unless $self->{dispw}; |
|
120
|
5
|
50
|
|
|
|
46
|
$self->{msgw} = min(60,$self->{dispw}) unless $self->{msgw}; # default message window size |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# create console object |
|
123
|
5
|
100
|
66
|
|
|
91
|
$self->{con} = new Games::Roguelike::Console(noinit=>$self->{noinit}, type=>$self->{console_type}) |
|
124
|
|
|
|
|
|
|
unless $self->{con} || $self->{noconsole}; |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=item area([name or Games::Roguelike::Area]) |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
No arguments: returns the current area |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
Specify a scalar name: returns an area with that name |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
Specify an Games::Roguelike::Area object: stores that object in the area hash, |
|
134
|
|
|
|
|
|
|
overwriting any with the same name, then makes it the active area |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=cut |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub area { |
|
139
|
12
|
|
|
12
|
1
|
27
|
my $self = shift; |
|
140
|
12
|
100
|
|
|
|
36
|
if (@_) { |
|
141
|
5
|
100
|
|
|
|
14
|
if (ref($_[0])) { |
|
142
|
4
|
|
|
|
|
17
|
my $area = shift; |
|
143
|
4
|
|
|
|
|
30
|
$self->addarea($area); |
|
144
|
4
|
|
|
|
|
10
|
$self->{area} = $area; |
|
145
|
|
|
|
|
|
|
} else { |
|
146
|
1
|
|
|
|
|
13
|
return $self->{areas}->{$_[0]}; |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
} |
|
149
|
11
|
|
|
|
|
228
|
return $self->{area}; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub areas { |
|
153
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
|
154
|
0
|
|
|
|
|
0
|
return values(%{$self->{areas}}); |
|
|
0
|
|
|
|
|
0
|
|
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub addarea { |
|
158
|
4
|
|
|
4
|
0
|
6
|
my $self = shift; |
|
159
|
4
|
|
|
|
|
7
|
my $area = shift; |
|
160
|
4
|
50
|
33
|
|
|
24
|
confess("this world already has an area named $area->{name}") |
|
161
|
|
|
|
|
|
|
if $self->{areas}->{$area->{name}} && $self->{areas}->{$area->{name}} != $area; |
|
162
|
4
|
|
|
|
|
14
|
$self->{areas}->{$area->{name}} = $area; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# perl accessors are slow compared to just accessing the hash directly |
|
166
|
|
|
|
|
|
|
# autoload is even slower |
|
167
|
|
|
|
|
|
|
sub AUTOLOAD { |
|
168
|
3
|
|
|
3
|
|
66
|
my $self = shift; |
|
169
|
3
|
50
|
|
|
|
15
|
my $pkg = ref($self) or croak "$self is not an object"; |
|
170
|
|
|
|
|
|
|
|
|
171
|
3
|
|
|
|
|
9
|
my $name = $AUTOLOAD; |
|
172
|
3
|
|
|
|
|
20
|
$name =~ s/.*://; # strip fully-qualified portion |
|
173
|
|
|
|
|
|
|
|
|
174
|
3
|
50
|
33
|
|
|
36
|
$name =~ s/^set// if @_ && !exists $self->{$name}; |
|
175
|
|
|
|
|
|
|
|
|
176
|
3
|
50
|
|
|
|
14
|
unless (exists $self->{$name}) { |
|
177
|
0
|
|
|
|
|
0
|
croak "Can't access `$name' field in class $pkg"; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
3
|
50
|
|
|
|
13
|
if (@_) { |
|
181
|
3
|
|
|
|
|
51
|
return $self->{$name} = $_[0]; |
|
182
|
|
|
|
|
|
|
} else { |
|
183
|
0
|
|
|
|
|
0
|
return $self->{$name}; |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
1
|
|
|
1
|
|
108
|
sub DESTROY { |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=item dprint ( msg1 [,msg2...msgn] [,level] ) |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Debug print messages |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
For now, hard coded to far right side of screen, at col 82, past most terminal game widths |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=cut |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub dprint { |
|
199
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
200
|
|
|
|
|
|
|
|
|
201
|
0
|
|
|
|
|
0
|
my $level = 1; |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# last arg is an integer number |
|
204
|
0
|
0
|
|
|
|
0
|
$level = pop if int(0+$_[$#_]) eq $_[$#_]; |
|
205
|
|
|
|
|
|
|
|
|
206
|
0
|
0
|
|
|
|
0
|
return unless $self->{debug} >= $level; |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
#windows cant have a "wide" console |
|
209
|
0
|
0
|
0
|
|
|
0
|
if ($self->{con} && ref($self->{con}) !~ /win32/i && ref($self->{con}) !~ /dump/i) { |
|
|
|
|
0
|
|
|
|
|
|
210
|
0
|
|
|
|
|
0
|
my $msg = substr(join("\t",@_),0,40); |
|
211
|
0
|
|
|
|
|
0
|
$self->{con}->addstr($self->{dn},82,$msg . (" " x (40-length($msg)))); |
|
212
|
0
|
|
|
|
|
0
|
++$self->{dn}; |
|
213
|
0
|
0
|
|
|
|
0
|
$self->{dn} = 0 if $self->{dn} > 30; |
|
214
|
|
|
|
|
|
|
} else { |
|
215
|
0
|
|
|
|
|
0
|
my $msg = join("\t",@_); |
|
216
|
0
|
|
|
|
|
0
|
open DEBUG, ">>rll-debug.txt"; |
|
217
|
0
|
|
|
|
|
0
|
print DEBUG scalar(localtime), "\t", $msg, "\n"; |
|
218
|
0
|
|
|
|
|
0
|
close DEBUG; |
|
219
|
|
|
|
|
|
|
} |
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=item getch () |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
Read one character, blocks until a char is pressed. |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=cut |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub getch { |
|
229
|
3
|
|
|
3
|
1
|
45
|
my $self = shift; |
|
230
|
3
|
|
|
|
|
23
|
$self->{con}->getch(); |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=item getstr ([echo=>1[,empty=>0]]) |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Calls getch repeatedly, optionally echoing characters to the active console. If "empty" is not |
|
236
|
|
|
|
|
|
|
set to true, it will not return empty strings. |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=cut |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub getstr { |
|
241
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
242
|
0
|
|
|
|
|
0
|
my %opts = @_; |
|
243
|
0
|
0
|
|
|
|
0
|
$opts{max} = 40 if !defined $opts{max}; |
|
244
|
0
|
0
|
|
|
|
0
|
$opts{echo} = 1 if !defined $opts{echo}; |
|
245
|
0
|
0
|
|
|
|
0
|
$opts{empty} = 0 if !defined $opts{empty}; |
|
246
|
|
|
|
|
|
|
|
|
247
|
0
|
|
|
|
|
0
|
$self->{con}->cursor(1); |
|
248
|
0
|
|
|
|
|
0
|
my ($c, $str); |
|
249
|
0
|
|
|
|
|
0
|
while (1) { |
|
250
|
0
|
|
|
|
|
0
|
$c = $self->{con}->getch(); |
|
251
|
0
|
0
|
|
|
|
0
|
if ($c =~ /[\n\r]/) { |
|
252
|
0
|
0
|
0
|
|
|
0
|
last if length($str) > 0 || $opts{empty}; |
|
253
|
|
|
|
|
|
|
} |
|
254
|
0
|
0
|
0
|
|
|
0
|
if ($opts{echo} && length($str) < $opts{max}) { |
|
255
|
0
|
0
|
0
|
|
|
0
|
if ($c eq 'BACKSPACE') { |
|
|
|
0
|
0
|
|
|
|
|
|
256
|
0
|
|
|
|
|
0
|
$self->{con}->addch(chr(8)); |
|
257
|
0
|
|
|
|
|
0
|
$self->{con}->addch(' '); |
|
258
|
0
|
|
|
|
|
0
|
$self->{con}->addch(chr(8)); |
|
259
|
|
|
|
|
|
|
} elsif ((length($c)==1) && (ord($c) > 30) && (ord($c) < 128)) { |
|
260
|
0
|
|
|
|
|
0
|
$self->{con}->addch($c); |
|
261
|
|
|
|
|
|
|
} |
|
262
|
|
|
|
|
|
|
} |
|
263
|
0
|
|
|
|
|
0
|
$self->{con}->refresh(); |
|
264
|
0
|
0
|
0
|
|
|
0
|
if ($c eq 'BACKSPACE') { |
|
|
|
0
|
0
|
|
|
|
|
|
265
|
0
|
|
|
|
|
0
|
$str = substr($str, 0, -1); |
|
266
|
|
|
|
|
|
|
} elsif ((length($c)==1) && (ord($c) > 30) && (ord($c) < 128)) { |
|
267
|
0
|
|
|
|
|
0
|
$str .= $c; |
|
268
|
|
|
|
|
|
|
}; |
|
269
|
0
|
0
|
|
|
|
0
|
$c = '' if !length($str); |
|
270
|
|
|
|
|
|
|
} |
|
271
|
|
|
|
|
|
|
|
|
272
|
0
|
|
|
|
|
0
|
$self->{con}->cursor(0); |
|
273
|
0
|
|
|
|
|
0
|
chomp $str; |
|
274
|
0
|
|
|
|
|
0
|
return $str; |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=item refresh () |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
Refreshes the console display. |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=cut |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub refresh { |
|
285
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
286
|
0
|
|
|
|
|
0
|
$self->{con}->refresh(); |
|
287
|
|
|
|
|
|
|
} |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
=item nbgetch () |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
Read one character, nonblocking, returns undef if none are available. |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=cut |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
sub nbgetch { |
|
296
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
297
|
0
|
|
|
|
|
0
|
$self->{con}->nbgetch(); |
|
298
|
|
|
|
|
|
|
} |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=item findfeature (symbol) |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
searches "map feature list" for the given symbol, returns coordinates if found |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=cut |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
sub findfeature { |
|
307
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
308
|
0
|
|
|
|
|
0
|
return $self->{area}->findfeature(@_); |
|
309
|
|
|
|
|
|
|
} |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
=item dispclear () |
|
312
|
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
Erases the "display world", and resets the "display line" (used by dispstr) |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
Useful for displaying an in-game menu, inventory, ability or skill list, etc. |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
=cut |
|
318
|
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
sub dispclear { |
|
320
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
321
|
|
|
|
|
|
|
|
|
322
|
0
|
|
|
|
|
0
|
my ($y) = @_; |
|
323
|
0
|
0
|
|
|
|
0
|
$y = $self->{dispy} if ! defined $y; |
|
324
|
|
|
|
|
|
|
|
|
325
|
0
|
|
|
|
|
0
|
for (my $i = $y; $i < ($self->{disph}+$self->{dispy}); ++$i) { |
|
326
|
0
|
|
|
|
|
0
|
$self->{con}->addstr($i,$self->{dispx}," " x ($self->{dispw})); |
|
327
|
|
|
|
|
|
|
} |
|
328
|
0
|
|
|
|
|
0
|
$self->{displine} = $self->{dispy}; |
|
329
|
|
|
|
|
|
|
} |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=item dispstr (str[, line]) |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
Draws a tagged string at the "displine" position and increments the "displine". |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
Return value: 0 (offscreen, did not draw), 1 (ok), 2 (ok, but next call will be offscreen). |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=cut |
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub dispstr { |
|
340
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
341
|
0
|
|
|
|
|
0
|
my ($str, $line) = @_; |
|
342
|
|
|
|
|
|
|
|
|
343
|
0
|
|
|
|
|
0
|
my $ret = 1; |
|
344
|
|
|
|
|
|
|
|
|
345
|
0
|
0
|
|
|
|
0
|
if ($line) { |
|
346
|
0
|
|
|
|
|
0
|
$self->{displine} = $line; |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
|
|
349
|
0
|
|
|
|
|
0
|
for (split(/\n/, $str)) { |
|
350
|
0
|
0
|
|
|
|
0
|
if ($self->{displine} >= ($self->{dispy} + $self->{disph})) { |
|
351
|
0
|
|
|
|
|
0
|
return 0; |
|
352
|
|
|
|
|
|
|
} |
|
353
|
0
|
|
|
|
|
0
|
$self->{con}->tagstr($self->{displine}, $self->{dispx}, rpad($_, $self->{dispw})); |
|
354
|
0
|
|
|
|
|
0
|
$self->{con}->move($self->{displine}, $self->{dispx}+length($_)); |
|
355
|
0
|
|
|
|
|
0
|
$self->{displine} += 1; |
|
356
|
|
|
|
|
|
|
} |
|
357
|
|
|
|
|
|
|
|
|
358
|
0
|
0
|
|
|
|
0
|
if ($self->{displine} >= ($self->{dispy} + $self->{disph})) { |
|
359
|
0
|
|
|
|
|
0
|
$ret = 2; |
|
360
|
|
|
|
|
|
|
} |
|
361
|
|
|
|
|
|
|
|
|
362
|
0
|
|
|
|
|
0
|
return $ret; |
|
363
|
|
|
|
|
|
|
} |
|
364
|
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
=item drawmap () |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
Draws the map, usually do this after each move |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
=cut |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub drawmap { |
|
372
|
3
|
|
|
3
|
1
|
27
|
my $self = shift; |
|
373
|
3
|
|
|
|
|
23
|
$self->{area}->draw($self); |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=item prompt (msg[, match]) |
|
377
|
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
Same as showmsg, but also shows the cursor, and gets a character response, optionally waiting until it matches. |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=cut |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub prompt { |
|
383
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
384
|
0
|
|
|
|
|
|
my ($msg, $match) = @_; |
|
385
|
0
|
0
|
|
|
|
|
$match = '.' if !$match; |
|
386
|
0
|
|
|
|
|
|
$self->showmsg($msg); |
|
387
|
0
|
|
|
|
|
|
$self->{con}->cursor(1); |
|
388
|
0
|
|
|
|
|
|
$self->{con}->move($self->{msgy},$self->{msgx}+length($msg)+1); |
|
389
|
0
|
|
|
|
|
|
my $c; |
|
390
|
0
|
|
|
|
|
|
do { |
|
391
|
0
|
|
|
|
|
|
$c = $self->getch(); |
|
392
|
|
|
|
|
|
|
} while ($c !~ /$match/); |
|
393
|
0
|
|
|
|
|
|
$self->{con}->cursor(0); |
|
394
|
0
|
|
|
|
|
|
return $c; |
|
395
|
|
|
|
|
|
|
} |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=item cursor (bool) |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
Turn on/off display of cursor for next operation. |
|
400
|
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=cut |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
sub cursor { |
|
404
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
405
|
0
|
|
|
|
|
|
$self->{con}->cursor(@_); |
|
406
|
|
|
|
|
|
|
} |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=item pushmsg (msg, color) |
|
409
|
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
Shows a message and pushes it into the log. Use of color argument is deprecated. Prefer to use "<$color>$msg" tagged strings. |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=cut |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
sub pushmsg { |
|
415
|
0
|
|
|
0
|
1
|
|
return showmsg(@_[0..2],1); |
|
416
|
|
|
|
|
|
|
} |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=item showmsg (msg, color[, push]) |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
Shows a message at msgx, msgy coorinates and optionally logs it. Also displays up to (msgh-1) old messages. |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=cut |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
sub showmsg { |
|
425
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
426
|
0
|
|
|
|
|
|
my ($msg, $color, $keep) = @_; |
|
427
|
0
|
|
|
|
|
|
$msg = substr($msg, 0, $self->{msgw}); |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# use the character's log, unless there is none |
|
430
|
0
|
0
|
|
|
|
|
my $msglog = $self->{vp} ? $self->{vp}->{msglog} : $self->{msglog} ? $self->{msglog} : ($self->{msglog} = []); |
|
|
|
0
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
|
|
432
|
0
|
|
|
|
|
|
push @$msglog, [$msg, $color]; |
|
433
|
|
|
|
|
|
|
|
|
434
|
0
|
0
|
|
|
|
|
if (@$msglog > $self->{maxlog}) { |
|
435
|
0
|
|
|
|
|
|
shift @$msglog; |
|
436
|
|
|
|
|
|
|
} |
|
437
|
|
|
|
|
|
|
|
|
438
|
0
|
|
|
|
|
|
my $mlx = $#{$msglog}; |
|
|
0
|
|
|
|
|
|
|
|
439
|
0
|
|
|
|
|
|
for (my $i = 0; $i < $self->{msgh}; ++$i) { |
|
440
|
0
|
0
|
|
|
|
|
next unless $i <= $mlx; # no more messages in log |
|
441
|
0
|
|
|
|
|
|
my ($m, $a) = @{$msglog->[$mlx-$i]}; |
|
|
0
|
|
|
|
|
|
|
|
442
|
0
|
0
|
|
|
|
|
if ($self->{msgoldcolor}) { |
|
443
|
0
|
0
|
|
|
|
|
$a = $self->{msgoldcolor} if $i > 0; |
|
444
|
0
|
|
|
|
|
|
$m =~ s/<[^<>]*>//g; |
|
445
|
|
|
|
|
|
|
} |
|
446
|
0
|
0
|
|
|
|
|
$m = "<$a>$m" if $a; |
|
447
|
0
|
|
|
|
|
|
$self->{con}->tagstr($self->{msgy}+$i, $self->{msgx}, $m.(' 'x($self->{msgw}-length($m)))); |
|
448
|
|
|
|
|
|
|
} |
|
449
|
|
|
|
|
|
|
|
|
450
|
0
|
|
|
|
|
|
$self->{con}->move($self->{msgy},$self->{msgx}+length($msglog->[0]->[0])); |
|
451
|
|
|
|
|
|
|
|
|
452
|
0
|
0
|
|
|
|
|
if (!$keep) { |
|
453
|
0
|
|
|
|
|
|
pop @$msglog; |
|
454
|
|
|
|
|
|
|
} |
|
455
|
|
|
|
|
|
|
|
|
456
|
0
|
|
|
|
|
|
$self->{con}->cursor(0); |
|
457
|
0
|
|
|
|
|
|
$self->{con}->refresh(); |
|
458
|
|
|
|
|
|
|
} |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
sub showmsglog { |
|
461
|
0
|
|
|
0
|
0
|
|
my @sort; |
|
462
|
0
|
|
|
|
|
|
my $self = shift; |
|
463
|
0
|
|
|
|
|
|
my $x = $self->{dispx}; |
|
464
|
0
|
|
|
|
|
|
my $y = $self->{dispy}; |
|
465
|
0
|
|
|
|
|
|
my $h = $self->{disph}; |
|
466
|
0
|
0
|
0
|
|
|
|
if ($x == $self->{msgx} && ($self->{msgy} + $self->{msgh}) == $y) { |
|
467
|
0
|
|
|
|
|
|
$y=$self->{msgy}; |
|
468
|
|
|
|
|
|
|
} |
|
469
|
0
|
0
|
0
|
|
|
|
if ($x == $self->{msgx} && ($y + $self->{disph}) == $self->{msgy}) { |
|
470
|
0
|
|
|
|
|
|
$h = $self->{disph} + $self->{msgh}; |
|
471
|
|
|
|
|
|
|
} |
|
472
|
0
|
|
|
|
|
|
for (@{$self->{vp}->{msglog}}) { |
|
|
0
|
|
|
|
|
|
|
|
473
|
0
|
|
|
|
|
|
my ($msg,$color) = @$_; |
|
474
|
0
|
|
|
|
|
|
$self->{con}->attrstr($color,$y,$x,$msg.(' 'x($self->{dispw}-length($msg)))); |
|
475
|
0
|
|
|
|
|
|
++$y; |
|
476
|
0
|
0
|
|
|
|
|
last if $y >= $h; |
|
477
|
|
|
|
|
|
|
} |
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=item save ([file]) |
|
481
|
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
Saves the world (!), optionally specify filename which defaults to "rll.world". |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
=cut |
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
sub save { |
|
487
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
488
|
0
|
|
|
|
|
|
my $fn = shift; |
|
489
|
0
|
0
|
|
|
|
|
$fn = "rll.world" if (!$fn); |
|
490
|
3
|
|
|
3
|
|
5772
|
use Storable; |
|
|
3
|
|
|
|
|
13389
|
|
|
|
3
|
|
|
|
|
519
|
|
|
491
|
0
|
|
|
|
|
|
local $self->{con} = undef; |
|
492
|
0
|
|
|
|
|
|
store $self,$fn; |
|
493
|
|
|
|
|
|
|
} |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
=item load ([file]) |
|
496
|
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
Loads a world, optionally specify filename, returns a reference to the new world. |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
Console is not initialized, and is, instead, copied from the current world. |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=cut |
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
sub load { |
|
504
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
|
505
|
0
|
|
|
|
|
|
my $fn = shift; |
|
506
|
0
|
0
|
|
|
|
|
$fn = "rll.world" if (!$fn); |
|
507
|
3
|
|
|
3
|
|
34
|
use Storable; |
|
|
3
|
|
|
|
|
6
|
|
|
|
3
|
|
|
|
|
347
|
|
|
508
|
|
|
|
|
|
|
|
|
509
|
0
|
|
|
|
|
|
my $n = retrieve $fn; |
|
510
|
|
|
|
|
|
|
|
|
511
|
0
|
|
|
|
|
|
$n->{con} = $self->{con}; |
|
512
|
0
|
|
|
|
|
|
$n->{console_type} = $self->{console_type}; |
|
513
|
|
|
|
|
|
|
|
|
514
|
0
|
|
|
|
|
|
return $n; |
|
515
|
|
|
|
|
|
|
} |
|
516
|
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
=back |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
L, L, L |
|
522
|
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=head1 AUTHOR |
|
524
|
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
Erik Aronesty C |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=head1 LICENSE |
|
528
|
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or |
|
530
|
|
|
|
|
|
|
modify it under the same terms as Perl itself. |
|
531
|
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
See L or the included LICENSE file. |
|
533
|
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
=cut |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
1; |
|
537
|
|
|
|
|
|
|
|