Mercurial > boomslang
comparison pyntnclick/main.py @ 854:79b5c1be9a5e default tip
Remove pyntnclick, it's its own library, now
author | Stefano Rivera <stefano@rivera.za.net> |
---|---|
date | Sat, 21 Jun 2014 22:06:09 +0200 |
parents | f95830b58336 |
children |
comparison
equal
deleted
inserted
replaced
852:f95830b58336 | 854:79b5c1be9a5e |
---|---|
1 '''Game main module. | |
2 | |
3 Contains the entry point used by the run_game.py script. | |
4 | |
5 ''' | |
6 import sys | |
7 import gettext | |
8 import locale | |
9 import os | |
10 from optparse import OptionParser | |
11 | |
12 import pygame | |
13 from pygame.locals import SWSURFACE | |
14 | |
15 from pyntnclick.i18n import _, get_module_i18n_path | |
16 from pyntnclick.engine import Engine | |
17 from pyntnclick.gamescreen import DefMenuScreen, DefEndScreen, GameScreen | |
18 from pyntnclick.constants import GameConstants, DEBUG_ENVVAR | |
19 from pyntnclick.resources import Resources | |
20 from pyntnclick.sound import Sound | |
21 from pyntnclick import state | |
22 | |
23 from pyntnclick.tools.rect_drawer import (RectEngine, RectDrawerError, | |
24 make_rect_display) | |
25 from pyntnclick.utils import list_scenes | |
26 | |
27 | |
28 class GameDescriptionError(Exception): | |
29 """Raised when an GameDescription is invalid.""" | |
30 | |
31 | |
32 class GameDescription(object): | |
33 | |
34 # initial scene for start of game (unless overridden by debug) | |
35 INITIAL_SCENE = None | |
36 | |
37 # list of game scenes | |
38 SCENE_LIST = None | |
39 | |
40 # starting menu | |
41 SCREENS = { | |
42 'menu': DefMenuScreen, | |
43 'end': DefEndScreen, | |
44 } | |
45 | |
46 START_SCREEN = 'menu' | |
47 | |
48 # Modules | |
49 RESOURCE_MODULE = 'data' | |
50 SCENE_MODULE = 'gamelib.scenes' | |
51 | |
52 def __init__(self): | |
53 if self.INITIAL_SCENE is None: | |
54 raise GameDescriptionError("A game must have an initial scene.") | |
55 if not self.SCENE_LIST: | |
56 raise GameDescriptionError("A game must have a non-empty list" | |
57 " of scenes.") | |
58 if 'game' in self.SCREENS: | |
59 raise GameDescriptionError("The 'game' screen is reserved for the" | |
60 " game itself.") | |
61 self._initial_scene = self.INITIAL_SCENE | |
62 self._scene_list = self.SCENE_LIST | |
63 self._resource_module = self.RESOURCE_MODULE | |
64 self._debug_rects = False | |
65 self._screens = self.SCREENS.copy() | |
66 self._screens['game'] = GameScreen | |
67 self.constants = self.game_constants() | |
68 | |
69 locale.setlocale(locale.LC_ALL, "") | |
70 lang = locale.getdefaultlocale(['LANGUAGE', 'LC_ALL', 'LC_CTYPE', | |
71 'LANG'])[0] | |
72 self.resource = Resources(self._resource_module, lang) | |
73 locale_path = self.resource.get_resource_path('locale') | |
74 gettext.bindtextdomain(self.constants.short_name, locale_path) | |
75 gettext.textdomain(self.constants.short_name) | |
76 | |
77 popath = self.resource.get_resource_path('po') | |
78 self._check_translations(popath, locale_path) | |
79 | |
80 self.sound = Sound(self.resource) | |
81 self.debug_options = [] | |
82 self.running = False | |
83 | |
84 def _check_translations(self, popath, locale_path): | |
85 """Check for outdated mo files""" | |
86 name = gettext.textdomain() # only check the current app | |
87 for candidate in os.listdir(popath): | |
88 if candidate.endswith('.po'): | |
89 polang = candidate.split('.', 1)[0] | |
90 pofile = os.path.join(popath, candidate) | |
91 mofile = gettext.find(name, locale_path, (polang,)) | |
92 if mofile is None: | |
93 print 'Missing mo file for %s' % pofile | |
94 continue | |
95 if os.stat(pofile).st_mtime > os.stat(mofile).st_mtime: | |
96 print 'po file %s is newer than mo file %s' % (pofile, | |
97 mofile) | |
98 | |
99 def initial_state(self, game_state=None): | |
100 """Create a copy of the initial game state.""" | |
101 initial_state = state.Game(self, self.game_state_class()(game_state)) | |
102 initial_state.set_debug_rects(self._debug_rects) | |
103 for scene in self._scene_list: | |
104 initial_state.load_scenes(scene) | |
105 if initial_state.data['current_scene'] is None: | |
106 initial_state.data.set_current_scene(self._initial_scene) | |
107 initial_state.change_scene(initial_state.data['current_scene']) | |
108 return initial_state | |
109 | |
110 def game_state_class(self): | |
111 return state.GameState | |
112 | |
113 def game_constants(self): | |
114 return GameConstants() | |
115 | |
116 def option_parser(self): | |
117 parser = OptionParser() | |
118 parser.add_option("--no-sound", action="store_false", default=True, | |
119 dest="sound", help="disable sound") | |
120 # We flag these, so we can warn the user that these require debug mode | |
121 self.debug_options = ['--scene', '--no-rects', '--rect-drawer', | |
122 '--list-scenes', '--details'] | |
123 if self.constants.debug: | |
124 parser.add_option("--scene", type="str", default=None, | |
125 dest="scene", help="initial scene") | |
126 parser.add_option("--no-rects", action="store_false", default=True, | |
127 dest="rects", help="disable debugging rects") | |
128 parser.add_option("--rect-drawer", action="store_true", | |
129 default=False, dest="rect_drawer", | |
130 help="Launch the rect drawing helper tool. Specify the" | |
131 " scene with --scene") | |
132 parser.add_option("--list-scenes", action="store_true", | |
133 default=False, dest='list_scenes', help="List all scenes" | |
134 " that can be used with --scene and exit.") | |
135 parser.add_option("--detail", type="str", default=None, | |
136 dest="detail", help="Detailed view for rect_drawer") | |
137 return parser | |
138 | |
139 def warn_debug(self, option): | |
140 """Warn the user that he needs debug mode""" | |
141 print '%s is only valid in debug mode' % option | |
142 print 'set %s to enable debug mode' % DEBUG_ENVVAR | |
143 print | |
144 | |
145 def main(self): | |
146 parser = self.option_parser() | |
147 # This is a bit hack'ish, but works | |
148 if not self.constants.debug: | |
149 for option in self.debug_options: | |
150 if option in sys.argv: | |
151 self.warn_debug(option) | |
152 opts, args = parser.parse_args(sys.argv) | |
153 pygame.display.init() | |
154 pygame.font.init() | |
155 if opts.sound: | |
156 self.sound.enable_sound(self.constants) | |
157 else: | |
158 self.sound.disable_sound() | |
159 if self.constants.debug: | |
160 if opts.scene is not None: | |
161 # debug the specified scene | |
162 self._initial_scene = opts.scene | |
163 self._debug_rects = opts.rects | |
164 if self.constants.debug and opts.list_scenes: | |
165 list_scenes(self.SCENE_MODULE, self._scene_list) | |
166 sys.exit(0) | |
167 if self.constants.debug and opts.rect_drawer: | |
168 if opts.scene is None: | |
169 print 'Need to supply a scene to use the rect drawer' | |
170 sys.exit(1) | |
171 locale_path = get_module_i18n_path( | |
172 self.resource.DEFAULT_RESOURCE_MODULE) | |
173 gettext.bindtextdomain('pyntnclick-tools', locale_path) | |
174 gettext.textdomain('pyntnclick-tools') | |
175 popath = get_module_i18n_path( | |
176 self.resource.DEFAULT_RESOURCE_MODULE, 'po') | |
177 self._check_translations(popath, locale_path) | |
178 make_rect_display() | |
179 try: | |
180 self.engine = RectEngine(self, opts.detail) | |
181 except RectDrawerError, e: | |
182 print 'RectDrawer failed with: %s' % e | |
183 sys.exit(1) | |
184 else: | |
185 pygame.display.set_mode(self.constants.screen, SWSURFACE) | |
186 if self.constants.icon: | |
187 pygame.display.set_icon(self.resource.get_image( | |
188 self.constants.icon, basedir='icons')) | |
189 if self.constants.title: | |
190 title = _(self.constants.title).encode('utf-8') | |
191 pygame.display.set_caption(title) | |
192 | |
193 self.engine = Engine(self) | |
194 # Initialize the special screens in the engine | |
195 for name, cls in self._screens.iteritems(): | |
196 screen = cls(self) | |
197 self.engine.add_screen(name, screen) | |
198 # Should we allow the menu not to be the opening screen? | |
199 self.engine.set_screen(self.START_SCREEN) | |
200 try: | |
201 self.engine.run() | |
202 except KeyboardInterrupt: | |
203 pass | |
204 | |
205 def get_default_save_location(self): | |
206 """Return a default save game location.""" | |
207 app = self.constants.short_name | |
208 if sys.platform.startswith("win"): | |
209 if "APPDATA" in os.environ: | |
210 return os.path.join(os.environ["APPDATA"], app) | |
211 return os.path.join(os.path.expanduser("~"), "." + app) | |
212 elif 'XDG_DATA_HOME' in os.environ: | |
213 return os.path.join(os.environ["XDG_DATA_HOME"], app) | |
214 return os.path.join(os.path.expanduser("~"), ".local", "share", app) |