#!/bin/python # -*- coding: utf-8 -*- """Standard initializations and functions shared by all games.""" from sys import exit import configparser import os from os import listdir from os.path import isfile, join from inspect import isfunction from xdg import BaseDirectory from setproctitle import setproctitle import pyglet import pyperclip import random import re import requests import webbrowser # Global variable for speech provider try: import speechd spd = speechd.Client() speechProvider = "speechd" except ImportError: import accessible_output2.outputs.auto s = accessible_output2.outputs.auto.Auto() speechProvider = "accessible_output2" except ImportError: print("No other speech providers found.") exit() import math import time localConfig = configparser.ConfigParser() globalConfig = configparser.ConfigParser() class scoreboard(): 'Handles scores and top 10' def __init__(self, startingScore = 0): read_config() try: localConfig.add_section("scoreboard") except: pass self.score = startingScore self.oldScores = [] for i in range(1, 11): try: self.oldScores.insert(i - 1, localConfig.getint("scoreboard", str(i))) except: pass self.oldScores.insert(i - 1, 0) for i in range(1, 11): if self.oldScores[i - 1] == None: self.oldScores[i - 1] = 0 def __del__(self): self.Update_Scores() try: write_config() except: pass def Decrease_Score(self, points = 1): self.score -= points def Get_High_Score(self, position = 1): return self.oldScores[position - 1] def Get_Score(self): return self.score def Increase_Score(self, points = 1): self.score += points def New_High_Score(self): for i, j in enumerate(self.oldScores): if self.score > j: return i + 1 return None def Update_Scores(self): # Update the scores for i, j in enumerate(self.oldScores): if self.score > j: self.oldScores.insert(i, self.score) break # Only keep the top 10 scores. self.oldScores = self.oldScores[:10] # Update the scoreboard section of the games config file. for i, j in enumerate(self.oldScores): localConfig.set("scoreboard", str(i + 1), str(j)) def write_config(writeGlobal = False): if writeGlobal == False: with open(gamePath + "/config.ini", 'w') as configfile: localConfig.write(configfile) else: with open(globalPath + "/config.ini", 'w') as configfile: globalConfig.write(configfile) def read_config(readGlobal = False): if readGlobal == False: try: with open(gamePath + "/config.ini", 'r') as configfile: localConfig.read_file(configfile) except: pass else: try: with open(globalPath + "/config.ini", 'r') as configfile: globalConfig.read_file(configfile) except: pass def speak(text, interupt = True): if speechProvider == "speechd": if interupt == True: spd.cancel() spd.say(text) else: if speechProvider == "accessible_output2": s.speak(text, interrupt=True) def exit_game(): if speechProvider == "speechd": spd.close() # Close the pyglet window pyglet.app.exit() def initialize_gui(gameTitle): # Check for, and possibly create, storm-games path global globalPath global gamePath globalPath = BaseDirectory.xdg_config_home + "/storm-games" gamePath = globalPath + "/" + str.lower(str.replace(gameTitle, " ", "-")) if not os.path.exists(gamePath): os.makedirs(gamePath) # Seed the random generator to the clock random.seed() # Set game's name global gameName gameName = gameTitle setproctitle(str.lower(str.replace(gameTitle, " ", ""))) # init pyglet window window = pyglet.window.Window(500, 300, gameTitle) # Load sounds from the sound directory and creates a list like {'bottle': 'bottle.ogg'} soundFiles = [f for f in listdir("sounds/") if isfile(join("sounds/", f)) and (f.split('.')[1].lower() in ["ogg","wav"])] # make a dict with pyglet media {'bottle':} soundData = {} for f in soundFiles: soundData[f.split('.')[0]] = pyglet.media.load("sounds/" + f, streaming = False) soundData['game-intro'].play() time.sleep(soundData['game-intro'].duration) return soundData def cut_scene(sounds, soundName): pygame.event.clear() pygame.mixer.stop() c = pygame.mixer.Channel(0) c.play(sounds[soundName]) while pygame.mixer.get_busy(): event = pygame.event.poll() if event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_RETURN, pygame.K_SPACE]: pygame.mixer.stop() pygame.event.pump() def obj_play(sounds, soundName, playerPos, objPos): distance = playerPos - objPos if distance > 9 or distance < -9: # The item is out of range, so play it at 0 left = 0 right = 0 elif distance == 0: left = 0.9 right = 0.9 else: angle = math.radians(distance * 5) left = math.sqrt(2)/2.0 * (math.cos(angle) + math.sin(angle)) right = math.sqrt(2)/2.0 * (math.cos(angle) - math.sin(angle)) if left < 0: left *= -1 if right < 0: right *= -1 # x is the channel for the sound x = sounds[soundName].play(-1) # Apply the position information to the channel x.set_volume(left, right) # return the channel so that it can be used in the update and stop functions. return x def obj_update(x, playerPos, objPos): distance = playerPos - objPos if distance > 9 or distance < -9: left = 0 right = 0 elif distance == 0: left = 0.9 right = 0.9 else: angle = math.radians(distance * 5) left = math.sqrt(2)/2.0 * (math.cos(angle) + math.sin(angle)) right = math.sqrt(2)/2.0 * (math.cos(angle) - math.sin(angle)) if left < 0: left *= -1 if right < 0: right *= -1 # Apply the position information to the channel x.set_volume(left, right) # return the channel return x def obj_stop(x): # Tries to stop a playing object channel try: x.stop() return None except: return x def play_random(sounds, soundName, pause = False, interrupt = False): key = [] for i in sounds.keys(): if re.match("^" + soundName + ".*", i): key.append(i) randomKey = random.choice(key) if interrupt == False: sounds[randomKey].play() else: cut_scene(sounds, randomKey) # Cut scenes override the pause option return if pause == True: time.sleep(sounds[randomKey].get_length()) def instructions(): # Read in the instructions file try: with open('files/instructions.txt', 'r') as f: info = f.readlines() except: info = ["Instructions file is missing."] display_text(info) def credits(): # Read in the credits file. try: with open('files/credits.txt', 'r') as f: info = f.readlines() # Add the header info.insert(0, gameName + ": brought to you by Storm Dragon") except: info = ["Credits file is missing."] display_text(info) def display_text(text): i = 0 text.insert(0, "Press space to read the whole text. Use up and down arrows to navigate the text line by line. Press c to copy the current line to the clipboard or t to copy the entire text. Press enter or escape when you are done reading.") text.append("End of text.") speak(text[i]) while True: event = pygame.event.wait() if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE or event.key == pygame.K_RETURN: return if event.key == pygame.K_DOWN and i < len(text) - 1: i = i + 1 if event.key == pygame.K_UP and i > 0: i = i - 1 if event.key == pygame.K_SPACE: speak(' '.join(text[1:])) else: speak(text[i]) if event.key == pygame.K_c: try: pyperclip.copy(text[i]) speak("Copied " + text[i] + " to the clipboard.") except: speak("Failed to copy the text to the clipboard.") if event.key == pygame.K_t: try: pyperclip.copy(' '.join(text[1:-1])) speak("Copied entire message to the clipboard.") except: speak("Failed to copy the text to the clipboard.") event = pygame.event.clear() time.sleep(0.001) def learn_sounds(sounds): loop = True pygame.mixer.music.pause() i = 0 soundFiles = [f for f in listdir("sounds/") if isfile(join("sounds/", f)) and (f.split('.')[1].lower() in ["ogg","wav"]) and (f.split('.')[0].lower() not in ["game-intro", "music_menu"])] # j keeps track of last spoken index so it isn't voiced on key up. j = -1 while loop == True: if i != j: speak(soundFiles[i][:-4]) j = i event = pygame.event.wait() if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: return "menu" if event.key == pygame.K_DOWN and i < len(soundFiles) - 1: pygame.mixer.stop() i = i + 1 if event.key == pygame.K_UP and i > 0: pygame.mixer.stop() i = i - 1 if event.key == pygame.K_RETURN: try: soundName = soundFiles[i][:-4] pygame.mixer.stop() sounds[soundName].play() continue except: j = -1 speak("Could not play sound.") continue event = pygame.event.clear() time.sleep(0.001) def game_menu(sounds, *options): loop = True pygame.mixer.stop() if pygame.mixer.music.get_busy(): pygame.mixer.music.unpause() else: pygame.mixer.music.load("sounds/music_menu.ogg") pygame.mixer.music.set_volume(0.75) pygame.mixer.music.play(-1) i = 0 # j keeps track of last spoken index so it isn't voiced on key up. j = -1 while loop == True: if i != j: speak(options[i]) j = i event = pygame.event.wait() if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: exit_game() if event.key == pygame.K_DOWN and i < len(options) - 1: i = i + 1 try: sounds['menu-move'].play() except: pass if options[i] != "donate": pygame.mixer.music.unpause() if event.key == pygame.K_UP and i > 0: i = i - 1 try: sounds['menu-move'].play() except: pass if options[i] != "donate": pygame.mixer.music.unpause() if event.key == pygame.K_HOME and i != 0: i = 0 try: sounds['menu-move'].play() except: pass if options[i] != "donate": pygame.mixer.music.unpause() if event.key == pygame.K_END and i != len(options) - 1: i = len(options) -1 try: sounds['menu-move'].play() except: pass if options[i] != "donate": pygame.mixer.music.unpause() if event.key == pygame.K_RETURN: try: j = -1 try: sounds['menu-select'].play() time.sleep(sounds['menu-select'].get_length()) except: pass eval(options[i] + "()") continue except: j = -1 return options[i] continue event = pygame.event.clear() time.sleep(0.001) def donate(): pygame.mixer.music.pause() webbrowser.open('https://ko-fi.com/stormux')