File size: 6,986 Bytes
390ca88
 
 
bd2a7ad
 
390ca88
 
 
 
bd2a7ad
 
 
390ca88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bd2a7ad
390ca88
 
 
 
 
 
bd2a7ad
 
390ca88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bd2a7ad
 
390ca88
bd2a7ad
390ca88
 
bd2a7ad
 
390ca88
 
bd2a7ad
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
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.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.door_pos = [48, 48]  # Door to next level at far end
        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_y] = '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'
        terrain[self.door_pos[1]][self.door_pos[0]] = 'd'  # 'd' for door
        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):
        # Center the visible 10x10 area around the player
        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)

        # Pad with empty space if near edges
        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 (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'

        return {'terrain': visible_terrain, 'entities': visible_entities}

    def get_game_state(self):
        visible = self.get_visible_area()
        return {
            'terrain': visible['terrain'],
            'entities': visible['entities'],
            'health': self.player_health,
            'inventory': self.inventory,
            'attack': self.player_attack,
            'level': self.level
        }

    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.terrain = self.generate_maze()
        self.player_pos = [1, 1]
        self.player_health = 10
        self.monsters = self.generate_monsters()
        self.items = self.generate_items()
        self.door_pos = [48, 48]

    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