Skip to content

Commit 8e5e891

Browse files
authored
Merge pull request #14 from nuzcraft/part_11
Part 11
2 parents 744627d + 6526578 commit 8e5e891

24 files changed

+1389
-136
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@ I want to use this as an opportunity to:
1212
4. make a roguelike
1313
5. practice with git
1414

15+
## Part 11 Dev Notes
16+
17+
### Delving into the Dungeon
18+
19+
https://rogueliketutorials.com/tutorials/tcod/v2/part-11/
20+
21+
This part looks like a part where we start putting in some bells and whistles to really flush out what the game can be. We'll add additional floors as well as exp and a level up system.
22+
23+
Adding additional floors was a bit of a treat! It allows us to play for a pseudo-goal (get as low in the dungeon as possible) and adds an 'infinite quality' aka we can play forever and keep winning if we wish. This is better (maybe?) than the previous version where we had one easy level to clear and be forced to quit the game with nothing new to do. I'm not really sure how much I like the GameWorld system whereby define the current_level then generate a new game_map when we need one. In a future version of my own game (based on this framework), I will likely add some options for keeping track of previous floors and such. I think it's interesting that this tutorial uses a new tile for the stairs as opposed to using an entity.
24+
25+
Adding the level up system was a significant amount of event handler work. We needed to add a new component to keep track of xp and the level as well as a new screen to level up certain attributes and a character screen. Implementing the screens and the inputs used in them is always interesting and the unit tests behind them are critical to making sure the screens act as expected.
26+
27+
Overall, I enjoyed working this part. It really feels like the game is coming together and I'm looking forward to the last (final?) part, which I would guess is level progression to make the lower levels of the game harder.
28+
1529
## Part 10 Dev Notes
1630

1731
### Saving and Loading

Tests/test_actions.py

Lines changed: 134 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import unittest
33
from unittest.mock import patch
44

