import random from flask_socketio import emit class Game: def __init__(self): self.map_size = 50 # Much larger dungeon self.visible_size = 10 # 10x10 visible area on screen self.door_pos = [48, 48] # Door to next level at far end - set before generating maze self.terrain = self.generate_maze() self.player_pos = [1, 1] # Start near top-left self.player_health = 10 self.player_attack = 2 self.inventory = [] self.monsters = self.generate_monsters() self.items = self.generate_items() self.level = 1 def generate_maze(self): # Simple recursive backtracking maze generation terrain = [['w' for _ in range(self.map_size)] for _ in range(self.map_size)] def carve(x, y): terrain[y][x] = 'f' directions = [(0, 2), (2, 0), (-2, 0), (0, -2)] # Right, Down, Left, Up (2 steps for corridors) random.shuffle(directions) for dx, dy in directions: nx, ny = x + dx, y + dy if (0 <= nx < self.map_size and 0 <= ny < self.map_size and terrain[ny][nx] == 'w'): mid_x, mid_y = x + dx // 2, y + dy // 2 terrain[mid_y][mid_x] = 'f' # Carve path carve(nx, ny) # Start carving from (1,1) to avoid edges carve(1, 1) # Ensure player start and door positions are accessible terrain[1][1] = 'f' if hasattr(self, 'door_pos'): # Safety check terrain[self.door_pos[1]][self.door_pos[0]] = 'd' # 'd' for door else: print("Warning: door_pos not set, using default [48, 48]") terrain[48][48] = 'd' # Fallback if door_pos is not set return terrain def generate_monsters(self): monsters = {} for _ in range(10): # 10 enemies (e.g., 5 goblins, 5 skeletons) while True: x, y = random.randint(2, self.map_size - 3), random.randint(2, self.map_size - 3) if self.terrain[y][x] == 'f' and (x, y) not in monsters and (x, y) != tuple(self.player_pos): monster_type = random.choice(['goblin', 'skeleton']) health = 5 if monster_type == 'goblin' else 6 attack = 1 if monster_type == 'goblin' else 2 monsters[(x, y)] = {'type': monster_type, 'health': health, 'attack': attack} break return monsters def generate_items(self): items = {} item_types = ['potion', 'sword'] for _ in range(5): # 5 items (e.g., 3 potions, 2 swords) while True: x, y = random.randint(2, self.map_size - 3), random.randint(2, self.map_size - 3) if self.terrain[y][x] == 'f' and (x, y) not in items and (x, y) not in self.monsters: items[(x, y)] = random.choice(item_types) break return items def get_visible_area(self): print("Generating visible area for player at:", self.player_pos) # Debug log px, py = self.player_pos half_size = self.visible_size // 2 start_x = max(0, px - half_size) start_y = max(0, py - half_size) end_x = min(self.map_size, px + half_size + 1) end_y = min(self.map_size, py + half_size + 1) visible_terrain = [['' for _ in range(self.visible_size)] for _ in range(self.visible_size)] visible_entities = [['' for _ in range(self.visible_size)] for _ in range(self.visible_size)] for y in range(start_y, end_y): for x in range(start_x, end_x): grid_y = y - (py - half_size) grid_x = x - (px - half_size) if 0 <= grid_y < self.visible_size and 0 <= grid_x < self.visible_size: visible_terrain[grid_y][grid_x] = self.terrain[y][x] if self.terrain[y][x] else 'f' # Default to 'f' if (x, y) == tuple(self.player_pos): visible_entities[grid_y][grid_x] = 'player' elif (x, y) in self.monsters: visible_entities[grid_y][grid_x] = self.monsters[(x, y)]['type'] elif (x, y) in self.items: visible_entities[grid_y][grid_x] = self.items[(x, y)] elif (x, y) == tuple(self.door_pos): visible_entities[grid_y][grid_x] = 'door' print("Visible terrain:", visible_terrain) # Debug log print("Visible entities:", visible_entities) # Debug log return {'terrain': visible_terrain, 'entities': visible_entities} def get_game_state(self): visible = self.get_visible_area() state = { 'terrain': visible['terrain'], 'entities': visible['entities'], 'health': self.player_health, 'inventory': self.inventory, 'attack': self.player_attack, 'level': self.level } print("Game state:", state) # Debug log return state def is_valid_position(self, x, y): return (0 <= x < self.map_size and 0 <= y < self.map_size and self.terrain[y][x] != 'w') def move_player(self, direction): dx, dy = {'up': (0, -1), 'down': (0, 1), 'left': (-1, 0), 'right': (1, 0)}[direction] new_x, new_y = self.player_pos[0] + dx, self.player_pos[1] + dy if self.is_valid_position(new_x, new_y): self.player_pos = [new_x, new_y] pos_tuple = tuple(self.player_pos) # Check for monster if pos_tuple in self.monsters: self.handle_combat(pos_tuple) # Check for item elif pos_tuple in self.items: item = self.items.pop(pos_tuple) self.inventory.append(item) if item == 'sword': self.player_attack += 1 emit('message', 'Picked up a sword! Attack increased.') else: emit('message', f'Picked up a {item}!') # Check for door elif pos_tuple == tuple(self.door_pos): self.level += 1 self.reset_level() emit('message', f'Entered Level {self.level}! New dungeon awaits.') def reset_level(self): self.door_pos = [48, 48] # Reset door position self.terrain = self.generate_maze() self.player_pos = [1, 1] self.player_health = 10 self.monsters = self.generate_monsters() self.items = self.generate_items() def handle_combat(self, pos): from flask_socketio import emit monster = self.monsters[pos] monster_health = monster['health'] while monster_health > 0 and self.player_health > 0: monster_health -= self.player_attack emit('message', f"You attack the {monster['type']} for {self.player_attack} damage.") if monster_health <= 0: emit('message', f"You defeated the {monster['type']}!") del self.monsters[pos] break self.player_health -= monster['attack'] emit('message', f"The {monster['type']} attacks you for {monster['attack']} damage.") if self.player_health <= 0: emit('message', 'Game over! You were defeated.') break