comparison gamelib/savegame.py @ 486:8897a436a8cb

Factor out save game logic and (new, simplified) dialogs into their own module. Add preferences folder to concept to config. Save games under preferences folder.
author Simon Cross <hodgestar@gmail.com>
date Wed, 25 Nov 2009 21:50:54 +0000
parents
children 75ef6ea3b7a6
comparison
equal deleted inserted replaced
485:6f0385ebcb4f 486:8897a436a8cb
1 """Utilities and widgets for saving and restoring games."""
2
3 import xmlrpclib
4 import os
5
6 from pgu import gui
7
8 import config
9 import version
10
11
12 class BaseSaveRestoreDialog(gui.Dialog):
13 """Save game dialog."""
14
15 def __init__(self, title_txt, button_txt, allow_new, cls="dialog"):
16 self.value = None
17 self.save_folder = config.config.save_folder
18
19 self.save_games = {}
20 self._populate_save_games()
21
22 if allow_new:
23 self.name_input = gui.Input()
24 else:
25 self.name_input = None
26
27 td_style = {
28 'padding_left': 4,
29 'padding_right': 4,
30 'padding_top': 2,
31 'padding_bottom': 2,
32 }
33
34 self.save_list = gui.List(width=350, height=250)
35 games = self.save_games.keys()
36 games.sort()
37 for name in games:
38 self.save_list.add(name, value=name)
39 self.save_list.set_vertical_scroll(0)
40 self.save_list.connect(gui.CHANGE, self._save_list_change)
41
42 button_ok = gui.Button(button_txt)
43 button_ok.connect(gui.CLICK, self._click_ok)
44
45 button_cancel = gui.Button("Cancel")
46 button_cancel.connect(gui.CLICK, self._click_cancel)
47
48 body = gui.Table()
49 body.tr()
50 body.td(self.save_list, style=td_style, colspan=2)
51 body.td(gui.Label("Image"), style=td_style, colspan=2)
52 body.tr()
53 if self.name_input:
54 body.td(gui.Label("Save as:"), style=td_style, align=1)
55 body.td(self.name_input, style=td_style)
56 else:
57 body.td(gui.Spacer(0, 0), style=td_style, colspan=2)
58 body.td(button_ok, style=td_style, align=1)
59 body.td(button_cancel, style=td_style, align=1)
60
61 title = gui.Label(title_txt, cls=cls + ".title.label")
62 gui.Dialog.__init__(self, title, body)
63
64 def get_fullpath(self):
65 """Return the fullpath of the select save game file or None."""
66 if self.value is None:
67 return None
68 return os.path.join(self.save_folder, self.value + ".xml")
69
70 def _populate_save_games(self):
71 """Read list of save games."""
72 for filename in os.listdir(self.save_folder):
73 fullpath = os.path.join(self.save_folder, filename)
74 root, ext = os.path.splitext(filename)
75 if not os.path.isfile(fullpath):
76 continue
77 if ext != ".xml":
78 continue
79 self.save_games[root] = None
80
81 def _save_list_change(self):
82 if self.name_input:
83 self.name_input.value = self.save_list.value
84
85 def _click_ok(self):
86 if self.name_input:
87 self.value = self.name_input.value
88 else:
89 self.value = self.save_list.value
90 if self.value:
91 self.send(gui.CHANGE)
92 self.close()
93
94 def _click_cancel(self):
95 self.value = None
96 self.send(gui.CHANGE)
97 self.close()
98
99
100 class SaveDialog(BaseSaveRestoreDialog):
101 """Save game dialog."""
102
103 def __init__(self, gameboard):
104 BaseSaveRestoreDialog.__init__(self, "Save Game ...", "Save", allow_new=True)
105 self.connect(gui.CHANGE, self._save, gameboard)
106
107 def _save(self, gameboard):
108 filename = self.get_fullpath()
109 if filename is None:
110 return
111 data = gameboard.save_game()
112 params = (version.SAVE_GAME_VERSION, data)
113 xml = xmlrpclib.dumps(params, "foxassault")
114 try:
115 open(filename, "wb").write(xml)
116 except Exception, e:
117 print "Failed to save game: %s" % (e,)
118
119
120 class RestoreDialog(BaseSaveRestoreDialog):
121 """Restore game dialog."""
122
123 def __init__(self, gameboard):
124 BaseSaveRestoreDialog.__init__(self, "Load Game ...", "Load", allow_new=False)
125 self.connect(gui.CHANGE, self._restore, gameboard)
126
127 def _restore(self, gameboard):
128 filename = self.get_fullpath()
129 if filename is None:
130 return
131 try:
132 xml = open(filename, "rb").read()
133 params, methodname = xmlrpclib.loads(xml)
134 if methodname != "foxassault":
135 raise ValueError("File does not appear to be a "
136 "Fox Assault save game.")
137 save_version = params[0]
138 if save_version != version.SAVE_GAME_VERSION:
139 raise ValueError("Incompatible save game version.")
140 data = params[1]
141 except Exception, e:
142 "Failed to load game: %s" % (e,)
143 return
144
145 gameboard.restore_game(data)