File size: 7,483 Bytes
390ca88
 
 
bd2a7ad
 
390ca88
 
a70ed2f
390ca88
 
bd2a7ad
 
 
390ca88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312acdf
390ca88
bd2a7ad
390ca88
 
 
 
 
a70ed2f
 
 
 
 
bd2a7ad
 
390ca88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312acdf
390ca88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312acdf
390ca88
 
 
 
 
 
 
 
 
312acdf
 
390ca88
bd2a7ad
 
390ca88
312acdf
390ca88
 
bd2a7ad
 
390ca88
 
bd2a7ad
312acdf
 
bd2a7ad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390ca88
 
 
 
 
 
 
a70ed2f
390ca88
 
 
 
 
bd2a7ad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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