def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.NO_BORDER): wx.Panel.__init__(self, parent, id=id, pos=pos, size=size, style=style) self.Viewport = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER) self.Scrollbar = wx.ScrollBar(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.SB_VERTICAL) sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(self.Viewport, 1, wx.EXPAND, 0) sizer.Add(self.Scrollbar, 0, wx.EXPAND, 0) self.SetSizer(sizer) self.Layout() sizer.Fit(self) self.Scrollbar.SetScrollbar(0, 0, 0, 0) self._presenter = Presenter.from_window(self.Viewport.GetHandle(), config.SCALE) self._camera = Camera(0, 0, 0, 0) self._tilemap = None self._tileset = None self._select_start = None self._select_end = None self._show_collision = False self.Viewport.Bind(wx.EVT_PAINT, self.paint) self.Viewport.Bind(wx.EVT_SIZE, self.resize) self.Viewport.Bind(wx.EVT_MOUSEWHEEL, self.mouse_wheel) self.Viewport.Bind(wx.EVT_LEFT_DOWN, self.mouse_left_down) self.Viewport.Bind(wx.EVT_LEFT_UP, self.mouse_left_up) self.Viewport.Bind(wx.EVT_MOTION, self.mouse_move) self.Scrollbar.Bind(wx.EVT_SCROLL, self.scroll)
SCREEN_HEIGHT = 720 HALF_SCREEN_WIDTH = SCREEN_WIDTH // 2 HALF_SCREEN_HEIGHT = SCREEN_HEIGHT // 2 if __name__ == "__main__": logging.basicConfig(format="[%(levelname)s @ %(name)s.%(funcName)s:%(lineno)s] %(message)s") window = pyglet.window.Window(SCREEN_WIDTH, SCREEN_HEIGHT) # create thread pool to allow async pathfinding pool = ThreadPoolExecutor(max_workers=2) generator = WorldGenerator(15, Vector2(100, 100), Vector2(300, 300), 50) # generate default world and dummy enemy world = generator.generate() camera = Camera(SCREEN_WIDTH, SCREEN_HEIGHT, 2) world.entities.append(EnemyEntity(world, Vector2(25, 25))) # enable player and give it the default Arrow Attack player = Player(world) player.skill = BowAttack() # add player, initialize labels world.entities.append(player) fps_display = FPSDisplay(window) fps_display.label.x += 200 support_display = Label("No Active Supports", font_size=12, x=window.width//2, y=12, anchor_x="center", anchor_y="center") score_display = Label("Score: ", font_size=12, x=window.width//2, y=24, anchor_x="center", anchor_y="center") @window.event def on_draw(): window.clear()
class TileSelector(wx.Panel): SelectEvent, EVT_SELECT_EVENT = wx.lib.newevent.NewEvent() def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.NO_BORDER): wx.Panel.__init__(self, parent, id=id, pos=pos, size=size, style=style) self.Viewport = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER) self.Scrollbar = wx.ScrollBar(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.SB_VERTICAL) sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(self.Viewport, 1, wx.EXPAND, 0) sizer.Add(self.Scrollbar, 0, wx.EXPAND, 0) self.SetSizer(sizer) self.Layout() sizer.Fit(self) self.Scrollbar.SetScrollbar(0, 0, 0, 0) self._presenter = Presenter.from_window(self.Viewport.GetHandle(), config.SCALE) self._camera = Camera(0, 0, 0, 0) self._tilemap = None self._tileset = None self._select_start = None self._select_end = None self._show_collision = False self.Viewport.Bind(wx.EVT_PAINT, self.paint) self.Viewport.Bind(wx.EVT_SIZE, self.resize) self.Viewport.Bind(wx.EVT_MOUSEWHEEL, self.mouse_wheel) self.Viewport.Bind(wx.EVT_LEFT_DOWN, self.mouse_left_down) self.Viewport.Bind(wx.EVT_LEFT_UP, self.mouse_left_up) self.Viewport.Bind(wx.EVT_MOTION, self.mouse_move) self.Scrollbar.Bind(wx.EVT_SCROLL, self.scroll) def set_tileset(self, tileset): self._tileset = tileset self.populate_tiles() self.Viewport.Refresh(False) def populate_tiles(self): if not self._tileset: self._tilemap.clear() surface = self._presenter.surface tiles_width = int(math.floor(surface.width / float(Tilemap.TILE_SIZE))) tiles_height = int(math.ceil(len(self._tileset.tiles) / float(tiles_width))) tiles = range(0, len(self._tileset.tiles)) self._tilemap = Tilemap(tiles, tiles_width, tiles_height) self._camera.set_max(tiles_width * Tilemap.TILE_SIZE, tiles_height * Tilemap.TILE_SIZE) self.Scrollbar.SetScrollbar(wx.VERTICAL, 0, surface.height, tiles_height, True) self.Scrollbar.SetThumbPosition(0) def resize(self, event): self._presenter.resize() surface = self._presenter.surface self._camera.set_size(surface.width, surface.height) if self._tileset: tiles_width = int(math.floor(surface.width / float(Tilemap.TILE_SIZE))) tiles_height = int(math.ceil((len(self._tileset.tiles) / tiles_width) * Tilemap.TILE_SIZE)) diff = int(tiles_height - surface.height) if diff: position = self.Scrollbar.GetThumbPosition() self.Scrollbar.SetScrollbar(position, surface.height, tiles_height, Tilemap.TILE_SIZE) else: self.Scrollbar.SetScrollbar(0, 0, 0, 0) def paint(self, event): if not self._tileset: return surface = self._presenter.surface surface.clear() self._camera.move_absolute(0, self.Scrollbar.GetThumbPosition()) self._tilemap.render(surface, self._camera, self._tileset, self._show_collision) if self._select_start: x1 = self._select_start[0] * Tilemap.TILE_SIZE y1 = self._select_start[1] * Tilemap.TILE_SIZE x2 = self._select_end[0] * Tilemap.TILE_SIZE y2 = self._select_end[1] * Tilemap.TILE_SIZE x1, y1 = self._camera.world_to_camera(x1, y1) x2, y2 = self._camera.world_to_camera(x2, y2) if x2 < x1: x2, x1 = x1, x2 if y2 < y1: y2, y1 = y1, y2 width = x2 - x1 + Tilemap.TILE_SIZE height = y2 - y1 + Tilemap.TILE_SIZE surface.box_fill(x1, y1, width, height, 0xFFFFFFFF, BlendOp.ALPHA50) self._presenter.present() def mouse_wheel(self, event): if not self._tileset: return position = self.Scrollbar.GetThumbPosition() position -= (event.GetWheelRotation() / 20) * Tilemap.TILE_SIZE self.Scrollbar.SetThumbPosition(position) self.Viewport.Refresh(False) def mouse_left_down(self, event): if not self._tileset: return if self._select_start: return pos = event.GetPosition() x, y = self.get_tile_position(pos) self._select_start = (x, y) self._select_end = self._select_start self.Viewport.Refresh(False) def mouse_left_up(self, event): if not self._tilemap: return if not self._select_end: return x1, y1 = self._select_start x2, y2 = self._select_end if x2 < x1: x2, x1 = x1, x2 if y2 < y1: y2, y1 = y1, y2 width = x2 - x1 + 1 height = y2 - y1 + 1 self._select_start = None self._select_end = None self.Viewport.Refresh(False) if width and height: selection = Tilemap.from_tilemap(self._tilemap, x1, y1, x2 + 1, y2 + 1) else: selection = None event = TileSelector.SelectEvent(selection=selection) wx.PostEvent(self.GetEventHandler(), event) def mouse_move(self, event): if not self._select_start: return pos = event.GetPosition() x, y = self.get_tile_position(pos) self._select_end = (x, y) self.Viewport.Refresh(False) def scroll(self, event): self.Viewport.Refresh(False) def get_tile_position(self, pos): x = pos[0] / self._presenter.scale y = pos[1] / self._presenter.scale x, y = self._camera.camera_to_world(x, y) x /= Tilemap.TILE_SIZE y /= Tilemap.TILE_SIZE return x, y def show_collision(self, show): self._show_collision = show self.Viewport.Refresh(False)
def start_game(config): # Loads game data, setups first map of the game then runs the main game loop. # Load all game data. tiles_data, generation_data, actor_data, item_data, animation_data = load_data( ) # Initialize map then generate a new map. current_map = Map(100, 100) start_x, start_y = generate_cave_map(current_map, generation_data, tiles_data, actor_data, item_data) # Initialize camera. camera = Camera(0, 0, config['camera_width'], config['camera_height'], 0, 0) # Spawn player. player_stats = { "hp": 100, "mp": 100, "starting_ap": 2, "max_ap": 10, "ap_recovery": 2, "base_damage": "1d4", "ac": 10, "hit": 4 } player = Actor(start_x, start_y, 'Player', '@', [255, 255, 255, 255]) player_inventory = Inventory(player) player.alive = Alive(player, player_stats, inventory=player_inventory) # Initialize FOV. fov = FOV(player, 5, current_map) under_mouse = None debug = False game_state = GameState.players_turn previous_state = None # Setup presets/containers for the game loop. actor_queue = PriorityQueue() actor_turns_left = False animations = [] no_block_animations = [] widgets = [] targeting_action = None terminal.refresh() while True: terminal.clear() if not debug: if current_map.tiles[player.x][player.y].is_stairs: player.x, player.y = generate_cave_map(current_map, generation_data, tiles_data, actor_data, item_data) current_map.depth += 1 render_all(player, current_map, fov, camera, under_mouse, animations, no_block_animations, widgets, targeting_action, game_state, config, animation_data) # Parse player input. action = handle_input(player, current_map, camera, fov, under_mouse, widgets, targeting_action, animations, no_block_animations, animation_data, game_state) under_mouse = get_under_mouse(player, current_map.tiles, current_map.actors, current_map.items, widgets, camera, game_state) # If an action was returned, complete that action. if isinstance(action, str): if action == 'restart': start_game(config) elif action == 'end-turn': if player.alive.check_in_combat(current_map.actors, fov): game_state = GameState.actors_turn elif action == 'toggle-inventory': if game_state == GameState.show_inventory: game_state = previous_state widgets = [] else: previous_state = game_state game_state = GameState.show_inventory fill_widgets(player, widgets, config, game_state) elif action == 'toggle-targeting': game_state = previous_state targeting_action = None elif action == 'toggle-map': if game_state == GameState.show_full_map: game_state = previous_state else: previous_state = game_state game_state = GameState.show_full_map elif action: if len(animations) == 0: if game_state == GameState.show_inventory: game_state = previous_state widgets = [] if action.item.targeting: previous_state = game_state game_state = GameState.targeting targeting_action = action elif game_state == GameState.targeting: game_state = previous_state targeting_action = None if game_state == GameState.players_turn: action.perform(animations, no_block_animations, animation_data) # Check if camera was moved, if it was, recalculate FOV. camera_moved = camera.move_camera(player.x, player.y, current_map) if camera_moved: fov.fov_recompute() # If player is in combat and out of ap, end the players turn. if player.alive.check_in_combat(current_map.actors, fov): if player.alive.get_ap(False) <= 0: game_state = GameState.actors_turn # Only continue if all animations have finished. if len(animations) == 0: # Go through all actors and let them take turns until # they are out of ap or decide not to take any actions. if game_state == GameState.actors_turn: # Fill the queue with actors that still need to take turns. if actor_queue.empty(): for actor in current_map.actors: if actor.alive and not actor.alive.turn_over and fov.in_fov( actor): actor_queue.put(actor, actor.alive.get_ap(False)) else: actor = actor_queue.get() if actor.alive: action = actor.alive.get_action( player, current_map, fov) if action: action.perform(animations, no_block_animations, animation_data) actor_turns_left = True else: actor.alive.turn_over = True # Player recovers ap at the end of the actors turn. if actor_queue.empty(): if not actor_turns_left: player.alive.recover_ap() game_state = GameState.players_turn for actor in current_map.actors: if actor.alive: actor.alive.turn_over = False actor_turns_left = False else: debug_render(player, current_map) # Parse player input. action = handle_input(player, current_map, camera) if action == 'restart': start_game(config) if action == 'debug': debug = not debug terminal.set("window: size='40x20', cellsize='24x24'") terminal.refresh()