def play(screen, playlist, configs, songconf, playmode): numplayers = len(configs) game = games.GAMES[playmode] songs_played = 0 # Decides whether or not the Ready?/Go! should be displayed before # the song. first = True display_songinfo = (mainconfig['songinfoscreen'] == 2 or (mainconfig['songinfoscreen'] == 1 and len(playlist) != 1)) songdata = None players = [] for playerID in range(numplayers): plr = Player(playerID, configs[playerID], songconf, game) players.append(plr) for songfn, diff in playlist: try: current_song = fileparsers.SongItem(songfn) except None: error.ErrorMessage( screen, _("There was an error loading ") + os.path.split(songfn)[1]) first = True continue songs_played += 1 prevscr = pygame.transform.scale(screen, (640, 480)) songdata = steps.SongData(current_song, songconf) if display_songinfo: if not SongInfoScreen(current_song, diff, playmode, songconf, configs, screen).proceed_to_song: break for playerID in range(numplayers): for opt, dummy in changeable_between: players[playerID].__dict__[opt] = configs[playerID][opt] for pid, player in enumerate(players): player.set_song(current_song, diff[pid], songdata.lyricdisplay) print(_("Playing"), songfn) print(songdata.title.encode(STDOUT_ENCODING, "replace"), "by", end=' ') print(songdata.artist.encode(STDOUT_ENCODING, "replace")) if dance(screen, songdata, players, prevscr, first, game): first = False break # Failed first = False if True in [p.escaped for p in players]: break if mainconfig['grading'] and not first and songdata: grade = gradescreen.GradingScreen(screen, players, songdata.banner) if songconf["audiosync"] == 2: old_offset = mainconfig["masteroffset"] new_offset = old_offset + players[0].stats.offset() # Do not just replace masteroffset with new offset. Feed it into masteroffset # with 33% significance. That way we approach the correct value across multiple # plays and avoid messing up the value based on a single "bad" play. mainconfig["masteroffset"] = (old_offset * 2 + new_offset) // 3 # If we only play one song (all the way through), then it's safe to enter # a grade. This means course grades are going to get kind of messy, # and have to be handled by the course stuff rather than here. if songs_played == 1 and not players[0].escaped: for p in players: if not p.failed: records.add(current_song.info["recordkey"], diff[p.pid], playmode, p.grade.rank(), " ") else: records.add(current_song.info["recordkey"], diff[p.pid], playmode, -2, " ")
def dance(screen, song, players, prevscr, ready_go, game): songFailed = False # text group, e.g. judgings and combos tgroup = RenderUpdates() # lyric display group lgroup = RenderUpdates() background = pygame.Surface([640, 480]) if song.movie != None: backmovie = BGMovie(song.movie) else: backmovie = None background.fill(colors.BLACK) screen.fill(colors.BLACK) if ready_go: ready_go_time = min(100, *[plr.ready for plr in players]) tgroup.add(ReadyGoSprite(ready_go_time)) if mainconfig['showbackground'] > 0: if backmovie is None: bgkludge = pygame.image.load(song.background).convert() bgkrect = bgkludge.get_rect() if (bgkrect.size[0] == 320) and (bgkrect.size[1] == 240): bgkludge = pygame.transform.scale2x(bgkludge) else: bgkludge = pygame.transform.scale(bgkludge, [640, 480]) bgkludge.set_alpha(mainconfig['bgbrightness'], RLEACCEL) q = mainconfig['bgbrightness'] / 256.0 # FIXME for i in range(0, 101, 5): p = i / 100.0 prevscr.set_alpha(256 * (1 - p) * q, RLEACCEL) screen.fill(colors.BLACK) screen.blit(prevscr, [0, 0]) screen.blit(bgkludge, [0, 0]) pygame.display.update() pygame.time.delay(1) background.blit(bgkludge, [0, 0]) else: pygame.display.update() else: pygame.display.update() if mainconfig["strobe"]: tgroup.add(Blinky(song.bpm)) if mainconfig["fpsdisplay"]: fpstext = FPSDisp() timewatch = TimeDisp() tgroup.add([fpstext, timewatch]) else: fpstext = None if mainconfig['showlyrics']: lgroup.add(song.lyricdisplay.channels()) fontfn, basesize = FontTheme.Dance_title_artist songtext = fontfx.zztext(song.title, 480, 12, basesize, fontfn) grptext = fontfx.zztext(song.artist, 160, 12, basesize, fontfn) songtext.zin() grptext.zin() tgroup.add([songtext, grptext]) song.init() if song.crapout != 0: error.ErrorMessage( screen, _("The audio file for this song ") + song.filename + _(" could not be found.")) return False # The player didn't fail. if mainconfig['assist']: music.set_volume(0.6) else: music.set_volume(1.0) song.play() for plr in players: plr.start_song() autofail = mainconfig['autofail'] screenshot = False ui.ui.clear() while True: if autofail: songFailed = True for plr in players: if not plr.lifebar.gameover: songFailed = False break if songFailed: song.kill() for plr in players: plr.get_next_events(song) if song.is_over(): break else: curtime = music.get_pos() / 1000.0 key = [] ev = ui.ui.poll_dance() while ev[1] != ui.PASS: if ev[1] == ui.CANCEL: for p in players: p.escaped = True return False elif ev[1] == ui.SCREENSHOT: screenshot = True elif ev[1] == ui.LEFT: key.append((ev[0], 'l')) elif ev[1] == ui.DOWNLEFT: key.append((ev[0], 'w')) elif ev[1] == ui.UPLEFT: key.append((ev[0], 'k')) elif ev[1] == ui.RIGHT: key.append((ev[0], 'r')) elif ev[1] == ui.UPRIGHT: key.append((ev[0], 'z')) elif ev[1] == ui.DOWNRIGHT: key.append((ev[0], 'g')) elif ev[1] == ui.UP: key.append((ev[0], 'u')) elif ev[1] == ui.DOWN: key.append((ev[0], 'd')) elif ev[1] == ui.CENTER: key.append((ev[0], 'c')) elif ev[1] == -ui.LEFT: key.append((ev[0], '-l')) elif ev[1] == -ui.DOWNLEFT: key.append((ev[0], '-w')) elif ev[1] == -ui.UPLEFT: key.append((ev[0], '-k')) elif ev[1] == -ui.RIGHT: key.append((ev[0], '-r')) elif ev[1] == -ui.UPRIGHT: key.append((ev[0], '-z')) elif ev[1] == -ui.DOWNRIGHT: key.append((ev[0], '-g')) elif ev[1] == -ui.UP: key.append((ev[0], '-u')) elif ev[1] == -ui.DOWN: key.append((ev[0], '-d')) elif ev[1] == -ui.CENTER: key.append((ev[0], '-c')) ev = ui.ui.poll_dance() for ev in key: if game.double: pid = ev[0] / 2 else: pid = ev[0] if pid >= 0 and pid < len(players): if ev[1][0] != '-': players[pid].handle_keydown(ev, curtime) else: players[pid].handle_keyup((ev[0], ev[1][1:]), curtime) rectlist = [] if backmovie: backmovie.update(curtime) if backmovie.changed or (fpstext.fps() > 30): backmovie.resetchange() screen.blit(backmovie.image, [0, 0]) for plr in players: rectlist.extend(plr.game_loop(curtime, screen)) lgroup.update(curtime) tgroup.update(curtime) rectlist.extend(tgroup.draw(screen)) rectlist.extend(lgroup.draw(screen)) if backmovie is None: pygame.display.update(rectlist) else: pygame.display.update() if screenshot: fn = os.path.join(rc_path, "screenshot.bmp") print(_("Saving a screenshot to"), fn) pygame.image.save(screen, fn) screenshot = False if backmovie is None: lgroup.clear(screen, background) tgroup.clear(screen, background) for plr in players: plr.clear_sprites(screen, background) if ((curtime > players[0].length - 1) and (songtext.zdir == 0) and (songtext.zoom > 0)): songtext.zout() grptext.zout() if fpstext: print(_("Average FPS for this song was %d.") % fpstext.fps()) return songFailed
def loop(self): pid, ev = ui.ui.poll() self._list.set_index(self._index) self._title.set_text(self._base_text + " - %d/%d" % (self._index + 1, len(self._songitems))) while not (ev == ui.CANCEL and (not self._folders or self._song.isfolder)): # Inactive player. If the event isn't set to ui.PASS, we try to use # the pid later, which will be bad. if pid >= len(self._diff_names): ev = ui.PASS elif pid >= 0 and ev in (ui.UP, ui.DOWN): # Only use menuing UP/DOWN ev = ui.PASS elif pid < 0 and ev in ( ui.LEFT, ui.RIGHT): # Need LEFT/RIGHT player-specific ev = ui.PASS elif ev == ui.UP: self._index -= 1 elif ev == ui.DOWN: self._index += 1 elif ev == ui.PGUP: self._index -= 7 ev = ui.UP elif ev == ui.PGDN: self._index += 7 ev = ui.DOWN elif ev == ui.LEFT: if not self._song.isfolder: namei = self._song.diff_list.index(self._diff_names[pid]) namei = (namei - 1) % len(self._song.diff_list) name = self._song.diff_list[namei] self._diff_names[pid] = name self._pref_diff_names[pid] = name self._last_player = pid elif ev == ui.RIGHT: if not self._song.isfolder: namei = self._song.diff_list.index(self._diff_names[pid]) namei = (namei + 1) % len(self._song.diff_list) name = self._song.diff_list[namei] self._diff_names[pid] = name self._pref_diff_names[pid] = name self._last_player = pid elif ev == ui.RANDOM: if self._song.isfolder: if len(self._all_valid_songitems) > 0: self._song = random.choice(self._all_valid_songitems) fol = self._song.folder[SORT_NAMES[ mainconfig["sortmode"]]] self._create_song_list(fol) self._index = self._songitems.index(self._song) else: error.ErrorMessage( screen, _("You don't have any songs that are marked ") + _("\"valid\" for random selection.")) else: valid_songs = [ s for s in self._songitems if s.info["valid"] ] if len(valid_songs) > 0: self._song = random.choice(valid_songs) self._index = self._songitems.index(self._song) else: error.ErrorMessage( screen, _("You don't have any songs here that ") + _("are marked \"valid\" for random selection.")) elif ev == ui.OPTIONS: opts = options.OptionScreen(self._configs, self._config, self._screen) self._screen.blit(self._bg, [0, 0]) self.update() pygame.display.update() if opts.start_dancing: ev = ui.CONFIRM continue elif ev == ui.SORT: s = self._songitems[self._index] mainconfig["sortmode"] = (mainconfig["sortmode"] + 1) % NUM_SORTS sort_name = self._update_songitems() if self._folders: if s.isfolder: self._create_folder_list() else: s = self._find_resorted() self._create_song_list(s.folder[sort_name]) self._index = self._songitems.index(s) else: s = self._find_resorted() self._base_text = _(sort_name).upper() self._songitems.sort(key=SORTS[sort_name]) self._index = self._songitems.index(s) self._list.set_items( [s.info["title"] for s in self._songitems]) elif ev == ui.CONFIRM: if self._song.isfolder: self._create_song_list(self._song.name) self._index = 0 else: music.fadeout(500) dance.play(self._screen, [(self._song.filename, self._diff_names)], self._configs, self._config, self._game) music.fadeout(500) # The just-played song self._screen.blit(self._bg, [0, 0]) pygame.display.update() ui.ui.clear() elif ev == ui.CANCEL: # first: get the parent folder of the active song sort_name = SORT_NAMES[mainconfig["sortmode"]] fol = folder_name(self._song.folder[sort_name], sort_name) # next: change folder self._create_folder_list() for d in self._diff_widgets: d.set("None", [127, 127, 127], 0, "?") lst = [s.info["title"] for s in self._songitems] self._index = lst.index(fol) elif ev == ui.FULLSCREEN: mainconfig["fullscreen"] ^= 1 pygame.display.toggle_fullscreen() self._index %= len(self._songitems) self._song = self._songitems[self._index] if self._locked and ev in [ui.LEFT, ui.RIGHT]: for i, sd in enumerate(self._diff_names): self._diff_names[i] = self._diff_names[pid] self._pref_diff_names[i] = self._diff_names[pid] if ev in [ ui.CANCEL, ui.UP, ui.DOWN, ui.RANDOM, ui.CONFIRM, ui.SORT ]: self._preview.preview(self._song) self._banner.set_song(self._song) if ev in [ ui.CANCEL, ui.UP, ui.DOWN, ui.RANDOM, ui.CONFIRM, ui.SORT ]: if ev == ui.UP: self._list.set_index(self._index, -1) elif ev == ui.DOWN: self._list.set_index(self._index, 1) else: self._list.set_index(self._index, 0) # don't animate self._title.set_text(self._base_text + " - %d/%d" % (self._index + 1, len(self._songitems))) if ev in [ui.UP, ui.DOWN, ui.RANDOM, ui.SORT, ui.CONFIRM]: if not self._song.isfolder: for pl, dname in enumerate(self._diff_names): name = self._pref_diff_names[pl] if name in self._song.diff_list: self._diff_names[pl] = name elif self._unify_difficulties( name) in self._song.diff_list: self._diff_names[pl] = self._unify_difficulties( name) else: # if both name and the song's difficulty list can be indexed: # find the nearest defined difficulty if (name in util.DIFFICULTY_LIST or self._unify_difficulties(name) in util.DIFFICULTY_LIST) and \ reduce(lambda a,b: a and b in util.DIFFICULTY_LIST, self._song.diff_list , True ): name = self._unify_difficulties(name) namei = util.DIFFICULTY_LIST.index(name) diffi = [ util.DIFFICULTY_LIST.index(d) for d in self._song.diff_list ] dds = [abs(d - namei) for d in diffi] self._diff_names[pl] = self._song.diff_list\ [dds.index(min(dds))] else: # no sensible way to resolve this: jump to middle of list difflen = len(self._song.diff_list) self._diff_names[pl] = self._song.diff_list[ difflen / 2] if ev in [ ui.UP, ui.DOWN, ui.LEFT, ui.RIGHT, ui.RANDOM, ui.CONFIRM ]: if not self._song.isfolder: for i, name in enumerate(self._diff_names): rank = records.get(self._song.info["recordkey"], name, self._game)[0] grade = grades.grades[ self._config["grade"]].grade_by_rank(rank) self._diff_widgets[i].set( name, DIFF_COLORS.get(name, [127, 127, 127]), self._song.difficulty[name], grade) self.update() pid, ev = ui.ui.poll()
def __init__(self, songs, courses, screen, game): InterfaceWindow.__init__(self, screen, "newss-bg.png") songs = [s for s in songs if s.difficulty.has_key(game)] if len(songs) == 0: error.ErrorMessage( screen, _("You don't have any songs for the game mode (") + game + _(") that you selected.") ) #TODO: format using % for better i18n return # Construct a mapping between songs displays and dance displays. songs_and_dances = [ (SongItemDisplay(s, game), [DanceItemDisplay(s, game, diff) for diff in s.diff_list[game]]) for s in songs ] for (s, ds) in songs_and_dances: for d in ds: s.danceitems[d.diff] = d d.songitem = s self._songs = [s[0] for s in songs_and_dances] self._dances = reduce(lambda x, y: x + y[1], songs_and_dances, []) self._index = 0 self._game = game self._config = dict(game_config) self._all_songs = self._songs self._all_dances = self._dances self._all_valid_songs = [s for s in self._songs if s.info["valid"]] self._all_valid_dances = [d for d in self._dances if d.info["valid"]] self._list = ListBox(FontTheme.SongSel_list, [255, 255, 255], 26, 16, 220, [408, 56]) # please use set constructions after python 2.4 is adopted sort_name = self._update_songitems() if mainconfig["folders"]: self._create_folders() self._create_folder_list() else: self._folders = None self._base_text = sort_name.upper() self._songitems.sort(key=SORTS[sort_name]) self._list.set_items([s.info["title"] for s in self._songitems]) self._preview = SongPreview() self._preview.preview(self._songitems[self._index]) self._song = self._songitems[self._index] # Both players must have the same difficulty in locked modes. self._locked = games.GAMES[self._game].couple players = games.GAMES[game].players # self._diffs = [] # Current difficulty setting self._diff_widgets = [] # Difficulty widgets self._configs = [] self._diff_names = [] # Current chosen difficulties self._pref_diff_names = [] # Last manually selected difficulty names self._last_player = 0 # Last player to change a difficulty for i in range(players): self._configs.append(dict(player_config)) d = DifficultyBox([84 + (233 * i), 434]) self._pref_diff_names.append(util.DIFFICULTY_LIST[0]) if not self._song.isfolder: self._diff_names.append(self._song.diff_list[0]) diff_name = self._diff_names[i] rank = records.get(self._song.info["recordkey"], diff_name, self._game)[0] grade = grades.grades[self._config["grade"]].grade_by_rank( rank) d.set(diff_name, DIFF_COLORS.get(diff_name, [127, 127, 127]), self._song.difficulty[diff_name], grade) else: self._diff_names.append(" ") d.set(_("None"), [127, 127, 127], 0, "?") self._diff_widgets.append(d) ActiveIndicator([405, 259], width=230).add(self._sprites) self._banner = BannerDisplay([205, 230]) self._banner.set_song(self._song) self._sprites.add( HelpText(SS_HELP, [255, 255, 255], [0, 0, 0], FontTheme.help, [206, 20])) self._title = TextDisplay('SongSel_sort_mode', [210, 28], [414, 27]) self._sprites.add(self._diff_widgets + [self._banner, self._list, self._title]) self._screen.blit(self._bg, [0, 0]) pygame.display.update() self.loop() music.fadeout(500) pygame.time.wait(500) # FIXME Does this belong in the menu code? Probably. music.load(os.path.join(sound_path, "menu.ogg")) music.set_volume(1.0) music.play(4, 0.0) player_config.update(self._configs[0]) # Save p1's settings game_config.update(self._config) # save game settings
def __init__(self, songitems, courses, screen, gametype): InterfaceWindow.__init__(self, screen, "endless-bg.png") pygame.display.update() self.player_configs = [dict(player_config)] if games.GAMES[gametype].players == 2: self.player_configs.append(dict(player_config)) self.game_config = dict(game_config) songitems = [s for s in songitems if s.difficulty.has_key(gametype)] # Autofail always has to be on for endless, so back up the old value. oldaf = mainconfig["autofail"] diffs = [] diff_count = {} # if we see a difficulty 2 times or more, use it for song in songitems: if song.difficulty.has_key(gametype): for d in song.difficulty[gametype]: if diff_count.has_key(d) and d not in diffs: diffs.append(d) else: diff_count[d] = True diffs.sort(util.difficulty_sort) if len(diffs) == 0: error.ErrorMessage( screen, _("You need more songs to play Endless Mode. ") + _("Otherwise, it's just really boring.")) return mainconfig["autofail"] = 1 self.constraints = [ Constraint("name", songitems[0].difficulty[gametype].keys()[0]) ] if games.GAMES[gametype].players == 2: if games.GAMES[gametype].couple == True: # Lock both players to the same constraints in couple modes. self.constraints.append(self.constraints[0]) else: c = Constraint("name", songitems[0].difficulty[gametype].keys()[0]) self.constraints.append(c) for i, c in enumerate(self.constraints): EndlessDiffDisplay(i, c).add(self._sprites) self._sprites.add( HelpText(ENDLESS_HELP, [255, 255, 255], [0, 0, 0], FontTheme.help, [320, 20])) music.load(os.path.join(sound_path, "menu.ogg")) music.play(4, 0.0) pid, ev = 0, ui.PASS while ev != ui.QUIT: pid, ev = ui.ui.poll() if ev == ui.START: options.OptionScreen(self.player_configs, self.game_config, screen) self._screen.blit(self._bg, [0, 0]) pygame.display.update() # Start game elif ev == ui.CONFIRM: dance.play( screen, FakePlaylist(songitems, self.constraints, screen, gametype), self.player_configs, self.game_config, gametype) self._screen.blit(self._bg, [0, 0]) pygame.display.update() music.load(os.path.join(sound_path, "menu.ogg")) music.play(4, 0.0) ui.ui.clear() # Ignore unknown events elif pid >= len(self.constraints): pass elif ev == ui.DOWN and self.constraints[pid].kind != "name": self.constraints[pid].kind = "name" self.constraints[pid].value = diffs[0] elif ev == ui.UP and self.constraints[pid].kind != "number": self.constraints[pid].kind = "number" self.constraints[pid].value = (1, 3) elif ev == ui.LEFT: # easier if self.constraints[pid].kind == "name": newi = max(0, diffs.index(self.constraints[pid].value) - 1) self.constraints[pid].value = diffs[newi] elif self.constraints[pid].kind == "number": newmin = max(self.constraints[pid].value[0] - 1, 1) self.constraints[pid].value = (newmin, newmin + 2) elif ev == ui.RIGHT: # harder if self.constraints[pid].kind == "name": newi = min( len(diffs) - 1, diffs.index(self.constraints[pid].value) + 1) self.constraints[pid].value = diffs[newi] elif self.constraints[pid].kind == "number": newmin = min(self.constraints[pid].value[0] + 1, 9) self.constraints[pid].value = (newmin, newmin + 2) elif ev == ui.FULLSCREEN: mainconfig["fullscreen"] ^= 1 pygame.display.toggle_fullscreen() self.update() mainconfig["autofail"] = oldaf player_config.update(self.player_configs[0])
def play(screen, playlist, configs, songconf, playmode): numplayers = len(configs) game = games.GAMES[playmode] songs_played = 0 # Decides whether or not the Ready?/Go! should be displayed before # the song. first = True display_songinfo = (mainconfig['songinfoscreen'] == 2 or (mainconfig['songinfoscreen'] == 1 and len(playlist) != 1)) songdata = None players = [] for playerID in range(numplayers): plr = Player(playerID, configs[playerID], songconf, game) players.append(plr) for songfn, diff in playlist: try: current_song = fileparsers.SongItem(songfn) except None: error.ErrorMessage( screen, _("There was an error loading ") + os.path.split(songfn)[1]) first = True continue songs_played += 1 prevscr = pygame.transform.scale(screen, (640, 480)) songdata = steps.SongData(current_song, songconf) if display_songinfo: if not SongInfoScreen(current_song, diff, playmode, songconf, configs, screen).proceed_to_song: break for playerID in range(numplayers): for opt, dummy in changeable_between: players[playerID].__dict__[opt] = configs[playerID][opt] for pid, player in enumerate(players): player.set_song(current_song, diff[pid], songdata.lyricdisplay) print _("Playing"), songfn print songdata.title.encode(sys.stdout.encoding, "replace"), "by", print songdata.artist.encode(sys.stdout.encoding, "replace") if dance(screen, songdata, players, prevscr, first, game): first = False break # Failed first = False if True in [p.escaped for p in players]: break if mainconfig['grading'] and not first and songdata: grade = gradescreen.GradingScreen(screen, players, songdata.banner) # If we only play one song (all the way through), then it's safe to enter # a grade. This means course grades are going to get kind of messy, # and have to be handled by the course stuff rather than here. if songs_played == 1 and not players[0].escaped: for p in players: if not p.failed: records.add(current_song.info["recordkey"], diff[p.pid], playmode, p.grade.rank(), " ") else: records.add(current_song.info["recordkey"], diff[p.pid], playmode, -2, " ")
def __next__(self): # We're done. if self.index == len(self.songs): raise StopIteration name, diff, mods = self.songs[self.index] fullname = None a, b = 0, 0 if isinstance(diff, list): pass elif diff.find("..") != -1: a, b = list(map(int, diff.split(".."))) elif len(diff) < 3: a, b = int(diff), int(diff) if a or b: diff = list(range(a, b + 1)) # Check for player's best/worst/likes/dislikes. There are stored # as a tuple of (type, number). if name[0] == _("BEST"): s = self.recordkeys.get(records.best(name[1], diff, self.gametype), None) if s: fullname = s.filename if isinstance(diff, list): diff = [ d for d in diff if d in s.difficulty[self.gametype] ][0] elif name[0] == _("WORST"): s = self.recordkeys.get( records.worst(name[1], diff, self.gametype), None) if s: fullname = s.filename if isinstance(diff, list): diff = [ d for d in diff if d in s.difficulty[self.gametype] ][0] elif name[0] == _("LIKES"): s = self.recordkeys.get(records.like(name[1], diff, self.gametype), None) if s: fullname = s.filename if isinstance(diff, list): diff = [ d for d in diff if d in s.difficulty[self.gametype] ][0] elif name[0] == _("DISLIKES"): s = self.recordkeys.get( records.dislike(name[1], diff, self.gametype), None) if s: fullname = s.filename if isinstance(diff, list): diff = [ d for d in diff if d in s.difficulty[self.gametype] ][0] elif name[-1] == "*": # A random song # First pull out all the songs that we might be acceptable. if "/" in name: # Random song from a specific mix. folder, dummy = name.split("/") folder = folder.lower() if folder in self.all_songs: songs = [ s for s in list(self.all_songs[folder].values()) if (s, diff) not in self.past_songs ] else: error.ErrorMessage(self.screen, folder + _(" was not found.")) raise StopIteration else: # Any random song. songs = [] for v in list(self.all_songs.values()): songs.extend(list(v.values())) songs = [ s for s in songs if (s, diff) not in self.past_songs and self._find_difficulty(s, diff) ] if len(songs) == 0: error.ErrorMessage(self.screen, _("No valid songs were found.")) raise StopIteration else: song = random.choice(songs) diff = self._find_difficulty(song, diff) fullname = song.filename # Let's try to find the damned song. # Unfortunately, it can be given as just a title(+subtitle), or a # mix with a title. Or a filename. That's why we need the # all_songs hash. else: for path in mainconfig["songdir"].split(os.pathsep): fn = os.path.join(path, name) fn = os.path.expanduser(fn) if os.path.isfile(fn): fullname = fn elif os.path.isdir(fn): file_list = util.find(fn, ["*.sm", "*.dwi"], 1) if len(file_list) != 0: fullname = file_list[0] if fullname: break if not fullname and len(name[0]) == 1: # Still haven't found it... folder, song = name.split("/") song = self.all_songs.get(folder.lower(), {}).get(song.lower()) if song: fullname = song.filename if not fullname: if len(name[0]) > 1: name = _("Player's %s #%d") % (name[0].capitalize(), name[1]) error.ErrorMessage(self.screen, name + _("was not found.")) raise StopIteration self.index += 1 self.past_songs.append((fullname, diff)) return (fullname, [diff] * len(self.player_configs))