2020-09-15 19:35:59 -04:00
#!/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 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 ( )
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 ( ( 320 , 200 ) )
pygame . display . set_caption ( gameTitle )
# Set 32 channels for sound by default
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 " ] ) ]
#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 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 ( )
2022-01-09 01:59:30 -05:00
webbrowser . open ( ' https://ko-fi.com/stormux ' )