Mention the Konami Code in README and explain its use when activated.
[naja.git] / naja / scenes / load_save.py
1 """
2 Load and save scenes.
3 """
4
5 import json
6 import os
7 from datetime import datetime
8
9 import pygame.locals as pgl
10
11 from naja.constants import KEYS
12 from naja.events import SceneChangeEvent, InvalidateTheWorld, LoadGameEvent
13 from naja.gamestate import GameState
14 from naja.options import options
15 from naja.scenes.scene import Scene
16 from naja.sound import sound
17 from naja.widgets.save_slot import SaveSlotWidget
18 from naja.widgets.selector import SelectorWidget
19
20
21 def save_path(path):
22     return os.path.join(options.save_location, *path.split('/'))
23
24
25 def ensure_save_path_exists():
26     location = save_path('')
27     if not os.path.isdir(location):
28         os.makedirs(location)
29
30
31 class LoadSaveGameBase(Scene):
32     def __init__(self, state):
33         super(LoadSaveGameBase, self).__init__(state)
34         selector = SelectorWidget()
35         self.add(selector)
36         self.slots = {}
37
38         for slot_num in range(8):
39             slot = self.make_slot_widget(slot_num)
40             self.slots[slot_num] = slot
41             selector.add(slot)
42
43     def save_path(self, slot_num):
44         return save_path('slot_%s.json' % (slot_num,))
45
46     def get_game_data(self, slot_num):
47         try:
48             with open(self.save_path(slot_num), 'r') as save_file:
49                 return json.load(save_file)
50         except IOError:
51             return None
52         except Exception as e:
53             print "Error reading savegame in slot %s: %s" % (slot_num, e)
54             return None
55
56     def make_slot_widget(self, slot_num):
57         game_data = self.get_game_data(slot_num)
58         y_offset = 74 * slot_num
59         slot = SaveSlotWidget((100, y_offset), slot_num, game_data)
60         slot.add_callback('click', lambda event: self.perform_action(slot_num))
61         return slot
62
63     def handle_scene_event(self, ev):
64         if ev.type == pgl.KEYDOWN and ev.key in KEYS.QUIT:
65             from naja.scenes.menu import MenuScene
66             SceneChangeEvent.post(MenuScene)
67             return
68
69     def fail(self):
70         sound.play_sound('error.ogg')
71         InvalidateTheWorld.post()
72
73     def succeed(self):
74         from naja.scenes.menu import MenuScene
75         sound.play_sound('chirp.ogg', volume=0.5)
76         SceneChangeEvent.post(MenuScene)
77
78     def perform_action(self, slot_num):
79         raise NotImplementedError("Nothing to see here.")
80
81
82 class SaveGameScene(LoadSaveGameBase):
83     def perform_action(self, slot_num):
84         save_data = {
85             'timestamp': datetime.now().ctime(),
86             'data': self.state.gameboard.export(),
87         }
88         try:
89             ensure_save_path_exists()
90             with open(self.save_path(slot_num), 'w') as save_file:
91                 json.dump(save_data, save_file)
92         except Exception as e:
93             print "Error saving game in slot %s: %s" % (slot_num, e)
94             self.fail()
95         else:
96             self.succeed()
97
98
99 class LoadGameScene(LoadSaveGameBase):
100     def perform_action(self, slot_num):
101         game_data = self.get_game_data(slot_num)
102         if game_data is not None:
103             state = GameState.load(game_data['data'])
104             LoadGameEvent.post(state)
105             self.succeed()
106         else:
107             self.fail()