/
cloak-of-darkness.tsx
241 lines (219 loc) · 6.17 KB
/
cloak-of-darkness.tsx
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
import type { ActionSequence, Story } from "../lib/engine/types";
import type { RoomWorldState } from "../lib/engine/formats/room";
import { roomStory, END } from "../lib/engine/formats/room";
import { tell, prompt } from "../lib/engine/actions";
/** Locations in the story. */
type RoomId = "outside" | "lobby" | "cloakroom" | "bar";
/** Player state consumed and manipulated within each room */
interface WorldState extends RoomWorldState<RoomId> {
turnsInBar: number;
hasCloak: boolean;
}
/** An ActionSequence yields tell and prompt pages, returns a destination RoomId (or END)*/
type Room = (state: WorldState) => ActionSequence<RoomId | typeof END>;
export const outside: Room = function* (state) {
yield* tell(
<>
Hurrying through the rainswept November night, you're glad to see the
bright lights of the Foyer. It's surprising that there aren't more people
about but, hey, what do you expect in a cheap demo game...?
</>
);
yield* tell(
<>Shaking the rain from your Cloak, you step gratefully inside.</>
);
return "lobby";
};
export const lobby: Room = function* (state) {
const choice = yield* prompt(
<>
You are standing in a spacious hall, splendidly decorated in red and gold,
with glittering chandeliers overhead. The entrance from the street is to
the north, and there are doorways south and west.
</>,
{
preventedNorth: <>Go North</>,
bar: <>Go South</>,
cloakroom: <>Go West</>,
...(state.hasCloak && { inspectCloak: <>Inspect your cloak</> }),
}
);
if (choice === "inspectCloak") {
yield* tell(
<>
A handsome cloak, of velvet trimmed with satin, and slightly spattered
with raindrops. Its blackness is so deep that it almost seems to suck
light from the room.
</>
);
return "lobby";
}
if (choice === "preventedNorth") {
yield* tell(
<>
You've only just arrived, and besides, the weather outside seems to be
getting worse.
</>
);
return "lobby";
}
return choice;
};
export const cloakroom: Room = function* (state) {
const choice = yield* prompt(
<>
The walls of this small room were clearly once lined with hooks, though
now only one remains.
{!state.hasCloak && <> It holds your cloak.</>}
</>,
{
east: <>Leave through the East door</>,
lookAtHook: <>Look at the hook</>,
...(state.hasCloak
? {
hangCloak: <>Hang up your Cloak</>,
}
: {
wearCloak: <>Put on your Cloak</>,
}),
}
);
if (choice === "east") {
return "lobby";
}
if (choice === "hangCloak") {
yield* tell(<>You hang up your cloak.</>);
state.hasCloak = false;
}
if (choice === "wearCloak") {
yield* tell(<>You put on your cloak</>);
state.hasCloak = true;
}
if (choice === "lookAtHook") {
yield* tell(
<>
It's just a small brass hook, screwed to the wall.
{!state.hasCloak && <> Your coat is hanging there.</>}
</>
);
}
return "cloakroom";
};
export const bar: Room = function* (state) {
if (state.hasCloak) {
return yield* darkBar(state);
} else {
return yield* lightBar(state);
}
};
export const darkBar: Room = function* (state) {
state.turnsInBar += 1;
const firstAttempt = yield* prompt(
<>
You can't see a thing! Not even the door you entered by--was it north,
south, east or west?
</>,
{
north: <>Grope north</>,
south: <>Grope south</>,
east: <>Grope east</>,
west: <>Grope west</>,
}
);
if (firstAttempt === "north") {
return "lobby";
}
state.turnsInBar += 1;
const secondAttempt = yield* prompt(
<>
Blundering around in the dark isn't a good idea! You can't tell left from
right, let alone east from west or north from south.
</>,
{
north: <>Stumble North</>,
south: <>Stumble South</>,
east: <>Stumble East</>,
west: <>Stumble West</>,
left: <>Stumble Left</>,
right: <>Stumble Right</>,
}
);
if (secondAttempt === "north") {
return "lobby";
}
state.turnsInBar += 1;
const thirdAttempt = yield* prompt(
<>
No, this isn't getting you anywhere... Let's see, the door was south,
wasn't it? So the exit must be north, unless you've gotten turned around.
</>,
{
confident: <>I'm sure which way is North</>,
unconfident: <>Maybe I've got turned around</>,
}
);
if (thirdAttempt === "confident") {
return "lobby";
}
state.turnsInBar += 1;
yield* tell(
<>Oops, this is just a blank wall! But perhaps if you follow it around...</>
);
return "lobby";
};
export const lightBar: Room = function* (state) {
yield* tell(
<>
The bar, much rougher than you'd have guessed after the opulence of the
foyer to the north, is completely empty. You're glad you hung up your
cloak. Its darkness would have sucked all the dim light from this room.
Through the dim light you make out some sort of message scrawled in the
sawdust on the floor.
</>
);
if (state.turnsInBar <= 3) {
yield* tell(
<>
The message, neatly marked in the sawdust, reads...
<h1>You have won!</h1>
</>
);
} else {
yield* tell(
<>
On the floor is a pile of sawdust scuffed by many footprints. You can
make out a few letters...
<h3>You h*v* w*n</h3>
...but the rest of the message has been lost. You can never know the
secret of the Opera House now.
<h1>You have lost!</h1>
</>
);
}
return END;
};
/** Delegates to roomStory() which yields title/tell/prompt actions, combining the
* rooms into a navigable world having shared global state. */
export const story: Story = function* () {
const rooms = {
outside,
lobby,
cloakroom,
bar,
};
const worldState: WorldState = {
turnsInBar: 0,
hasCloak: true,
currentRoomId: "outside",
roomTitles: {
outside: <>Outside the Opera House</>,
lobby: <>In the Lobby</>,
cloakroom: <>In the Cloakroom</>,
bar: <>In the Bar</>,
},
};
yield* roomStory({
rooms,
worldState,
});
};