-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexecution.py
331 lines (281 loc) · 11.1 KB
/
execution.py
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
from random import randint
from time import sleep
class Logic():
"""This class contains the actual opcodes to execute for the game.
Subclasses override methods to control when this can execute, but the
actual execution is all here.
"""
def __init__(self, game, extracted_action):
self.game = game
self.conditions = []
args = []
for val, op in extracted_action.conditions:
if op == 0:
args.append(val)
else:
self.conditions.append(self.create_condition(op, val))
def get_arg():
val = args[0]
del args[0]
return val
self.actions = []
for op in extracted_action.actions:
self.actions.append(self.create_action(op, get_arg))
def is_available(self):
"""Runs conditions for the logic; returns true if this logic can execute."""
for c in self.conditions:
if not c():
return False
return True
def check_occurance(self):
"""True if this is an occurance that should run now.
This rolls the dice for the chance of the occurance, so repeated
calls don't always agree. Also checks availability.
"""
return False
def check_command(self, verb, noun):
"""True if this is a command to handle the user command indicated
by verb and noun. Also checks availability."""
return False
def check_available_command(self, noun):
"""True if this is a command to handle the user command indicated
by noun only. Also checks availability."""
return False
def is_continuation(self):
"""True if this is a continuation action; is_available() must be checked separately."""
return False
def execute(self):
"""Runs the action. This applies changes to self.game."""
for a in self.actions:
yield a()
def create_condition(self, op, val):
"""Returns a function (no arguments, returns a boolean) that
implements a condition, given its opcode and value.
This does not handle opcode 0, the 'argument carrier' for action opcodes-
that is a special case.
"""
def undefined(): raise ValueError(f"Undefined condition op: {op}")
game = self.game
if op == 1:
return lambda: game.items[val].room == game.inventory
if op == 2:
return lambda: game.items[val].room == game.player_room
if op == 3:
return lambda: game.items[val].room in [game.player_room, game.inventory]
if op == 4:
return lambda: game.player_room == game.rooms[val]
if op == 5:
return lambda: game.items[val].room != game.player_room
if op == 6:
return lambda: game.items[val].room != game.inventory
if op == 7:
return lambda: game.player_room != game.rooms[val]
if op == 8:
return lambda: game.flags[val].state
if op == 9:
return lambda: not game.flags[val].state
if op == 10:
return lambda: len(game.inventory.get_items()) > 0
if op == 11:
return lambda: len(game.inventory.get_items()) == 0
if op == 12:
return lambda: game.items[val].room not in [game.player_room, game.inventory]
if op == 13:
return lambda: game.items[val].room != None
if op == 14:
return lambda: game.items[val].room == None
if op == 15:
return lambda: game.counter.value <= val
if op == 16:
return lambda: game.counter.value > val
if op == 17:
return lambda: game.items[val].room == game.items[val].starting_room
if op == 18:
return lambda: game.items[val].room != game.items[val].starting_room
if op == 19:
return lambda: game.counter.value == val
return undefined()
def create_action(self, op, value_source):
"""Returns a function (no arguments, returns nothing) that implements
an action opcode.
value_source is not an opcode argument, but a function that extracts the
next one from the argument carries (which are among the conditions of all
things.) It can be called repeatedly for multiple arguments.
"""
game = self.game
def clear_screen(): pass # we don't do this
def get_item(): game.get_item(item)
def superget_item(): game.get_item(item, force=True)
def drop_item(): game.drop_item(item)
def move_item(): game.move_item(item, room)
def remove_item(): game.move_item(item, None)
def swap_items(): game.swap_items(item1, item2)
def put_item_with(): game.move_item(item1, item2.room)
def move_player(): game.move_player(room)
def swap_loc():
saved_player_room = game.saved_player_room
game.saved_player_room = game.player_room
game.move_player(saved_player_room)
def set_counter(): game.counter.value = counter_value
def swap_counter(): counter.swap(game)
def add_counter(): game.counter.value += counter_value
def subtract_counter(): game.counter.value -= counter_value
def decrement_counter(): game.counter.value -= 1
def print_counter(): game.output(f"{game.counter.value} ")
def set_flag(): flag.state = True
def reset_flag(): flag.state = False
def die():
game.move_player(game.rooms[len(game.rooms) - 1])
game.dark_flag.state = False
def game_over(): game.game_over = True
def check_score(): game.check_score()
def save_game(): game.save_game()
def describe_room(): game.needs_room_update = True
def refill_lamp():
game.light_remaining = game.light_duration
game.move_item(game.lamp_item, game.inventory)
def swap_specific_loc():
saved_player_room = game.saved_player_rooms[saved_room_value]
game.saved_player_rooms[saved_room_value] = game.player_room
game.move_player(saved_player_room)
def continue_actions(): game.continuing_commands = True
def undefined(): raise ValueError(f"Undefined action op: {op}")
if op == 0:
return lambda: None
if op <= 51:
return lambda: game.output_line(game.messages[op])
if op == 52:
item = game.items[value_source()]
return get_item
if op == 53:
item = game.items[value_source()]
return drop_item
if op == 54:
room = game.rooms[value_source()]
return move_player
if op == 55 or op == 59:
item = game.items[value_source()]
return remove_item
if op == 56:
flag = game.dark_flag
return set_flag
if op == 57:
flag = game.dark_flag
return reset_flag
if op == 58:
flag = game.flags[value_source()]
return set_flag
if op == 60:
flag = game.flags[value_source()]
return reset_flag
if op == 61:
return die
if op == 62:
item = game.items[value_source()]
room = game.rooms[value_source()]
return move_item
if op == 63:
return game_over
if op == 64 or op == 76:
return describe_room
if op == 65:
return check_score
if op == 66:
return lambda: game.output_inventory_text()
if op == 67:
flag = game.flags[0]
return set_flag
if op == 68:
flag = game.flags[0]
return reset_flag
if op == 69:
return refill_lamp
if op == 70:
return clear_screen
if op == 71:
return save_game
if op == 72:
item1 = game.items[value_source()]
item2 = game.items[value_source()]
return swap_items
if op == 73:
return continue_actions
if op == 74:
item = game.items[value_source()]
return superget_item
if op == 75:
item1 = game.items[value_source()]
item2 = game.items[value_source()]
return put_item_with
if op == 77:
return decrement_counter
if op == 78:
return print_counter
if op == 79:
counter_value = value_source()
return set_counter
if op == 80:
return swap_loc
if op == 81:
counter = game.counters[value_source()]
return swap_counter
if op == 82:
counter_value = value_source()
return add_counter
if op == 83:
counter_value = value_source()
return subtract_counter
if op == 84:
return lambda: game.output(game.parsed_noun)
if op == 85:
return lambda: game.output_line(game.parsed_noun)
if op == 86:
return lambda: game.output_line()
if op == 87:
saved_room_value = value_source()
return swap_specific_loc
if op == 88:
return lambda: DelayRequest(2000)
if op >= 102:
return lambda: game.output_line(game.messages[op - 50])
return undefined()
class Occurance(Logic):
"""These logics run before user input, and let the game take actions
not commanded by the user. These can have a chance-to-run, so they only
run now and again.
"""
def __init__(self, game, extracted_action):
Logic.__init__(self, game, extracted_action)
self.chance = extracted_action.noun
def check_occurance(self):
return self.is_available() and randint(1, 100) <= self.chance
class Command(Logic):
"""These logics handle specific user commands."""
def __init__(self, game, extracted, extracted_action):
Logic.__init__(self, game, extracted_action)
verb_index = extracted_action.verb
noun_index = extracted_action.noun
self.verb = game.get_verb(extracted.verbs[verb_index])
self.noun = game.get_noun(
extracted.nouns[noun_index]) if noun_index > 0 else None
def check_command(self, verb, noun):
if self.verb == verb:
if self.noun is None or self.noun == noun:
return self.is_available()
return False
def check_available_command(self, noun):
return self.noun == noun and self.is_available()
class Continuation(Logic):
"""These logics are weird. They are continuations of commands or occurances
which they follow. They run if a command executes the continue opcode, and
if their condiiton is also met."""
def __init__(self, game, extracted_action):
Logic.__init__(self, game, extracted_action)
def is_continuation(self):
return True
class DelayRequest():
"""This object represents a request for the UI to pause
before proceeding to the next command. This can be
returned from the command execute() method."""
def __init__(self, milliseconds):
self.milliseconds = milliseconds