Skip to content

Commit 6fa7fb3

Browse files
authored
Merge pull request #13 from nuzcraft/part_10
Part 10
2 parents 6dfd91f + a9ce3a7 commit 6fa7fb3

16 files changed

+684
-215
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,6 @@ dmypy.json
134134
.vscode/
135135

136136
RLTut_Python3.code-workspace
137+
138+
# saved games
139+
*.sav

README.md

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

15+
## Part 10 Dev Notes
16+
17+
### Saving and Loading
18+
19+
https://rogueliketutorials.com/tutorials/tcod/v2/part-10/
20+
21+
Holy crap, this is quite the refactor. I can see this having SIGNIFICANT impacts on the unit tests I've written. Beyond that, I'm looking forward to putting some polishing touches in! Things like a menu + saving and loading will make it feel more like a proper gain and less like a tech demo.
22+
23+
Okay...as of right now, I've finished the event_handler refactor and I'm actually kind of afraid to run my unit test suite. Fingers crossed it's not as bad as I expect...
24+
25+
Wow, way better than I expected! 228/248 unit tests passed! Only 20 failures means the changes didn't actually break too many things...though it's possible (and likely) that I'll need to update/add tests to cover the changed situations.
26+
27+
And unit test updates are complete! It wasn't nearly as bad as I expected, though I'm a bit concerned there's a bit of built up technical debt for unit tests that continue to reference the event_handler of the engine.
28+
29+
OH SHIT, the next part has us remove that reference...we'll see what the damage is...no damage! Whew! Onwards to some actual good and new development.
30+
31+
Heyo, adding in the saving and loading was a bit fun! We also refactored and added a title screen which makes things look and feel way better. Towards the end of the chapter I skimped a bit on some unit tests around loading saves...hopefully that doesn't come back to bite me! It feels really good to have this section finished and I'm looking forward to the end of the tutorial! I already have some ideas for taking the finished product and giving it a new theme and features.
32+
1533
## Part 9 Dev Notes
1634

1735
### Ranged Scrolls and Targeting
@@ -20,7 +38,7 @@ https://rogueliketutorials.com/tutorials/tcod/v2/part-9/
2038

2139
Woot! No additional refactoring yet! This section should be fun because it will give us the opportunity to use the code we just built to add more items that do unique things. Hopefully (outside of targeting) the additional things should be relatively minor and relatively atomic.
2240

23-
This part was really insightful to develop as I believe it will pave the way for a significant amount of future development. We developed some unique spells that function in very different ways; one that automatically targets the nearest actor and 2 the require additional user input mid-cast. This additional input is implemented in an interesting way and by watching it get out in place I think I understand the code flow.
41+
This part was really insightful to develop as I believe it will pave the way for a significant amount of future development. We developed some unique spells that function in very different ways; one that automatically targets the nearest actor and 2 the require additional user input mid-cast. This additional input is implemented in an interesting way and by watching it get out in place I think I understand the code flow.
2442

2543
From a unit testing standpoint, this part was intense. Adding new handlers for user input meant a significant amount of unit testing. I'm also noticing that there is a lot id dependencies around the player, engine, and game map objects that makes it cumbersome to set up tests on other objects. All in, unit testing is becoming more comfortable and I'm looking forward to a time when I feel like I can push what I know to make it more organized and more performant.
2644

Tests/test_consumable.py

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,8 @@ def test_get_action(self):
104104
cm.parent = item
105105
with patch('message_log.MessageLog.add_message') as patch_add_message:
106106
action = cm.get_action(consumer=actor)
107-
self.assertIsNone(action)
108107
patch_add_message.assert_called_once()
109-
self.assertIsInstance(cm.engine.event_handler,
110-
SingleRangedAttackHandler)
108+
self.assertIsInstance(action, SingleRangedAttackHandler)
111109

