def start(self): self.tileset = Tilesheet("tileset.png", 24, 24) #Tileset self.tilemap = Tilemap(self.tileset, 32, 32) #On-screen tiles self._generate_map() self.turn = 0 self.turn_player = 0 self.victorious_side = None self.quit_popup = False self.red_cursor = [ 0, 19] self.blu_cursor = [13, 31] self.red_charge_wall = 0 self.red_charge_floor = 0 self.blu_charge_wall = 0 self.blu_charge_floor = 0 self.red_points = 0 self.blu_points = 0 self.red_image = pygame.Surface((8 * 24 + 3, 4 * 24 + 3)) self.blu_image = pygame.Surface((8 * 24 + 3, 4 * 24 + 3)) self._prerender_popups() self._update_status()
class PegMode(Mode): def start(self): self.tileset = Tilesheet("tileset.png", 24, 24) #Tileset self.tilemap = Tilemap(self.tileset, 32, 32) #On-screen tiles self._generate_map() self.turn = 0 self.turn_player = 0 self.victorious_side = None self.quit_popup = False self.red_cursor = [ 0, 19] self.blu_cursor = [13, 31] self.red_charge_wall = 0 self.red_charge_floor = 0 self.blu_charge_wall = 0 self.blu_charge_floor = 0 self.red_points = 0 self.blu_points = 0 self.red_image = pygame.Surface((8 * 24 + 3, 4 * 24 + 3)) self.blu_image = pygame.Surface((8 * 24 + 3, 4 * 24 + 3)) self._prerender_popups() self._update_status() def _prerender_popups(self): font = pygame.font.Font(None, 32) text = font.render("Really quit (Y/Esc)?", 1, (230, 230, 50)) textpos = text.get_rect() self.quit_image = pygame.Surface((textpos[2], textpos[3])) self.quit_image.blit(text, textpos) text1 = font.render("Red player wins!", 1, RED_RED ) text2 = font.render("Blue player wins!", 1, BLU_BLUE) textpos = text1.get_rect(left=3, top=3) self.victory_image_red = pygame.Surface((textpos[2] + 6, textpos[3] + 6)) self.victory_image_blu = pygame.Surface((textpos[2] + 6, textpos[3] + 6)) self.victory_image_red.fill(RED_RED) self.victory_image_red.fill((0,0,0), textpos) self.victory_image_red.blit(text1, textpos) self.victory_image_blu.fill(BLU_BLUE) self.victory_image_blu.fill((0,0,0), textpos) self.victory_image_blu.blit(text2, textpos) def _generate_map(self, mode = MAP_MODE_ASYMMETRICAL): tiles = gen_list2d(32, 32) density_sectors = [ [10, 10, 10, 9, 6, 4, 3, 1], [10, 10, 7, 6, 8, 3, 2], [10, 9, 3, 5, 2, 3], [ 9, 7, 8, 3, 2], [ 4, 3, 2, 1], [ 0, 1, 6], [ 1, 4], [ 8] ] #Mirror the density sectors for y, row in enumerate(density_sectors): for x in range(len(row), 8): d = density_sectors[7-x][7-y] density_sectors[y] += [d] self.goals = ( (30, 1), (16, 15), (10, 8), (31 - 8, 31 - 10), (18, 1), (31 - 1, 31 - 18) ) RED_BASE_POS = (0, 21) BLU_BASE_POS = (31 - 21, 31) for x in range(32): for y in range(32): #Upper left and bottom right fills if (x + y <= 15) or ((31-x) + (31-y) <= 15): tiles[x][y] = T_OBSTACLE #Lower left corner fill elif (x + (32-y) <= 5): tiles[x][y] = T_OBSTACLE elif (x, y) == RED_BASE_POS: tiles[x][y] = T_RED_BASE elif (x, y) == BLU_BASE_POS: tiles[x][y] = T_BLU_BASE elif (x, y) in self.goals: tiles[x][y] = T_GOAL elif (x > 1) and (y < 30): d = density_sectors[y // 4][x // 4] if random.randint(0, 15) <= d: tiles[x][y] = T_OBSTACLE else: tiles[x][y] = T_FLOOR #Some simple cellular automata magic to hopefully make the map nicer oldmap = [x[:] for x in tiles] for x in range(1, 30): for y in range(1, 30): if (x + y <= 15) or ((32-x) + (32-y) <= 15): continue elif (x + (32-y) <= 5): continue obstacle_count = 0 for (mx, my) in [(1, -1), (1, 0), (1, 1), (0, -1), (0, 1), (-1, -1), (-1, 0), (-1, 1)]: obstacle_count += int(oldmap[x+mx][y+my] == T_OBSTACLE) floor_count = 8 - obstacle_count d = density_sectors[y // 4][x // 4] if oldmap[x][y] == T_OBSTACLE: if random.randint(0, max(0, floor_count + d)) <= 3: tiles[x][y] = T_FLOOR elif oldmap[x][y] == T_FLOOR: if random.randint(0, obstacle_count + 10 - d) == 0: tiles[x][y] = T_OBSTACLE if mode == MAP_MODE_SYMMETRICAL: #Make the map symmetrical for x in range(0, 32): for y in range(0, 32 - x): if tiles[x][y] in [T_OBSTACLE, T_FLOOR, T_FLOOR2]: tiles[31 - y][31 - x] = tiles[x][y] #Surround the goals with immutable ground tiles for goal in self.goals: gx = goal[0] gy = goal[1] for x in range(gx - PROTECTED_RADIUS, gx + PROTECTED_RADIUS + 1): for y in range(gy - PROTECTED_RADIUS, gy + PROTECTED_RADIUS + 1): if (x < 0) or (x > 31) or (y < 0) or (y > 31): continue elif tiles[x][y] == T_FLOOR: tiles[x][y] = T_FLOOR2 self.tilemap.from_list(tiles) self._cast_paths() def _cast_paths(self): #Clear paths for x in range(32): for y in range(32): if self.tilemap.get_tile(x, y) in [T_BLU_PATH, T_RED_PATH, T_MIX_PATH]: self.tilemap.set_tile(x, y, T_FLOOR) if self.tilemap.get_tile(x, y) in [T_BLU_PATH2, T_RED_PATH2, T_MIX_PATH2]: self.tilemap.set_tile(x, y, T_FLOOR2) #Recalculate paths for x in range(32): for y in range(32): d = [ { "own_pegs": [T_BLU_BASE, T_BLU_PEG], "enemy_path": [T_RED_PATH, T_MIX_PATH], "enemy_path2": [T_RED_PATH2, T_MIX_PATH2], "own_path": T_BLU_PATH, "own_path2": T_BLU_PATH2, }, { "own_pegs": [T_RED_BASE, T_RED_PEG], "enemy_path": [T_BLU_PATH, T_MIX_PATH], "enemy_path2": [T_BLU_PATH2, T_MIX_PATH2], "own_path": T_RED_PATH, "own_path2": T_RED_PATH2, } ] for dataset in d: if self.tilemap.get_tile(x, y) in dataset["own_pegs"]: for direction in [(-1, 0), (1, 0), (0, -1), (0, 1)]: x2 = x + direction[0] y2 = y + direction[1] f_passable_tiles = lambda x, y: self.tilemap.get_tile(x2, y2) in PASSABLE_TILES while (x2 >= 0) and (x2 < 32) and (y2 >= 0) and (y2 < 32) and f_passable_tiles(x2, y2): if self.tilemap.get_tile(x2, y2) in dataset["enemy_path"]: ttype = T_MIX_PATH elif self.tilemap.get_tile(x2, y2) in dataset["enemy_path2"]: ttype = T_MIX_PATH2 elif self.tilemap.get_tile(x2, y2) == T_FLOOR2: ttype = dataset["own_path2"] elif self.tilemap.get_tile(x2, y2) == dataset["own_path2"]: ttype = dataset["own_path2"] else: ttype = dataset["own_path"] self.tilemap.set_tile(x2, y2, ttype) x2 += direction[0] y2 += direction[1] def place_peg(self, player, x, y): paths = ( [T_RED_PATH, T_RED_PATH2], [T_BLU_PATH, T_BLU_PATH2] )[player] + [T_MIX_PATH, T_MIX_PATH2] peg = (T_RED_PEG, T_BLU_PEG)[player] if self.tilemap.get_tile(x, y) in paths: self.tilemap.set_tile(x, y, peg) self._end_turn() return True return False def place_obstacle(self, player, x, y): for goal in self.goals: gx = goal[0] gy = goal[1] if x in range(gx - PROTECTED_RADIUS, gx + PROTECTED_RADIUS + 1): if y in range(gy - PROTECTED_RADIUS, gy + PROTECTED_RADIUS + 1): return False charge = (self.red_charge_wall, self.blu_charge_wall)[player] if charge == CHARGE_OBSTACLE: for d in [(-1, 0), ( 1, 0), ( 0,-1), ( 0, 1)]: x2, y2 = x + d[0], y + d[1] if x2 < 0 or x2 > 31 or y2 < 0 or y2 > 31: continue enemy_pegs = ( [T_RED_PEG, T_RED_BASE], [T_BLU_PEG, T_BLU_BASE], )[player ^ 1] if self.tilemap.get_tile(x2, y2) in enemy_pegs: return False if self.tilemap.get_tile(x, y) not in IMMUTABLE_TILES: self.tilemap.set_tile(x, y, T_OBSTACLE2) if player == P_RED: self.red_charge_wall = -1 else: self.blu_charge_wall = -1 self._end_turn() return True return False def place_floor(self, player, x, y): charge = (self.red_charge_floor, self.blu_charge_floor)[player] if charge == CHARGE_FLOOR: if self.tilemap.get_tile(x, y) not in IMMUTABLE_TILES: for x2 in range(x - 1, x + 2): for y2 in range(y - 1, y + 2): if x2 < 0 or x2 > 31 or y2 < 0 or y2 > 31: continue if self.tilemap.get_tile(x2, y2) == T_FLOOR: self.tilemap.set_tile(x2, y2, T_FLOOR2) self.tilemap.set_tile(x, y, T_FLOOR2) if player == P_RED: self.red_charge_floor = -1 else: self.blu_charge_floor = -1 self._end_turn() return True return False def _update_status(self): self.red_points = 0 self.blu_points = 0 for goal_pos in self.goals: red_scored = False blu_scored = False for direction in [(-1, 0), (1, 0), (0, -1), (0, 1)]: x = goal_pos[0] + direction[0] y = goal_pos[1] + direction[1] tile = self.tilemap.get_tile(x, y) if tile == T_RED_PEG and not red_scored: self.red_points += 1 red_scored = True elif tile == T_BLU_PEG and not blu_scored: self.blu_points += 1 blu_scored = True icon_y = int(2.5 * 24) icon1pos = int(3.5 * 24) icon2pos = int(5.0 * 24) icon3pos = int(6.5 * 24) black = (0, 0, 0) gray75 = (192, 192, 192) green = (0, 192, 0) color = RED_RED if (self.turn_player == 0) else gray75 self.red_image.fill(color) color = BLU_BLUE if (self.turn_player == 1) else gray75 self.blu_image.fill(color) self.red_image.fill(black, (0, 0, 8*24, 4*24)) self.blu_image.fill(black, (3, 3, 8*24, 4*24)) icons = [ [icon1pos, 1, 1, 1, T_ICON_RED_PEG, T_ICON_BLU_PEG], [icon2pos, self.red_charge_wall, self.blu_charge_wall, CHARGE_OBSTACLE, T_ICON_OBSTACLE, T_ICON_OBSTACLE], [icon3pos, self.red_charge_floor, self.blu_charge_floor, CHARGE_FLOOR, T_ICON_FLOOR, T_ICON_FLOOR], ] for icon in icons: red_charge = 1.0 - 1.0 * icon[1] / icon[3] blu_charge = 1.0 - 1.0 * icon[2] / icon[3] red_color = green if (self.turn_player == 0) else gray75 blu_color = green if (self.turn_player == 1) else gray75 red_y = icon_y - 2 + int(red_charge * 28) red_h = 28 - int(red_charge * 28) blu_y = icon_y - 2 + int(blu_charge * 28) blu_h = 28 - int(blu_charge * 28) self.red_image.fill(red_color, (icon[0] - 2, red_y, 28, red_h)) self.red_image.fill(black, (icon[0], icon_y, 24, 24)) self.blu_image.fill(blu_color, (icon[0] - 2 + 3, blu_y + 3, 28, blu_h)) self.blu_image.fill(black, (icon[0] + 3, icon_y + 3, 24, 24)) rect = self.tileset.get_tile_rect(icon[4]) self.red_image.blit(self.tileset.image, (icon[0], icon_y) , rect) rect = self.tileset.get_tile_rect(icon[5]) self.blu_image.blit(self.tileset.image, (icon[0]+3, icon_y+3) , rect) font = pygame.font.Font(None, 32) red_text = font.render("Player 1 - %ipts" % self.red_points, 1, RED_RED) red_textpos = red_text.get_rect(left=10, top=10) blu_text = font.render("Player 2 - %ipts" % self.blu_points, 1, BLU_BLUE) blu_textpos = blu_text.get_rect(left=13, top=13) self.red_image.blit(red_text, red_textpos) self.blu_image.blit(blu_text, blu_textpos) #TODO: Add key captions def _end_turn(self): self.turn += 1 self.turn_player ^= 1 if self.turn_player == 0: self.red_charge_wall = min(self.red_charge_wall + 1, CHARGE_OBSTACLE ) self.red_charge_floor = min(self.red_charge_floor + 1, CHARGE_FLOOR) self.blu_charge_wall = min(self.blu_charge_wall + 1, CHARGE_OBSTACLE ) self.blu_charge_floor = min(self.blu_charge_floor + 1, CHARGE_FLOOR) self._cast_paths() self._update_status() def _handle_input(self): pass def run(self, delta_time): if self.red_points > 3: self.victorious_side = P_RED if self.blu_points > 3: self.victorious_side = P_BLU if self.victorious_side is not None: if keyboard.just_pressed("escape"): self.parent.set_mode(MenuMode()) elif keyboard.just_pressed("enter"): self.parent.set_mode(MenuMode()) return if self.quit_popup: if keyboard.just_pressed("escape"): self.quit_popup = False elif keyboard.just_pressed("y"): self.parent.set_mode(MenuMode()) #elif keyboard.just_pressed("y"): self.parent.running = False return if keyboard.just_pressed("escape"): self.quit_popup = True return if keyboard.just_pressed("r") and self.turn == 0: self._generate_map() elif keyboard.just_pressed("t") and self.turn == 0: self._generate_map(mode=MAP_MODE_SYMMETRICAL) self._handle_input() def render(self, surface): surface.blit(self.tilemap.image, (0, 0)) color = (255, 0, 255) interval = 768 / 8 #Render cursors pos1 = (self.red_cursor[0] * 24, self.red_cursor[1] * 24) pos2 = (self.blu_cursor[0] * 24, self.blu_cursor[1] * 24) rect1 = self.tileset.get_tile_rect(T_CURSOR_RED) rect2 = self.tileset.get_tile_rect(T_CURSOR_BLU) rect3 = self.tileset.get_tile_rect(T_CURSOR_MIX) if pos1 == pos2: surface.blit(self.tileset.image, pos1, rect3) else: #Render RED cursor surface.blit(self.tileset.image, pos1, rect1) #Render BLU cursor surface.blit(self.tileset.image, pos2, rect2) surface.blit(self.red_image, (0, 0)) blu_status_pos = ( 768 - self.blu_image.get_width(), 768 - self.blu_image.get_height() ) surface.blit(self.blu_image, blu_status_pos) if self.victorious_side is not None: pos = ( (surface.get_width() - self.victory_image_red.get_width()) / 2, (surface.get_height() - self.victory_image_red.get_height()) / 2, ) if self.victorious_side == P_RED: surface.blit(self.victory_image_red, pos) else: surface.blit(self.victory_image_blu, pos) elif self.quit_popup: pos = ( (surface.get_width() - self.quit_image.get_width()) / 2, (surface.get_height() - self.quit_image.get_height()) / 2, ) surface.blit(self.quit_image, pos)