-
Notifications
You must be signed in to change notification settings - Fork 0
/
readable.pl
executable file
·132 lines (103 loc) · 4.55 KB
/
readable.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/perl
#
#
# Copyright © 2019 Olga Ustiuzhanina <me@laserbat.pw>
#
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# the COPYING file for more details.
#
# Please excuse English used in these annotations. I wrote them a long time ago
# in a big hurry, and my English was way worse back then.
# Curses module, used for terminal I/O
use Curses;
# Important variables:
# @w - indexes of every tile on the map.
# @m - offsets for movement keys.
# $v - position of stairs
# $p - position of player
# @l - level
# Cell types:
# 0 - "#" - wall
# 1 - "." - floor
# 2 - ">" - stairs
# 3 - reserved
# 4 - "B" - monster
# The level is 1D array, it is indexed by one variable. The index in it can be
# converted to x, y coordinates by using division and modulo 80.
# x = i % 80
# y = i / 80
# To convert backwards:
# i = y * 80 + k
for(
@w = 0..1920; # Used for indexing the map.
@m = (-1, clear, 80, -80, 1); # Directions, calls clear every update
$l[$v] = 2 # Put stairs in its place.
){
# Render level.
# Since (x ^ y = 0) => (x != y)
# Xor is used to check that current cell isn't occupied by player.
# B in that array is same thing as "B" but uses less characters.
addch $_ ^ $p ? ("#", ".", ">", 0, B)[$l[$_]] : "@" for @w;
# Read input from used and move.
# Puts in variable $z new possible position of player.
# Movement is done by vi-keys so it expects keys h, j, k, l
# h has index 104 in ASCII table, j's index is 106 (that's why second element
# of @m is zero), k - 107, l - 108.
# $m[index - 104] is offset for new position on the map.
# x & 3 is zero when x is 4 or 0. It checks if new position is occupied by
# a wall or a monster.
$p = $z if $l[$z = $p + $m[ord(getch) - 104]] & 3;
# Since monsters are represented by value 4, and 4 % 3 == 1 (floor tile)
# it creates a floor tile in place where monster used to be when player
# moves into a monster.
$l[$z] %= 3;
# Player stepped on stairs.
# x & 2 is not zero when x is 2. 2 represents stairs.
# This code generates new level when player steps on stairs.
if($l[$p] & 2){
# Generate level.
@l = 0 * initscr; # initscr returns some data so 0 * is needed to
# create empty level.
# map is used to repeat code 100 times.
map{
# Checks if current cell ($_) is inside a circle-like curve
# defined by formula x^2 + abs(y) < 6
# $n is offset of this curve from center.
($_ % 80 - $n % 80)**2 + abs($_ - $n) / 80 < 6?
# If it is, roll a 100 sided virtual die and check if result is
# 0 or 1. If it is put a monster in this cell and update $p
# if it isn't put a floor tile here.
# 4 % ~($p = $_) is (almost?) always 4 and updates $p with $_.
# It will be useful later.
# $p here is not related to position of player.
$l[$_] = rand 99 < 2 ? 4 % ~($p = $_) : 1
: 0 # Do nothing.
for @w, # The code above is repeated for ever cell on
# the map, $_ is position of cell being worked on currently.
$n = $p + $n % 4 # Set the new center of the curve to place where
# the last monster was put and add ($n % 4) to make it look a bit
# more random.
} 0..99;
# Do nothing until random values for $v (position of stairs) and $p
# (position of player) are found and are both on unoccupied tiles.
1 until $l[$v = rand @w] & $l[$p = rand @w]
}
$l[$_] & 4? # Checks if cell is 4 (monster)
# $n is the new position of current monster.
# This code checks if new position is floor ($l[$n] == 1)
# and if it's not occupied by player ($n ^ $p, xor being used as !=)
# if it isn't it changes current cell to 9 | something
# Which will be reset to 4 later.
# If it is, it sets $l[$n] to 9 | something and current cell is reset
# to 1 by the second part of this expression.
$l[$l[$n] == 1 && $n ^ $p? $n : $_]=9 |
($n = $_ + $m[rand 4 + ($l[$_]=1)])
: 0 # Do nothing.
for @w; # For every cell on the map.
# For every cell on the level, cells that are bigger than 3 with 4.
# Keep other cells same.
map $_ = $_ > 3? 4 : $_, @l
}