5+
from numpy import power
6+
57
from actions import (
68
Action, ActionWithDirection,
79
MovementAction,
@@ -10,14 +12,16 @@
1012
PickupAction,
1113
ItemAction,
1214
DropItem,
15+
TakeStairAction,
1316
)
1417
from entity import Entity, Actor, Item
15-
from game_map import GameMap
18+
from game_map import GameMap, GameWorld
1619
from engine import Engine
1720
from components.ai import BaseAI, HostileEnemy
1821
from components.fighter import Fighter
1922
from components.consumable import Consumable
2023
from components.inventory import Inventory
24+
from components.level import Level
2125
import tile_types
2226
import color
2327
from exceptions import Impossible
@@ -62,6 +66,61 @@ def test_perform(self):
6266
'''
6367

6468

69+
class Test_Actions_TakeStairsAction(unittest.TestCase):
70+
def test_perform_with_stairs(self):
71+
actor = Actor(
72+
ai_cls=BaseAI,
73+
fighter=Fighter(hp=10, defense=10, power=10),
74+
inventory=Inventory(capacity=5),
75+
level=Level()
76+
)
77+
eng = Engine(player=actor)
78+
eng.game_world = GameWorld(
79+
engine=eng,
80+
map_width=10,
81+
map_height=10,
82+
max_rooms=5,
83+
room_min_size=3,
84+
room_max_size=4,
85+
max_monsters_per_room=2,
86+
max_items_per_room=1,
87+
)
88+
eng.game_world.generate_floor()
89+
actor.x, actor.y = eng.game_map.downstairs_location
90+
action = TakeStairAction(entity=actor)
91+
92+
with patch('message_log.MessageLog.add_message') as patch_add_message:
93+
action.perform()
94+
95+
self.assertEqual(action.engine.game_world.current_floor, 2)
96+
patch_add_message.assert_called_once()
97+
98+
def test_perform_no_stairs(self):
99+
actor = Actor(
100+
ai_cls=BaseAI,
101+
fighter=Fighter(hp=10, defense=10, power=10),
102+
inventory=Inventory(capacity=5),
103+
level=Level()
104+
)
105+
eng = Engine(player=actor)
106+
eng.game_world = GameWorld(
107+
engine=eng,
108+
map_width=10,
109+
map_height=10,
110+
max_rooms=5,
111+
room_min_size=3,
112+
room_max_size=4,
113+
max_monsters_per_room=2,
114+
max_items_per_room=1,
115+
)
116+
eng.game_world.generate_floor()
117+
# actor.x, actor.y = eng.game_map.downstairs_location
118+
action = TakeStairAction(entity=actor)
119+
120+
with self.assertRaises(Impossible):
121+
action.perform()
122+
123+
65124
class Test_Actions_ActionWithDirection(unittest.TestCase):
66125
def test_init(self):
67126
'''
@@ -125,10 +184,20 @@ def test_target_actor_with_actor(self):
125184
test that target_actor returns and actor if one exists at the location
126185
of the action
127186
'''
128-
pl = Actor(ai_cls=BaseAI, fighter=Fighter(
129-
hp=10, defense=10, power=10), inventory=Inventory(capacity=5)) # player at 0, 0
130-
ent = Actor(x=1, y=1, ai_cls=BaseAI, fighter=Fighter(
131-
hp=10, defense=10, power=10), inventory=Inventory(capacity=5)) # entity at 1, 1
187+
pl = Actor(
188+
ai_cls=BaseAI,
189+
fighter=Fighter(hp=10, defense=10, power=10),
190+
inventory=Inventory(capacity=5),
191+
level=Level(),
192+
) # player at 0, 0
193+
ent = Actor(
194+
x=1,
195+
y=1,
196+
ai_cls=BaseAI,
197+
fighter=Fighter(hp=10, defense=10, power=10),
198+
inventory=Inventory(capacity=5),
199+
level=Level(),
200+
) # entity at 1, 1
132201
eng = Engine(player=pl)
133202
gm = GameMap(engine=eng, width=10, height=10)
134203
gm.entities = {pl, ent}
@@ -143,8 +212,12 @@ def test_target_actor_noner(self):
143212
test that target_actor returns nothing when none exists at the location
144213
of the action
145214
'''
146-
pl = Actor(ai_cls=BaseAI, fighter=Fighter(
147-
hp=10, defense=10, power=10), inventory=Inventory(capacity=5)) # player at 0, 0
215+
pl = Actor(
216+
ai_cls=BaseAI,
217+
fighter=Fighter(hp=10, defense=10, power=10),
218+
inventory=Inventory(capacity=5),
219+
level=Level()
220+
) # player at 0, 0
148221
eng = Engine(player=pl)
149222
gm = GameMap(engine=eng, width=10, height=10)
150223
gm.entities = {pl, }
@@ -184,9 +257,11 @@ def test_perform_player_with_target_and_damage(self, mock_add_message):
184257
put out a message with the correct color
185258
'''
186259
pl = Actor(x=0, y=0, ai_cls=HostileEnemy, fighter=Fighter(
187-
hp=10, defense=0, power=5), inventory=Inventory(capacity=5)) # player at 0,0
260+
hp=10, defense=0, power=5), inventory=Inventory(capacity=5),
261+
level=Level()) # player at 0,0
188262
ent = Actor(x=1, y=1, ai_cls=HostileEnemy, fighter=Fighter(
189-
hp=10, defense=0, power=5), inventory=Inventory(capacity=5)) # blocking entity at 1,1
263+
hp=10, defense=0, power=5), inventory=Inventory(capacity=5),
264+
level=Level()) # blocking entity at 1,1
190265
eng = Engine(player=pl)
191266
gm = GameMap(engine=eng, width=10, height=10)
192267
# add blocking entity to the game map, add game map to engine and player
@@ -213,11 +288,14 @@ def test_perform_enemy_with_target_and_damage(self, mock_add_message):
213288
put out a message with the correct color
214289
'''
215290
pl = Actor(x=0, y=0, ai_cls=HostileEnemy, fighter=Fighter(
216-
hp=10, defense=0, power=5), inventory=Inventory(capacity=5)) # player at 0,0
291+
hp=10, defense=0, power=5), inventory=Inventory(capacity=5),
292+
level=Level()) # player at 0,0
217293
ent = Actor(x=1, y=1, ai_cls=HostileEnemy, fighter=Fighter(
218-
hp=10, defense=0, power=5), inventory=Inventory(capacity=5)) # blocking entity at 1,1
294+
hp=10, defense=0, power=5), inventory=Inventory(capacity=5),
295+
level=Level()) # blocking entity at 1,1
219296
ent2 = Actor(x=2, y=2, ai_cls=HostileEnemy, fighter=Fighter(
220-
hp=10, defense=0, power=5), inventory=Inventory(capacity=5)) # blocking entity at 1,1
297+
hp=10, defense=0, power=5), inventory=Inventory(capacity=5),
298+
level=Level()) # blocking entity at 1,1
221299
eng = Engine(player=pl)
222300
gm = GameMap(engine=eng, width=10, height=10)
223301
# add blocking entity to the game map, add game map to engine and player
@@ -244,9 +322,11 @@ def test_perform_with_target_and_no_damage(self, mock_add_message):
244322
test that a Melee Action with a target will print when no damage is done
245323
'''
246324
pl = Actor(x=0, y=0, ai_cls=HostileEnemy, fighter=Fighter(
247-
hp=10, defense=0, power=5), inventory=Inventory(capacity=5)) # player at 0,0
325+
hp=10, defense=0, power=5), inventory=Inventory(capacity=5),
326+
level=Level()) # player at 0,0
248327
ent = Actor(x=1, y=1, ai_cls=HostileEnemy, fighter=Fighter(
249-
hp=10, defense=5, power=5), inventory=Inventory(capacity=5)) # blocking entity at 1,1
328+
hp=10, defense=5, power=5), inventory=Inventory(capacity=5),
329+
level=Level()) # blocking entity at 1,1
250330
eng = Engine(player=pl)
251331
gm = GameMap(engine=eng, width=10, height=10)
252332
# add blocking entity to the game map, add game map to engine and player
@@ -350,10 +430,22 @@ def test_perform_melee(self, mock_add_message):
350430
verify that a BumpAction performs the same as a MeleeAction
351431
basically a copy of Test_Actions_MeleeAction.test_perform_with_target
352432
'''
353-
pl = Actor(x=0, y=0, ai_cls=HostileEnemy, fighter=Fighter(
354-
hp=10, defense=0, power=5), inventory=Inventory(capacity=5)) # player at 0,0
355-
ent = Actor(x=1, y=1, ai_cls=HostileEnemy, fighter=Fighter(
356-
hp=10, defense=0, power=5), inventory=Inventory(capacity=5)) # blocking entity at 1,1
433+
pl = Actor(
434+
x=0,
435+
y=0,
436+
ai_cls=HostileEnemy,
437+
fighter=Fighter(hp=10, defense=0, power=5),
438+
inventory=Inventory(capacity=5),
439+
level=Level()
440+
) # player at 0,0
441+
ent = Actor(
442+
x=1,
443+
y=1,
444+
ai_cls=HostileEnemy,
445+
fighter=Fighter(hp=10, defense=0, power=5),
446+
inventory=Inventory(capacity=5),
447+
level=Level()
448+
) # blocking entity at 1,1
357449
eng = Engine(player=pl)
358450
gm = GameMap(engine=eng, width=10, height=10)
359451
# add blocking entity to the game map, add game map to engine and player
@@ -398,7 +490,8 @@ def test_init(self):
398490
test that a pickup action can be initialized okay
399491
'''
400492
actor = Actor(ai_cls=HostileEnemy, fighter=Fighter(
401-
hp=10, defense=10, power=10), inventory=Inventory(capacity=5))
493+
hp=10, defense=10, power=10), inventory=Inventory(capacity=5),
494+
level=Level())
402495
action = PickupAction(entity=actor)
403496
self.assertIsInstance(action, PickupAction)
404497

@@ -412,7 +505,9 @@ def test_perform_with_item_and_capacity(self):
412505
x=5, y=6,
413506
ai_cls=HostileEnemy,
414507
fighter=Fighter(hp=10, defense=10, power=10),
415-
inventory=Inventory(capacity=5))
508+
inventory=Inventory(capacity=5),
509+
level=Level()
510+
)
416511
eng = Engine(player=actor)
417512
gm = GameMap(engine=eng, width=10, height=10)
418513
item = Item(
@@ -445,7 +540,9 @@ def test_perform_with_no_item_on_map(self):
445540
x=5, y=6,
446541
ai_cls=HostileEnemy,
447542
fighter=Fighter(hp=10, defense=10, power=10),
448-
inventory=Inventory(capacity=5))
543+
inventory=Inventory(capacity=5),
544+
level=Level()
545+
)
449546
eng = Engine(player=actor)
450547
gm = GameMap(engine=eng, width=10, height=10)
451548
# item = Item(
@@ -471,7 +568,9 @@ def test_perform_with_item_in_wrong_spot(self):
471568
x=5, y=6,
472569
ai_cls=HostileEnemy,
473570
fighter=Fighter(hp=10, defense=10, power=10),
474-
inventory=Inventory(capacity=5))
571+
inventory=Inventory(capacity=5),
572+
level=Level()
573+
)
475574
eng = Engine(player=actor)
476575
gm = GameMap(engine=eng, width=10, height=10)
477576
item = Item(
@@ -497,7 +596,9 @@ def test_perform_with_no_capacity(self):
497596
x=5, y=6,
498597
ai_cls=HostileEnemy,
499598
fighter=Fighter(hp=10, defense=10, power=10),
500-
inventory=Inventory(capacity=0))
599+
inventory=Inventory(capacity=0),
600+
level=Level()
601+
)
501602
eng = Engine(player=actor)
502603
gm = GameMap(engine=eng, width=10, height=10)
503604
item = Item(
@@ -522,7 +623,8 @@ def test_init_no_targetxy(self):
522623
and the target_xy gets set to the x, y of the entity
523624
'''
524625
actor = Actor(x=5, y=6, ai_cls=HostileEnemy, fighter=Fighter(
525-
hp=10, defense=10, power=10), inventory=Inventory(capacity=5))
626+
hp=10, defense=10, power=10), inventory=Inventory(capacity=5),
627+
level=Level())
526628
item = Item(consumable=Consumable())
527629
item_action = ItemAction(entity=actor, item=item)
528630
self.assertEqual(item_action.item, item)
@@ -534,7 +636,8 @@ def test_init_with_targetxy(self):
534636
and the target_xy gets set
535637
'''
536638
actor = Actor(ai_cls=HostileEnemy, fighter=Fighter(
537-
hp=10, defense=10, power=10), inventory=Inventory(capacity=5))
639+
hp=10, defense=10, power=10), inventory=Inventory(capacity=5),
640+
level=Level())
538641
item = Item(consumable=Consumable())
539642
item_action = ItemAction(entity=actor, item=item, target_xy=(5, 6))
540643
self.assertEqual(item_action.item, item)
@@ -545,7 +648,8 @@ def test_property_target_actor(self):
545648
test that get_actor_at_location is called with the correct inputs
546649
'''
547650
actor = Actor(ai_cls=HostileEnemy, fighter=Fighter(
548-
hp=10, defense=10, power=10), inventory=Inventory(capacity=5))
651+
hp=10, defense=10, power=10), inventory=Inventory(capacity=5),
652+
level=Level())
549653
item = Item(consumable=Consumable())
550654
eng = Engine(player=actor)
551655
gm = GameMap(engine=eng, width=10, height=10)
@@ -564,7 +668,8 @@ def test_perform(self):
564668
passing in the existing itemAction
565669
'''
566670
actor = Actor(ai_cls=HostileEnemy, fighter=Fighter(
567-
hp=10, defense=10, power=10), inventory=Inventory(capacity=5))
671+
hp=10, defense=10, power=10), inventory=Inventory(capacity=5),
672+
level=Level())
568673
item = Item(consumable=Consumable())
569674
item_action = ItemAction(entity=actor, item=item)
570675

@@ -582,7 +687,8 @@ def test_perform(self):
582687
ent = Actor(
583688
ai_cls=BaseAI,
584689
fighter=Fighter(hp=10, defense=10, power=10),
585-
inventory=Inventory(capacity=1)
690+
inventory=Inventory(capacity=1),
691+
level=Level()
586692
)
587693
item = Item(consumable=Consumable())
588694
ent.inventory.items.append(item)

0 commit comments

Comments
 (0)