22
33import copy
44import random
5- from typing import Iterator , List , Tuple , TYPE_CHECKING
5+ from typing import Dict , Iterator , List , Tuple , TYPE_CHECKING
66
77import tcod
88
1515 import game .game_map
1616
1717
18+ max_items_by_floor = [
19+ (1 , 1 ),
20+ (4 , 2 ),
21+ ]
22+
23+ max_monsters_by_floor = [
24+ (1 , 2 ),
25+ (4 , 3 ),
26+ (6 , 5 ),
27+ ]
28+
29+ item_chances : Dict [int , List [Tuple [game .entity .Entity , int ]]] = {
30+ 0 : [(game .entity_factories .health_potion , 35 )],
31+ 2 : [(game .entity_factories .confusion_scroll , 10 )],
32+ 4 : [(game .entity_factories .lightning_scroll , 25 )],
33+ 6 : [(game .entity_factories .fireball_scroll , 25 )],
34+ }
35+
36+ enemy_chances : Dict [int , List [Tuple [game .entity .Entity , int ]]] = {
37+ 0 : [(game .entity_factories .orc , 80 )],
38+ 3 : [(game .entity_factories .troll , 15 )],
39+ 5 : [(game .entity_factories .troll , 30 )],
40+ 7 : [(game .entity_factories .troll , 60 )],
41+ }
42+
43+
44+ def get_max_value_for_floor (
45+ weighted_chances_by_floor : List [Tuple [int , int ]], floor : int
46+ ) -> int :
47+ current_value = 0
48+
49+ for floor_minimum , value in weighted_chances_by_floor :
50+ if floor_minimum > floor :
51+ break
52+ else :
53+ current_value = value
54+
55+ return current_value
56+
57+
58+ def get_entities_at_random (
59+ weighted_chances_by_floor : Dict [int , List [Tuple [game .entity .Entity , int ]]],
60+ number_of_entities : int ,
61+ floor : int ,
62+ ) -> List [game .entity .Entity ]:
63+ entity_weighted_chances = {}
64+
65+ for key , values in weighted_chances_by_floor .items ():
66+ if key > floor :
67+ break
68+ else :
69+ for value in values :
70+ entity = value [0 ]
71+ weighted_chance = value [1 ]
72+
73+ entity_weighted_chances [entity ] = weighted_chance
74+
75+ entities = list (entity_weighted_chances .keys ())
76+ entity_weighted_chance_values = list (entity_weighted_chances .values ())
77+
78+ chosen_entities = random .choices (
79+ entities , weights = entity_weighted_chance_values , k = number_of_entities
80+ )
81+
82+ return chosen_entities
83+
84+
1885class RectangularRoom :
1986 def __init__ (self , x : int , y : int , width : int , height : int ):
2087 self .x1 = x
@@ -60,40 +127,29 @@ def tunnel_between(
60127
61128
62129def place_entities (
63- room : RectangularRoom , dungeon : game .game_map .GameMap , maximum_monsters : int , maximum_items : int ,
130+ room : RectangularRoom , dungeon : game .game_map .GameMap , floor_number : int ,
64131) -> None :
65- number_of_monsters = random .randint (0 , maximum_monsters )
66- number_of_items = random .randint (0 , maximum_items )
67-
68- for _ in range (number_of_monsters ):
69- x = random .randint (room .x1 + 1 , room .x2 - 1 )
70- y = random .randint (room .y1 + 1 , room .y2 - 1 )
71-
72- if not any (entity .x == x and entity .y == y for entity in dungeon .entities ):
73- if random .random () < 0.8 :
74- monster = copy .deepcopy (game .entity_factories .orc )
75- else :
76- monster = copy .deepcopy (game .entity_factories .troll )
77-
78- monster .place (x , y , dungeon )
79-
80- for _ in range (number_of_items ):
132+ number_of_monsters = random .randint (
133+ 0 , get_max_value_for_floor (max_monsters_by_floor , floor_number )
134+ )
135+ number_of_items = random .randint (
136+ 0 , get_max_value_for_floor (max_items_by_floor , floor_number )
137+ )
138+
139+ monsters : List [game .entity .Entity ] = get_entities_at_random (
140+ enemy_chances , number_of_monsters , floor_number
141+ )
142+ items : List [game .entity .Entity ] = get_entities_at_random (
143+ item_chances , number_of_items , floor_number
144+ )
145+
146+ for entity in monsters + items :
81147 x = random .randint (room .x1 + 1 , room .x2 - 1 )
82148 y = random .randint (room .y1 + 1 , room .y2 - 1 )
83149
84150 if not any (entity .x == x and entity .y == y for entity in dungeon .entities ):
85- item_chance = random .random ()
86-
87- if item_chance < 0.7 :
88- item = copy .deepcopy (game .entity_factories .health_potion )
89- elif item_chance < 0.8 :
90- item = copy .deepcopy (game .entity_factories .fireball_scroll )
91- elif item_chance < 0.9 :
92- item = copy .deepcopy (game .entity_factories .confusion_scroll )
93- else :
94- item = copy .deepcopy (game .entity_factories .lightning_scroll )
95-
96- item .place (x , y , dungeon )
151+ entity_copy = copy .deepcopy (entity )
152+ entity_copy .place (x , y , dungeon )
97153
98154
99155def generate_dungeon (
@@ -102,8 +158,7 @@ def generate_dungeon(
102158 room_max_size : int ,
103159 map_width : int ,
104160 map_height : int ,
105- max_monsters_per_room : int ,
106- max_items_per_room : int ,
161+ current_floor : int ,
107162 engine : game .engine .Engine ,
108163) -> game .game_map .GameMap :
109164 """Generate a new dungeon map."""
@@ -138,7 +193,7 @@ def generate_dungeon(
138193 for x , y in tunnel_between (rooms [- 1 ].center , new_room .center ):
139194 dungeon .tiles [x , y ] = game .tiles .floor
140195
141- place_entities (new_room , dungeon , max_monsters_per_room , max_items_per_room )
196+ place_entities (new_room , dungeon , current_floor )
142197
143198 # Finally, append the new room to the list.
144199 rooms .append (new_room )
0 commit comments