def loadVideo(self, libraryName, songName): vidSource = None if self.songStage == 1: songBackgroundVideoPath = os.path.join(libraryName, songName, "background.ogv") if os.path.isfile(songBackgroundVideoPath): vidSource = songBackgroundVideoPath loop = False else: log.warn("Video not found: %s" % songBackgroundVideoPath) if vidSource is None: vidSource = os.path.join(self.pathfull, "default.ogv") loop = True if not os.path.isfile(vidSource): log.warn("Video not found: %s" % vidSource) log.warn("Falling back to default stage mode.") self.mode = 1 # Fallback return try: # Catches invalid video files or unsupported formats log.debug("Attempting to load video: %s" % vidSource) self.vidPlayer = VideoLayer(self.engine, vidSource, mute = True, loop = loop) self.engine.view.pushLayer(self.vidPlayer) except (IOError, VideoPlayerError): self.mode = 1 log.error("Failed to load song video (falling back to default stage mode):")
def run(self): # Perhapse this could be implemented in a better way... # Play the intro video if it is present, we have the capability, and # we are not in one-shot mode. if not self.engine.cmdPlay: themename = Config.get("coffee", "themename") vidSource = os.path.join(Version.dataPath(), 'themes', themename, 'menu', 'intro.ogv') if os.path.isfile(vidSource): try: vidPlayer = VideoLayer(self.engine, vidSource, cancellable=True) except (IOError, VideoPlayerError): log.error("Error loading intro video:") else: vidPlayer.play() self.engine.view.pushLayer(vidPlayer) self.videoLayer = True self.engine.ticksAtStart = pygame.time.get_ticks() while not vidPlayer.finished: self.engine.run() self.engine.view.popLayer(vidPlayer) self.engine.view.pushLayer(MainMenu(self.engine)) if not self.videoLayer: self.engine.setStartupLayer(MainMenu(self.engine)) # Run the main game loop. try: self.engine.ticksAtStart = pygame.time.get_ticks() while self.engine.run(): pass except KeyboardInterrupt: log.notice("Left mainloop due to KeyboardInterrupt.") # don't reraise # Restart the program if the engine is asking that we do so. if self.engine.restartRequested: self.restart() # evilynux - MainMenu class already calls this - useless? self.engine.quit()
def __init__(self, engine, songName = None): self.engine = engine self.time = 0.0 self.offset = 0.5 # akedrou - this seems to fix the delay issue, but I'm not sure why. Return here! self.speedDiv = 20000.0 self.speedDir = 1.0 self.doneList = [] self.themename = Config.get("coffee", "themename") nf = self.engine.data.font ns = 0.002 bs = 0.001 hs = 0.003 c1 = (1, 1, .5, 1) c2 = (1, .75, 0, 1) self.text_size = nf.getLineSpacing(scale = hs) #akedrou - Translatable Strings: self.bank = {} self.bank['intro'] = [_("Frets on Fire X is a progression of MFH-mod,"), _("which was built on Alarian's mod,"), _("which was built on UltimateCoffee's Ultimate mod,"), _("which was built on RogueF's RF_mod 4.15,"), _("which was, of course, built on Frets on Fire 1.2.451,"), _("which was created by Unreal Voodoo")] self.bank['noOrder'] = [_("No particular order")] self.bank['accessOrder']= [_("In order of project commit access")] self.bank['coders'] = [_("Active Coders")] self.bank['otherCoding']= [_("Programming")] self.bank['graphics'] = [_("Graphic Design")] self.bank['3d'] = [_("3D Textures")] self.bank['logo'] = [_("FoFiX Logo Design")] self.bank['hollowmind'] = [_("Hollowmind Necks")] self.bank['themes'] = [_("Included Themes")] self.bank['shaders'] = [_("Shaders")] self.bank['sounds'] = [_("Sound Design")] self.bank['translators']= [_("Translators")] self.bank['honorary'] = [_("Honorary Credits")] self.bank['codeHonor'] = [_("Without whom this game would not exist")] self.bank['giveThanks'] = [_("Special Thanks to")] self.bank['community'] = [_("nwru and all of the community at fretsonfire.net")] self.bank['other'] = [_("Other Contributors:")] self.bank['tutorial'] = [_("Jurgen FoF tutorial inspired by adam02"), _("Drum test song tutorial by Heka"), _("Drum Rolls practice tutorial by venom426")] self.bank['disclaimer'] = [_("If you have contributed to this game and are not credited,"), _("please let us know what and when you contributed.")] self.bank['thanks'] = [_("Thank you for your contribution.")] self.bank['oversight'] = [_("Please keep in mind that it is not easy to trace down and"), _("credit every single person who contributed; if your name is"), _("not included, it was not meant to slight you."), _("It was an oversight.")] # evilynux - Theme strings self.bank['themeCreators'] = [_("%s theme credits:") % self.themename] self.bank['themeThanks'] = [_("%s theme specific thanks:") % self.themename] # Languages self.bank['french'] = [_("French")] self.bank['french90'] = [_("French (reform 1990)")] self.bank['german'] = [_("German")] self.bank['italian'] = [_("Italian")] self.bank['piglatin'] = [_("Pig Latin")] self.bank['portuguese-b'] = [_("Portuguese (Brazilian)")] self.bank['russian'] = [_("Russian")] self.bank['spanish'] = [_("Spanish")] self.bank['swedish'] = [_("Swedish")] self.videoLayer = False self.background = None vidSource = os.path.join(Version.dataPath(), 'themes', self.themename, \ 'menu', 'credits.ogv') if os.path.isfile(vidSource): try: self.vidPlayer = VideoLayer(self.engine, vidSource, mute = True, loop = True) except (IOError, VideoPlayerError): Log.error('Error loading credits video:') else: self.vidPlayer.play() self.engine.view.pushLayer(self.vidPlayer) self.videoLayer = True if not self.videoLayer and \ not self.engine.loadImgDrawing(self, 'background', os.path.join('themes', self.themename, 'menu', 'credits.png')): self.background = None if not self.engine.loadImgDrawing(self, 'topLayer', os.path.join('themes', self.themename, 'menu', 'creditstop.png')): self.topLayer = None space = Text(nf, hs, c1, "center", " ") self.credits = [ Picture(self.engine, "fofix_logo.png", .10), Text(nf, ns, c1, "center", "%s" % Version.version()), space] # evilynux: Main FoFiX credits (taken from CREDITS). self.parseText("CREDITS") self.credits.extend([space, space, space]) # evilynux: Theme credits (taken from data/themes/<theme name>/CREDITS). self.parseText(os.path.join('data', 'themes', self.themename, 'CREDITS')) self.credits.extend( [ space, space, Text(nf, ns, c1, "left", _("Made with:")), Text(nf, ns, c2, "right", "Python " + sys.version.split(' ')[0]), #stump: the version that's actually in use Text(nf, bs, c2, "right", "http://www.python.org"), space, Text(nf, ns, c2, "right", "PyGame " + pygame.version.ver.replace('release', '')), #stump: the version that's actually in use Text(nf, bs, c2, "right", "http://www.pygame.org"), space, Text(nf, ns, c2, "right", "PyOpenGL " + OpenGL.__version__), #evilynux: the version that's actually in use Text(nf, bs, c2, "right", "http://pyopengl.sourceforge.net"), space, Text(nf, ns, c2, "right", "Illusoft Collada module 0.3.159"), Text(nf, bs, c2, "right", "http://colladablender.illusoft.com"), space, Text(nf, ns, c2, "right", "MXM Python Midi Package 0.1.4"), Text(nf, bs, c2, "right", "http://www.mxm.dk/products/public/pythonmidi"), space, space, Text(nf, bs, c1, "center", _("Source Code available under the GNU General Public License")), Text(nf, bs, c2, "center", "http://code.google.com/p/fofix"), space, space, Text(nf, bs, c1, "center", _("Copyright 2006, 2007 by Unreal Voodoo")), Text(nf, bs, c1, "center", _("Copyright 2008-2013 by Team FoFiX")), space, space ])
class Credits(Layer, KeyListener): """Credits scroller.""" def __init__(self, engine, songName = None): self.engine = engine self.time = 0.0 self.offset = 0.5 # akedrou - this seems to fix the delay issue, but I'm not sure why. Return here! self.speedDiv = 20000.0 self.speedDir = 1.0 self.doneList = [] self.themename = Config.get("coffee", "themename") nf = self.engine.data.font ns = 0.002 bs = 0.001 hs = 0.003 c1 = (1, 1, .5, 1) c2 = (1, .75, 0, 1) self.text_size = nf.getLineSpacing(scale = hs) #akedrou - Translatable Strings: self.bank = {} self.bank['intro'] = [_("Frets on Fire X is a progression of MFH-mod,"), _("which was built on Alarian's mod,"), _("which was built on UltimateCoffee's Ultimate mod,"), _("which was built on RogueF's RF_mod 4.15,"), _("which was, of course, built on Frets on Fire 1.2.451,"), _("which was created by Unreal Voodoo")] self.bank['noOrder'] = [_("No particular order")] self.bank['accessOrder']= [_("In order of project commit access")] self.bank['coders'] = [_("Active Coders")] self.bank['otherCoding']= [_("Programming")] self.bank['graphics'] = [_("Graphic Design")] self.bank['3d'] = [_("3D Textures")] self.bank['logo'] = [_("FoFiX Logo Design")] self.bank['hollowmind'] = [_("Hollowmind Necks")] self.bank['themes'] = [_("Included Themes")] self.bank['shaders'] = [_("Shaders")] self.bank['sounds'] = [_("Sound Design")] self.bank['translators']= [_("Translators")] self.bank['honorary'] = [_("Honorary Credits")] self.bank['codeHonor'] = [_("Without whom this game would not exist")] self.bank['giveThanks'] = [_("Special Thanks to")] self.bank['community'] = [_("nwru and all of the community at fretsonfire.net")] self.bank['other'] = [_("Other Contributors:")] self.bank['tutorial'] = [_("Jurgen FoF tutorial inspired by adam02"), _("Drum test song tutorial by Heka"), _("Drum Rolls practice tutorial by venom426")] self.bank['disclaimer'] = [_("If you have contributed to this game and are not credited,"), _("please let us know what and when you contributed.")] self.bank['thanks'] = [_("Thank you for your contribution.")] self.bank['oversight'] = [_("Please keep in mind that it is not easy to trace down and"), _("credit every single person who contributed; if your name is"), _("not included, it was not meant to slight you."), _("It was an oversight.")] # evilynux - Theme strings self.bank['themeCreators'] = [_("%s theme credits:") % self.themename] self.bank['themeThanks'] = [_("%s theme specific thanks:") % self.themename] # Languages self.bank['french'] = [_("French")] self.bank['french90'] = [_("French (reform 1990)")] self.bank['german'] = [_("German")] self.bank['italian'] = [_("Italian")] self.bank['piglatin'] = [_("Pig Latin")] self.bank['portuguese-b'] = [_("Portuguese (Brazilian)")] self.bank['russian'] = [_("Russian")] self.bank['spanish'] = [_("Spanish")] self.bank['swedish'] = [_("Swedish")] self.videoLayer = False self.background = None vidSource = os.path.join(Version.dataPath(), 'themes', self.themename, \ 'menu', 'credits.ogv') if os.path.isfile(vidSource): try: self.vidPlayer = VideoLayer(self.engine, vidSource, mute = True, loop = True) except (IOError, VideoPlayerError): Log.error('Error loading credits video:') else: self.vidPlayer.play() self.engine.view.pushLayer(self.vidPlayer) self.videoLayer = True if not self.videoLayer and \ not self.engine.loadImgDrawing(self, 'background', os.path.join('themes', self.themename, 'menu', 'credits.png')): self.background = None if not self.engine.loadImgDrawing(self, 'topLayer', os.path.join('themes', self.themename, 'menu', 'creditstop.png')): self.topLayer = None space = Text(nf, hs, c1, "center", " ") self.credits = [ Picture(self.engine, "fofix_logo.png", .10), Text(nf, ns, c1, "center", "%s" % Version.version()), space] # evilynux: Main FoFiX credits (taken from CREDITS). self.parseText("CREDITS") self.credits.extend([space, space, space]) # evilynux: Theme credits (taken from data/themes/<theme name>/CREDITS). self.parseText(os.path.join('data', 'themes', self.themename, 'CREDITS')) self.credits.extend( [ space, space, Text(nf, ns, c1, "left", _("Made with:")), Text(nf, ns, c2, "right", "Python " + sys.version.split(' ')[0]), #stump: the version that's actually in use Text(nf, bs, c2, "right", "http://www.python.org"), space, Text(nf, ns, c2, "right", "PyGame " + pygame.version.ver.replace('release', '')), #stump: the version that's actually in use Text(nf, bs, c2, "right", "http://www.pygame.org"), space, Text(nf, ns, c2, "right", "PyOpenGL " + OpenGL.__version__), #evilynux: the version that's actually in use Text(nf, bs, c2, "right", "http://pyopengl.sourceforge.net"), space, Text(nf, ns, c2, "right", "Illusoft Collada module 0.3.159"), Text(nf, bs, c2, "right", "http://colladablender.illusoft.com"), space, Text(nf, ns, c2, "right", "MXM Python Midi Package 0.1.4"), Text(nf, bs, c2, "right", "http://www.mxm.dk/products/public/pythonmidi"), space, space, Text(nf, bs, c1, "center", _("Source Code available under the GNU General Public License")), Text(nf, bs, c2, "center", "http://code.google.com/p/fofix"), space, space, Text(nf, bs, c1, "center", _("Copyright 2006, 2007 by Unreal Voodoo")), Text(nf, bs, c1, "center", _("Copyright 2008-2013 by Team FoFiX")), space, space ]) # evilynux - Text parsing method. Provides some style functionalities. def parseText(self, filename): nf = self.engine.data.font ns = 0.002 bs = 0.001 hs = 0.003 c1 = (1, 1, .5, 1) c2 = (1, .75, 0, 1) space = Text(nf, hs, c1, "center", " ") scale = 1 path = filename if not hasattr(sys,"frozen"): #MFH - add ".." to path only if running from sources - not if running from EXE path = os.path.join("..", path) if not os.path.exists(path): return file = open(path) for line in file: line = line.strip("\n") if line.startswith("=====") or line.startswith("-----"): continue try: if line.startswith("!") and line.endswith("!"): scale = float(line.strip("!")) continue except ValueError: Log.warn("CREDITS file does not parse properly") if line == "": self.credits.append(space) elif line.startswith("`") and line.endswith("`"): line = line.strip("`") if line.startswith("%") and line.endswith("%"): line = line.strip("%") try: for text in self.bank[line]: self.credits.append( Text(nf, bs*scale, c1, "left", "%s" % text) ) except KeyError: self.credits.append( Text(nf, bs*scale, c1, "left", "%s" % line) ) else: self.credits.append( Text(nf, bs*scale, c1, "left", "%s" % line) ) elif line.startswith("_") and line.endswith("_"): line = line.strip("_") if line.startswith("%") and line.endswith("%"): line = line.strip("%") try: for text in self.bank[line]: self.credits.append( Text(nf, ns*scale, c2, "center", "%s" % text) ) except KeyError: self.credits.append( Text(nf, ns*scale, c2, "center", "%s" % line) ) else: self.credits.append( Text(nf, ns*scale, c2, "center", "%s" % line) ) elif line.startswith("=") and line.endswith("="): line = line.strip("=") if line.startswith("%") and line.endswith("%"): line = line.strip("%") try: for text in self.bank[line]: self.credits.append( Text(nf, ns*scale, c1, "left", "%s" % text) ) except KeyError: self.credits.append( Text(nf, ns*scale, c1, "left", "%s" % line) ) else: self.credits.append( Text(nf, ns*scale, c1, "left", "%s" % line) ) else: if line.startswith("%") and line.endswith("%"): line = line.strip("%") try: for text in self.bank[line]: self.credits.append( Text(nf, ns*scale, c2, "right", "%s" % text) ) except KeyError: self.credits.append( Text(nf, ns*scale, c2, "right", "%s" % line) ) else: self.credits.append( Text(nf, ns*scale, c2, "right", "%s" % line) ) def shown(self): self.engine.input.addKeyListener(self) def hidden(self): self.engine.input.removeKeyListener(self) self.engine.view.pushLayer(self.engine.mainMenu) #rchiav: use already-existing MainMenu instance def quit(self): if self.videoLayer: self.engine.view.popLayer(self.vidPlayer) self.engine.view.popLayer(self) def keyPressed(self, key, unicode): if self.engine.input.controls.getMapping(key) in (Player.menuYes + Player.menuNo) or key == pygame.K_RETURN or key == pygame.K_ESCAPE: self.quit() elif self.engine.input.controls.getMapping(key) in (Player.menuDown) or key == pygame.K_DOWN: #akedrou: so I was bored. if self.speedDiv > 1000.0: self.speedDiv -= 1000.0 if self.speedDiv < 1000.0: self.speedDiv = 1000.0 elif self.engine.input.controls.getMapping(key) in (Player.menuUp) or key == pygame.K_UP: if self.speedDiv < 30000.0: self.speedDiv += 1000.0 if self.speedDiv > 30000.0: self.speedDiv = 30000.0 elif self.engine.input.controls.getMapping(key) in (Player.key3s): self.speedDir *= -1 elif self.engine.input.controls.getMapping(key) in (Player.key4s): if self.speedDir != 0: self.speedDir = 0 else: self.speedDir = 1.0 return True def run(self, ticks): self.time += ticks / 50.0 #self.offset -= ticks / 7500.0 # evilynux - corresponds to scroll speed #self.offset -= ticks / 15000.0 #MFH - slowin it down - # evilynux - corresponds to scroll speed self.offset -= (ticks / self.speedDiv) * self.speedDir #akedrou - some credits fun. # evilynux - approximating the end of the list from the (mostly used font size * lines) if self.offset < -( self.text_size * len(self.credits) ) or self.offset > 1.5: #(MFH - adding 5% to estimated font height) undone: using larger scale for estimation. self.quit() if len(self.credits) == len(self.doneList): #akedrou - goofy workaround for string size glitch. self.quit() def render(self, visibility, topMost): v = 1.0 - ((1 - visibility) ** 2) # render the background w, h = self.engine.view.geometry[2:4] with self.engine.view.orthogonalProjection(normalize = True): if self.background: drawImage(self.background, scale = (1.0,-1.0), coord = (w/2,h/2), stretched = FULL_SCREEN) else: self.engine.fadeScreen(.4) self.doneList = [] # render the scroller elements y = self.offset glTranslatef(-(1 - v), 0, 0) for element in self.credits: hE = element.getHeight() if y + hE > 0.0 and y < 1.0: element.render(y) if y + hE < 0.0: self.doneList.append(element) y += hE if y > 1.0: break if self.topLayer: wFactor = 640.000/self.topLayer.width1() hPos = h - ((self.topLayer.height1() * wFactor)*.75) if hPos < h * .6: hPos = h * .6 drawImage(self.topLayer, scale = (wFactor,-wFactor), coord = (w/2,hPos))
class Stage(object): def __init__(self, guitarScene, configFileName): self.scene = guitarScene self.engine = guitarScene.engine self.config = LinedConfigParser() self.backgroundLayers = [] self.foregroundLayers = [] self.textures = {} self.reset() self.wFull = None #MFH - needed for new stage background handling self.hFull = None # evilynux - imported myfingershurt stuff from GuitarScene self.mode = self.engine.config.get("game", "stage_mode") self.songStage = self.engine.config.get("game", "song_stage") self.animatedFolder = self.engine.config.get("game", "animated_stage_folder") # evilynux - imported myfingershurt stuff from GuitarScene w/ minor modifs #MFH TODO - alter logic to accommodate separated animation and slideshow # settings based on selected animated stage folder animationMode = self.engine.config.get("game", "stage_animate") slideShowMode = self.engine.config.get("game", "rotate_stages") if self.animatedFolder == _("None"): self.rotationMode = 0 #MFH: if no animated stage folders are available, disable rotation. elif self.animatedFolder == "Normal": self.rotationMode = slideShowMode else: self.rotationMode = animationMode self.imgArr = [] #QQstarS:random self.imgArrScaleFactors = [] #MFH - for precalculated scale factors self.rotateDelay = self.engine.config.get("game", "stage_rotate_delay") #myfingershurt - user defined stage rotate delay self.animateDelay = self.engine.config.get("game", "stage_animate_delay") #myfingershurt - user defined stage rotate delay self.animation = False self.indexCount = 0 #QQstarS:random time counter self.arrNum = 0 #QQstarS:random the array num self.arrDir = 1 #forwards self.config.read(configFileName) # evilynux - Improved stage error handling self.themename = self.engine.data.themeLabel self.path = os.path.join("themes",self.themename,"backgrounds") self.pathfull = self.engine.getPath(self.path) if not os.path.exists(self.pathfull): # evilynux log.warn("Stage folder does not exist: %s" % self.pathfull) self.mode = 1 # Fallback to song-specific stage self.loadLayers(configFileName) def loadLayers(self, configFileName): self.config.read(configFileName) path = os.path.join("themes", self.themename, "stage") # Build the layers for i in range(32): section = "layer%d" % i if self.config.has_section(section): def get(value, type = str, default = None): if self.config.has_option(section, value): return type(self.config.get(section, value)) return default xres = get("xres", int, 256) yres = get("yres", int, 256) texture = get("texture") try: drawing = self.textures[texture] except KeyError: drawing = self.engine.loadImgDrawing(self, None, os.path.join(path, texture), textureSize = (xres, yres)) self.textures[texture] = drawing layer = Layer(self, drawing) layer.position = (get("xpos", float, 0.0), get("ypos", float, 0.0)) layer.scale = (get("xscale", float, 1.0), get("yscale", float, 1.0)) layer.angle = math.pi * get("angle", float, 0.0) / 180.0 layer.srcBlending = getattr(gl, "GL_%s" % get("src_blending", str, "src_alpha").upper()) layer.dstBlending = getattr(gl, "GL_%s" % get("dst_blending", str, "one_minus_src_alpha").upper()) layer.color = (get("color_r", float, 1.0), get("color_g", float, 1.0), get("color_b", float, 1.0), get("color_a", float, 1.0)) # Load any effects fxClasses = { "light": LightEffect, "rotate": RotateEffect, "wiggle": WiggleEffect, "scale": ScaleEffect, } for j in range(32): fxSection = "layer%d:fx%d" % (i, j) if self.config.has_section(fxSection): type = self.config.get(fxSection, "type") if not type in fxClasses: continue options = self.config.options(fxSection) options = dict([(opt, self.config.get(fxSection, opt)) for opt in options]) fx = fxClasses[type](layer, options) layer.effects.append(fx) if get("foreground", int): self.foregroundLayers.append(layer) else: self.backgroundLayers.append(layer) def loadVideo(self, libraryName, songName): vidSource = None if self.songStage == 1: songBackgroundVideoPath = os.path.join(libraryName, songName, "background.ogv") if os.path.isfile(songBackgroundVideoPath): vidSource = songBackgroundVideoPath loop = False else: log.warn("Video not found: %s" % songBackgroundVideoPath) if vidSource is None: vidSource = os.path.join(self.pathfull, "default.ogv") loop = True if not os.path.isfile(vidSource): log.warn("Video not found: %s" % vidSource) log.warn("Falling back to default stage mode.") self.mode = 1 # Fallback return try: # Catches invalid video files or unsupported formats log.debug("Attempting to load video: %s" % vidSource) self.vidPlayer = VideoLayer(self.engine, vidSource, mute = True, loop = loop) self.engine.view.pushLayer(self.vidPlayer) except (IOError, VideoPlayerError): self.mode = 1 log.error("Failed to load song video (falling back to default stage mode):") def restartVideo(self): if not self.mode == 3: return self.vidPlayer.restart() def load(self, libraryName, songName, practiceMode = False): if self.scene.coOpType: rm = os.path.join("themes", self.themename, "rockmeter_coop.ini") elif self.scene.battle: rm = os.path.join("themes", self.themename, "rockmeter_profaceoff.ini") elif self.scene.gamePlayers > 1: rm = os.path.join("themes", self.themename, "rockmeter_faceoff.ini") else: rm = os.path.join("themes", self.themename, "rockmeter.ini") if os.path.exists(os.path.join("..", "data", rm)): rockmeter = self.engine.resource.fileName(rm) else: rockmeter = self.engine.resource.fileName(os.path.join("themes", self.themename, "rockmeter.ini")) self.rockmeter = Rockmeter.Rockmeter(self.scene, rockmeter, self.scene.coOpType) # evilynux - Fixes a self.background not defined crash self.background = None #MFH - new background stage logic: if self.mode == 2: #blank / no stage self.songStage = 0 self.rotationMode = 0 elif practiceMode: #check for existing practice stage; always disable stage rotation here self.songStage = 0 self.rotationMode = 0 self.mode = 1 #separated practice stages for the instruments by k.i.d if self.scene.instruments[0].isDrum: background = "practicedrum" elif self.scene.instruments[0].isBassGuitar: background = "practicebass" else: background = "practice" if not self.engine.loadImgDrawing(self, "background", os.path.join("themes",self.themename,"backgrounds",background)): #MFH - must first fall back on the old practice.png before forcing blank stage mode! if not self.engine.loadImgDrawing(self, "background", os.path.join("themes",self.themename,"backgrounds","practice")): log.warn("No practice stage, falling back on a forced Blank stage mode") # evilynux self.mode = 2 #if no practice stage, just fall back on a forced Blank stage mode elif self.songStage == 1: #check for song-specific background test = True if not self.engine.loadImgDrawing(self, "background", os.path.join(libraryName, songName, "background")): log.notice("No song-specific stage found") # evilynux test = False if test: #does a song-specific background exist? self.rotationMode = 0 self.mode = 1 else: self.songStage = 0 #MFH - now, after the above logic, we can run the normal stage mode logic # only worrying about checking for Blank, song-specific and # practice stage modes if self.mode != 2 and self.mode != 3 and self.songStage == 0 and not practiceMode: #still need to load stage(s) #myfingershurt: assign this first if self.mode == 1: #just use Default.png if not self.engine.loadImgDrawing(self, "background", os.path.join(self.path, "default")): log.warn("No default stage; falling back on a forced Blank stage mode") # evilynux self.mode = 2 #if no practice stage, just fall back on a forced Blank stage mode ##This checks how many Stage-background we have to select from if self.mode == 0 and self.rotationMode == 0: #MFH: just display a random stage files = [] fileIndex = 0 allfiles = os.listdir(self.pathfull) for name in allfiles: if os.path.splitext(name)[0].lower() != "practice" and os.path.splitext(name)[0].lower() != "practicedrum" and os.path.splitext(name)[0].lower() != "practicebass" and name != ".git": log.debug("Valid background found, index (" + str(fileIndex) + "): " + name) files.append(name) fileIndex += 1 else: log.debug("Practice background filtered: " + name) # evilynux - improved error handling, fallback to blank background if no background are found if fileIndex == 0: log.warn("No valid stage found!") self.mode = 2; else: i = random.randint(0,len(files)-1) filename = files[i] ##End check number of Stage-backgrounds if not self.engine.loadImgDrawing(self, "background", os.path.join(self.path, filename)): self.mode = 2; elif self.rotationMode > 0 and self.mode != 2: files = [] fileIndex = 0 if self.animatedFolder == "Random": #Select one of the subfolders under stages\ to animate randomly numAniStageFolders = len(self.engine.stageFolders) if numAniStageFolders > 0: self.animatedFolder = random.choice(self.engine.stageFolders) else: self.animatedFolder = "Normal" elif self.animatedFolder == "None": self.mode = 2 if self.animatedFolder != "Normal" and self.mode != 2: #just use the base Stages folder for rotation self.path = os.path.join("themes",self.themename,"backgrounds",self.animatedFolder) self.pathfull = self.engine.getPath(self.path) self.animation = True allfiles = os.listdir(self.pathfull) for name in allfiles: if os.path.splitext(name)[1].lower() == ".png" or os.path.splitext(name)[1].lower() == ".jpg" or os.path.splitext(name)[1].lower() == ".jpeg": if os.path.splitext(name)[0].lower() != "practice" and os.path.splitext(name)[0].lower() != "practicedrum" and os.path.splitext(name)[0].lower() != "practicebass": log.debug("Valid background found, index (" + str(fileIndex) + "): " + name) files.append(name) fileIndex += 1 else: log.debug("Practice background filtered: " + name) files.sort() if self.rotationMode > 0 and self.mode != 2: #alarian: blank stage option is not selected #myfingershurt: just populate the image array in order, they are pulled in whatever order requested: for j in range(len(files)): self.engine.loadImgDrawing(self, "backgroundA", os.path.join(self.path, files[j])) self.imgArr.append(getattr(self, "backgroundA", os.path.join(self.path, files[j]))) if self.rotationMode > 0 and len(self.imgArr) == 0: self.rotationMode = 0 #stage rotation def rotate(self): if self.animation: whichDelay = self.animateDelay else: whichDelay = self.rotateDelay self.indexCount = self.indexCount + 1 if self.indexCount > whichDelay: #myfingershurt - adding user setting for stage rotate delay self.indexCount = 0 if self.rotationMode == 1: #QQstarS:random self.arrNum = random.randint(0,len(self.imgArr)-1) elif self.rotationMode == 2: #myfingershurt: in order display mode self.arrNum += 1 if self.arrNum > (len(self.imgArr)-1): self.arrNum = 0 elif self.rotationMode == 3: #myfingershurt: in order, back and forth display mode if self.arrDir == 1: #forwards self.arrNum += 1 if self.arrNum > (len(self.imgArr)-1): self.arrNum -= 2 self.arrDir = 0 else: self.arrNum -= 1 if self.arrNum < 0: self.arrNum += 2 self.arrDir = 1 def renderBackground(self): #myfingershurt: multiple rotation modes if self.mode != 2: if self.rotationMode == 0: drawImage(self.background, scale = (1.0,-1.0), coord = (self.wFull/2,self.hFull/2), stretched = FULL_SCREEN) #myfingershurt: else: #MFH - use precalculated scale factors instead drawImage(self.imgArr[self.arrNum], scale = (1.0,-1.0), coord = (self.wFull/2,self.hFull/2), stretched = FULL_SCREEN) def updateDelays(self): self.rotateDelay = self.engine.config.get("game", "stage_rotate_delay") #myfingershurt - user defined stage rotate delay self.animateDelay = self.engine.config.get("game", "stage_animate_delay") #myfingershurt - user defined stage rotate delay def reset(self): self.lastBeatPos = None self.lastQuarterBeatPos = None self.lastMissPos = None self.lastPickPos = None self.beat = 0 self.quarterBeat = 0 self.pos = 0.0 self.playedNotes = [] self.averageNotes = [0.0] self.beatPeriod = 0.0 def triggerPick(self, pos, notes): if notes: self.lastPickPos = pos self.playedNotes = self.playedNotes[-3:] + [sum(notes) / float(len(notes))] self.averageNotes[-1] = sum(self.playedNotes) / float(len(self.playedNotes)) self.rockmeter.triggerPick(pos, notes) def triggerMiss(self, pos): self.lastMissPos = pos self.rockmeter.triggerMiss(pos) def triggerQuarterBeat(self, pos, quarterBeat): self.lastQuarterBeatPos = pos self.quarterBeat = quarterBeat def triggerBeat(self, pos, beat): self.lastBeatPos = pos self.beat = beat self.averageNotes = self.averageNotes[-4:] + self.averageNotes[-1:] def run(self, pos, period): self.pos = pos self.beatPeriod = period quarterBeat = int(4 * pos / period) if quarterBeat > self.quarterBeat: self.triggerQuarterBeat(pos, quarterBeat) beat = quarterBeat / 4 if beat > self.beat: self.triggerBeat(pos, beat) def renderLayers(self, layers, visibility): if self.mode != 3: with self.engine.view.orthogonalProjection(normalize = True): for layer in layers: layer.render(visibility) def render(self, visibility): if self.mode != 3: self.renderBackground() self.renderLayers(self.backgroundLayers, visibility) if shaders.enable("stage"): height = 0.0 for i in shaders.var["color"].keys(): shaders.modVar("color",shaders.var["color"][i],0.05,10.0) height += shaders.var["color"][i][3]/3.0 height=height**2 shaders.setVar("height",2*height) shaders.setVar("ambientGlow",height/1.5) shaders.setVar("glowStrength",60+height*80.0) gl.glBegin(gl.GL_TRIANGLE_STRIP) gl.glVertex3f(-8.0, 1.0,7.0) gl.glVertex3f(8.0, 1.0,7.0) gl.glVertex3f(-8.0, 4.0,7.0) gl.glVertex3f(8.0, 4.0,7.0) gl.glEnd() shaders.disable() self.scene.renderGuitar() self.renderLayers(self.foregroundLayers, visibility) self.rockmeter.render(visibility)
def __init__(self, engine, songName = None): self.engine = engine self.time = 0.0 self.offset = 0.5 # akedrou - this seems to fix the delay issue, but I'm not sure why. Return here! self.speedDiv = 20000.0 self.speedDir = 1.0 self.doneList = [] self.themename = Config.get("coffee", "themename") nf = self.engine.data.font ns = 0.002 bs = 0.001 hs = 0.003 c1 = (1, 1, .5, 1) c2 = (1, .75, 0, 1) self.text_size = nf.getLineSpacing(scale = hs) #akedrou - Translatable Strings: self.bank = {} self.bank['intro'] = [_("Frets on Fire X is a progression of MFH-mod,"), _("which was built on Alarian's mod,"), _("which was built on UltimateCoffee's Ultimate mod,"), _("which was built on RogueF's RF_mod 4.15,"), _("which was, of course, built on Frets on Fire 1.2.451,"), _("which was created by Unreal Voodoo")] self.bank['noOrder'] = [_("No particular order")] self.bank['accessOrder']= [_("In order of project commit access")] self.bank['coders'] = [_("Active Coders")] self.bank['otherCoding']= [_("Programming")] self.bank['graphics'] = [_("Graphic Design")] self.bank['3d'] = [_("3D Textures")] self.bank['logo'] = [_("FoFiX Logo Design")] self.bank['hollowmind'] = [_("Hollowmind Necks")] self.bank['themes'] = [_("Included Themes")] self.bank['shaders'] = [_("Shaders")] self.bank['sounds'] = [_("Sound Design")] self.bank['translators']= [_("Translators")] self.bank['honorary'] = [_("Honorary Credits")] self.bank['codeHonor'] = [_("Without whom this game would not exist")] self.bank['giveThanks'] = [_("Special Thanks to")] self.bank['community'] = [_("nwru and all of the community at fretsonfire.net")] self.bank['other'] = [_("Other Contributors:")] self.bank['tutorial'] = [_("Jurgen FoF tutorial inspired by adam02"), _("Drum test song tutorial by Heka"), _("Drum Rolls practice tutorial by venom426")] self.bank['disclaimer'] = [_("If you have contributed to this game and are not credited,"), _("please let us know what and when you contributed.")] self.bank['thanks'] = [_("Thank you for your contribution.")] self.bank['oversight'] = [_("Please keep in mind that it is not easy to trace down and"), _("credit every single person who contributed; if your name is"), _("not included, it was not meant to slight you."), _("It was an oversight.")] # evilynux - Theme strings self.bank['themeCreators'] = [_("%s theme credits:") % self.themename] self.bank['themeThanks'] = [_("%s theme specific thanks:") % self.themename] # Languages self.bank['french'] = [_("French")] self.bank['french90'] = [_("French (reform 1990)")] self.bank['german'] = [_("German")] self.bank['italian'] = [_("Italian")] self.bank['piglatin'] = [_("Pig Latin")] self.bank['portuguese-b'] = [_("Portuguese (Brazilian)")] self.bank['russian'] = [_("Russian")] self.bank['spanish'] = [_("Spanish")] self.bank['swedish'] = [_("Swedish")] self.videoLayer = False self.background = None vidSource = os.path.join(Version.dataPath(), 'themes', self.themename, 'menu', 'credits.ogv') if os.path.isfile(vidSource): try: self.vidPlayer = VideoLayer(self.engine, vidSource, mute = True, loop = True) except (IOError, VideoPlayerError): Log.error('Error loading credits video:') else: self.vidPlayer.play() self.engine.view.pushLayer(self.vidPlayer) self.videoLayer = True if not self.videoLayer and \ not self.engine.loadImgDrawing(self, 'background', os.path.join('themes', self.themename, 'menu', 'credits.png')): self.background = None if not self.engine.loadImgDrawing(self, 'topLayer', os.path.join('themes', self.themename, 'menu', 'creditstop.png')): self.topLayer = None space = Text(nf, hs, c1, "center", " ") self.credits = [ Picture(self.engine, "fofix_logo.png", .10), Text(nf, ns, c1, "center", "%s" % Version.version()), space] # evilynux: Main FoFiX credits (taken from CREDITS). self.parseText("CREDITS") self.credits.extend([space, space, space]) # evilynux: Theme credits (taken from data/themes/<theme name>/CREDITS). self.parseText(os.path.join('data', 'themes', self.themename, 'CREDITS')) self.credits.extend( [ space, space, Text(nf, ns, c1, "left", _("Made with:")), Text(nf, ns, c2, "right", "Python " + sys.version.split(' ')[0]), #stump: the version that's actually in use Text(nf, bs, c2, "right", "http://www.python.org"), space, Text(nf, ns, c2, "right", "PyGame " + pygame.version.ver.replace('release', '')), #stump: the version that's actually in use Text(nf, bs, c2, "right", "http://www.pygame.org"), space, Text(nf, ns, c2, "right", "PyOpenGL " + OpenGL.__version__), #evilynux: the version that's actually in use Text(nf, bs, c2, "right", "http://pyopengl.sourceforge.net"), space, Text(nf, ns, c2, "right", "Illusoft Collada module 0.3.159"), Text(nf, bs, c2, "right", "http://colladablender.illusoft.com"), space, Text(nf, ns, c2, "right", "MXM Python Midi Package 0.1.4"), Text(nf, bs, c2, "right", "http://www.mxm.dk/products/public/pythonmidi"), space, space, Text(nf, bs, c1, "center", _("Source Code available under the GNU General Public License")), Text(nf, bs, c2, "center", "http://code.google.com/p/fofix"), space, space, Text(nf, bs, c1, "center", _("Copyright 2006, 2007 by Unreal Voodoo")), Text(nf, bs, c1, "center", _("Copyright 2008-2013 by Team FoFiX")), space, space ])
class Credits(Layer, KeyListener): """Credits scroller.""" def __init__(self, engine, songName = None): self.engine = engine self.time = 0.0 self.offset = 0.5 # akedrou - this seems to fix the delay issue, but I'm not sure why. Return here! self.speedDiv = 20000.0 self.speedDir = 1.0 self.doneList = [] self.themename = Config.get("coffee", "themename") nf = self.engine.data.font ns = 0.002 bs = 0.001 hs = 0.003 c1 = (1, 1, .5, 1) c2 = (1, .75, 0, 1) self.text_size = nf.getLineSpacing(scale = hs) #akedrou - Translatable Strings: self.bank = {} self.bank['intro'] = [_("Frets on Fire X is a progression of MFH-mod,"), _("which was built on Alarian's mod,"), _("which was built on UltimateCoffee's Ultimate mod,"), _("which was built on RogueF's RF_mod 4.15,"), _("which was, of course, built on Frets on Fire 1.2.451,"), _("which was created by Unreal Voodoo")] self.bank['noOrder'] = [_("No particular order")] self.bank['accessOrder']= [_("In order of project commit access")] self.bank['coders'] = [_("Active Coders")] self.bank['otherCoding']= [_("Programming")] self.bank['graphics'] = [_("Graphic Design")] self.bank['3d'] = [_("3D Textures")] self.bank['logo'] = [_("FoFiX Logo Design")] self.bank['hollowmind'] = [_("Hollowmind Necks")] self.bank['themes'] = [_("Included Themes")] self.bank['shaders'] = [_("Shaders")] self.bank['sounds'] = [_("Sound Design")] self.bank['translators']= [_("Translators")] self.bank['honorary'] = [_("Honorary Credits")] self.bank['codeHonor'] = [_("Without whom this game would not exist")] self.bank['giveThanks'] = [_("Special Thanks to")] self.bank['community'] = [_("nwru and all of the community at fretsonfire.net")] self.bank['other'] = [_("Other Contributors:")] self.bank['tutorial'] = [_("Jurgen FoF tutorial inspired by adam02"), _("Drum test song tutorial by Heka"), _("Drum Rolls practice tutorial by venom426")] self.bank['disclaimer'] = [_("If you have contributed to this game and are not credited,"), _("please let us know what and when you contributed.")] self.bank['thanks'] = [_("Thank you for your contribution.")] self.bank['oversight'] = [_("Please keep in mind that it is not easy to trace down and"), _("credit every single person who contributed; if your name is"), _("not included, it was not meant to slight you."), _("It was an oversight.")] # evilynux - Theme strings self.bank['themeCreators'] = [_("%s theme credits:") % self.themename] self.bank['themeThanks'] = [_("%s theme specific thanks:") % self.themename] # Languages self.bank['french'] = [_("French")] self.bank['french90'] = [_("French (reform 1990)")] self.bank['german'] = [_("German")] self.bank['italian'] = [_("Italian")] self.bank['piglatin'] = [_("Pig Latin")] self.bank['portuguese-b'] = [_("Portuguese (Brazilian)")] self.bank['russian'] = [_("Russian")] self.bank['spanish'] = [_("Spanish")] self.bank['swedish'] = [_("Swedish")] self.videoLayer = False self.background = None vidSource = os.path.join(Version.dataPath(), 'themes', self.themename, 'menu', 'credits.ogv') if os.path.isfile(vidSource): try: self.vidPlayer = VideoLayer(self.engine, vidSource, mute = True, loop = True) except (IOError, VideoPlayerError): Log.error('Error loading credits video:') else: self.vidPlayer.play() self.engine.view.pushLayer(self.vidPlayer) self.videoLayer = True if not self.videoLayer and \ not self.engine.loadImgDrawing(self, 'background', os.path.join('themes', self.themename, 'menu', 'credits.png')): self.background = None if not self.engine.loadImgDrawing(self, 'topLayer', os.path.join('themes', self.themename, 'menu', 'creditstop.png')): self.topLayer = None space = Text(nf, hs, c1, "center", " ") self.credits = [ Picture(self.engine, "fofix_logo.png", .10), Text(nf, ns, c1, "center", "%s" % Version.version()), space] # evilynux: Main FoFiX credits (taken from CREDITS). self.parseText("CREDITS") self.credits.extend([space, space, space]) # evilynux: Theme credits (taken from data/themes/<theme name>/CREDITS). self.parseText(os.path.join('data', 'themes', self.themename, 'CREDITS')) self.credits.extend( [ space, space, Text(nf, ns, c1, "left", _("Made with:")), Text(nf, ns, c2, "right", "Python " + sys.version.split(' ')[0]), #stump: the version that's actually in use Text(nf, bs, c2, "right", "http://www.python.org"), space, Text(nf, ns, c2, "right", "PyGame " + pygame.version.ver.replace('release', '')), #stump: the version that's actually in use Text(nf, bs, c2, "right", "http://www.pygame.org"), space, Text(nf, ns, c2, "right", "PyOpenGL " + OpenGL.__version__), #evilynux: the version that's actually in use Text(nf, bs, c2, "right", "http://pyopengl.sourceforge.net"), space, Text(nf, ns, c2, "right", "Illusoft Collada module 0.3.159"), Text(nf, bs, c2, "right", "http://colladablender.illusoft.com"), space, Text(nf, ns, c2, "right", "MXM Python Midi Package 0.1.4"), Text(nf, bs, c2, "right", "http://www.mxm.dk/products/public/pythonmidi"), space, space, Text(nf, bs, c1, "center", _("Source Code available under the GNU General Public License")), Text(nf, bs, c2, "center", "http://code.google.com/p/fofix"), space, space, Text(nf, bs, c1, "center", _("Copyright 2006, 2007 by Unreal Voodoo")), Text(nf, bs, c1, "center", _("Copyright 2008-2013 by Team FoFiX")), space, space ]) # evilynux - Text parsing method. Provides some style functionalities. def parseText(self, filename): nf = self.engine.data.font ns = 0.002 bs = 0.001 hs = 0.003 c1 = (1, 1, .5, 1) c2 = (1, .75, 0, 1) space = Text(nf, hs, c1, "center", " ") scale = 1 path = filename if not hasattr(sys,"frozen"): #MFH - add ".." to path only if running from sources - not if running from EXE path = os.path.join("..", path) if not os.path.exists(path): return file = open(path) for line in file: line = line.strip("\n") if line.startswith("=====") or line.startswith("-----"): continue try: if line.startswith("!") and line.endswith("!"): scale = float(line.strip("!")) continue except ValueError: Log.warn("CREDITS file does not parse properly") if line == "": self.credits.append(space) elif line.startswith("`") and line.endswith("`"): line = line.strip("`") if line.startswith("%") and line.endswith("%"): line = line.strip("%") try: for text in self.bank[line]: self.credits.append( Text(nf, bs*scale, c1, "left", "%s" % text) ) except KeyError: self.credits.append( Text(nf, bs*scale, c1, "left", "%s" % line) ) else: self.credits.append( Text(nf, bs*scale, c1, "left", "%s" % line) ) elif line.startswith("_") and line.endswith("_"): line = line.strip("_") if line.startswith("%") and line.endswith("%"): line = line.strip("%") try: for text in self.bank[line]: self.credits.append( Text(nf, ns*scale, c2, "center", "%s" % text) ) except KeyError: self.credits.append( Text(nf, ns*scale, c2, "center", "%s" % line) ) else: self.credits.append( Text(nf, ns*scale, c2, "center", "%s" % line) ) elif line.startswith("=") and line.endswith("="): line = line.strip("=") if line.startswith("%") and line.endswith("%"): line = line.strip("%") try: for text in self.bank[line]: self.credits.append( Text(nf, ns*scale, c1, "left", "%s" % text) ) except KeyError: self.credits.append( Text(nf, ns*scale, c1, "left", "%s" % line) ) else: self.credits.append( Text(nf, ns*scale, c1, "left", "%s" % line) ) else: if line.startswith("%") and line.endswith("%"): line = line.strip("%") try: for text in self.bank[line]: self.credits.append( Text(nf, ns*scale, c2, "right", "%s" % text) ) except KeyError: self.credits.append( Text(nf, ns*scale, c2, "right", "%s" % line) ) else: self.credits.append( Text(nf, ns*scale, c2, "right", "%s" % line) ) def shown(self): self.engine.input.addKeyListener(self) def hidden(self): self.engine.input.removeKeyListener(self) self.engine.view.pushLayer(self.engine.mainMenu) #rchiav: use already-existing MainMenu instance def quit(self): if self.videoLayer: self.engine.view.popLayer(self.vidPlayer) self.engine.view.popLayer(self) def keyPressed(self, key, unicode): if self.engine.input.controls.getMapping(key) in (Player.menuYes + Player.menuNo) or key == pygame.K_RETURN or key == pygame.K_ESCAPE: self.quit() elif self.engine.input.controls.getMapping(key) in (Player.menuDown) or key == pygame.K_DOWN: #akedrou: so I was bored. if self.speedDiv > 1000.0: self.speedDiv -= 1000.0 if self.speedDiv < 1000.0: self.speedDiv = 1000.0 elif self.engine.input.controls.getMapping(key) in (Player.menuUp) or key == pygame.K_UP: if self.speedDiv < 30000.0: self.speedDiv += 1000.0 if self.speedDiv > 30000.0: self.speedDiv = 30000.0 elif self.engine.input.controls.getMapping(key) in (Player.key3s): self.speedDir *= -1 elif self.engine.input.controls.getMapping(key) in (Player.key4s): if self.speedDir != 0: self.speedDir = 0 else: self.speedDir = 1.0 return True def run(self, ticks): self.time += ticks / 50.0 #self.offset -= ticks / 7500.0 # evilynux - corresponds to scroll speed #self.offset -= ticks / 15000.0 #MFH - slowin it down - # evilynux - corresponds to scroll speed self.offset -= (ticks / self.speedDiv) * self.speedDir #akedrou - some credits fun. # evilynux - approximating the end of the list from the (mostly used font size * lines) if self.offset < -( self.text_size * len(self.credits) ) or self.offset > 1.5: #(MFH - adding 5% to estimated font height) undone: using larger scale for estimation. self.quit() if len(self.credits) == len(self.doneList): #akedrou - goofy workaround for string size glitch. self.quit() def render(self, visibility, topMost): v = 1.0 - ((1 - visibility) ** 2) # render the background w, h = self.engine.view.geometry[2:4] with self.engine.view.orthogonalProjection(normalize = True): if self.background: drawImage(self.background, scale = (1.0,-1.0), coord = (w/2,h/2), stretched = FULL_SCREEN) else: self.engine.fadeScreen(.4) self.doneList = [] # render the scroller elements y = self.offset glTranslatef(-(1 - v), 0, 0) for element in self.credits: hE = element.getHeight() if y + hE > 0.0 and y < 1.0: element.render(y) if y + hE < 0.0: self.doneList.append(element) y += hE if y > 1.0: break if self.topLayer: wFactor = 640.000/self.topLayer.width1() hPos = h - ((self.topLayer.height1() * wFactor)*.75) if hPos < h * .6: hPos = h * .6 drawImage(self.topLayer, scale = (wFactor,-wFactor), coord = (w/2,hPos))
class Stage(object): def __init__(self, guitarScene, configFileName): self.scene = guitarScene self.engine = guitarScene.engine self.config = LinedConfigParser() self.backgroundLayers = [] self.foregroundLayers = [] self.textures = {} self.reset() self.wFull = None #MFH - needed for new stage background handling self.hFull = None # evilynux - imported myfingershurt stuff from GuitarScene self.mode = self.engine.config.get("game", "stage_mode") self.songStage = self.engine.config.get("game", "song_stage") self.animatedFolder = self.engine.config.get("game", "animated_stage_folder") # evilynux - imported myfingershurt stuff from GuitarScene w/ minor modifs #MFH TODO - alter logic to accommodate separated animation and slideshow # settings based on selected animated stage folder animationMode = self.engine.config.get("game", "stage_animate") slideShowMode = self.engine.config.get("game", "rotate_stages") if self.animatedFolder == _("None"): self.rotationMode = 0 #MFH: if no animated stage folders are available, disable rotation. elif self.animatedFolder == "Normal": self.rotationMode = slideShowMode else: self.rotationMode = animationMode self.imgArr = [] #QQstarS:random self.imgArrScaleFactors = [] #MFH - for precalculated scale factors self.rotateDelay = self.engine.config.get("game", "stage_rotate_delay") #myfingershurt - user defined stage rotate delay self.animateDelay = self.engine.config.get("game", "stage_animate_delay") #myfingershurt - user defined stage rotate delay self.animation = False self.indexCount = 0 #QQstarS:random time counter self.arrNum = 0 #QQstarS:random the array num self.arrDir = 1 #forwards self.config.read(configFileName) # evilynux - Improved stage error handling self.themename = self.engine.data.themeLabel self.path = os.path.join("themes",self.themename,"backgrounds") self.pathfull = self.engine.getPath(self.path) if not os.path.exists(self.pathfull): # evilynux log.warn("Stage folder does not exist: %s" % self.pathfull) self.mode = 1 # Fallback to song-specific stage self.loadLayers(configFileName) def loadLayers(self, configFileName): self.config.read(configFileName) path = os.path.join("themes", self.themename, "stage") # Build the layers for i in range(32): section = "layer%d" % i if self.config.has_section(section): def get(value, type = str, default = None): if self.config.has_option(section, value): return type(self.config.get(section, value)) return default xres = get("xres", int, 256) yres = get("yres", int, 256) texture = get("texture") try: drawing = self.textures[texture] except KeyError: drawing = self.engine.loadImgDrawing(self, None, os.path.join(path, texture), textureSize = (xres, yres)) self.textures[texture] = drawing layer = Layer(self, drawing) layer.position = (get("xpos", float, 0.0), get("ypos", float, 0.0)) layer.scale = (get("xscale", float, 1.0), get("yscale", float, 1.0)) layer.angle = math.pi * get("angle", float, 0.0) / 180.0 layer.srcBlending = getattr(gl, "GL_%s" % get("src_blending", str, "src_alpha").upper()) layer.dstBlending = getattr(gl, "GL_%s" % get("dst_blending", str, "one_minus_src_alpha").upper()) layer.color = (get("color_r", float, 1.0), get("color_g", float, 1.0), get("color_b", float, 1.0), get("color_a", float, 1.0)) # Load any effects fxClasses = { "light": LightEffect, "rotate": RotateEffect, "wiggle": WiggleEffect, "scale": ScaleEffect, } for j in range(32): fxSection = "layer%d:fx%d" % (i, j) if self.config.has_section(fxSection): type = self.config.get(fxSection, "type") if not type in fxClasses: continue options = self.config.options(fxSection) options = dict([(opt, self.config.get(fxSection, opt)) for opt in options]) fx = fxClasses[type](layer, options) layer.effects.append(fx) if get("foreground", int): self.foregroundLayers.append(layer) else: self.backgroundLayers.append(layer) def loadVideo(self, libraryName, songName): vidSource = None if self.songStage == 1: songBackgroundVideoPath = os.path.join(libraryName, songName, "background.ogv") if os.path.isfile(songBackgroundVideoPath): vidSource = songBackgroundVideoPath loop = False else: log.warn("Video not found: %s" % songBackgroundVideoPath) if vidSource is None: vidSource = os.path.join(self.pathfull, "default.ogv") loop = True if not os.path.isfile(vidSource): log.warn("Video not found: %s" % vidSource) log.warn("Falling back to default stage mode.") self.mode = 1 # Fallback return try: # Catches invalid video files or unsupported formats log.debug("Attempting to load video: %s" % vidSource) self.vidPlayer = VideoLayer(self.engine, vidSource, mute = True, loop = loop) self.engine.view.pushLayer(self.vidPlayer) except (IOError, VideoPlayerError): self.mode = 1 log.error("Failed to load song video (falling back to default stage mode):") def restartVideo(self): if not self.mode == 3: return self.vidPlayer.restart() def load(self, libraryName, songName, practiceMode = False): if self.scene.coOpType: rm = os.path.join("themes", self.themename, "rockmeter_coop.ini") elif self.scene.battle: rm = os.path.join("themes", self.themename, "rockmeter_profaceoff.ini") elif self.scene.gamePlayers > 1: rm = os.path.join("themes", self.themename, "rockmeter_faceoff.ini") else: rm = os.path.join("themes", self.themename, "rockmeter.ini") if os.path.exists(os.path.join("..", "data", rm)): rockmeter = self.engine.resource.fileName(rm) else: rockmeter = self.engine.resource.fileName(os.path.join("themes", self.themename, "rockmeter.ini")) self.rockmeter = Rockmeter.Rockmeter(self.scene, rockmeter, self.scene.coOpType) # evilynux - Fixes a self.background not defined crash self.background = None #MFH - new background stage logic: if self.mode == 2: #blank / no stage self.songStage = 0 self.rotationMode = 0 elif practiceMode: #check for existing practice stage; always disable stage rotation here self.songStage = 0 self.rotationMode = 0 self.mode = 1 #separated practice stages for the instruments by k.i.d if self.scene.instruments[0].isDrum: background = "practicedrum" elif self.scene.instruments[0].isBassGuitar: background = "practicebass" else: background = "practice" if not self.engine.loadImgDrawing(self, "background", os.path.join("themes",self.themename,"backgrounds",background)): #MFH - must first fall back on the old practice.png before forcing blank stage mode! if not self.engine.loadImgDrawing(self, "background", os.path.join("themes",self.themename,"backgrounds","practice")): log.warn("No practice stage, falling back on a forced Blank stage mode") # evilynux self.mode = 2 #if no practice stage, just fall back on a forced Blank stage mode elif self.songStage == 1: #check for song-specific background test = True if not self.engine.loadImgDrawing(self, "background", os.path.join(libraryName, songName, "background")): log.notice("No song-specific stage found") # evilynux test = False if test: #does a song-specific background exist? self.rotationMode = 0 self.mode = 1 else: self.songStage = 0 #MFH - now, after the above logic, we can run the normal stage mode logic # only worrying about checking for Blank, song-specific and # practice stage modes if self.mode != 2 and self.mode != 3 and self.songStage == 0 and not practiceMode: #still need to load stage(s) #myfingershurt: assign this first if self.mode == 1: #just use Default.png if not self.engine.loadImgDrawing(self, "background", os.path.join(self.path, "default")): log.warn("No default stage; falling back on a forced Blank stage mode") # evilynux self.mode = 2 #if no practice stage, just fall back on a forced Blank stage mode ##This checks how many Stage-background we have to select from if self.mode == 0 and self.rotationMode == 0: #MFH: just display a random stage files = [] fileIndex = 0 allfiles = os.listdir(self.pathfull) for name in allfiles: if os.path.splitext(name)[0].lower() != "practice" and os.path.splitext(name)[0].lower() != "practicedrum" and os.path.splitext(name)[0].lower() != "practicebass" and name != ".svn": log.debug("Valid background found, index (" + str(fileIndex) + "): " + name) files.append(name) fileIndex += 1 else: log.debug("Practice background filtered: " + name) # evilynux - improved error handling, fallback to blank background if no background are found if fileIndex == 0: log.warn("No valid stage found!") self.mode = 2; else: i = random.randint(0,len(files)-1) filename = files[i] ##End check number of Stage-backgrounds if not self.engine.loadImgDrawing(self, "background", os.path.join(self.path, filename)): self.mode = 2; elif self.rotationMode > 0 and self.mode != 2: files = [] fileIndex = 0 if self.animatedFolder == "Random": #Select one of the subfolders under stages\ to animate randomly numAniStageFolders = len(self.engine.stageFolders) if numAniStageFolders > 0: self.animatedFolder = random.choice(self.engine.stageFolders) else: self.animatedFolder = "Normal" elif self.animatedFolder == "None": self.mode = 2 if self.animatedFolder != "Normal" and self.mode != 2: #just use the base Stages folder for rotation self.path = os.path.join("themes",self.themename,"backgrounds",self.animatedFolder) self.pathfull = self.engine.getPath(self.path) self.animation = True allfiles = os.listdir(self.pathfull) for name in allfiles: if os.path.splitext(name)[1].lower() == ".png" or os.path.splitext(name)[1].lower() == ".jpg" or os.path.splitext(name)[1].lower() == ".jpeg": if os.path.splitext(name)[0].lower() != "practice" and os.path.splitext(name)[0].lower() != "practicedrum" and os.path.splitext(name)[0].lower() != "practicebass": log.debug("Valid background found, index (" + str(fileIndex) + "): " + name) files.append(name) fileIndex += 1 else: log.debug("Practice background filtered: " + name) files.sort() if self.rotationMode > 0 and self.mode != 2: #alarian: blank stage option is not selected #myfingershurt: just populate the image array in order, they are pulled in whatever order requested: for j in range(len(files)): self.engine.loadImgDrawing(self, "backgroundA", os.path.join(self.path, files[j])) self.imgArr.append(getattr(self, "backgroundA", os.path.join(self.path, files[j]))) if self.rotationMode > 0 and len(self.imgArr) == 0: self.rotationMode = 0 #stage rotation def rotate(self): if self.animation: whichDelay = self.animateDelay else: whichDelay = self.rotateDelay self.indexCount = self.indexCount + 1 if self.indexCount > whichDelay: #myfingershurt - adding user setting for stage rotate delay self.indexCount = 0 if self.rotationMode == 1: #QQstarS:random self.arrNum = random.randint(0,len(self.imgArr)-1) elif self.rotationMode == 2: #myfingershurt: in order display mode self.arrNum += 1 if self.arrNum > (len(self.imgArr)-1): self.arrNum = 0 elif self.rotationMode == 3: #myfingershurt: in order, back and forth display mode if self.arrDir == 1: #forwards self.arrNum += 1 if self.arrNum > (len(self.imgArr)-1): self.arrNum -= 2 self.arrDir = 0 else: self.arrNum -= 1 if self.arrNum < 0: self.arrNum += 2 self.arrDir = 1 def renderBackground(self): #myfingershurt: multiple rotation modes if self.mode != 2: if self.rotationMode == 0: drawImage(self.background, scale = (1.0,-1.0), coord = (self.wFull/2,self.hFull/2), stretched = FULL_SCREEN) #myfingershurt: else: #MFH - use precalculated scale factors instead drawImage(self.imgArr[self.arrNum], scale = (1.0,-1.0), coord = (self.wFull/2,self.hFull/2), stretched = FULL_SCREEN) def updateDelays(self): self.rotateDelay = self.engine.config.get("game", "stage_rotate_delay") #myfingershurt - user defined stage rotate delay self.animateDelay = self.engine.config.get("game", "stage_animate_delay") #myfingershurt - user defined stage rotate delay def reset(self): self.lastBeatPos = None self.lastQuarterBeatPos = None self.lastMissPos = None self.lastPickPos = None self.beat = 0 self.quarterBeat = 0 self.pos = 0.0 self.playedNotes = [] self.averageNotes = [0.0] self.beatPeriod = 0.0 def triggerPick(self, pos, notes): if notes: self.lastPickPos = pos self.playedNotes = self.playedNotes[-3:] + [sum(notes) / float(len(notes))] self.averageNotes[-1] = sum(self.playedNotes) / float(len(self.playedNotes)) self.rockmeter.triggerPick(pos, notes) def triggerMiss(self, pos): self.lastMissPos = pos self.rockmeter.triggerMiss(pos) def triggerQuarterBeat(self, pos, quarterBeat): self.lastQuarterBeatPos = pos self.quarterBeat = quarterBeat def triggerBeat(self, pos, beat): self.lastBeatPos = pos self.beat = beat self.averageNotes = self.averageNotes[-4:] + self.averageNotes[-1:] def run(self, pos, period): self.pos = pos self.beatPeriod = period quarterBeat = int(4 * pos / period) if quarterBeat > self.quarterBeat: self.triggerQuarterBeat(pos, quarterBeat) beat = quarterBeat / 4 if beat > self.beat: self.triggerBeat(pos, beat) def renderLayers(self, layers, visibility): if self.mode != 3: with self.engine.view.orthogonalProjection(normalize = True): for layer in layers: layer.render(visibility) def render(self, visibility): if self.mode != 3: self.renderBackground() self.renderLayers(self.backgroundLayers, visibility) if shaders.enable("stage"): height = 0.0 for i in shaders.var["color"].keys(): shaders.modVar("color",shaders.var["color"][i],0.05,10.0) height += shaders.var["color"][i][3]/3.0 height=height**2 shaders.setVar("height",2*height) shaders.setVar("ambientGlow",height/1.5) shaders.setVar("glowStrength",60+height*80.0) gl.glBegin(gl.GL_TRIANGLE_STRIP) gl.glVertex3f(-8.0, 1.0,7.0) gl.glVertex3f(8.0, 1.0,7.0) gl.glVertex3f(-8.0, 4.0,7.0) gl.glVertex3f(8.0, 4.0,7.0) gl.glEnd() shaders.disable() self.scene.renderGuitar() self.renderLayers(self.foregroundLayers, visibility) self.rockmeter.render(visibility)