diff -urN a/code/allmodules.py b/code/allmodules.py --- a/code/allmodules.py +++ b/code/allmodules.py @@ -8,7 +8,7 @@ modules_string = """ game, gameplay, gamemenu, gamename, gamestart, gamesetup, gamewin, gamehelp, gamepause, gamepref, -gfx, snd, txt, hud, levels, main, input, score, +gfx, snd, txt, hud, levels, solarmain, input, score, objbox, objexplode, objguard, objpopshot, objtele, objship, objshot, objsmoke, objtext, objwarp, stars, objpowerup, objasteroid """ diff -urN a/code/game.py b/code/game.py --- a/code/game.py +++ b/code/game.py @@ -37,7 +37,6 @@ site_url = 'http://pygame.org/shredwheat/solarwolf' -news_url = 'http://pygame.org/shredwheat/solarwolf/thenews.html' @@ -101,7 +100,14 @@ def make_dataname(filename): - if os.name == 'posix': + if os.path.isdir('/saves'): + #on the web the page keeps the /saves folder in the browser + fullhome = '/saves/solarwolf' + if not os.path.isdir(fullhome): + try: os.mkdir(fullhome, 0o755) + except OSError: fullhome = '/saves' + filename = os.path.join(fullhome, filename) + elif os.name == 'posix': home = os.environ['HOME'] fullhome = os.path.join(home, '.solarwolf') if not os.path.isdir(fullhome): diff -urN a/code/gamecreds.py b/code/gamecreds.py --- a/code/gamecreds.py +++ b/code/gamecreds.py @@ -30,11 +30,6 @@ fonts.append((txt.Font(fontname, 30), (50, 120, 100))) fonts.append((txt.Font(fontname, 44), (100, 100, 250))) - img = gfx.load('oldsolarfox.png') - r = img.get_rect() - r.bottomright = gfx.rect.bottomright - images.append((img, r)) - img = gfx.load('pygame_powered.gif') r = img.get_rect().move(540, 20) images.append((img, r)) diff -urN a/code/gameinit.py b/code/gameinit.py --- a/code/gameinit.py 2026-11-04 23:08:00.007537897 -0300 +++ b/code/gameinit.py 2026-11-04 23:08:00.032157485 -0300 @@ -2,7 +2,7 @@ import pygame, pygame.draw from pygame.locals import * -import sys, threading +import sys import game, gfx, snd, txt, input load_total = 0 @@ -13,27 +13,36 @@ load_finished_module = '' load_finished_type = '' -def loadresources(): - global load_total, load_current +loading_done = False +loading_funcs = [] +loading_module = '' + +def startloading(): + "the original loaded in a background thread; a browser has none, so run() loads one module per frame" + global load_total, load_current, loading_funcs hunt = 'load_game_resources' - load_total = 0 load_current = 0 - allmods = sys.modules.values() - funcs = [(m.__name__, getattr(m, hunt)) for m in allmods if hasattr(m, hunt)] - load_total = len(funcs) - m = '' + allmods = list(sys.modules.values()) + loading_funcs = [(m.__name__, getattr(m, hunt)) for m in allmods if callable(getattr(m, hunt, None))] + load_total = len(loading_funcs) + +def loadnext(): + global load_current, loading_done, loading_module + global load_finished_status, load_finished_message, load_finished_module, load_finished_type + if not loading_funcs: + loading_done = True + return + loading_module, f = loading_funcs.pop(0) try: - for m, f in funcs: - if game.threadstop: break - load_current += 1 - f() + load_current += 1 + f() except: #raise - global load_finished_status, load_finished_message, load_finished_module, load_finished_type - load_finished_message = str(sys.exc_value) - load_finished_type = str(sys.exc_type) + ' in module ' + m + etype, evalue = sys.exc_info()[:2] + load_finished_message = str(evalue) + load_finished_type = str(etype) + ' in module ' + loading_module load_finished_status = -1 - game.thread = None + loading_done = True class GameInit: @@ -55,10 +64,7 @@ self.starttime = pygame.time.get_ticks() #self.gatherinfo() self.handlederror = 0 - self.thread = threading.Thread(None, loadresources) - game.threadstop = 0 - game.thread = self.thread - self.thread.start() + startloading() def gatherinfo(self): @@ -161,7 +167,9 @@ now = pygame.time.get_ticks() #we let the screen stay up for at about 1 second - if not self.thread.isAlive(): + if not loading_done: + loadnext() + if loading_done: if load_finished_status >= 0: if now-self.starttime > 1200: self.quit() diff -urN a/code/gamemenu.py b/code/gamemenu.py --- a/code/gamemenu.py +++ b/code/gamemenu.py @@ -7,7 +7,7 @@ import gfx, snd, txt import input import players -import gamecreds, gamenews, gamestart, gamepref +import gamecreds, gamestart, gamepref import gamewin @@ -35,10 +35,8 @@ menu = [ MenuItem('start', gamestart.preGameStart), - MenuItem('news', gamenews.GameNews), MenuItem('creds', gamecreds.GameCreds), MenuItem('setup', gamepref.GamePref), - MenuItem('quit', None), ] @@ -105,7 +103,10 @@ def starting(self): - snd.playmusic('aster2_sw.xm') + snd.playmusic('aster2_sw.ogg') + #the menu is where a game ends up: save the players and the preferences + players.save_players() + gamepref.save_prefs() gfx.dirty(gfx.surface.blit(self.logo, self.logorect)) gfx.dirty(gfx.surface.blit(self.bigship, self.bigshiprect)) @@ -113,8 +114,8 @@ self.fame = self.renderhall() def quit(self): - self.current = len(menu)-1 - self.workbutton() + #there is nothing to quit to on a web page + pass def renderhall(self): diff -urN a/code/gamename.py b/code/gamename.py --- a/code/gamename.py +++ b/code/gamename.py @@ -10,7 +10,6 @@ import players import gameplay import gamecreds -import gamenews charset = string.ascii_uppercase + '-.' diff -urN a/code/gameplay.py b/code/gameplay.py --- a/code/gameplay.py +++ b/code/gameplay.py @@ -12,7 +12,7 @@ import levels, hud, players -Songs = [('arg.xm', 1.0), ('h2.ogg', 0.6)] +Songs = [('arg.ogg', 1.0), ('h2.ogg', 0.6)] def load_game_resources(): snd.preload('gameover', 'startlife', 'levelskip', 'explode') diff -urN a/code/gamepref.py b/code/gamepref.py --- a/code/gamepref.py +++ b/code/gamepref.py @@ -12,7 +12,6 @@ Prefs = { "music": ("Off", "Low", "Normal"), "volume": ("Off", "Low", "Normal"), -"display": ("Window", "Fullscreen"), "comments": ("None", "Some", "Chatty"), "help": ("Full Screens", "Quick Comments"), "thruster": ("Normal", "Inverted"), diff -urN a/code/input.py b/code/input.py --- a/code/input.py 2026-11-04 23:08:00.020545169 -0300 +++ b/code/input.py 2026-11-04 23:08:00.045091132 -0300 @@ -204,7 +204,7 @@ if event.key == K_PRINT: if event.type == KEYDOWN: global ScreenshotNum - dir = os.environ.get('HOME', '.') + dir = '.' file = 'solarwolf%02d.bmp' % ScreenshotNum fullname = os.path.join(dir, file) print('Screenshot: {}'.format(fullname)) diff -urN a/code/main.py b/code/main.py --- a/code/main.py +++ b/code/main.py @@ -1,5 +1,6 @@ """main module, starts game and main loop""" +import asyncio import pygame import game, gfx, snd, txt, input import allmodules @@ -13,15 +14,15 @@ -def main(args): +async def main(args): try: - gamemain(args) + await gamemain(args) except KeyboardInterrupt: print('Keyboard Interrupt...') print('Exiting') -def gamemain(args): +async def gamemain(args): #initialize all our code (not load resources) pygame.init() game.clock = pygame.time.Clock() @@ -31,10 +32,9 @@ gamepref.load_prefs() size = 800, 600 - full = game.display - if '-window' in args: - full = 0 - gfx.initialize(size, full) + #a web page has no fullscreen switch of its own + game.display = 0 + gfx.initialize(size, 0) pygame.display.set_caption('SolarWolf') if not '-nosound' in args: @@ -49,13 +49,15 @@ from gamefinish import GameFinish game.handler = GameInit(GameFinish(None)) - #set timer to control stars.. - pygame.time.set_timer(pygame.USEREVENT, 1000) + #the original set a one second timer to control the stars; pygame.time.set_timer is not + #available on the web, so the loop below does it #psyco.full() gamestart = pygame.time.get_ticks() numframes = 0 + lastsave = gamestart + laststars = gamestart #random.seed(0) @@ -68,6 +70,10 @@ lasthandler = handler if hasattr(handler, 'starting'): handler.starting() + now = pygame.time.get_ticks() + if now - laststars >= 1000: + laststars = now + gfx.starobj.recalc_num_stars(game.clock.get_fps()) for event in pygame.event.get(): if event.type == pygame.USEREVENT: fps = game.clock.get_fps() @@ -85,11 +91,6 @@ else: game.handler.lostfocus() continue - if event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN: - if event.mod&pygame.KMOD_ALT: - game.display = not game.display - gfx.switchfullscreen() - continue inputevent = input.translate(event) if inputevent.normalized != None: inputevent = input.exclusive((input.UP, input.DOWN, input.LEFT, input.RIGHT), inputevent) @@ -99,12 +100,17 @@ break handler.event(event) handler.run() - game.clockticks = game.clock.tick(40) + #40 frames a second, without keeping the browser busy (Clock.tick(40) would block it) + game.clockticks = game.clock.tick() + await asyncio.sleep(max(0.0, 0.025 - game.clock.get_rawtime() / 1000.0)) #print 'ticks=%d rawticks=%d fps=%.2f'%(game.clock.get_time(), game.clock.get_rawtime(), game.clock.get_fps()) gfx.update() - while not pygame.display.get_active(): - pygame.time.wait(100) - pygame.event.pump() + #the player and preference files live in the browser: write them out now and then + now = pygame.time.get_ticks() + if now - lastsave > 5000: + lastsave = now + players.save_players() + gamepref.save_prefs() #pygame.time.wait(10) diff -urN a/solarwolf.py b/solarwolf.py --- a/solarwolf.py +++ b/solarwolf.py @@ -1,192 +1,22 @@ -#!/usr/bin/env python3 +import pygame """ Solarwolf, created by Pete Shinners. """ -import sys, os +import asyncio, sys, os +def setup(): + #the game lives next to this file (the web build unpacks it in a folder of its own) + here = os.path.dirname(os.path.abspath(__file__)) + os.chdir(here) + sys.path.insert(0, os.path.join(here, 'code')) -#these directories will be used if solarwolf cannot find -#the directories in the location of the main program -if sys.platform == "win32": - DATADIR = "C:\\Program Files\\Solarwolf" - CODEDIR = "C:\\Program Files\\Solarwolf\\code" -else: - DATADIR = "/usr/share/games/solarwolf" - CODEDIR = "/usr/lib/games/solarwolf" - - - -def main(): - #figure out our directories - global DATADIR, CODEDIR - localpath = os.path.split(os.path.abspath(sys.argv[0]))[0] - testdata = localpath - testcode = os.path.join(localpath, 'code') - if os.path.isdir(os.path.join(testdata, 'data')): - DATADIR = testdata - if os.path.isdir(testcode): - CODEDIR = testcode - - #apply our directories and test environment - os.chdir(DATADIR) - sys.path.insert(0, CODEDIR) - checkdependencies() - - #install pychecker if debugging - try: - import game - if game.DEBUG >= 2: - import pychecker.checker - print('Pychecker Enabled') - except ImportError as m: - pass - - #run game and protect from exceptions - try: - import main, pygame - main.main(sys.argv) - except KeyboardInterrupt: - print('Keyboard Interrupt (Control-C)...') - except: - #must wait on any threading - if game.thread: - game.threadstop = 1 - while game.thread: - pygame.time.wait(10) - print('waiting on thread...') - exception_handler() - if game.DEBUG: - raise - - - - -def checkdependencies(): - "only returns if everything looks ok" - msgs = [] - - #make sure this looks like the right directory - if not os.path.isdir(CODEDIR): - msgs.append('Cannot locate SolarWolf modules') - if not os.path.isdir('data'): - msgs.append('Cannot locate SolarWolf data files') - - #first, we need python >= 2.1 - if int(sys.version[0]) < 2: - errorbox('Requires Python-2.1 or Greater') - - #is correct pygame found? - try: - import pygame - if pygame.ver < '1.5.6': - msgs.append('Requires Pygame-1.5.6 or Greater, You Have ' + pygame.ver) - except ImportError: - msgs.append("Cannot import Pygame, install version 1.5.6 or higher") - pygame = None - - #check that we have FONT and IMAGE - if pygame: - if not pygame.font: - msgs.append('Pygame requires the SDL_ttf library, not available') - if not pygame.image or not pygame.image.get_extended(): - msgs.append('Pygame requires the SDL_image library, not available') - - if msgs: - msg = '\n'.join(msgs) - errorbox(msg) - - - -#Pretty Error Handling Code... - -def __windowsbox(title, message): - raise ImportError #the MessageBox command is crashing! - import win32ui, win32con - win32ui.MessageBox(message, title, win32con.MB_ICONERROR) - -def __wxpythonbox(title, message): - import wxPython.wx as wx - class LameApp(wx.wxApp): - def OnInit(self): return 1 - app = LameApp() - dlg = wx.wxMessageDialog(None, message, title, wx.wxOK|wx.wxICON_EXCLAMATION) - dlg.ShowModal() - dlg.Destroy() - -def __tkinterbox(title, message): - import Tkinter, tkMessageBox - Tkinter.Tk().wm_withdraw() - tkMessageBox.showerror(title, message) - -def __pygamebox(title, message): - try: - import pygame - pygame.quit() #clean out anything running - pygame.display.init() - pygame.font.init() - screen = pygame.display.set_mode((460, 140)) - pygame.display.set_caption(title) - font = pygame.font.Font(None, 18) - foreg, backg, liteg = (0, 0, 0), (180, 180, 180), (210, 210, 210) - ok = font.render('Ok', 1, foreg, liteg) - okbox = ok.get_rect().inflate(200, 10) - okbox.centerx = screen.get_rect().centerx - okbox.bottom = screen.get_rect().bottom - 10 - screen.fill(backg) - screen.fill(liteg, okbox) - screen.blit(ok, okbox.inflate(-200, -10)) - pos = [10, 10] - for text in message.split('\n'): - if text: - msg = font.render(text, 1, foreg, backg) - screen.blit(msg, pos) - pos[1] += font.get_height() - pygame.display.flip() - stopkeys = pygame.K_ESCAPE, pygame.K_SPACE, pygame.K_RETURN, pygame.K_KP_ENTER - while 1: - e = pygame.event.wait() - if e.type == pygame.QUIT or \ - (e.type == pygame.KEYDOWN and e.key in stopkeys) or \ - (e.type == pygame.MOUSEBUTTONDOWN and okbox.collidepoint(e.pos)): - break - pygame.quit() - except pygame.error: - raise ImportError - -handlers = __pygamebox, __tkinterbox, __wxpythonbox, __windowsbox - -def __showerrorbox(message): - title = os.path.splitext(os.path.split(sys.argv[0])[1])[0] - title = title.capitalize() + ' Error' - for e in handlers: - try: - e(title, message) - break - except (ImportError, NameError, AttributeError): - pass - -def errorbox(message): - message = str(message) - if not message: message = 'Error' - __showerrorbox(message) - sys.stderr.write('ERROR: ' + message + '\n') - raise SystemExit - -def exception_handler(): - import traceback - type, info, trace = sys.exc_info() - tracetop = traceback.extract_tb(trace)[-1] - tracetext = 'File %s, Line %d' % tracetop[:2] - if tracetop[2] != '?': - tracetext += ', Function %s' % tracetop[2] - exception_message = '%s:\n%s\n\n%s\n"%s"' - message = exception_message % (str(type), str(info), tracetext, tracetop[3]) - if type not in (KeyboardInterrupt, SystemExit): - __showerrorbox(message) - raise +async def main(): + setup() + import solarmain + await solarmain.main(sys.argv) -if __name__ == '__main__': main() +asyncio.run(main())