32 Commits

Author SHA1 Message Date
e1451f69b0 Started work on making this more library like. 2024-07-27 21:51:12 -04:00
401b2a8527 Merged with latest code from master. 2024-07-27 21:41:46 -04:00
428a48678d Power bars are now visual as well as audio. 2024-07-22 22:20:15 -04:00
9a6d6374f9 Added text along with the speak command. Updated window size. 2024-07-22 16:08:42 -04:00
df386cbbd9 Improved check_for_exit function. 2024-07-16 14:22:36 -04:00
38522aee78 First pass at creating requirements files. 2024-07-15 19:52:02 -04:00
0e9c52f5e1 A few fixes for x-powerbar, more accurately exiting when exit keys are pressed, etc. 2024-07-14 03:51:35 -04:00
fabf48ff42 Powerbars added and working. 2024-07-13 03:03:32 -04:00
0c73e98876 Improved sound while walking on left/right only. 2024-07-05 17:24:23 -04:00
0ef11785ec Revert "A new try at sound panning with walking."
This reverts commit 58ab5aa854.
2024-07-05 17:04:12 -04:00
58ab5aa854 A new try at sound panning with walking. 2024-06-20 02:03:06 -04:00
639198e8de Somewhat of a start on switching over to pyglet. It's in a very broken state with some remaining calls to pygame. 2022-03-27 00:59:07 -04:00
155ed6ec39 Updated donation link to use ko-fi. 2022-01-09 01:59:30 -05:00
68ad08be46 moved the libstormgames.py file to __init__.py so you can just import libstormgames. 2020-09-15 19:35:59 -04:00
536659338e Updated the object placement code code so that if sounds are out of range they still clame the channel, but they do not play at an audible level.[A 2020-09-10 18:02:53 -04:00
37aa764d68 Small update to object positioning. 2020-09-10 13:44:51 -04:00
84a722bb8e Attempt to fix object positioning. 2020-09-10 02:51:33 -04:00
b897abf0a3 Quickly jump to the top or bottom of the game menu with home or end keys. 2020-09-09 21:38:59 -04:00
678af54346 More work on the sound functions for object placement. 2020-09-09 20:55:40 -04:00
d456b8b3b3 Fixed a couple bugs on the object positioning code. 2020-09-09 20:41:41 -04:00
c5c32943e2 Added the rest of the object management functions, hopefully. 2020-09-09 20:06:34 -04:00
34d89ca54b Started work on sound positioning for objects. 2020-09-09 19:50:56 -04:00
e8bf4f9565 Scoreboard now works! Finally! 2020-09-04 11:17:05 -04:00
dd350c0285 Scoreboard still not saving past the first position. 2020-08-30 02:00:07 -04:00
ae93e02e69 Another approach to writing the scoreboard. 2020-08-30 01:41:52 -04:00
21c0795ea9 Updated scoreboard. 2020-08-30 01:23:32 -04:00
67d2315cef Finally fixed the scoreboard I think. 2020-08-29 22:11:06 -04:00
b6afb5450e New_High_Score method added. 2019-12-11 23:31:19 -05:00
42266d4b6c More progress on the scoreboard. Not complete yet. 2019-12-11 23:09:31 -05:00
54842bac29 Scoreboard mostly working. It doesn't read the existing scores correctly yet though. 2019-12-11 21:45:52 -05:00
08f06699c8 Merge branch 'devel'
Merged in set process name
2019-12-11 09:38:30 -05:00
7ef11be54c New scoreboard feature added. Partially implimented. 2019-12-11 09:32:50 -05:00
4 changed files with 275 additions and 24 deletions

View File

@ -0,0 +1,4 @@
#!/bin/python
# -*- coding: utf-8 -*-
from .libstormgames import *

View File

@ -15,6 +15,7 @@ import pyperclip
import random
import re
import requests
import textwrap
import webbrowser
# Global variable for speech provider
try:
@ -28,7 +29,8 @@ except ImportError:
except ImportError:
print("No other speech providers found.")
exit()
import math
import numpy as np
import time
localConfig = configparser.ConfigParser()
@ -37,39 +39,116 @@ globalConfig = configparser.ConfigParser()
class scoreboard():
'Handles scores and top 10'
def __init__(self):
def __init__(self, startingScore = 0):
read_config()
try:
localConfig.add_section("scoreboard")
except:
pass
self.score = startingScore
self.oldScores = []
for i in range(9):
for i in range(1, 11):
try:
self.oldScores[i] = read_config("scoreboard", i)
self.oldScores.insert(i - 1, localConfig.getint("scoreboard", str(i)))
except:
self.oldScores[i] = 0
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:
with open(gamePath + "/config.ini", 'w') as configfile:
localConfig.write(configfile)
else:
with open(globalPath + "config.ini", 'w') as configfile:
with open(globalPath + "/config.ini", 'w') as configfile:
globalConfig.write(configfile)
def read_config(section, value, readGlobal = False):
def read_config(readGlobal = False):
if readGlobal == False:
with open(gamePath + "config.ini", 'r') as configfile:
return localConfig.read(section, value)
try:
with open(gamePath + "/config.ini", 'r') as configfile:
localConfig.read_file(configfile)
except:
pass
else:
with open(globalPath + "config.ini", 'r') as configfile:
return globalConfig.read(section, value)
try:
with open(globalPath + "/config.ini", 'r') as configfile:
globalConfig.read_file(configfile)
except:
pass
def speak(text, interupt = True):
def speak(text, interupt=True):
if speechProvider == "speechd":
if interupt == True: spd.cancel()
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()
@ -93,15 +172,20 @@ def initialize_gui(gameTitle):
# start pygame
pygame.init()
# start the display (required by the event loop)
pygame.display.set_mode((320, 200))
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 that {'bottle': 'bottle.ogg'}
soundFiles = [f for f in listdir("sounds/") if isfile(join("sounds/", f)) and (f.split('.')[1].lower() in ["ogg","wav"])]
# 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:
@ -110,6 +194,76 @@ def initialize_gui(gameTitle):
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()
@ -121,6 +275,72 @@ def cut_scene(sounds, soundName):
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():
@ -179,7 +399,7 @@ def display_text(text):
speak("Failed to copy the text to the clipboard.")
if event.key == pygame.K_t:
try:
pyperclip.copy(''.join(text[1:-1]))
pyperclip.copy(' '.join(text[1:-1]))
speak("Copied entire message to the clipboard.")
except:
speak("Failed to copy the text to the clipboard.")
@ -190,7 +410,7 @@ 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"])]
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:
@ -221,12 +441,16 @@ def learn_sounds(sounds):
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)
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
@ -251,6 +475,20 @@ def game_menu(sounds, *options):
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
@ -270,4 +508,4 @@ def game_menu(sounds, *options):
def donate():
pygame.mixer.music.pause()
webbrowser.open('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=stormdragon2976@gmail.com&lc=US&item_name=Donation+to+Storm+Games&no_note=0&cn=&currency_code=USD&bn=PP-DonationsBF:btn_donateCC_LG.gif:NonHosted')
webbrowser.open('https://ko-fi.com/stormux')

7
requirements.txt Normal file
View File

@ -0,0 +1,7 @@
pygame>=2.0.0
pyperclip>=1.8.0
requests>=2.25.0
pyxdg>=0.27
setproctitle>=1.2.0
numpy>=1.19.0
accessible-output2>=0.14

2
requirements_linux.txt Normal file
View File

@ -0,0 +1,2 @@
-r requirements.txt
python-speechd>=0.11.1