1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 from OpenGL.GL import *
24 import pygame
25 import os
26 import sys
27
28 from Engine import Engine, Task
29 from Video import Video
30 from Audio import Audio
31 from View import View
32 from Input import Input, KeyListener, SystemEventListener
33 from Resource import Resource
34 from Data import Data
35 from Server import Server
36 from Session import ClientSession
37 from Svg import SvgContext, SvgDrawing, LOW_QUALITY, NORMAL_QUALITY, HIGH_QUALITY
38 from Debug import DebugLayer
39 from Language import _
40 import Network
41 import Log
42 import Config
43 import Dialogs
44 import Theme
45 import Version
46 import Mod
47
48
49 Config.define("engine", "tickrate", float, 1.0)
50 Config.define("engine", "highpriority", bool, True)
51 Config.define("game", "uploadscores", bool, False, text = _("Upload Highscores"), options = {False: _("No"), True: _("Yes")})
52 Config.define("game", "uploadurl", str, "http://fretsonfire.sourceforge.net/play")
53 Config.define("game", "leftymode", bool, False, text = _("Lefty mode"), options = {False: _("No"), True: _("Yes")})
54 Config.define("game", "tapping", bool, True, text = _("Tappable notes"), options = {False: _("No"), True: _("Yes")})
55 Config.define("video", "fullscreen", bool, True, text = _("Fullscreen Mode"), options = {False: _("No"), True: _("Yes")})
56 Config.define("video", "multisamples", int, 4, text = _("Antialiasing Quality"), options = {0: _("None"), 2: _("2x"), 4: _("4x"), 6: _("6x"), 8: _("8x")})
57 Config.define("video", "resolution", str, "640x480")
58 Config.define("video", "fps", int, 80, text = _("Frames per Second"), options = dict([(n, n) for n in range(1, 120)]))
59 Config.define("opengl", "svgquality", int, NORMAL_QUALITY, text = _("SVG Quality"), options = {LOW_QUALITY: _("Low"), NORMAL_QUALITY: _("Normal"), HIGH_QUALITY: _("High")})
60 Config.define("audio", "frequency", int, 44100, text = _("Sample Frequency"), options = [8000, 11025, 22050, 32000, 44100, 48000])
61 Config.define("audio", "bits", int, 16, text = _("Sample Bits"), options = [16, 8])
62 Config.define("audio", "stereo", bool, True)
63 Config.define("audio", "buffersize", int, 2048, text = _("Buffer Size"), options = [256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536])
64 Config.define("audio", "delay", int, 100, text = _("A/V delay"), options = dict([(n, n) for n in range(0, 301)]))
65 Config.define("audio", "screwupvol", float, 0.25, text = _("Screw Up Sounds"), options = {0.0: _("Off"), .25: _("Quiet"), .5: _("Loud"), 1.0: _("Painful")})
66 Config.define("audio", "guitarvol", float, 1.0, text = _("Guitar Volume"), options = dict([(n / 100.0, "%02d/10" % (n / 9)) for n in range(0, 110, 10)]))
67 Config.define("audio", "songvol", float, 1.0, text = _("Song Volume"), options = dict([(n / 100.0, "%02d/10" % (n / 9)) for n in range(0, 110, 10)]))
68 Config.define("audio", "rhythmvol", float, 1.0, text = _("Rhythm Volume"), options = dict([(n / 100.0, "%02d/10" % (n / 9)) for n in range(0, 110, 10)]))
69 Config.define("video", "fontscale", float, 1.0, text = _("Text scale"), options = dict([(n / 100.0, "%3d%%" % n) for n in range(50, 260, 10)]))
70
72 """
73 A keyboard listener that looks for special built-in key combinations,
74 such as the fullscreen toggle (Alt-Enter).
75 """
77 self.engine = engine
78 self.altStatus = False
79
81 if key == pygame.K_LALT:
82 self.altStatus = True
83 elif key == pygame.K_RETURN and self.altStatus:
84 if not self.engine.toggleFullscreen():
85 Log.error("Unable to toggle fullscreen mode.")
86 return True
87 elif key == pygame.K_d and self.altStatus:
88 self.engine.setDebugModeEnabled(not self.engine.isDebugModeEnabled())
89 return True
90 elif key == pygame.K_g and self.altStatus and self.engine.isDebugModeEnabled():
91 self.engine.debugLayer.gcDump()
92 return True
93
95 if key == pygame.K_LALT:
96 self.altStatus = False
97
99 """
100 A system event listener that takes care of restarting the game when needed
101 and reacting to screen resize events.
102 """
105
108
111
114
116 """The main game engine."""
118 """
119 Constructor.
120
121 @param config: L{Config} instance for settings
122 """
123
124 if not config:
125 config = Config.load()
126
127 self.config = config
128
129 fps = self.config.get("video", "fps")
130 tickrate = self.config.get("engine", "tickrate")
131 Engine.__init__(self, fps = fps, tickrate = tickrate)
132
133 pygame.init()
134
135 self.title = _("Frets on Fire")
136 self.restartRequested = False
137 self.handlingException = False
138 self.video = Video(self.title)
139 self.audio = Audio()
140
141 Log.debug("Initializing audio.")
142 frequency = self.config.get("audio", "frequency")
143 bits = self.config.get("audio", "bits")
144 stereo = self.config.get("audio", "stereo")
145 bufferSize = self.config.get("audio", "buffersize")
146
147 self.audio.pre_open(frequency = frequency, bits = bits, stereo = stereo, bufferSize = bufferSize)
148 pygame.init()
149 self.audio.open(frequency = frequency, bits = bits, stereo = stereo, bufferSize = bufferSize)
150
151 Log.debug("Initializing video.")
152 width, height = [int(s) for s in self.config.get("video", "resolution").split("x")]
153 fullscreen = self.config.get("video", "fullscreen")
154 multisamples = self.config.get("video", "multisamples")
155 self.video.setMode((width, height), fullscreen = fullscreen, multisamples = multisamples)
156
157
158 if self.config.get("engine", "highpriority"):
159 Log.debug("Enabling high priority timer.")
160 self.timer.highPriority = True
161
162 viewport = glGetIntegerv(GL_VIEWPORT)
163 h = viewport[3] - viewport[1]
164 w = viewport[2] - viewport[0]
165 geometry = (0, 0, w, h)
166 self.svg = SvgContext(geometry)
167 self.svg.setRenderingQuality(self.config.get("opengl", "svgquality"))
168 glViewport(int(viewport[0]), int(viewport[1]), int(viewport[2]), int(viewport[3]))
169
170 self.input = Input()
171 self.view = View(self, geometry)
172 self.resizeScreen(w, h)
173
174 self.resource = Resource(Version.dataPath())
175 self.server = None
176 self.sessions = []
177 self.mainloop = self.loading
178
179
180 Mod.init(self)
181 theme = Config.load(self.resource.fileName("theme.ini"))
182 Theme.open(theme)
183
184
185 if self.config.get("game", "uploadurl").startswith("http://kempele.fi"):
186 self.config.set("game", "uploadurl", "http://fretsonfire.sourceforge.net/play")
187
188 self.addTask(self.input, synchronized = False)
189 self.addTask(self.view)
190 self.addTask(self.resource, synchronized = False)
191 self.data = Data(self.resource, self.svg)
192
193 self.input.addKeyListener(FullScreenSwitcher(self), priority = True)
194 self.input.addSystemEventListener(SystemEventHandler(self))
195
196 self.debugLayer = None
197 self.startupLayer = None
198 self.loadingScreenShown = False
199
200 Log.debug("Ready.")
201
203 """
204 Set the L{Layer} that will be shown when the all
205 the resources have been loaded. See L{Data}
206
207 @param startupLayer: Startup L{Layer}
208 """
209 self.startupLayer = startupLayer
210
212 return bool(self.debugLayer)
213
215 """
216 Show or hide the debug layer.
217
218 @type enabled: bool
219 """
220 if enabled:
221 self.debugLayer = DebugLayer(self)
222 else:
223 self.debugLayer = None
224
226 """
227 Toggle between fullscreen and windowed mode.
228
229 @return: True on success
230 """
231 if not self.video.toggleFullscreen():
232
233 self.input.broadcastSystemEvent("restartRequested")
234 self.config.set("video", "fullscreen", not self.video.fullscreen)
235 return True
236 self.config.set("video", "fullscreen", self.video.fullscreen)
237 return True
238
246
248 """
249 Resize the game screen.
250
251 @param width: New width in pixels
252 @param height: New height in pixels
253 """
254 self.view.setGeometry((0, 0, width, height))
255 self.svg.setGeometry((0, 0, width, height))
256
258 return bool(self.server)
259
261 """Start the game server."""
262 if not self.server:
263 Log.debug("Starting server.")
264 self.server = Server(self)
265 self.addTask(self.server, synchronized = False)
266
268 """
269 Connect to a game server.
270
271 @param host: Name of host to connect to
272 @return: L{Session} connected to remote server
273 """
274 Log.debug("Connecting to host %s." % host)
275 session = ClientSession(self)
276 session.connect(host)
277 self.addTask(session, synchronized = False)
278 self.sessions.append(session)
279 return session
280
282 """Stop the game server."""
283 if self.server:
284 Log.debug("Stopping server.")
285 self.removeTask(self.server)
286 self.server = None
287
289 """
290 Disconnect a L{Session}
291
292 param session: L{Session} to disconnect
293 """
294 if session in self.sessions:
295 Log.debug("Disconnecting.")
296 self.removeTask(session)
297 self.sessions.remove(session)
298
299 - def loadSvgDrawing(self, target, name, fileName, textureSize = None):
300 """
301 Load an SVG drawing synchronously.
302
303 @param target: An object that will own the drawing
304 @param name: The name of the attribute the drawing will be assigned to
305 @param fileName: The name of the file in the data directory
306 @param textureSize Either None or (x, y), in which case the file will
307 be rendered to an x by y texture
308 @return: L{SvgDrawing} instance
309 """
310 return self.data.loadSvgDrawing(target, name, fileName, textureSize)
311
327
330
332 """Main state loop."""
333
334
335 if self.view.isTransitionInProgress():
336 self.boostBackgroundThreads(False)
337 else:
338 self.boostBackgroundThreads(True)
339
340 done = Engine.run(self)
341 self.clearScreen()
342 self.view.render()
343 if self.debugLayer:
344 self.debugLayer.render(1.0, True)
345 self.video.flip()
346 return done
347
349 try:
350 return self.mainloop()
351 except KeyboardInterrupt:
352 sys.exit(0)
353 except SystemExit:
354 sys.exit(0)
355 except Exception, e:
356 def clearMatrixStack(stack):
357 try:
358 glMatrixMode(stack)
359 for i in range(16):
360 glPopMatrix()
361 except:
362 pass
363
364 if self.handlingException:
365
366 sys.exit(1)
367
368 self.handlingException = True
369 Log.error("%s: %s" % (e.__class__, e))
370 import traceback
371 traceback.print_exc()
372
373 clearMatrixStack(GL_PROJECTION)
374 clearMatrixStack(GL_MODELVIEW)
375
376 Dialogs.showMessage(self, unicode(e))
377 self.handlingException = False
378 return True
379