@ticktockbent/rogue-ts 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +175 -0
- package/dist/armor.d.ts +18 -0
- package/dist/armor.d.ts.map +1 -0
- package/dist/armor.js +84 -0
- package/dist/armor.js.map +1 -0
- package/dist/chase.d.ts +15 -0
- package/dist/chase.d.ts.map +1 -0
- package/dist/chase.js +152 -0
- package/dist/chase.js.map +1 -0
- package/dist/command.d.ts +12 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +761 -0
- package/dist/command.js.map +1 -0
- package/dist/curses.d.ts +102 -0
- package/dist/curses.d.ts.map +1 -0
- package/dist/curses.js +47 -0
- package/dist/curses.js.map +1 -0
- package/dist/daemon.d.ts +43 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +116 -0
- package/dist/daemon.js.map +1 -0
- package/dist/daemons.d.ts +47 -0
- package/dist/daemons.d.ts.map +1 -0
- package/dist/daemons.js +194 -0
- package/dist/daemons.js.map +1 -0
- package/dist/fight.d.ts +52 -0
- package/dist/fight.d.ts.map +1 -0
- package/dist/fight.js +508 -0
- package/dist/fight.js.map +1 -0
- package/dist/globals.d.ts +387 -0
- package/dist/globals.d.ts.map +1 -0
- package/dist/globals.js +935 -0
- package/dist/globals.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +30 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +159 -0
- package/dist/init.js.map +1 -0
- package/dist/io.d.ts +48 -0
- package/dist/io.d.ts.map +1 -0
- package/dist/io.js +248 -0
- package/dist/io.js.map +1 -0
- package/dist/list.d.ts +37 -0
- package/dist/list.d.ts.map +1 -0
- package/dist/list.js +109 -0
- package/dist/list.js.map +1 -0
- package/dist/main.d.ts +23 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +207 -0
- package/dist/main.js.map +1 -0
- package/dist/misc.d.ts +53 -0
- package/dist/misc.d.ts.map +1 -0
- package/dist/misc.js +296 -0
- package/dist/misc.js.map +1 -0
- package/dist/monsters.d.ts +55 -0
- package/dist/monsters.d.ts.map +1 -0
- package/dist/monsters.js +211 -0
- package/dist/monsters.js.map +1 -0
- package/dist/move.d.ts +23 -0
- package/dist/move.d.ts.map +1 -0
- package/dist/move.js +270 -0
- package/dist/move.js.map +1 -0
- package/dist/new_level.d.ts +17 -0
- package/dist/new_level.d.ts.map +1 -0
- package/dist/new_level.js +173 -0
- package/dist/new_level.js.map +1 -0
- package/dist/pack.d.ts +47 -0
- package/dist/pack.d.ts.map +1 -0
- package/dist/pack.js +359 -0
- package/dist/pack.js.map +1 -0
- package/dist/passages.d.ts +23 -0
- package/dist/passages.d.ts.map +1 -0
- package/dist/passages.js +277 -0
- package/dist/passages.js.map +1 -0
- package/dist/potions.d.ts +13 -0
- package/dist/potions.d.ts.map +1 -0
- package/dist/potions.js +239 -0
- package/dist/potions.js.map +1 -0
- package/dist/rings.d.ts +13 -0
- package/dist/rings.d.ts.map +1 -0
- package/dist/rings.js +173 -0
- package/dist/rings.js.map +1 -0
- package/dist/rip.d.ts +22 -0
- package/dist/rip.d.ts.map +1 -0
- package/dist/rip.js +216 -0
- package/dist/rip.js.map +1 -0
- package/dist/rooms.d.ts +62 -0
- package/dist/rooms.d.ts.map +1 -0
- package/dist/rooms.js +432 -0
- package/dist/rooms.js.map +1 -0
- package/dist/save.d.ts +25 -0
- package/dist/save.d.ts.map +1 -0
- package/dist/save.js +565 -0
- package/dist/save.js.map +1 -0
- package/dist/scrolls.d.ts +13 -0
- package/dist/scrolls.d.ts.map +1 -0
- package/dist/scrolls.js +305 -0
- package/dist/scrolls.js.map +1 -0
- package/dist/sticks.d.ts +9 -0
- package/dist/sticks.d.ts.map +1 -0
- package/dist/sticks.js +379 -0
- package/dist/sticks.js.map +1 -0
- package/dist/things.d.ts +28 -0
- package/dist/things.d.ts.map +1 -0
- package/dist/things.js +307 -0
- package/dist/things.js.map +1 -0
- package/dist/types.d.ts +113 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +36 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +198 -0
- package/dist/util.js.map +1 -0
- package/dist/weapons.d.ts +22 -0
- package/dist/weapons.d.ts.map +1 -0
- package/dist/weapons.js +185 -0
- package/dist/weapons.js.map +1 -0
- package/package.json +31 -0
package/dist/command.js
ADDED
|
@@ -0,0 +1,761 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Command dispatcher.
|
|
3
|
+
* Ported from command.c
|
|
4
|
+
*
|
|
5
|
+
* Handles all key input during the main game loop.
|
|
6
|
+
*/
|
|
7
|
+
import { state, ESCAPE, NUMLINES, NUMCOLS, STAIRS, ISHUH, ISHALU, ISLEVIT, ISWEARING, R_SEARCH, R_TELEPORT, FLOOR, PASSAGE, DOOR, TRAP, POTION, SCROLL, RING, STICK, CALLABLE, INDEX, chat, flat, F_REAL, F_PASS, F_TMASK, pot_info, scr_info, ring_info, ws_info, MAXPOTIONS, MAXSCROLLS, MAXRINGS, MAXSTICKS, helpstr, tr_name, monsters as monsterTemplates, } from "./globals.js";
|
|
8
|
+
import { CTRL, rnd } from "./util.js";
|
|
9
|
+
import { msg, readchar, wait_for, status, getBackend } from "./io.js";
|
|
10
|
+
import { do_move, do_run } from "./move.js";
|
|
11
|
+
import { pick_up, drop, eat, get_item } from "./pack.js";
|
|
12
|
+
import { inventory } from "./pack.js";
|
|
13
|
+
import { look } from "./misc.js";
|
|
14
|
+
import { quit } from "./rip.js";
|
|
15
|
+
import { wield, missile } from "./weapons.js";
|
|
16
|
+
import { wear, take_off } from "./armor.js";
|
|
17
|
+
import { quaff } from "./potions.js";
|
|
18
|
+
import { read_scroll } from "./scrolls.js";
|
|
19
|
+
import { ring_on, ring_off } from "./rings.js";
|
|
20
|
+
import { do_zap } from "./sticks.js";
|
|
21
|
+
import { inv_name } from "./things.js";
|
|
22
|
+
// Direction deltas for movement keys
|
|
23
|
+
const dirMap = {
|
|
24
|
+
h: [0, -1],
|
|
25
|
+
j: [1, 0],
|
|
26
|
+
k: [-1, 0],
|
|
27
|
+
l: [0, 1],
|
|
28
|
+
y: [-1, -1],
|
|
29
|
+
u: [-1, 1],
|
|
30
|
+
b: [1, -1],
|
|
31
|
+
n: [1, 1],
|
|
32
|
+
};
|
|
33
|
+
// Uppercase = run in that direction
|
|
34
|
+
const runMap = {
|
|
35
|
+
H: "h", J: "j", K: "k", L: "l",
|
|
36
|
+
Y: "y", U: "u", B: "b", N: "n",
|
|
37
|
+
};
|
|
38
|
+
// Ctrl+dir = run until adjacent to something
|
|
39
|
+
const ctrlDirMap = {
|
|
40
|
+
[CTRL("H")]: "h", [CTRL("J")]: "j", [CTRL("K")]: "k", [CTRL("L")]: "l",
|
|
41
|
+
[CTRL("Y")]: "y", [CTRL("U")]: "u", [CTRL("B")]: "b", [CTRL("N")]: "n",
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* command: Read and execute a command.
|
|
45
|
+
* Returns true if the turn should end (monsters move).
|
|
46
|
+
*/
|
|
47
|
+
export async function command() {
|
|
48
|
+
const backend = getBackend();
|
|
49
|
+
// Handle no_command (paralysis, etc.)
|
|
50
|
+
if (state.no_command > 0) {
|
|
51
|
+
state.no_command--;
|
|
52
|
+
if (state.no_command === 0) {
|
|
53
|
+
await msg("you can move again");
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
// If counting moves, continue the last direction
|
|
58
|
+
if (state.count > 0) {
|
|
59
|
+
state.count--;
|
|
60
|
+
return await executeDirection(state.last_dir);
|
|
61
|
+
}
|
|
62
|
+
state.after = true;
|
|
63
|
+
// If running, continue the run
|
|
64
|
+
if (state.running) {
|
|
65
|
+
return await executeDirection(state.runch);
|
|
66
|
+
}
|
|
67
|
+
// Draw surrounding area
|
|
68
|
+
await look(true);
|
|
69
|
+
await status();
|
|
70
|
+
backend.move(state.player.t_pos.y, state.player.t_pos.x);
|
|
71
|
+
backend.refresh();
|
|
72
|
+
// Pick up items if auto-pickup is pending
|
|
73
|
+
if (state.take !== "") {
|
|
74
|
+
const takeCh = state.take;
|
|
75
|
+
state.take = "";
|
|
76
|
+
if (!state.move_no_pickup) {
|
|
77
|
+
await pick_up(takeCh);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Read the command
|
|
81
|
+
let ch = await readchar();
|
|
82
|
+
// C original: numeric prefix — read digits to build a count
|
|
83
|
+
if (ch >= "0" && ch <= "9") {
|
|
84
|
+
state.count = 0;
|
|
85
|
+
while (ch >= "0" && ch <= "9") {
|
|
86
|
+
state.count = state.count * 10 + (ch.charCodeAt(0) - "0".charCodeAt(0));
|
|
87
|
+
ch = await readchar();
|
|
88
|
+
}
|
|
89
|
+
state.count--;
|
|
90
|
+
}
|
|
91
|
+
// Check for movement
|
|
92
|
+
if (dirMap[ch]) {
|
|
93
|
+
const [dy, dx] = dirMap[ch];
|
|
94
|
+
state.last_dir = ch;
|
|
95
|
+
await do_move(dy, dx);
|
|
96
|
+
return state.after;
|
|
97
|
+
}
|
|
98
|
+
// Check for running
|
|
99
|
+
if (runMap[ch]) {
|
|
100
|
+
const dir = runMap[ch];
|
|
101
|
+
do_run(dir);
|
|
102
|
+
state.last_dir = dir;
|
|
103
|
+
const [dy, dx] = dirMap[dir];
|
|
104
|
+
await do_move(dy, dx);
|
|
105
|
+
return state.after;
|
|
106
|
+
}
|
|
107
|
+
// Check for ctrl+dir (run until adjacent)
|
|
108
|
+
const ctrlDir = ctrlDirMap[ch.charCodeAt(0)];
|
|
109
|
+
if (ctrlDir !== undefined) {
|
|
110
|
+
do_run(ctrlDir);
|
|
111
|
+
state.last_dir = ctrlDir;
|
|
112
|
+
const [dy, dx] = dirMap[ctrlDir];
|
|
113
|
+
await do_move(dy, dx);
|
|
114
|
+
return state.after;
|
|
115
|
+
}
|
|
116
|
+
// Other commands
|
|
117
|
+
switch (ch) {
|
|
118
|
+
case ".":
|
|
119
|
+
// Rest — do nothing, let monsters move
|
|
120
|
+
break;
|
|
121
|
+
case "s":
|
|
122
|
+
// Search for hidden doors/traps
|
|
123
|
+
await search();
|
|
124
|
+
break;
|
|
125
|
+
case ">":
|
|
126
|
+
// Go down stairs
|
|
127
|
+
await goDownStairs();
|
|
128
|
+
break;
|
|
129
|
+
case "<":
|
|
130
|
+
// Go up stairs (need amulet)
|
|
131
|
+
await goUpStairs();
|
|
132
|
+
break;
|
|
133
|
+
case "i":
|
|
134
|
+
// Inventory
|
|
135
|
+
state.after = false;
|
|
136
|
+
await inventory(state.player.t_pack, 0);
|
|
137
|
+
break;
|
|
138
|
+
case ",":
|
|
139
|
+
case "g":
|
|
140
|
+
// Pick up item
|
|
141
|
+
{
|
|
142
|
+
const pickCh = chat(state.player.t_pos.y, state.player.t_pos.x);
|
|
143
|
+
if (pickCh === FLOOR || pickCh === PASSAGE || pickCh === DOOR || pickCh === " ") {
|
|
144
|
+
await msg("nothing to pick up");
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
await pick_up(pickCh);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
case "d":
|
|
152
|
+
// Drop item
|
|
153
|
+
await drop();
|
|
154
|
+
break;
|
|
155
|
+
case "e":
|
|
156
|
+
// Eat food
|
|
157
|
+
await eat();
|
|
158
|
+
break;
|
|
159
|
+
case "w":
|
|
160
|
+
// Wield weapon
|
|
161
|
+
await wield();
|
|
162
|
+
break;
|
|
163
|
+
case "W":
|
|
164
|
+
// Wear armor
|
|
165
|
+
await wear();
|
|
166
|
+
break;
|
|
167
|
+
case "T":
|
|
168
|
+
// Take off armor
|
|
169
|
+
await take_off();
|
|
170
|
+
break;
|
|
171
|
+
case "q":
|
|
172
|
+
// Quaff potion
|
|
173
|
+
await quaff();
|
|
174
|
+
break;
|
|
175
|
+
case "r":
|
|
176
|
+
// Read scroll
|
|
177
|
+
await read_scroll();
|
|
178
|
+
break;
|
|
179
|
+
case "P":
|
|
180
|
+
// Put on ring
|
|
181
|
+
await ring_on();
|
|
182
|
+
break;
|
|
183
|
+
case "R":
|
|
184
|
+
// Remove ring
|
|
185
|
+
await ring_off();
|
|
186
|
+
break;
|
|
187
|
+
case "z":
|
|
188
|
+
// Zap wand/staff
|
|
189
|
+
await do_zap();
|
|
190
|
+
break;
|
|
191
|
+
case "t":
|
|
192
|
+
// Throw something
|
|
193
|
+
await missile();
|
|
194
|
+
break;
|
|
195
|
+
case "f":
|
|
196
|
+
// Fight to death or near death
|
|
197
|
+
{
|
|
198
|
+
state.to_death = true;
|
|
199
|
+
const fightDir = await readchar();
|
|
200
|
+
if (dirMap[fightDir]) {
|
|
201
|
+
state.last_dir = fightDir;
|
|
202
|
+
const [dy, dx] = dirMap[fightDir];
|
|
203
|
+
await do_move(dy, dx);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
case "F":
|
|
208
|
+
// Fight to the death (kamikaze)
|
|
209
|
+
{
|
|
210
|
+
state.to_death = true;
|
|
211
|
+
state.kamikaze = true;
|
|
212
|
+
const fightDir = await readchar();
|
|
213
|
+
if (dirMap[fightDir]) {
|
|
214
|
+
state.last_dir = fightDir;
|
|
215
|
+
const [dy, dx] = dirMap[fightDir];
|
|
216
|
+
await do_move(dy, dx);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
break;
|
|
220
|
+
case "m":
|
|
221
|
+
// Move without picking up
|
|
222
|
+
{
|
|
223
|
+
state.move_no_pickup = true;
|
|
224
|
+
const moveDir = await readchar();
|
|
225
|
+
if (dirMap[moveDir]) {
|
|
226
|
+
state.last_dir = moveDir;
|
|
227
|
+
const [dy, dx] = dirMap[moveDir];
|
|
228
|
+
await do_move(dy, dx);
|
|
229
|
+
}
|
|
230
|
+
state.move_no_pickup = false;
|
|
231
|
+
}
|
|
232
|
+
break;
|
|
233
|
+
case "c":
|
|
234
|
+
// Call/name an item
|
|
235
|
+
state.after = false;
|
|
236
|
+
await call_it();
|
|
237
|
+
break;
|
|
238
|
+
case "a":
|
|
239
|
+
// Repeat last command
|
|
240
|
+
state.again = true;
|
|
241
|
+
break;
|
|
242
|
+
case ")":
|
|
243
|
+
// Print current weapon
|
|
244
|
+
state.after = false;
|
|
245
|
+
if (state.cur_weapon !== null && state.cur_weapon._kind === "object") {
|
|
246
|
+
await msg("you are wielding %s (%s)", inv_name(state.cur_weapon, false), state.cur_weapon.o_packch);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
await msg("you are empty handed");
|
|
250
|
+
}
|
|
251
|
+
break;
|
|
252
|
+
case "]":
|
|
253
|
+
// Print current armor
|
|
254
|
+
state.after = false;
|
|
255
|
+
if (state.cur_armor !== null && state.cur_armor._kind === "object") {
|
|
256
|
+
await msg("you are wearing %s", inv_name(state.cur_armor, false));
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
await msg("you are not wearing any armor");
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
case "=":
|
|
263
|
+
// Print current rings
|
|
264
|
+
state.after = false;
|
|
265
|
+
{
|
|
266
|
+
let foundRing = false;
|
|
267
|
+
for (let hand = 0; hand < 2; hand++) {
|
|
268
|
+
const ring = state.cur_ring[hand];
|
|
269
|
+
if (ring !== null && ring._kind === "object") {
|
|
270
|
+
await msg("on %s hand: %s", hand === 0 ? "left" : "right", inv_name(ring, false));
|
|
271
|
+
foundRing = true;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (!foundRing) {
|
|
275
|
+
await msg("not wearing any rings");
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
break;
|
|
279
|
+
case "@":
|
|
280
|
+
// Toggle stat_msg / print current stats
|
|
281
|
+
state.after = false;
|
|
282
|
+
state.stat_msg = !state.stat_msg;
|
|
283
|
+
await msg("terse stats %s", state.stat_msg ? "on" : "off");
|
|
284
|
+
break;
|
|
285
|
+
case "D":
|
|
286
|
+
// Recall discoveries
|
|
287
|
+
state.after = false;
|
|
288
|
+
await discovered();
|
|
289
|
+
break;
|
|
290
|
+
case "/":
|
|
291
|
+
// Identify character on screen
|
|
292
|
+
state.after = false;
|
|
293
|
+
await identify_char();
|
|
294
|
+
break;
|
|
295
|
+
case "^":
|
|
296
|
+
// Identify trap type
|
|
297
|
+
state.after = false;
|
|
298
|
+
await identify_trap();
|
|
299
|
+
break;
|
|
300
|
+
case "I":
|
|
301
|
+
// Inventory single item
|
|
302
|
+
state.after = false;
|
|
303
|
+
{
|
|
304
|
+
await msg("which item? ");
|
|
305
|
+
const itemCh = await readchar();
|
|
306
|
+
if (itemCh.charCodeAt(0) === ESCAPE) {
|
|
307
|
+
await msg("");
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
let found = false;
|
|
311
|
+
let item = state.player.t_pack;
|
|
312
|
+
while (item !== null) {
|
|
313
|
+
if (item._kind === "object" && item.o_packch === itemCh) {
|
|
314
|
+
await msg("%s (%s)", inv_name(item, false), item.o_packch);
|
|
315
|
+
found = true;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
item = item.l_next;
|
|
319
|
+
}
|
|
320
|
+
if (!found) {
|
|
321
|
+
await msg("'%s' not in pack", itemCh);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
break;
|
|
325
|
+
case "o":
|
|
326
|
+
// Options
|
|
327
|
+
state.after = false;
|
|
328
|
+
await set_options();
|
|
329
|
+
break;
|
|
330
|
+
case "S":
|
|
331
|
+
// Save game
|
|
332
|
+
state.after = false;
|
|
333
|
+
{
|
|
334
|
+
const { saveGame } = await import("./save.js");
|
|
335
|
+
const saveData = saveGame();
|
|
336
|
+
state._saveData = saveData;
|
|
337
|
+
await msg("game saved");
|
|
338
|
+
// Signal the game loop to exit cleanly
|
|
339
|
+
state.playing = false;
|
|
340
|
+
const { RogueExit } = await import("./types.js");
|
|
341
|
+
throw new RogueExit(0);
|
|
342
|
+
}
|
|
343
|
+
case "Q":
|
|
344
|
+
// Quit
|
|
345
|
+
state.after = false;
|
|
346
|
+
await msg("really quit?");
|
|
347
|
+
{
|
|
348
|
+
const answer = await readchar();
|
|
349
|
+
if (answer === "y" || answer === "Y") {
|
|
350
|
+
await quit();
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
await msg("");
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
break;
|
|
357
|
+
case String.fromCharCode(CTRL("R")):
|
|
358
|
+
// Redraw screen
|
|
359
|
+
state.after = false;
|
|
360
|
+
if (state.stdscr !== null) {
|
|
361
|
+
backend.clearok(state.stdscr, true);
|
|
362
|
+
}
|
|
363
|
+
backend.refresh();
|
|
364
|
+
break;
|
|
365
|
+
case String.fromCharCode(CTRL("P")):
|
|
366
|
+
// Repeat last message
|
|
367
|
+
state.after = false;
|
|
368
|
+
if (state.huh !== "") {
|
|
369
|
+
await msg(state.huh);
|
|
370
|
+
}
|
|
371
|
+
break;
|
|
372
|
+
case "?":
|
|
373
|
+
// Help
|
|
374
|
+
state.after = false;
|
|
375
|
+
await help();
|
|
376
|
+
break;
|
|
377
|
+
case "v":
|
|
378
|
+
// Version
|
|
379
|
+
state.after = false;
|
|
380
|
+
await msg("rogue-ts version: 5.4.4-ts (Phase 8)");
|
|
381
|
+
break;
|
|
382
|
+
default:
|
|
383
|
+
// Unknown command
|
|
384
|
+
state.after = false;
|
|
385
|
+
if (state.terse) {
|
|
386
|
+
await msg("illegal cmd '%s'", ch);
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
await msg("illegal command '%s'", ch);
|
|
390
|
+
}
|
|
391
|
+
state.count = 0;
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
// C original: ring of searching auto-searches each turn
|
|
395
|
+
if (state.after && ISWEARING(R_SEARCH)) {
|
|
396
|
+
await search();
|
|
397
|
+
}
|
|
398
|
+
// C original: ring of teleportation randomly teleports
|
|
399
|
+
if (state.after && ISWEARING(R_TELEPORT) && rnd(50) === 0) {
|
|
400
|
+
const { find_floor, roomin } = await import("./rooms.js");
|
|
401
|
+
const { floor_at } = await import("./misc.js");
|
|
402
|
+
const heroPos = state.player.t_pos;
|
|
403
|
+
const newPos = { y: 0, x: 0 };
|
|
404
|
+
find_floor(null, newPos, false, true);
|
|
405
|
+
const backend = getBackend();
|
|
406
|
+
backend.mvaddch(heroPos.y, heroPos.x, floor_at().charCodeAt(0));
|
|
407
|
+
heroPos.y = newPos.y;
|
|
408
|
+
heroPos.x = newPos.x;
|
|
409
|
+
state.player.t_room = roomin(heroPos);
|
|
410
|
+
await msg("teleport!");
|
|
411
|
+
}
|
|
412
|
+
return state.after;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* executeDirection: Execute movement in a saved direction.
|
|
416
|
+
*/
|
|
417
|
+
async function executeDirection(dir) {
|
|
418
|
+
if (!dirMap[dir])
|
|
419
|
+
return false;
|
|
420
|
+
const [dy, dx] = dirMap[dir];
|
|
421
|
+
await do_move(dy, dx);
|
|
422
|
+
return state.after;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* search: Look for hidden things around the hero.
|
|
426
|
+
*/
|
|
427
|
+
async function search() {
|
|
428
|
+
const backend = getBackend();
|
|
429
|
+
const heroPos = state.player.t_pos;
|
|
430
|
+
// C original: confused search has probability of failure per cell, not total failure
|
|
431
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
432
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
433
|
+
if (dy === 0 && dx === 0)
|
|
434
|
+
continue;
|
|
435
|
+
const ny = heroPos.y + dy;
|
|
436
|
+
const nx = heroPos.x + dx;
|
|
437
|
+
if (ny <= 0 || ny >= NUMLINES - 1 || nx < 0 || nx >= NUMCOLS)
|
|
438
|
+
continue;
|
|
439
|
+
// Confused: each cell has a chance to fail
|
|
440
|
+
if ((state.player.t_flags & ISHUH) && rnd(5) !== 0)
|
|
441
|
+
continue;
|
|
442
|
+
const pp = INDEX(ny, nx);
|
|
443
|
+
if (!(pp.p_flags & F_REAL)) {
|
|
444
|
+
if (rnd(5) === 0) {
|
|
445
|
+
pp.p_flags |= F_REAL;
|
|
446
|
+
pp.p_ch = (pp.p_flags & F_PASS) ? PASSAGE : DOOR;
|
|
447
|
+
state.count = 0;
|
|
448
|
+
state.running = false;
|
|
449
|
+
if (!(state.player.t_flags & ISHALU)) {
|
|
450
|
+
backend.mvaddch(ny, nx, pp.p_ch.charCodeAt(0));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* goDownStairs: Descend to the next level.
|
|
459
|
+
*/
|
|
460
|
+
async function goDownStairs() {
|
|
461
|
+
if (chat(state.player.t_pos.y, state.player.t_pos.x) !== STAIRS) {
|
|
462
|
+
if (state.terse) {
|
|
463
|
+
await msg("no stairs");
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
await msg("I see no way down");
|
|
467
|
+
}
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
// C original: levit_check — levitating players can't use stairs
|
|
471
|
+
if (levit_check())
|
|
472
|
+
return;
|
|
473
|
+
state.level++;
|
|
474
|
+
state.seenstairs = false;
|
|
475
|
+
state._newLevel = true;
|
|
476
|
+
// C original: stairs don't give monsters a free turn
|
|
477
|
+
state.after = false;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* goUpStairs: Ascend (only with the amulet, only at level 1).
|
|
481
|
+
*/
|
|
482
|
+
async function goUpStairs() {
|
|
483
|
+
if (chat(state.player.t_pos.y, state.player.t_pos.x) !== STAIRS) {
|
|
484
|
+
if (state.terse) {
|
|
485
|
+
await msg("no stairs");
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
await msg("I see no way up");
|
|
489
|
+
}
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
if (!state.amulet) {
|
|
493
|
+
await msg("your way is magically blocked");
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
// C original: levit_check — levitating players can't use stairs
|
|
497
|
+
if (levit_check())
|
|
498
|
+
return;
|
|
499
|
+
state.level--;
|
|
500
|
+
if (state.level <= 0) {
|
|
501
|
+
const { total_winner } = await import("./rip.js");
|
|
502
|
+
await total_winner();
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
state._newLevel = true;
|
|
506
|
+
state.after = false;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* call_it: Allow the player to name/call an item type.
|
|
510
|
+
*/
|
|
511
|
+
async function call_it() {
|
|
512
|
+
const obj = await get_item("call", CALLABLE);
|
|
513
|
+
if (obj === null)
|
|
514
|
+
return;
|
|
515
|
+
const typeChar = String.fromCharCode(obj.o_type);
|
|
516
|
+
let infoTable = null;
|
|
517
|
+
let idx = obj.o_which;
|
|
518
|
+
switch (typeChar) {
|
|
519
|
+
case POTION:
|
|
520
|
+
infoTable = pot_info;
|
|
521
|
+
break;
|
|
522
|
+
case SCROLL:
|
|
523
|
+
infoTable = scr_info;
|
|
524
|
+
break;
|
|
525
|
+
case RING:
|
|
526
|
+
infoTable = ring_info;
|
|
527
|
+
break;
|
|
528
|
+
case STICK:
|
|
529
|
+
infoTable = ws_info;
|
|
530
|
+
break;
|
|
531
|
+
default:
|
|
532
|
+
// Can also name individual objects
|
|
533
|
+
await msg("what do you want to call it?");
|
|
534
|
+
{
|
|
535
|
+
const name = await readName();
|
|
536
|
+
if (name !== "") {
|
|
537
|
+
obj.o_label = name;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
await msg("what do you want to call it?");
|
|
543
|
+
const name = await readName();
|
|
544
|
+
if (name !== "" && infoTable !== null) {
|
|
545
|
+
infoTable[idx].oi_guess = name;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* readName: Read a string from the player for naming items.
|
|
550
|
+
*/
|
|
551
|
+
async function readName() {
|
|
552
|
+
let name = "";
|
|
553
|
+
for (;;) {
|
|
554
|
+
const ch = await readchar();
|
|
555
|
+
if (ch === "\n" || ch === "\r")
|
|
556
|
+
break;
|
|
557
|
+
if (ch.charCodeAt(0) === ESCAPE)
|
|
558
|
+
return "";
|
|
559
|
+
if (ch === "\b" || ch.charCodeAt(0) === 127) {
|
|
560
|
+
if (name.length > 0)
|
|
561
|
+
name = name.slice(0, -1);
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
if (name.length < 30) {
|
|
565
|
+
name += ch;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return name;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* help: Display the help screen using the helpstr table.
|
|
572
|
+
*/
|
|
573
|
+
async function help() {
|
|
574
|
+
const backend = getBackend();
|
|
575
|
+
backend.clear();
|
|
576
|
+
let row = 0;
|
|
577
|
+
for (const entry of helpstr) {
|
|
578
|
+
if (!entry.h_print)
|
|
579
|
+
continue;
|
|
580
|
+
let line;
|
|
581
|
+
if (entry.h_ch === 0) {
|
|
582
|
+
// Category header
|
|
583
|
+
line = entry.h_desc.replace(/^\t/, " ");
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
const keyStr = entry.h_ch < 32
|
|
587
|
+
? "^" + String.fromCharCode(entry.h_ch + 64)
|
|
588
|
+
: String.fromCharCode(entry.h_ch);
|
|
589
|
+
// h_desc is like "<dir>\tdescription" or "\tdescription"
|
|
590
|
+
const parts = entry.h_desc.split("\t");
|
|
591
|
+
const prefix = parts[0] || "";
|
|
592
|
+
const desc = parts[1] || "";
|
|
593
|
+
line = keyStr + prefix + " " + desc;
|
|
594
|
+
}
|
|
595
|
+
backend.mvaddstr(row, 0, line);
|
|
596
|
+
row++;
|
|
597
|
+
if (row >= NUMLINES - 1) {
|
|
598
|
+
backend.mvaddstr(NUMLINES - 1, 0, "--Press space to continue--");
|
|
599
|
+
backend.refresh();
|
|
600
|
+
await wait_for(" ");
|
|
601
|
+
backend.clear();
|
|
602
|
+
row = 0;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
backend.mvaddstr(NUMLINES - 1, 0, "--Press space to continue--");
|
|
606
|
+
backend.refresh();
|
|
607
|
+
await wait_for(" ");
|
|
608
|
+
if (state.stdscr !== null) {
|
|
609
|
+
backend.clearok(state.stdscr, true);
|
|
610
|
+
}
|
|
611
|
+
backend.refresh();
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* discovered: Show what items have been discovered/identified.
|
|
615
|
+
*/
|
|
616
|
+
async function discovered() {
|
|
617
|
+
const backend = getBackend();
|
|
618
|
+
const lines = [];
|
|
619
|
+
// Potions
|
|
620
|
+
for (let i = 0; i < MAXPOTIONS; i++) {
|
|
621
|
+
if (pot_info[i].oi_know) {
|
|
622
|
+
lines.push(`A potion of ${pot_info[i].oi_name} (${state.p_colors[i]})`);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
// Scrolls
|
|
626
|
+
for (let i = 0; i < MAXSCROLLS; i++) {
|
|
627
|
+
if (scr_info[i].oi_know) {
|
|
628
|
+
lines.push(`A scroll of ${scr_info[i].oi_name} (${state.s_names[i]})`);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
// Rings
|
|
632
|
+
for (let i = 0; i < MAXRINGS; i++) {
|
|
633
|
+
if (ring_info[i].oi_know) {
|
|
634
|
+
lines.push(`A ring of ${ring_info[i].oi_name} (${state.r_stones[i]})`);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
// Sticks
|
|
638
|
+
for (let i = 0; i < MAXSTICKS; i++) {
|
|
639
|
+
if (ws_info[i].oi_know) {
|
|
640
|
+
const stickType = state.ws_type[i] || "staff";
|
|
641
|
+
lines.push(`A ${stickType} of ${ws_info[i].oi_name} (${state.ws_made[i]})`);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
if (lines.length === 0) {
|
|
645
|
+
await msg("nothing discovered yet");
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
backend.clear();
|
|
649
|
+
let row = 0;
|
|
650
|
+
for (const line of lines) {
|
|
651
|
+
backend.mvaddstr(row, 0, line);
|
|
652
|
+
row++;
|
|
653
|
+
if (row >= NUMLINES - 1) {
|
|
654
|
+
backend.mvaddstr(NUMLINES - 1, 0, "--Press space to continue--");
|
|
655
|
+
backend.refresh();
|
|
656
|
+
await wait_for(" ");
|
|
657
|
+
backend.clear();
|
|
658
|
+
row = 0;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
backend.mvaddstr(NUMLINES - 1, 0, "--Press space to continue--");
|
|
662
|
+
backend.refresh();
|
|
663
|
+
await wait_for(" ");
|
|
664
|
+
if (state.stdscr !== null) {
|
|
665
|
+
backend.clearok(state.stdscr, true);
|
|
666
|
+
}
|
|
667
|
+
backend.refresh();
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* identify_char: Tell the player what a character on the screen represents.
|
|
671
|
+
*/
|
|
672
|
+
async function identify_char() {
|
|
673
|
+
await msg("what do you want identified? ");
|
|
674
|
+
const ch = await readchar();
|
|
675
|
+
const charNames = {
|
|
676
|
+
"|": "wall of a room",
|
|
677
|
+
"-": "wall of a room",
|
|
678
|
+
".": "floor",
|
|
679
|
+
"#": "passage",
|
|
680
|
+
"+": "door",
|
|
681
|
+
"^": "trap",
|
|
682
|
+
"%": "staircase",
|
|
683
|
+
"*": "gold",
|
|
684
|
+
":": "food",
|
|
685
|
+
"!": "potion",
|
|
686
|
+
"?": "scroll",
|
|
687
|
+
")": "weapon",
|
|
688
|
+
"]": "armor",
|
|
689
|
+
"=": "ring",
|
|
690
|
+
"/": "wand or staff",
|
|
691
|
+
",": "the Amulet of Yendor",
|
|
692
|
+
"@": "you",
|
|
693
|
+
" ": "solid rock",
|
|
694
|
+
};
|
|
695
|
+
// Check if it's a monster letter
|
|
696
|
+
if (ch >= "A" && ch <= "Z") {
|
|
697
|
+
const monsterIndex = ch.charCodeAt(0) - "A".charCodeAt(0);
|
|
698
|
+
await msg("'%s': %s", ch, monsterTemplates[monsterIndex].m_name);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
const description = charNames[ch];
|
|
702
|
+
if (description !== undefined) {
|
|
703
|
+
await msg("'%s': %s", ch, description);
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
await msg("'%s': unknown character", ch);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* identify_trap: Show the type of an adjacent trap.
|
|
711
|
+
*/
|
|
712
|
+
async function identify_trap() {
|
|
713
|
+
const { get_dir } = await import("./misc.js");
|
|
714
|
+
if (!await get_dir())
|
|
715
|
+
return;
|
|
716
|
+
const trapY = state.player.t_pos.y + state.delta.y;
|
|
717
|
+
const trapX = state.player.t_pos.x + state.delta.x;
|
|
718
|
+
if (trapY <= 0 || trapY >= NUMLINES - 1 || trapX < 0 || trapX >= NUMCOLS) {
|
|
719
|
+
await msg("no trap there");
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
const pp = INDEX(trapY, trapX);
|
|
723
|
+
if (pp.p_ch !== TRAP) {
|
|
724
|
+
await msg("no trap there");
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
const trapFlags = flat(trapY, trapX);
|
|
728
|
+
const trapType = trapFlags & F_TMASK;
|
|
729
|
+
const trapName = tr_name[trapType] || "a mysterious trap";
|
|
730
|
+
await msg("%s", trapName);
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* set_options: Allow the player to examine and set game options.
|
|
734
|
+
*/
|
|
735
|
+
async function set_options() {
|
|
736
|
+
const backend = getBackend();
|
|
737
|
+
backend.clear();
|
|
738
|
+
backend.mvaddstr(0, 0, "Game options (press space to continue):");
|
|
739
|
+
backend.mvaddstr(2, 0, `terse: ${state.terse ? "on" : "off"}`);
|
|
740
|
+
backend.mvaddstr(3, 0, `fruit: ${state.fruit}`);
|
|
741
|
+
backend.mvaddstr(4, 0, `name: ${state.whoami}`);
|
|
742
|
+
backend.mvaddstr(5, 0, `jump: ${state.jump ? "on" : "off"}`);
|
|
743
|
+
backend.mvaddstr(NUMLINES - 1, 0, "--Press space to continue--");
|
|
744
|
+
backend.refresh();
|
|
745
|
+
await wait_for(" ");
|
|
746
|
+
if (state.stdscr !== null) {
|
|
747
|
+
backend.clearok(state.stdscr, true);
|
|
748
|
+
}
|
|
749
|
+
backend.refresh();
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* levit_check: Check if the player is levitating and can't use stairs.
|
|
753
|
+
* Returns true if the player is levitating (action blocked).
|
|
754
|
+
*/
|
|
755
|
+
function levit_check() {
|
|
756
|
+
if (state.player.t_flags & ISLEVIT) {
|
|
757
|
+
return true;
|
|
758
|
+
}
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
//# sourceMappingURL=command.js.map
|