-
Notifications
You must be signed in to change notification settings - Fork 25
/
ship.py
347 lines (308 loc) · 12 KB
/
ship.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
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
import random
import enemies
import sys
import items
class MapTile:
""" Map with x and y coordinates"""
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return self.inventory
def intro_text(self):
raise NotImplementedError("Create a subclass instead!")
def modify_player(self, player):
"""Added modify_player to every tile"""
pass
class StartTile(MapTile):
"""Player starting position"""
def intro_text(self):
"""Descriptive text for the Start Tile"""
return """
You find yourself in space under attack by an unknown enemy that
is boarding your ship.
You need an escape pod to travel to safety on the nearby planet.
You need supplies for the trip and survival on the planet.
You can go four directions: forward, aftward, port, starboard
You have four actions: inventory, attack, heal, protect
"""
class BoringTile(MapTile):
"""Position with no materials"""
def intro_text(self):
return """
There are no supplies or escape pod here.
"""
class ViewMapTile(MapTile):
"""Position that prints a map"""
def intro_text(self):
"""Descriptive text for the Viewable Map Tile"""
return """
You see a map on the wall.
"""
def print_map(self):
"""Print a map of the ship with directions"""
self.ship_printable = """
forward
| |Supplies| |
port | | |You are Here| starboard
| | Start | |
|Escape Pod| | |
aftward
"""
print(self.ship_printable)
class SuppliesTile(MapTile):
"""Position that contains survival supplies"""
def __init__(self, x, y):
"""Initial supplies at the tile"""
# index for switching descriptive messagages
self.i = 0
self.name = "Supplies"
self.inventory = [items.Blaster(), items.OxygenTank(),
items.SpaceSuit(), items.FirstAid(),
items.CrustyBread(), items.Water(), items.Shelter()]
super().__init__(x, y)
def intro_text(self):
"""Descriptive texts for the Start Tile"""
# initial description
self.start_supplies = """
You see a large metal trunk. You open it.
It's supplies! You found a first aid kit, an oxygen tank,
a space suit, food, water, a pocket knife, and a ray gun.
"""
# description after supplies are added
self.no_supplies = "No supplies left at this location"
# define the descriptive text for the supply text
supply_text = [self.start_supplies, self.no_supplies]
# switch messages after the supplies are added
if self.i == 0:
self.i += 1
return supply_text[0]
else:
return supply_text[1]
def suppy(self):
"""Message for what items were added"""
for i, item in enumerate(self.inventory, 1):
print("You added the following items to your inventory!")
print("{}. {}.".format(i, item.name))
self.add_inventory()
def add_inventory(self, current_inventory):
"""Add items from the supply tile to the player's inventory"""
for item in self.inventory:
current_inventory.append(item)
# remove supplies from the tile
self.inventory = []
class EscapePod(MapTile):
"""Position that contains the escape pod"""
def modify_player(self, player):
"""Player wins the game if they reach the escape pod"""
player.victory = True
sys.exit()
def intro_text(self):
return """
You found the escape pod! You open the door and enter the pod.
The escape pod slowly disengages from the ship and travels to
the nearby planet. You are safe, for now...
"""
class EnemyTile(MapTile):
"""Enemy position and messages"""
def __init__(self, x, y):
"""Creates a random position for each enemy"""
# Indices j, k for switching alive_text and dead_text messages
self.j = 0
self.k = 0
# generate a random number to estabilish a random enemy
r = random.random()
# encounter Drones about 50% of the time
if r < 0.30:
self.enemy = enemies.Drone()
alive_start = """
You hear a buzzing noise. You turn around and see an enemy drone
with its guns aimed at you
"""
alive_attack = "The drone attacks."
self.alive_text = [alive_start, alive_attack]
dead_start = """
The buzzing stops, the drone explodes and falls to the floor
"""
dead_return = "A disabled drone lays on the ground"
self.dead_text = [dead_start, dead_return]
# print(r)
# encounter Soldiers about 30% of the time
elif r < 0.60 and r >= 0.30:
self.enemy = enemies.Soldier()
alive_start = """
An enemy solider in a space suit jumps out from around the corner
and starts to fire.
"""
alive_attack = "The solider attacks."
self.alive_text = [alive_start, alive_attack]
dead_start = """
The solider drops its weapon and slumps to the floor.
"""
dead_return = "A dead solider lays on the ground"
self.dead_text = [dead_start, dead_return]
# print(r)
# encounter robots about 15% of the time
elif r < 0.75 and r >= 0.60:
self.enemy = enemies.Robot()
alive_start = """
Your eye catches the glint of chrome in the flickering light. A
large red eye turns, scans your body, pauses and then opens fire.
"""
alive_attack = "The robot attacks."
self.alive_text = [alive_start, alive_attack]
dead_start = """
The large red eye grows dim as sparks fly from the disabled robot.
"""
dead_return = "A disabled robot lays on the ground"
self.dead_text = [dead_start, dead_return]
# print(r)
# encounter trolls about 5% of the time
elif r < 0.90 and r >= 0.75:
self.enemy = enemies.Troll()
alive_start = """
Debris flies everywhere as a large space troll smashes equipment.
It suddenly stops and notices you trying to hide. It approaches
quickly and swings at you with its large fists.
"""
alive_attack = "The troll attacks."
self.alive_text = [alive_start, alive_attack]
dead_start = """
The troll clutches its mortal wounds as it falls with a loud thud
that shakes the whole ship.
"""
dead_return = "A dead troll lays on the ground"
self.dead_text = [dead_start, dead_return]
# print(r)
else:
self.enemy = enemies.SpaceDucks()
alive_start = """
You hear a deafening chorus of quacks. Suddenly you are lost in a
flock of blue space ducks as they peck at your head.
"""
alive_attack = "The ducks attack."
self.alive_text = [alive_start, alive_attack]
dead_start = """
The last duck explodes into a cloud of feathers. You wade through
large banks of blue feathers and try to clean off the ship's
equipment and unclog the blocked air ducts.
"""
dead_return = "Dead ducks lie an a cloud of blue feathers"
self.dead_text = [dead_start, dead_return]
super().__init__(x, y)
def intro_text(self):
"""Intro message dependent on enemy health points"""
if self.enemy.is_alive():
# Switch from the intro message after the player starts attacking
if self.j == 0:
self.j += 1
return self.alive_text[0]
else:
return self.alive_text[1]
# switch from the intro message if the player returns to the tile
# where there is a dead enemy
else:
if self.k == 0:
self.k += 1
return self.dead_text[0]
else:
return self.dead_text[1]
def modify_player(self, player):
"""
Checks the enemy's current strength so it can respond to the player
"""
if self.enemy.is_alive():
# continue play if there's enough health points
if player.hp > self.enemy.damage:
player.hp -= self.enemy.damage
print("The {} does {} damage. You have {} HP remaining".
format(self.enemy.name,
self.enemy.damage,
player.hp))
# end the game if the player runs out of health points
elif player.hp <= self.enemy.damage:
print("The {} causes mortal damage. You die.".
format(self.enemy.name))
sys.exit()
# defining the layout of the space ship
# ship_map = [
# [EnemyTile(0, 0), SuppliesTile(1, 0), BoringTile(2, 0)],
# [BoringTile(0, 1), BoringTile(1, 1), BoringTile(2, 1)],
# [EnemyTile(0, 2), StartTile(1, 2), EnemyTile(2, 2)],
# [EscapePod(0, 3), BoringTile(1, 3), BoringTile(2, 3)]
# ]
# initialize the ship's map
ship_map = []
def tile_at(x, y):
"""Locates the tile at a coordinate"""
if x < 0 or y < 0:
return None
try:
return ship_map[y][x]
except IndexError:
return None
# ship's map
ship_dsl = """
|ET|IT|BT|
|BT|BT|MP|
|ET|ST|ET|
|EP|BT|BT|
"""
def is_dsl_valid(dsl):
"""
Check to make sure there is only one start tile and escape pod.
Also check that each row has the same number of columns
"""
if dsl.count("|ST|") != 1:
return False
if dsl.count("|EP|") == 0:
return False
lines = dsl.splitlines()
lines = [l for l in lines if l]
pipe_counts = [line.count("|") for line in lines]
for count in pipe_counts:
if count != pipe_counts[0]:
return False
return True
# key to the ship's map
tile_type_dict = {"EP": EscapePod,
"ST": StartTile,
"IT": SuppliesTile,
"ET": EnemyTile,
"BT": BoringTile,
"MP": ViewMapTile,
" ": None}
# initialize the start tile
start_tile_location = None
def parse_ship_dsl():
"""Taking the ship map as a string and returning a list"""
if not is_dsl_valid(ship_dsl):
raise SyntaxError("DSL is invalid!")
dsl_lines = ship_dsl.splitlines()
dsl_lines = [x for x in dsl_lines if x]
# Iterate over each line in the DSL.
for y, dsl_row in enumerate(dsl_lines):
# Create an object to store the tiles
row = []
# Split the line into abbreviations
dsl_cells = dsl_row.split("|")
# The split method includes the beginning
# and end of the line so we need to remove
# those nonexistent cells
dsl_cells = [c for c in dsl_cells if c]
# Iterate over each cell in the DSL line
for x, dsl_cells in enumerate(dsl_cells):
# Look up the abbreviation in the dictionary
tile_type = tile_type_dict[dsl_cells]
# set the start tile location
if tile_type == StartTile:
global start_tile_location
start_tile_location = x, y
# If the dictionary returned a valid type, create
# a new tile object, pass it the X-Y coordinates
# as required by the tile __init__(), and add
# it to the row object. If None was found in the
# dictionary, we just add None.
row.append(tile_type(x, y) if tile_type else None)
# Add the whole row to the ship_map
ship_map.append(row)