--- a/bombman.py +++ b/bombman.py @@ -1,7 +1,7 @@ #!/usr/bin/env python2.7 # coding=utf-8 # -# Bombman - free and open-source Bomberman clone +# Blast Arena (originally Bombman) - free and open-source arena game # # Copyright (C) 2016 Miloslav Číž # @@ -71,6 +71,7 @@ # <0-9> - starting position of the player specified by the number import sys +import asyncio import pygame import os import math @@ -588,7 +589,7 @@ if chosen_disease[0] == Player.DISEASE_SWITCH_PLAYERS: if game_map != None: - players = filter(lambda p: not p.is_dead(), game_map.get_players()) + players = list(filter(lambda p: not p.is_dead(), game_map.get_players())) player_to_switch = self @@ -1394,7 +1395,7 @@ def update_danger_map(self): # reset the map: - self.danger_map = [map(lambda tile: 0 if tile.shouldnt_walk() else GameMap.SAFE_DANGER_VALUE, tile_row) for tile_row in self.tiles] + self.danger_map = [list(map(lambda tile: 0 if tile.shouldnt_walk() else GameMap.SAFE_DANGER_VALUE, tile_row)) for tile_row in self.tiles] for bomb in self.bombs: bomb_tile = bomb.get_tile_position() @@ -1855,10 +1856,10 @@ player_tile.item = None if player.is_in_air(): - if player.get_state_time() > Player.JUMP_DURATION / 2: # jump to destination tile in the middle of the flight + if player.get_state_time() > Player.JUMP_DURATION // 2: # jump to destination tile in the middle of the flight player.move_to_tile_center(player.get_jump_destination()) elif player.is_teleporting(): - if player.get_state_time() > Player.TELEPORT_DURATION / 2: + if player.get_state_time() > Player.TELEPORT_DURATION // 2: player.move_to_tile_center(player.get_teleport_destination()) elif player_tile.special_object == MapTile.SPECIAL_OBJECT_TRAMPOLINE and player.is_near_tile_center(): player.send_to_air(self) @@ -2472,7 +2473,7 @@ # check mouse control: if self.allow_mouse_control: - screen_center = (Renderer.get_screen_size()[0] / 2,Renderer.get_screen_size()[1] / 2) + screen_center = (Renderer.get_screen_size()[0] // 2,Renderer.get_screen_size()[1] // 2) mouse_position = pygame.mouse.get_pos(screen_center) pressed = pygame.mouse.get_pressed() @@ -2596,13 +2597,8 @@ self.sounds[SoundPlayer.SOUND_EVENT_EARTHQUAKE] = pygame.mixer.Sound(os.path.join(Game.RESOURCE_PATH,"earthquake.wav")) self.sounds[SoundPlayer.SOUND_EVENT_CONFIRM] = pygame.mixer.Sound(os.path.join(Game.RESOURCE_PATH,"confirm.wav")) - self.music_filenames = [ - "music_loyalty_freak_slow_pogo.wav", - "music_anonymous420_start_to_play.wav", - "music_anonymous420_first_step_for_your_tech.wav", - "music_anonymous420_echo_blues_effect.wav", - "music_loyalty_freak_music_enby.wav" - ] + # the music tracks of the original are not included in this version + self.music_filenames = [] self.current_music_index = -1 @@ -2620,6 +2616,9 @@ def set_music_volume(self, new_volume): self.music_volume = new_volume if new_volume > Settings.SOUND_VOLUME_THRESHOLD else 0 + + if len(self.music_filenames) == 0: + return debug_log("changing music volume to " + str(self.music_volume)) @@ -2644,6 +2643,9 @@ #---------------------------------------------------------------------------- def change_music(self): + if len(self.music_filenames) == 0: + return + while True: new_music_index = random.randint(0,len(self.music_filenames) - 1) @@ -2724,7 +2726,7 @@ def __init__(self, filename_prefix, start_number, end_number, filename_postfix, framerate = 10): self.framerate = framerate - self.frame_time = 1000 / self.framerate + self.frame_time = 1000 // self.framerate self.frame_images = [] @@ -2739,7 +2741,7 @@ def play(self, coordinates): # convert center coordinates to top left coordinates: - top_left = (coordinates[0] - self.frame_images[0].get_size()[0] / 2,coordinates[1] - self.frame_images[0].get_size()[1] / 2) + top_left = (coordinates[0] - self.frame_images[0].get_size()[0] // 2,coordinates[1] - self.frame_images[0].get_size()[1] // 2) self.playing_instances.append((top_left,pygame.time.get_ticks())) #---------------------------------------------------------------------------- @@ -3290,7 +3292,7 @@ helper_array = (PlayerKeyMaps.ACTION_UP,PlayerKeyMaps.ACTION_RIGHT,PlayerKeyMaps.ACTION_DOWN,PlayerKeyMaps.ACTION_LEFT,PlayerKeyMaps.ACTION_BOMB,PlayerKeyMaps.ACTION_SPECIAL) helper_action = helper_array[action_index] - self.waiting_for_key = (helper_index / 6,helper_action) + self.waiting_for_key = (helper_index // 6,helper_action) self.wait_for_release = True @@ -3306,7 +3308,7 @@ def __init__(self,sound_player): super(AboutMenu,self).__init__(sound_player) - self.text = ("^#2E44BFBombman^#FFFFFF - free Bomberman clone, ^#4EF259version " + Game.VERSION_STR + "\n" + self.text = ("^#2E44BFBlast Arena^#FFFFFF - free bomb-dropping arena game, ^#4EF259version " + Game.VERSION_STR + "\n" "Miloslav \"tastyfish\" Ciz, 2016\n\n" "This game is free software, published under CC0 1.0.\n") self.items = [["ok, nice, back"]] @@ -3462,8 +3464,8 @@ MAP_TILE_WIDTH = 50 ##< tile width in pixels MAP_TILE_HEIGHT = 45 ##< tile height in pixels - MAP_TILE_HALF_WIDTH = MAP_TILE_WIDTH / 2 - MAP_TILE_HALF_HEIGHT = MAP_TILE_HEIGHT / 2 + MAP_TILE_HALF_WIDTH = MAP_TILE_WIDTH // 2 + MAP_TILE_HALF_HEIGHT = MAP_TILE_HEIGHT // 2 PLAYER_SPRITE_CENTER = (30,80) ##< player's feet (not geometrical) center of the sprite in pixels BOMB_SPRITE_CENTER = (22,33) @@ -3497,8 +3499,8 @@ self.preview_map_name = "" self.preview_map_image = None - self.font_small = pygame.font.Font(os.path.join(Game.RESOURCE_PATH,"LibertySans.ttf"),Renderer.FONT_SMALL_SIZE) - self.font_normal = pygame.font.Font(os.path.join(Game.RESOURCE_PATH,"LibertySans.ttf"),Renderer.FONT_NORMAL_SIZE) + self.font_small = pygame.font.Font(os.path.join(Game.RESOURCE_PATH,"LiberationSans-Regular.ttf"),Renderer.FONT_SMALL_SIZE) + self.font_normal = pygame.font.Font(os.path.join(Game.RESOURCE_PATH,"LiberationSans-Regular.ttf"),Renderer.FONT_NORMAL_SIZE) self.previous_mouse_coordinates = (-1,-1) @@ -3669,7 +3671,7 @@ def update_screen_info(self): self.screen_resolution = Renderer.get_screen_size() - self.screen_center = (self.screen_resolution[0] / 2,self.screen_resolution[1] / 2) + self.screen_center = (self.screen_resolution[0] // 2,self.screen_resolution[1] // 2) self.map_render_location = Renderer.get_map_render_position() #---------------------------------------------------------------------------- @@ -3730,7 +3732,7 @@ @staticmethod def get_map_render_position(): screen_size = Renderer.get_screen_size() - return ((screen_size[0] - Renderer.MAP_BORDER_WIDTH * 2 - Renderer.MAP_TILE_WIDTH * GameMap.MAP_WIDTH) / 2,(screen_size[1] - Renderer.MAP_BORDER_WIDTH * 2 - Renderer.MAP_TILE_HEIGHT * GameMap.MAP_HEIGHT - 50) / 2) + return ((screen_size[0] - Renderer.MAP_BORDER_WIDTH * 2 - Renderer.MAP_TILE_WIDTH * GameMap.MAP_WIDTH) // 2,(screen_size[1] - Renderer.MAP_BORDER_WIDTH * 2 - Renderer.MAP_TILE_HEIGHT * GameMap.MAP_HEIGHT - 50) // 2) #---------------------------------------------------------------------------- @@ -3916,7 +3918,7 @@ y_step = font.get_height() + Renderer.MENU_LINE_SPACING for i in range(len(rendered_lines)): - result.blit(rendered_lines[i],(0 if not center else (width - rendered_lines[i].get_size()[0]) / 2,i * y_step)) + result.blit(rendered_lines[i],(0 if not center else (width - rendered_lines[i].get_size()[0]) // 2,i * y_step)) return result @@ -3973,7 +3975,7 @@ if self.menu_background_image == None: self.menu_background_image = pygame.image.load(os.path.join(Game.RESOURCE_PATH,"gui_menu_background.png")) - background_position = (self.screen_center[0] - self.menu_background_image.get_size()[0] / 2,self.screen_center[1] - self.menu_background_image.get_size()[1] / 2) + background_position = (self.screen_center[0] - self.menu_background_image.get_size()[0] // 2,self.screen_center[1] - self.menu_background_image.get_size()[1] // 2) profiler.measure_start("menu rend. backg.") result.blit(self.menu_background_image,background_position) @@ -4031,7 +4033,7 @@ y = self.screen_center[1] + Renderer.MENU_DESCRIPTION_Y_OFFSET if len(menu_to_render.get_text()) != 0: - result.blit(self.menu_item_images[0][1],(self.screen_center[0] - self.menu_item_images[0][1].get_size()[0] / 2,y)) # menu description text image is at index 0 + result.blit(self.menu_item_images[0][1],(self.screen_center[0] - self.menu_item_images[0][1].get_size()[0] // 2,y)) # menu description text image is at index 0 y += self.menu_item_images[0][1].get_size()[1] + Renderer.MENU_LINE_SPACING * 2 menu_items = menu_to_render.get_items() @@ -4041,9 +4043,9 @@ column_x_space = 150 if columns % 2 == 0: - xs = [self.screen_center[0] + i * column_x_space - ((columns - 1) * column_x_space / 2) for i in range(columns)] # even number of columns + xs = [self.screen_center[0] + i * column_x_space - ((columns - 1) * column_x_space // 2) for i in range(columns)] # even number of columns else: - xs = [self.screen_center[0] + (i - columns / 2) * column_x_space for i in range(columns)] + xs = [self.screen_center[0] + (i - columns // 2) * column_x_space for i in range(columns)] selected_coordinates = menu_to_render.get_selected_item() @@ -4079,13 +4081,13 @@ for i in range(min(Menu.MENU_MAX_ITEMS_VISIBLE,len(menu_items[j]) - menu_to_render.get_scroll_position())): item_image = self.menu_item_images[(j,i + menu_to_render.get_scroll_position())][1] - x = xs[j] - item_image.get_size()[0] / 2 + x = xs[j] - item_image.get_size()[0] // 2 if (i + menu_to_render.get_scroll_position(),j) == selected_coordinates: # item is selected scale = (8 + math.sin(pygame.time.get_ticks() / 40.0)) / 7.0 # make the pulsating effect item_image = pygame.transform.scale(item_image,(int(scale * item_image.get_size()[0]),int(scale * item_image.get_size()[1]))) - x = xs[j] - item_image.get_size()[0] / 2 + x = xs[j] - item_image.get_size()[0] // 2 pygame.draw.rect(result,(255,0,0),pygame.Rect(x - 4,y - 2,item_image.get_size()[0] + 8,item_image.get_size()[1] + 4)) result.blit(item_image,(x,y)) @@ -4113,16 +4115,16 @@ if menu_to_render.get_state() == Menu.MENU_STATE_CONFIRM_PROMPT: width = 120 height = 80 - x = self.screen_center[0] - width / 2 - y = self.screen_center[1] - height / 2 + x = self.screen_center[0] - width // 2 + y = self.screen_center[1] - height // 2 pygame.draw.rect(result,(0,0,0),pygame.Rect(x,y,width,height)) pygame.draw.rect(result,(255,255,255),pygame.Rect(x,y,width,height),1) text_image = pygame.transform.rotate(self.gui_images["prompt"],math.sin(pygame.time.get_ticks() / 100) * 5) - x = self.screen_center[0] - text_image.get_size()[0] / 2 - y = self.screen_center[1] - text_image.get_size()[1] / 2 + x = self.screen_center[0] - text_image.get_size()[0] // 2 + y = self.screen_center[1] - text_image.get_size()[1] // 2 result.blit(text_image,(x,y)) @@ -4158,7 +4160,7 @@ self.preview_map_name = map_filename tile_size = 7 - tile_half_size = tile_size / 2 + tile_half_size = tile_size // 2 map_info_border_size = 5 @@ -4282,7 +4284,7 @@ game_info_text = self.render_text(self.font_small,"game " + str(game_info[0]) + " of " + str(game_info[1]),(255,255,255)) - self.prerendered_map_background.blit(game_info_text,((self.prerendered_map_background.get_size()[0] - game_info_text.get_size()[0]) / 2,self.prerendered_map_background.get_size()[1] - game_info_text.get_size()[1])) + self.prerendered_map_background.blit(game_info_text,((self.prerendered_map_background.get_size()[0] - game_info_text.get_size()[0]) // 2,self.prerendered_map_background.get_size()[1] - game_info_text.get_size()[1])) self.prerendered_map = map_to_render @@ -4302,14 +4304,14 @@ return (None, (0,0), (0,0), False, []) sprite_center = Renderer.PLAYER_SPRITE_CENTER - animation_frame = (player.get_state_time() / 100) % 4 + animation_frame = (player.get_state_time() // 100) % 4 color_index = player.get_number() if game_map.get_state() == GameMap.STATE_WAITING_TO_PLAY else player.get_team_number() if player.is_in_air(): - if player.get_state_time() < Player.JUMP_DURATION / 2: - quotient = abs(player.get_state_time() / float(Player.JUMP_DURATION / 2)) + if player.get_state_time() < Player.JUMP_DURATION // 2: + quotient = abs(player.get_state_time() / float(Player.JUMP_DURATION // 2)) else: - quotient = 2.0 - abs(player.get_state_time() / float(Player.JUMP_DURATION / 2)) + quotient = 2.0 - abs(player.get_state_time() / float(Player.JUMP_DURATION // 2)) scale = (1 + 0.5 * quotient) @@ -4317,7 +4319,7 @@ image_to_render = pygame.transform.scale(player_image,(int(scale * player_image.get_size()[0]),int(scale * player_image.get_size()[1]))) draw_shadow = False - relative_offset[0] = -1 * (image_to_render.get_size()[0] / 2 - Renderer.PLAYER_SPRITE_CENTER[0]) # offset caused by scale + relative_offset[0] = -1 * (image_to_render.get_size()[0] // 2 - Renderer.PLAYER_SPRITE_CENTER[0]) # offset caused by scale relative_offset[1] = -1 * int(math.sin(quotient * math.pi / 2.0) * Renderer.MAP_TILE_HEIGHT * GameMap.MAP_HEIGHT) # height offset elif player.is_teleporting(): @@ -4354,7 +4356,7 @@ def __get_bomb_render_info(self, bomb, game_map): profiler.measure_start("map rend. bomb") sprite_center = Renderer.BOMB_SPRITE_CENTER - animation_frame = (bomb.time_of_existence / 100) % 4 + animation_frame = (bomb.time_of_existence // 100) % 4 relative_offset = [0,0] overlay_images = [] @@ -4373,7 +4375,7 @@ int(bomb.flight_info.direction[0] * helper_offset * Renderer.MAP_TILE_WIDTH), int(bomb.flight_info.direction[1] * helper_offset * Renderer.MAP_TILE_HALF_HEIGHT)] - relative_offset[1] -= int(math.sin(normalised_distance_travelled * math.pi) * bomb.flight_info.total_distance_to_travel * Renderer.MAP_TILE_HEIGHT / 2) # height in air + relative_offset[1] -= int(math.sin(normalised_distance_travelled * math.pi) * bomb.flight_info.total_distance_to_travel * Renderer.MAP_TILE_HEIGHT // 2) # height in air image_to_render = self.bomb_images[animation_frame] @@ -4424,7 +4426,7 @@ line_number = 0 object_to_render_index = 0 - flame_animation_frame = (pygame.time.get_ticks() / 100) % 2 + flame_animation_frame = (pygame.time.get_ticks() // 100) % 2 for line in tiles: x = (GameMap.MAP_WIDTH - 1) * Renderer.MAP_TILE_WIDTH + Renderer.MAP_BORDER_WIDTH + self.map_render_location[0] @@ -4534,11 +4536,11 @@ profiler.measure_stop("map rend. earthquake") if map_to_render.get_state() == GameMap.STATE_WAITING_TO_PLAY: - third = GameMap.START_GAME_AFTER / 3 + third = GameMap.START_GAME_AFTER // 3 - countdown_image_index = max(3 - map_to_render.get_map_time() / third,1) + countdown_image_index = max(3 - map_to_render.get_map_time() // third,1) countdown_image = self.gui_images["countdown"][countdown_image_index] - countdown_position = (self.screen_center[0] - countdown_image.get_size()[0] / 2,self.screen_center[1] - countdown_image.get_size()[1] / 2) + countdown_position = (self.screen_center[0] - countdown_image.get_size()[0] // 2,self.screen_center[1] - countdown_image.get_size()[1] // 2) result.blit(countdown_image,countdown_position) @@ -4587,7 +4589,7 @@ def decide_general_direction(self): players = self.game_map.get_players() - enemy_players = filter(lambda p: p.is_enemy(self.player) and not p.is_dead(), players) + enemy_players = list(filter(lambda p: p.is_enemy(self.player) and not p.is_dead(), players)) enemy_player = enemy_players[0] if len(enemy_players) > 0 else self.player my_tile_position = self.player.get_tile_position() @@ -5087,7 +5089,8 @@ RESOURCE_PATH = "resources" MAP_PATH = "maps" - SETTINGS_FILE_PATH = "settings.txt" + # on the web the page keeps the /saves folder in the browser + SETTINGS_FILE_PATH = "/saves/settings.txt" if os.path.isdir("/saves") else "settings.txt" #---------------------------------------------------------------------------- @@ -5112,7 +5115,7 @@ self.settings.save_to_file(Game.SETTINGS_FILE_PATH) # save the reformatted settings file (or create a new one) - pygame.display.set_caption("Bombman") + pygame.display.set_caption("Blast Arena") self.renderer = Renderer() self.apply_screen_settings() @@ -5190,7 +5193,7 @@ self.screen = pygame.display.set_mode(self.settings.screen_resolution,display_flags) - screen_center = (Renderer.get_screen_size()[0] / 2,Renderer.get_screen_size()[1] / 2) + screen_center = (Renderer.get_screen_size()[0] // 2,Renderer.get_screen_size()[1] // 2) pygame.mouse.set_pos(screen_center) self.renderer.update_screen_info() @@ -5347,7 +5350,7 @@ #---------------------------------------------------------------------------- - def run(self): + async def run(self): time_before = pygame.time.get_ticks() show_fps_in = 0 @@ -5439,7 +5442,9 @@ self.sound_player.change_music() self.state = Game.STATE_PLAYING elif self.state == Game.STATE_EXIT: - break + # a web page has nothing to quit to: back to the main menu + self.active_menu.leaving() + self.state = Game.STATE_MENU_MAIN else: # in menu self.manage_menus() @@ -5448,7 +5453,8 @@ profiler.measure_stop("menu rend.") pygame.display.flip() - pygame_clock.tick() + pygame_clock.tick(60) + await asyncio.sleep(0) if show_fps_in <= 0: if DEBUG_FPS: @@ -5473,7 +5479,8 @@ def filter_out_disallowed_actions(self, actions): player_slots = self.play_setup.get_slots() - result = filter(lambda a: (player_slots[a[0]] != None and player_slots[a[0]] >=0) or (a[1] == PlayerKeyMaps.ACTION_MENU), actions) + # (Python 2 also compared the slot tuple with 0, which is always true) + result = list(filter(lambda a: (player_slots[a[0]] != None) or (a[1] == PlayerKeyMaps.ACTION_MENU), actions)) return result #---------------------------------------------------------------------------- @@ -5543,4 +5550,4 @@ elif "--test3" in sys.argv: game.setup_test_game(2) - game.run() + asyncio.run(game.run())