Compare commits
	
		
			3 Commits
		
	
	
		
			e7d5b03e55
			...
			testing
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e1451f69b0 | ||
| 
						 | 
					401b2a8527 | ||
| 
						 | 
					639198e8de | 
							
								
								
									
										1081
									
								
								__init__.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										1081
									
								
								__init__.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										511
									
								
								libstormgames.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										511
									
								
								libstormgames.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,511 @@
 | 
				
			|||||||
 | 
					#!/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 pygame
 | 
				
			||||||
 | 
					import pyperclip
 | 
				
			||||||
 | 
					import random
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import requests
 | 
				
			||||||
 | 
					import textwrap
 | 
				
			||||||
 | 
					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 numpy as np
 | 
				
			||||||
 | 
					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: spd.cancel()
 | 
				
			||||||
 | 
					        spd.say(text)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        if speechProvider == "accessible_output2":
 | 
				
			||||||
 | 
					            s.speak(text, interrupt=True)
 | 
				
			||||||
 | 
					    # Display the text on screen
 | 
				
			||||||
 | 
					    screen = pygame.display.get_surface()
 | 
				
			||||||
 | 
					    font = pygame.font.Font(None, 36)
 | 
				
			||||||
 | 
					    # Wrap the text
 | 
				
			||||||
 | 
					    maxWidth = screen.get_width() - 40  # Leave a 20-pixel margin on each side
 | 
				
			||||||
 | 
					    wrappedText = textwrap.wrap(text, width=maxWidth // font.size('A')[0])
 | 
				
			||||||
 | 
					    # Render each line
 | 
				
			||||||
 | 
					    textSurfaces = [font.render(line, True, (255, 255, 255)) for line in wrappedText]
 | 
				
			||||||
 | 
					    screen.fill((0, 0, 0))  # Clear screen with black
 | 
				
			||||||
 | 
					    # Calculate total height of text block
 | 
				
			||||||
 | 
					    totalHeight = sum(surface.get_height() for surface in textSurfaces)
 | 
				
			||||||
 | 
					    # Start y-position (centered vertically)
 | 
				
			||||||
 | 
					    currentY = (screen.get_height() - totalHeight) // 2
 | 
				
			||||||
 | 
					    # Blit each line of text
 | 
				
			||||||
 | 
					    for surface in textSurfaces:
 | 
				
			||||||
 | 
					        textRect = surface.get_rect(center=(screen.get_width() // 2, currentY + surface.get_height() // 2))
 | 
				
			||||||
 | 
					        screen.blit(surface, textRect)
 | 
				
			||||||
 | 
					        currentY += surface.get_height()
 | 
				
			||||||
 | 
					    pygame.display.flip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def check_for_exit():
 | 
				
			||||||
 | 
					    for event in pygame.event.get():
 | 
				
			||||||
 | 
					        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					    pygame.event.pump()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def exit_game():
 | 
				
			||||||
 | 
					    if speechProvider == "speechd": spd.close()
 | 
				
			||||||
 | 
					    pygame.mixer.music.stop()
 | 
				
			||||||
 | 
					    pygame.quit()
 | 
				
			||||||
 | 
					    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, " ", "")))
 | 
				
			||||||
 | 
					    # start pygame
 | 
				
			||||||
 | 
					    pygame.init()
 | 
				
			||||||
 | 
					    # start the display (required by the event loop)
 | 
				
			||||||
 | 
					    pygame.display.set_mode((800, 600))
 | 
				
			||||||
 | 
					    pygame.display.set_caption(gameTitle)
 | 
				
			||||||
 | 
					    # Set 32 channels for sound by default
 | 
				
			||||||
 | 
					    pygame.mixer.pre_init(44100, -16, 2, 1024)
 | 
				
			||||||
 | 
					    pygame.mixer.init()
 | 
				
			||||||
 | 
					    pygame.mixer.set_num_channels(32)
 | 
				
			||||||
 | 
					    # Reserve the cut scene channel
 | 
				
			||||||
 | 
					    pygame.mixer.set_reserved(0)
 | 
				
			||||||
 | 
					    # Load sounds from the sound directory and creates a list like {'bottle': 'bottle.ogg'}
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        soundFiles = [f for f in listdir("sounds/") if isfile(join("sounds/", f)) and (f.split('.')[1].lower() in ["ogg","wav"])]
 | 
				
			||||||
 | 
					    except Exception as e:
 | 
				
			||||||
 | 
					        print("No sounds found.")
 | 
				
			||||||
 | 
					        speak("No sounds found.", False)
 | 
				
			||||||
 | 
					    #lets make a dict with pygame.mixer.Sound() objects {'bottle':<soundobject>}
 | 
				
			||||||
 | 
					    soundData = {}
 | 
				
			||||||
 | 
					    for f in soundFiles:
 | 
				
			||||||
 | 
					        soundData[f.split('.')[0]] = pygame.mixer.Sound("sounds/" + f)
 | 
				
			||||||
 | 
					    soundData['game-intro'].play()
 | 
				
			||||||
 | 
					    time.sleep(soundData['game-intro'].get_length())
 | 
				
			||||||
 | 
					    return soundData
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def generate_tone(frequency, duration=0.1, sample_rate=44100, volume = 0.2):
 | 
				
			||||||
 | 
					    t = np.linspace(0, duration, int(sample_rate * duration), False)
 | 
				
			||||||
 | 
					    tone = np.sin(2 * np.pi * frequency * t)
 | 
				
			||||||
 | 
					    stereo_tone = np.vstack((tone, tone)).T  # Create a 2D array for stereo
 | 
				
			||||||
 | 
					    stereo_tone = (stereo_tone * 32767).astype(np.int16)
 | 
				
			||||||
 | 
					    stereo_tone = (stereo_tone * 32767 * volume).astype(np.int16)  # Apply volume
 | 
				
			||||||
 | 
					    stereo_tone = np.ascontiguousarray(stereo_tone)  # Ensure C-contiguous array
 | 
				
			||||||
 | 
					    return pygame.sndarray.make_sound(stereo_tone)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def x_powerbar():
 | 
				
			||||||
 | 
					    clock = pygame.time.Clock()
 | 
				
			||||||
 | 
					    screen = pygame.display.get_surface()
 | 
				
			||||||
 | 
					    position = -50  # Start from the leftmost position
 | 
				
			||||||
 | 
					    direction = 1   # Move right initially
 | 
				
			||||||
 | 
					    barHeight = 20
 | 
				
			||||||
 | 
					    while True:
 | 
				
			||||||
 | 
					        frequency = 440  # A4 note
 | 
				
			||||||
 | 
					        leftVolume = (50 - position) / 100
 | 
				
			||||||
 | 
					        rightVolume = (position + 50) / 100
 | 
				
			||||||
 | 
					        tone = generate_tone(frequency)
 | 
				
			||||||
 | 
					        channel = tone.play()
 | 
				
			||||||
 | 
					        channel.set_volume(leftVolume, rightVolume)
 | 
				
			||||||
 | 
					        # Visual representation
 | 
				
			||||||
 | 
					        screen.fill((0, 0, 0))
 | 
				
			||||||
 | 
					        barWidth = screen.get_width() - 40  # Leave 20px margin on each side
 | 
				
			||||||
 | 
					        pygame.draw.rect(screen, (100, 100, 100), (20, screen.get_height() // 2 - barHeight // 2, barWidth, barHeight))
 | 
				
			||||||
 | 
					        markerPos = int(20 + (position + 50) / 100 * barWidth)
 | 
				
			||||||
 | 
					        pygame.draw.rect(screen, (255, 0, 0), (markerPos - 5, screen.get_height() // 2 - barHeight, 10, barHeight * 2))
 | 
				
			||||||
 | 
					        pygame.display.flip()
 | 
				
			||||||
 | 
					        for event in pygame.event.get():
 | 
				
			||||||
 | 
					            check_for_exit()
 | 
				
			||||||
 | 
					            if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
 | 
				
			||||||
 | 
					                channel.stop()
 | 
				
			||||||
 | 
					                return position  # This will return a value between -50 and 50
 | 
				
			||||||
 | 
					        position += direction
 | 
				
			||||||
 | 
					        if position > 50:
 | 
				
			||||||
 | 
					            position = 50
 | 
				
			||||||
 | 
					            direction = -1
 | 
				
			||||||
 | 
					        elif position < -50:
 | 
				
			||||||
 | 
					            position = -50
 | 
				
			||||||
 | 
					            direction = 1
 | 
				
			||||||
 | 
					        clock.tick(40) # Speed of bar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def y_powerbar():
 | 
				
			||||||
 | 
					    clock = pygame.time.Clock()
 | 
				
			||||||
 | 
					    screen = pygame.display.get_surface()
 | 
				
			||||||
 | 
					    power = 0
 | 
				
			||||||
 | 
					    direction = 1  # 1 for increasing, -1 for decreasing
 | 
				
			||||||
 | 
					    barWidth = 20
 | 
				
			||||||
 | 
					    while True:
 | 
				
			||||||
 | 
					        frequency = 220 + (power * 5)  # Adjust these values to change the pitch range
 | 
				
			||||||
 | 
					        tone = generate_tone(frequency)
 | 
				
			||||||
 | 
					        channel = tone.play()
 | 
				
			||||||
 | 
					        # Visual representation
 | 
				
			||||||
 | 
					        screen.fill((0, 0, 0))
 | 
				
			||||||
 | 
					        barHeight = screen.get_height() - 40  # Leave 20px margin on top and bottom
 | 
				
			||||||
 | 
					        pygame.draw.rect(screen, (100, 100, 100), (screen.get_width() // 2 - barWidth // 2, 20, barWidth, barHeight))
 | 
				
			||||||
 | 
					        markerPos = int(20 + (100 - power) / 100 * barHeight)
 | 
				
			||||||
 | 
					        pygame.draw.rect(screen, (255, 0, 0), (screen.get_width() // 2 - barWidth, markerPos - 5, barWidth * 2, 10))
 | 
				
			||||||
 | 
					        pygame.display.flip()
 | 
				
			||||||
 | 
					        for event in pygame.event.get():
 | 
				
			||||||
 | 
					            check_for_exit()
 | 
				
			||||||
 | 
					            if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
 | 
				
			||||||
 | 
					                channel.stop()
 | 
				
			||||||
 | 
					                return power
 | 
				
			||||||
 | 
					        power += direction
 | 
				
			||||||
 | 
					        if power >= 100 or power <= 0:
 | 
				
			||||||
 | 
					            direction *= -1  # Reverse direction at limits
 | 
				
			||||||
 | 
					        clock.tick(40)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 calculate_volume_and_pan(player_pos, obj_pos):
 | 
				
			||||||
 | 
					    distance = abs(player_pos - obj_pos)
 | 
				
			||||||
 | 
					    max_distance = 12  # Maximum audible distance
 | 
				
			||||||
 | 
					    if distance > max_distance:
 | 
				
			||||||
 | 
					        return 0, 0, 0  # No sound if out of range
 | 
				
			||||||
 | 
					    # Calculate volume (non-linear scaling for more noticeable changes)
 | 
				
			||||||
 | 
					    volume = ((max_distance - distance) / max_distance) ** 1.5
 | 
				
			||||||
 | 
					    # Determine left/right based on relative position
 | 
				
			||||||
 | 
					    if player_pos < obj_pos:
 | 
				
			||||||
 | 
					        # Object is to the right
 | 
				
			||||||
 | 
					        left = max(0, 1 - (obj_pos - player_pos) / max_distance)
 | 
				
			||||||
 | 
					        right = 1
 | 
				
			||||||
 | 
					    elif player_pos > obj_pos:
 | 
				
			||||||
 | 
					        # Object is to the left
 | 
				
			||||||
 | 
					        left = 1
 | 
				
			||||||
 | 
					        right = max(0, 1 - (player_pos - obj_pos) / max_distance)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        # Player is on the object
 | 
				
			||||||
 | 
					        left = right = 1
 | 
				
			||||||
 | 
					    return volume, left, right
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def obj_play(sounds, soundName, player_pos, obj_pos):
 | 
				
			||||||
 | 
					    volume, left, right = calculate_volume_and_pan(player_pos, obj_pos)
 | 
				
			||||||
 | 
					    if volume == 0:
 | 
				
			||||||
 | 
					        return None  # Don't play if out of range
 | 
				
			||||||
 | 
					    # Play the sound on a new channel
 | 
				
			||||||
 | 
					    x = sounds[soundName].play(-1)
 | 
				
			||||||
 | 
					    # Apply the volume and pan
 | 
				
			||||||
 | 
					    x.set_volume(volume * left, volume * right)
 | 
				
			||||||
 | 
					    return x
 | 
				
			||||||
 | 
					def obj_update(x, player_pos, obj_pos):
 | 
				
			||||||
 | 
					    if x is None:
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					    volume, left, right = calculate_volume_and_pan(player_pos, obj_pos)
 | 
				
			||||||
 | 
					    if volume == 0:
 | 
				
			||||||
 | 
					        x.stop()
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					    # Apply the volume and pan
 | 
				
			||||||
 | 
					    x.set_volume(volume * left, volume * right)
 | 
				
			||||||
 | 
					    return x
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					def obj_stop(x):
 | 
				
			||||||
 | 
					    # Tries to stop a playing object channel
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        x.stop()
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					    except:
 | 
				
			||||||
 | 
					        return x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def play_ambiance(sounds, soundNames, probability, randomLocation = False):
 | 
				
			||||||
 | 
					    # Check if any of the sounds in the list is already playing
 | 
				
			||||||
 | 
					    for soundName in soundNames:
 | 
				
			||||||
 | 
					        if pygame.mixer.find_channel(True) and pygame.mixer.find_channel(True).get_busy():
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					    if random.randint(1, 100) > probability:
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    # Choose a random sound from the list
 | 
				
			||||||
 | 
					    ambianceSound = random.choice(soundNames)
 | 
				
			||||||
 | 
					    channel = sounds[ambianceSound].play()
 | 
				
			||||||
 | 
					    if randomLocation and channel:
 | 
				
			||||||
 | 
					        left_volume = random.random()
 | 
				
			||||||
 | 
					        right_volume = random.random()
 | 
				
			||||||
 | 
					        channel.set_volume(left_volume, right_volume)
 | 
				
			||||||
 | 
					    return channel  # Return the channel object for potential further manipulation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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"]) and (not f.lower().startswith("_"))]
 | 
				
			||||||
 | 
					    # 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:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            pygame.mixer.music.load("sounds/music_menu.ogg")
 | 
				
			||||||
 | 
					            pygame.mixer.music.set_volume(0.75)
 | 
				
			||||||
 | 
					            pygame.mixer.music.play(-1)
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					    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')
 | 
				
			||||||
@@ -5,4 +5,3 @@ pyxdg>=0.27
 | 
				
			|||||||
setproctitle>=1.2.0
 | 
					setproctitle>=1.2.0
 | 
				
			||||||
numpy>=1.19.0
 | 
					numpy>=1.19.0
 | 
				
			||||||
accessible-output2>=0.14
 | 
					accessible-output2>=0.14
 | 
				
			||||||
wxpython
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user