--- a/pathological.py +++ b/pathological.py @@ -20,11 +20,15 @@ """ # Import Modules -import os, pygame, random, time, math, re, sys, hashlib +import asyncio, os, pygame, random, time, math, re, sys, hashlib from pygame.locals import * # Parse the command line -highscores_file = os.path.join(os.environ["HOME"], ".pathological_scores") +if os.path.isdir("/saves"): + # on the web the page keeps the /saves folder in the browser + highscores_file = "/saves/pathological_scores" +else: + highscores_file = os.path.join(os.environ.get("HOME", "."), ".pathological_scores") screenshot = 0 fullscreen = 0 colorblind = 0 @@ -187,11 +191,8 @@ def toggle_fullscreen(): global fullscreen - if pygame.display.toggle_fullscreen(): - fullscreen = fullscreen ^ 1 - return 1 - else: - return 0 + # Full screen is left to the web page, not the game + return 1 def toggle_sound(): global sound_on @@ -211,7 +212,7 @@ # A better tick function next_frame = pygame.time.get_ticks() -def my_tick( frames_per_sec): +async def my_tick( frames_per_sec): global next_frame # Wait for the next frame next_frame += 1000.0 / frames_per_sec @@ -221,7 +222,7 @@ # and keep going as fast as we can. next_frame = now else: - pygame.time.wait( int(next_frame) - now) + await asyncio.sleep( (int(next_frame) - now) / 1000.0) # Load the sounds def load_sounds(): @@ -467,7 +468,8 @@ if self.spinpos: return b1, b2, b3 = pygame.mouse.get_pressed() - if b3: + # (Shift + click also turns the wheel, for mice and trackpads without a right button) + if b3 or (pygame.key.get_mods() & KMOD_SHIFT): # First, make sure that no marbles are currently entering for i in self.marbles: if i == -1 or i == -2: return @@ -1377,7 +1379,7 @@ # 1: Level completed successfully # 2: User requested a skip to the next level # 3: User requested a skip to the previous level - def play_level( self): + async def play_level( self): # Perform the first render self.update() @@ -1393,7 +1395,7 @@ # Game Loop while not self.board_complete: # Wait for the next frame - my_tick( frames_per_sec) + await my_tick( frames_per_sec) # Handle Input Events for event in pygame.event.get(): @@ -1502,8 +1504,8 @@ except: print("Warning: Problem saving highscores.") -def wait_one_sec(): - time.sleep(1) +async def wait_one_sec(): + await asyncio.sleep(1) pygame.event.get() # Clear the event queue def popup( text, minsize=None): @@ -1605,7 +1607,7 @@ # 0: The game was aborted # 1: Game completed normally # 2: User achieved a highscore - def play(self): + async def play(self): # Draw the loading screen backdrop = load_image('backdrop.jpg', None, (screen_width, screen_height)) @@ -1622,7 +1624,7 @@ # Play a level board = Board( self, board_pos) - rc = board.play_level() + rc = await board.play_level() # Check for the user closing the window if rc == -4: return -1 @@ -1646,13 +1648,13 @@ self.lives -= 1 if self.lives > 0: - rc = self.board_dialog( message+'\nClick to try again.', + rc = await self.board_dialog( message+'\nClick to try again.', rc != -3) elif self.highscores.qualifies( self.score): popup("Congratulations!\n"+ "You have a highscore!\n"+ "Please enter your name:", (300, 180)) - name = get_name( self.screen, popup_font, + name = await get_name( self.screen, popup_font, ((screen_width-250)//2,310,250,popup_font.get_height()), (255,255,255), (0,0,0)) if name is None: return -1 @@ -1662,7 +1664,7 @@ return 2 else: - rc = self.board_dialog( message + + rc = await self.board_dialog( message + '\nGame Over.\nClick to continue\n', rc != -3) if rc == 1: return 1 @@ -1696,7 +1698,7 @@ "Bonus for " + repr(empty_holes) + "% holes empty: " + \ repr(holes_bonus) + '\nClick to continue.' - rc = self.board_dialog( message, 1, 1) + rc = await self.board_dialog( message, 1, 1) self.level += 1 if rc == -2: return -1 @@ -1707,13 +1709,13 @@ # -1: User pressed escape # 0: User pressed 'b' or 'n' # 1: Some other user event - def board_dialog( self, message, pause=1, complete=0): + async def board_dialog( self, message, pause=1, complete=0): popup(message) - if pause: wait_one_sec() + if pause: await wait_one_sec() # Wait for a mouse click to continue while 1: - pygame.time.wait(20) + await asyncio.sleep(0.02) for event in pygame.event.get(): if event.type == QUIT: return -2 @@ -1775,7 +1777,7 @@ elif key == ord("="): key = ord('+') return key -def get_name( screen, font, cursor_box, backcol, forecol): +async def get_name( screen, font, cursor_box, backcol, forecol): cursor_width = cursor_box[3] // 3 cursor_pos = [cursor_box[0], cursor_box[1], cursor_width, cursor_box[3]] name = "" @@ -1799,7 +1801,7 @@ # Keep track of the shift keys shift_state = pygame.key.get_mods() & KMOD_SHIFT - pygame.time.wait(20) + await asyncio.sleep(0.02) for event in pygame.event.get(): if event.type == QUIT: return None @@ -1927,8 +1929,7 @@ lt_r.top = self.menu_pos[1] self.screen.blit(levelt, lt_r) - if fullscreen: offon = 'On' - else: offon = 'Off' + offon = '-' # full screen is left to the web page offon = self.menu_font.render( offon, 1, self.menu_color) self.screen.blit( offon, (self.menu_pos[0]+self.menu_option_left, @@ -1988,7 +1989,7 @@ if IntroScreen.start_level > 1: IntroScreen.start_level -= 1 - def do(self, show_highscores=0): + async def do(self, show_highscores=0): self.scroller_pos = -self.scroller_rect[2] if( show_highscores): @@ -2002,7 +2003,7 @@ while 1: # Wait for the next frame - my_tick( frames_per_sec) + await my_tick( frames_per_sec) self.dirty_rects = [] self.draw_scroller() @@ -2012,7 +2013,7 @@ if self.scroller_pos >= self.scroller_image.get_rect().width: self.scroller_pos = -self.scroller_rect[2] - pygame.time.wait(20) + await asyncio.sleep(0.02) for event in pygame.event.get(): if event.type == QUIT: if self.curpage == 1: @@ -2211,27 +2212,36 @@ setup_everything() -# Main loop -show_highscores = 0 -while 1: - # Display the intro screen +async def main(): + global fullscreen + # Main loop + show_highscores = 0 while 1: - rc = introscreen.do( show_highscores) - if rc == -3: - # Warm restart to toggle fullscreen - fullscreen = fullscreen ^ 1 - setup_everything() - else: - break - - if rc < 0: break # Handle the QUIT message - - # If rc is positive, it's a level. - game = Game(screen, 'all-boards', highscores, rc - 1) - - show_highscores = 1 - - rc = game.play() - if rc < 0: break # Handle the QUIT message - if rc == 0: show_highscores = 0 - + # Display the intro screen + while 1: + rc = await introscreen.do( show_highscores) + if rc == -3: + # Warm restart to toggle fullscreen + fullscreen = fullscreen ^ 1 + setup_everything() + else: + break + + if rc < 0: + # Nothing to quit to on a web page: back to the menu + show_highscores = 0 + continue + + # If rc is positive, it's a level. + game = Game(screen, 'all-boards', highscores, rc - 1) + + show_highscores = 1 + + rc = await game.play() + if rc < 0: + # Nothing to quit to on a web page: back to the menu + show_highscores = 0 + continue + if rc == 0: show_highscores = 0 + +asyncio.run(main())