112110
def test_activate_good_target(self):
113111
'''
@@ -136,10 +134,10 @@ def test_activate_good_target(self):
136134
item.parent = actor.inventory
137135
cm.parent = item
138136
# get_action will initiate user input phase
139-
cm.get_action(consumer=actor)
137+
handler = cm.get_action(consumer=actor)
140138
# calling the callback with the target tile will return
141139
# the action we need
142-
action = cm.engine.event_handler.callback((1, 1))
140+
action = handler.callback((1, 1))
143141

144142
with patch('message_log.MessageLog.add_message') as patch_add_message:
145143
with patch('components.consumable.Consumable.consume') as patch_consume:
@@ -175,10 +173,10 @@ def test_activate_not_visible(self):
175173
item.parent = actor.inventory
176174
cm.parent = item
177175
# get_action will initiate user input phase
178-
cm.get_action(consumer=actor)
176+
handler = cm.get_action(consumer=actor)
179177
# calling the callback with the target tile will return
180178
# the action we need
181-
action = cm.engine.event_handler.callback((1, 1))
179+
action = handler.callback((1, 1))
182180

183181
with self.assertRaises(Impossible):
184182
cm.activate(action=action)
@@ -209,10 +207,10 @@ def test_activate_no_target(self):
209207
item.parent = actor.inventory
210208
cm.parent = item
211209
# get_action will initiate user input phase
212-
cm.get_action(consumer=actor)
210+
handler = cm.get_action(consumer=actor)
213211
# calling the callback with the target tile will return
214212
# the action we need NOTE target does not match ent location
215-
action = cm.engine.event_handler.callback((2, 2))
213+
action = handler.callback((2, 2))
216214

217215
with self.assertRaises(Impossible):
218216
cm.activate(action=action)
@@ -236,10 +234,10 @@ def test_activate_self(self):
236234
item.parent = actor.inventory
237235
cm.parent = item
238236
# get_action will initiate user input phase
239-
cm.get_action(consumer=actor)
237+
handler = cm.get_action(consumer=actor)
240238
# calling the callback with the target tile will return
241239
# the action we need NOTE target does not match ent location
242-
action = cm.engine.event_handler.callback((0, 0))
240+
action = handler.callback((0, 0))
243241

244242
with self.assertRaises(Impossible):
245243
cm.activate(action=action)
@@ -298,6 +296,7 @@ def test_activate_without_recovery(self):
298296
with self.assertRaises(Impossible):
299297
consumable.activate(action=action)
300298

299+
301300
class TestFireballDamageConsumable(unittest.TestCase):
302301
def test_init(self):
303302
'''
@@ -326,10 +325,8 @@ def test_get_action(self):
326325
cm.parent = item
327326
with patch('message_log.MessageLog.add_message') as patch_add_message:
328327
action = cm.get_action(consumer=actor)
329-
self.assertIsNone(action)
330328
patch_add_message.assert_called_once()
331-
self.assertIsInstance(cm.engine.event_handler,
332-
AreaRangedAttackHandler)
329+
self.assertIsInstance(action, AreaRangedAttackHandler)
333330

334331
def test_activate_hit_actor(self):
335332
'''
@@ -358,10 +355,10 @@ def test_activate_hit_actor(self):
358355
item.parent = actor.inventory
359356
cm.parent = item
360357
# get_action will initiate user input phase
361-
cm.get_action(consumer=actor)
358+
handler = cm.get_action(consumer=actor)
362359
# calling the callback with the target tile will return
363360
# the action we need
364-
action = cm.engine.event_handler.callback((6, 6))
361+
action = handler.callback((6, 6))
365362

366363
with patch('message_log.MessageLog.add_message') as patch_add_message:
367364
with patch('components.consumable.Consumable.consume') as patch_consume:
@@ -405,10 +402,10 @@ def test_activate_hit_actors(self):
405402
item.parent = actor.inventory
406403
cm.parent = item
407404
# get_action will initiate user input phase
408-
cm.get_action(consumer=actor)
405+
handler = cm.get_action(consumer=actor)
409406
# calling the callback with the target tile will return
410407
# the action we need
411-
action = cm.engine.event_handler.callback((6, 6))
408+
action = handler.callback((6, 6))
412409

413410
with patch('message_log.MessageLog.add_message') as patch_add_message:
414411
with patch('components.consumable.Consumable.consume') as patch_consume:
@@ -453,10 +450,10 @@ def test_activate_not_visible(self):
453450
item.parent = actor.inventory
454451
cm.parent = item
455452
# get_action will initiate user input phase
456-
cm.get_action(consumer=actor)
453+
handler = cm.get_action(consumer=actor)
457454
# calling the callback with the target tile will return
458455
# the action we need
459-
action = cm.engine.event_handler.callback((6, 6))
456+
action = handler.callback((6, 6))
460457

461458
with self.assertRaises(Impossible):
462459
cm.activate(action=action)
@@ -481,14 +478,15 @@ def test_activate_no_targets(self):
481478
item.parent = actor.inventory
482479
cm.parent = item
483480
# get_action will initiate user input phase
484-
cm.get_action(consumer=actor)
481+
handler = cm.get_action(consumer=actor)
485482
# calling the callback with the target tile will return
486483
# the action we need
487-
action = cm.engine.event_handler.callback((6, 6))
484+
action = handler.callback((6, 6))
488485

489486
with self.assertRaises(Impossible):
490487
cm.activate(action=action)
491488

489+
492490
class TestLightningDamageConsumable(unittest.TestCase):
493491
def test_init(self):
494492
'''

Tests/test_fighter.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def test_entity_set(self):
2929
test that an entity can be set without issues
3030
'''
3131
ft = Fighter(hp=10, defense=10, power=10)
32-
act = Actor(ai_cls=HostileEnemy, fighter=ft, inventory=Inventory(capacity=5))
32+
act = Actor(ai_cls=HostileEnemy, fighter=ft,
33+
inventory=Inventory(capacity=5))
3334
ft.entity = act
3435
self.assertEqual(act, ft.entity)
3536

@@ -55,7 +56,8 @@ def test_setter_hp_too_low(self):
5556
when setting below 0
5657
'''
5758
ft = Fighter(hp=10, defense=10, power=10)
58-
act = Actor(ai_cls=HostileEnemy, fighter=ft, inventory=Inventory(capacity=5))
59+
act = Actor(ai_cls=HostileEnemy, fighter=ft,
60+
inventory=Inventory(capacity=5))
5961
ft.entity = act
6062

6163
eng = Engine(player=act)
@@ -81,7 +83,8 @@ def test_setter_die(self):
8183
'''
8284
ft = Fighter(hp=10, defense=10, power=10)
8385
# this will set the ai to HostileEnemy
84-
act = Actor(ai_cls=HostileEnemy, fighter=ft, inventory=Inventory(capacity=5))
86+
act = Actor(ai_cls=HostileEnemy, fighter=ft,
87+
inventory=Inventory(capacity=5))
8588
ft.parent = act
8689

8790
eng = Engine(player=act)
@@ -101,7 +104,8 @@ def test_die_player(self, mock_add_message):
101104
'''
102105
ft = Fighter(hp=10, defense=10, power=10)
103106
# this will set the ai to HostileEnemy
104-
act = Actor(name="player", ai_cls=HostileEnemy, fighter=ft, inventory=Inventory(capacity=5))
107+
act = Actor(name="player", ai_cls=HostileEnemy,
108+
fighter=ft, inventory=Inventory(capacity=5))
105109
ft.parent = act
106110

107111
eng = Engine(player=act)
@@ -117,7 +121,6 @@ def test_die_player(self, mock_add_message):
117121
self.assertIsNone(ft.parent.ai)
118122
self.assertEqual(ft.parent.name, "remains of player")
119123
self.assertEqual(ft.parent.render_order, RenderOrder.CORPSE)
120-
self.assertIsInstance(ft.engine.event_handler, GameOverEventHandler)
121124
mock_add_message.assert_called_with("You died!", color.player_die)
122125

123126
@patch('message_log.MessageLog.add_message')
@@ -126,11 +129,13 @@ def test_die_other_actor(self, mock_add_message):
126129
test that when an actor (not player) dies, they get set well
127130
'''
128131
ft = Fighter(hp=10, defense=10, power=10)
129-
act = Actor(name="actor", ai_cls=HostileEnemy, fighter=ft, inventory=Inventory(capacity=5))
132+
act = Actor(name="actor", ai_cls=HostileEnemy,
133+
fighter=ft, inventory=Inventory(capacity=5))
130134
ft.parent = act
131135

132136
ft2 = Fighter(hp=10, defense=10, power=10)
133-
act2 = Actor(name="player", ai_cls=HostileEnemy, fighter=ft2, inventory=Inventory(capacity=5))
137+
act2 = Actor(name="player", ai_cls=HostileEnemy,
138+
fighter=ft2, inventory=Inventory(capacity=5))
134139
ft2.parent = act2
135140

136141
eng = Engine(player=act2)

0 commit comments

Comments
 (0)